aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorcolin <colin@cicadas.surf>2023-11-12 12:07:41 -0800
committercolin <colin@cicadas.surf>2023-11-12 12:07:41 -0800
commita8fd8ff49a95e610c3cd38aba02ee28129d4d881 (patch)
treed1fd74ac58b6a351c2b90575510f5f7af28b441c
parent9ab26f07d209a387252a87dc10e986995bbc154a (diff)
committing what I've got
-rw-r--r--INSTALL.md2
-rw-r--r--README.md9
-rw-r--r--README.org14
-rw-r--r--about.lisp23
-rw-r--r--build/build.lisp (renamed from build.lisp)5
-rw-r--r--definition-macros.lisp19
-rw-r--r--explore.lisp46
-rw-r--r--home.lisp166
-rw-r--r--login.lisp32
-rw-r--r--model.lisp187
-rw-r--r--navigation.lisp11
-rw-r--r--new-account.lisp75
-rw-r--r--playlist.lisp544
-rw-r--r--session.lisp33
-rw-r--r--src/api.lisp191
-rw-r--r--src/config.lisp38
-rw-r--r--src/downloader.lisp (renamed from downloader.lisp)19
-rw-r--r--src/hunchentoot/handle-static-file-monkeypatch.lisp (renamed from hunchentoot-handle-static-file.lisp)0
-rw-r--r--src/log.lisp10
-rw-r--r--src/logger.lisp10
-rw-r--r--src/mailbox.lisp17
-rw-r--r--src/model.lisp260
-rw-r--r--src/package.lisp (renamed from package.lisp)9
-rw-r--r--src/run.lisp (renamed from run.lisp)0
-rw-r--r--src/session.lisp16
-rw-r--r--src/site.lisp26
-rw-r--r--src/utilities.lisp (renamed from utilities.lisp)54
-rw-r--r--src/vampire.lisp46
-rw-r--r--src/zipper.lisp (renamed from zipper.lisp)0
-rw-r--r--static/boot.html17
-rw-r--r--static/bootstrap.html19
-rw-r--r--static/config.sexp (renamed from config.lisp)0
-rw-r--r--static/css/main-2.css101
-rw-r--r--static/css/main-3.css150
-rw-r--r--static/css/main-4.css165
-rw-r--r--static/css/main.css73
-rw-r--r--static/css/reset.css2
-rw-r--r--static/debug.html18
-rw-r--r--static/favicon.icobin958 -> 0 bytes
-rw-r--r--static/js/boot.js121
-rw-r--r--static/js/jquery-ui.js19057
-rw-r--r--static/js/jquery.min.js2
-rw-r--r--style.lisp8
-rw-r--r--vampire.asd38
-rw-r--r--vampire.lisp74
45 files changed, 697 insertions, 21010 deletions
diff --git a/INSTALL.md b/INSTALL.md
index c2b6a17..3161f89 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -14,8 +14,6 @@ Install ffmpeg
sudo apt-get install ffmpeg
-
-
# BUILDING
I have only tested vampire using SBCL on Linux.
diff --git a/README.md b/README.md
deleted file mode 100644
index 7bc5900..0000000
--- a/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# vampire
-### _Your Name <your.name@example.com>_
-
-This is a project to do ... something.
-
-## License
-
-Specify license here
-
diff --git a/README.org b/README.org
deleted file mode 100644
index 1858e94..0000000
--- a/README.org
+++ /dev/null
@@ -1,14 +0,0 @@
-* 🧛 Vampire 🧛
-
-Vampire is a web based tool for collaborative creation of
-playlists. You can edit and arrange playlists in real time with your
-collaborators. It is meant to be self-hosted and shared by small
-groups of friends.
-
-Vampire was built with love in [[https://common-lisp.net/][Common Lisp]]. It uses the excellent [[https://github.com/rabbibotton/clog][CLOG]]
-system for its front end, and the easy-as-pie object prevelence system
-system [[https://github.com/sharplispers/bknr.datastore][BKNR.DATASTORE]] for its backend.
-
-To build and deploy, see the INSTALL file in this repository.
-
-
diff --git a/about.lisp b/about.lisp
deleted file mode 100644
index 1eb42aa..0000000
--- a/about.lisp
+++ /dev/null
@@ -1,23 +0,0 @@
-;;;; about.lisp -- an about page.
-
-(in-package :vampire)
-
-(defun about-page (body)
- (include-style body)
- (with-clog-create body
- (div ()
- (navigation-header ())
- (div (:class "centered-column")
- (div ())
- (div ()
- (p ( :content "Vampire is a small private app shared
- between friends. Its purpose is to create and share audio playlists,
- and to collaborate on playlists with your friends in real time."))
- (p ( :content "The app is called vampire because it sucks
- content from other sources, backed by the popular
- youtube-dl tool."))
-
- (p ( :content "Vampire is written in Common Lisp using the
- CLOG system."))
- (p ( :content "I hope you enjoy using Vampire.")))
- (div ())))))
diff --git a/build.lisp b/build/build.lisp
index 1cb8322..6cd0401 100644
--- a/build.lisp
+++ b/build/build.lisp
@@ -13,4 +13,7 @@
SWANK-IO-PACKAGE::SWANK-REPL))
(ensure-directories-exist #P"./bin/")
-(sb-ext:save-lisp-and-die "bin/vampire" :toplevel #'vampire::run-vampire :executable t )
+(sb-ext:save-lisp-and-die
+ "bin/vampire"
+ :toplevel #'vampire::run-vampire
+ :executable t)
diff --git a/definition-macros.lisp b/definition-macros.lisp
deleted file mode 100644
index 0439e76..0000000
--- a/definition-macros.lisp
+++ /dev/null
@@ -1,19 +0,0 @@
-;;;; definition-macros.lisp
-
-(in-package :vampire)
-
-(defmacro defclass/bknr (name supers slotdefs &rest options)
- "Defines a class using defclass/std syntax. Ensures that the class
- is a sublcas of STORE-OBJECT with metaclass PERSISTENT-CLASS."
- (let* ((include-store-object-p
- (notany (lambda (c) (closer-mop:subclassp c 'store-object))
- supers))
- (supers
- (if include-store-object-p
- `(store-object ,@supers)
- supers)))
- `(eval-when (:compile-toplevel :load-toplevel :execute)
- (defclass/std ,name ,supers
- ,slotdefs
- (:metaclass persistent-class)
- ,@options))))
diff --git a/explore.lisp b/explore.lisp
deleted file mode 100644
index 5c99fb8..0000000
--- a/explore.lisp
+++ /dev/null
@@ -1,46 +0,0 @@
-;;; explore.lisp
-
-(in-package :vampire)
-
-(defun create-media-search-area (parent)
- (with-clog-create parent
- (p (:content "media search area"))))
-
-(defun create-playlist-explore-card (parent pl)
- (with-clog-create parent
- (div (:bind card :class "card")
- (a (:link (url-to-playlist pl) )
- (img (:bind thumb :class "thumb"))
- (br ())
- (span (:content (playlist-title pl)))
- (span (:content " -- "))
- (span (:content (secs-to-hms (playlist-duration pl))))))
- (when-let (track (first (playlist-tracks pl)))
- (setf (url-src thumb) (or (track-thumb-url track) "")))))
-
-(defun create-recent-playlists-area (parent)
- (let* ((container (create-div parent :class "row")))
- (dolist (pl (recent-playlists 100))
- (create-playlist-explore-card container pl))))
-
-(defun create-user-list (parent)
- (with-clog-create parent
- (unordered-list (:bind user-container))
- (dolist (user (store-objects-with-class 'user))
- (with-clog-create user-container
- (list-item ()
- (a (:link (url-to-user user)
- :content (format nil " ~a " (user-name user)))))))))
-
-(defun explore-page (body)
- (include-style body)
- (with-clog-create body
- (div ()
- (navigation-header ())
- (div (:class "row")
- (div (:bind playlist-area)
- (section (:h2 :content "Recent Playlists" :class "center"))
- (recent-playlists-area ()))
- (div ()
- (section (:h3 :content "Who uses this?" :class "center"))
- (user-list ()))))))
diff --git a/home.lisp b/home.lisp
deleted file mode 100644
index cac1c3b..0000000
--- a/home.lisp
+++ /dev/null
@@ -1,166 +0,0 @@
-;;;; user.lisp
-
-(in-package :vampire)
-
-;;; CLIENT UI
-
-(defun create-new-playlist-form (parent)
- (with-clog-create parent
- (form ()
- (section (:h3 :content "Create New Playlist"))
- (label (:content "Playlist Title:"))
- (form-element (:text :bind pl-title))
- (button (:content "Create" :bind btn)))
- (set-on-click
- btn
- (thunk*
- (new-playlist (session-user parent) :title (value pl-title))
- (reload (location (connection-body parent)))))))
-
-(defun url-to-playlist (pl)
- (format nil "/playlist/~a"
- (key pl)))
-
-(defun create-playlist-listing (parent &optional user)
- (dolist (pl (user-playlists (or user (session-user parent))))
- (with-clog-create parent
- (div (:bind pl-item)
- (div ()
- (playlist-explore-card (pl))
- (button (:content "delete" :bind btn))))
- (cond
- ((eq user (session-user parent))
- (set-on-click
- btn
- (thunk*
- (destroy-playlist pl)
- (destroy pl-item))))
- (t
- (destroy btn))))))
-
-(defun create-invite-list-item (invite-list invite)
- (with-clog-create invite-list
- (list-item (:bind item)
- (button (:bind delbtn :content "delete"))
- (p ()
- (span (:content "Code: "))
- (span (:content (key invite))))
- (p ()
- (span (:content "Uses Remaining: "))
- (span (:content
- (format nil "~a"
- (or (uses-remaining invite) "unlimited"))))))
- (set-on-click delbtn (thunk*
- (destroy-invite invite)
- (destroy item)))))
-
-(defun create-invite-control (parent)
- (let* ((user (session-user parent))
- (container (create-div parent))
- (invite-list (create-unordered-list parent)))
- (place-after (create-section container :h3 :content "Your Invites")
- invite-list)
- ;; list invites
- (dolist (invite (invites-by-maker user))
- (create-invite-list-item invite-list invite))
-
- (with-clog-create container
- (form ()
- (button (:bind createbtn :content "Create Invite"))
- (form-element (:number :bind count))
- (p (:bind invite-explainer
- :content "Share invite codes with friends to invite
- them to this server. Optinally say how many times an
- invite code can be used by setting the Uses count before
- clicking the Create Invite button.")))
- (setf
- (maximum-width invite-explainer) "500px"
- (minimum count) 0
- (place-holder count) "Uses"
- (width count) 70)
- (set-on-click
- createbtn
- (thunk*
- (let ((invite (make-invite user (parse-integer (value count) :junk-allowed t))))
- (create-invite-list-item invite-list invite)))))))
-
-(defun create-password-reset (parent)
- (with-clog-create parent
- (div ()
- (button (:content "Password Reset" :bind pw-reset-toggle))
- (form (:hidden t :bind pw-reset-form)
- (form-element (:password :bind pw-input))
- (br ())
- (form-element (:password :bind pw-repeated))
- (br ())
- (button (:content "Change password" :bind pw-update)))
- (p (:bind notice-area)))
-
- (setf (place-holder pw-input) "New Password"
- (place-holder pw-repeated) "Repeat New Password"
- (disabledp pw-update) t)
-
- (set-on-key-down
- pw-repeated
- (thunk* (when (equal (value pw-input) (value pw-repeated))
- (setf (disabledp pw-update) nil))))
-
- (flet ((toggle-form ()
- (cond ((visiblep pw-reset-form)
- (setf (visiblep pw-reset-form) nil
- (text pw-reset-toggle) "Password Reset"
- (text notice-area) ""
- (disabledp pw-update) t
- (value pw-input) ""
- (value pw-repeated) ""))
- (t
- (setf (visiblep pw-reset-form) t
- (text notice-area) ""
- (text pw-reset-toggle) "Nevermind")))))
-
- (set-on-click pw-update
- (thunk*
- ;; assumes pw-input and pw-repeat are equal
- (set-new-password (session-user parent) (value pw-input))
- (toggle-form)
- (setf (text notice-area)
- "Password updated!")))
-
- (set-on-click pw-reset-toggle
- (thunk* (toggle-form))))))
-
-
-(defun user-home-page (body)
- (include-style body)
- (with-clog-create body
- (div ()
- (navigation-header ())
- (div (:class "row")
- (div ()
- (section (:pre :content (format nil "Welcome ~a" (user-name (session-user body)))))
- (section (:h3 :content "Your Playlists"))
- (div (:class "row") (playlist-listing ()))
- (new-playlist-form ())
- (invite-control ())
- (password-reset ()))))))
-
-(defun user-key-from-url (url)
- (first (last (ppcre:split "/" (nth 4 (multiple-value-list (quri:parse-uri url)))))))
-
-(defun user-listing-page (body)
- (when-let* ((user-id
- (user-key-from-url (url (location body))))
- (user
- (object-with-key user-id)))
- (include-style body)
- (with-clog-create body
- (div ()
- (navigation-header ())
- (div (:class "row")
- (div ()
- (section (:h3 :content (format nil "Playlists by ~a"
- (user-name user))))
- (div (:class "row")
- (playlist-listing (user)))))))))
-
-
diff --git a/login.lisp b/login.lisp
deleted file mode 100644
index 0cf08b5..0000000
--- a/login.lisp
+++ /dev/null
@@ -1,32 +0,0 @@
-;;;; login.lisp
-
-(in-package :vampire)
-
-(defun login-page (body)
- (include-style body)
- (with-clog-create body
- (div (:class "login")
- (div ()
- (section (:h3 :content "LOGIN"))
- (form ()
- (form-element (:text :bind name-input))
- (br ())
- (form-element (:password :bind pw-input))
- (br ())
- (button (:bind btn :content "Click here to log in"))))
- (div ()
- (:p ()
- (:a (:link "/new-account" :content "Create an account")))))
- (setf (place-holder name-input) "Name"
- (place-holder pw-input) "Password")
- (set-on-click
- btn
- (thunk*
- (let ((user
- (login-user (value name-input) (value pw-input))))
- (if user
- (let ((session (make-session user)))
- (setf (session-key (window body)) (key session)
- (url (location body)) "/home"))
- (alert (window body) "Error logging in.")))))))
-
diff --git a/model.lisp b/model.lisp
deleted file mode 100644
index dcaf780..0000000
--- a/model.lisp
+++ /dev/null
@@ -1,187 +0,0 @@
-;;;; model.lisp
-
-(in-package :vampire)
-
-;;; CLASSES
-
-(defclass/bknr keyed ()
- ((key :r :std (nuid)
- :index-type string-unique-index
- :index-reader object-with-key)))
-
-(defclass/bknr user (keyed)
- ((name :with
- :index-type string-unique-index
- :index-reader user-with-name
- :index-initargs (:test 'equalp))
- (playlists :with :std (list))
- (pwsalt :with :std (nuid))
- (pwhash :with)))
-
-(defclass/bknr invite (keyed)
- ((maker :ri :std nil
- :index-type hash-index
- :index-reader invites-by-maker)
- (uses-remaining :std nil)))
-
-(defclass/bknr playlist (keyed)
- ((title :with :std (default-name "playlist"))
- (tracks editors :with :std (list))
- (cover-image :with :std nil :doc "A url to the cover of this album.")
- (user :with
- :std (error "A USER is required to have created the content."))))
-
-(defmethod initialize-instance :after ((pl playlist) &key)
- (pushnew pl (user-playlists (playlist-user pl)) :test #'eq))
-
-(defclass/bknr track (keyed)
- ((source file title artist album thumb-url duration codec :with)
- (playlists :with :std (list) :doc "A list of playlists in which this track appears")))
-
-(defun track-file (track)
- (with-slots (file) track
- (merge-pathnames
- (path:basename file)
- (merge-pathnames "media/" (static-directory *config*)))))
-
-;;; MODEL OPERATIONS
-
-(defun can-edit-p (user playlist)
- (or (eq (playlist-user playlist) user)
- (member user (playlist-editors playlist) :test #'eq)))
-
-(defun invite-by-code (code)
- "Returns NIL if CODE is an invalid invite code. Returns the INVITE
- instance otherwise"
- (when-let (obj (object-with-key code))
- (and (typep obj 'invite)
- (or (null (uses-remaining obj))
- (plusp (uses-remaining obj)))
- obj)))
-
-(defun user-with-key (key)
- (when-let (obj (object-with-key key))
- (when (typep obj 'user)
- obj)))
-
-(defun login-user (username password)
- (when-let (user (user-with-name username))
- (with-slots (pwhash pwsalt) user
- (when (equalp pwhash (hash-string password pwsalt))
- user))))
-
-(defun last-change (obj)
- (slot-value obj 'bknr.datastore::last-change))
-
-(defun recent-playlists (&optional (count 10))
- (take count
- (sort (copy-seq (store-objects-with-class 'playlist))
- #'>
- :key #'last-change)))
-(defun playlist-duration (pl)
- (reduce #'+
- (playlist-tracks pl)
- :key (lambda (tr) (or (track-duration tr) 0))
- :initial-value 0))
-
-(defun add-track (tr pl &optional (n -1))
- (setf (playlist-tracks pl)
- (insert-nth tr n (playlist-tracks pl))))
-
-(defun remove-nth-from-playlist (pl n)
- (multiple-value-bind (newlist track)
- (remove-nth n (playlist-tracks pl) t)
- (setf (playlist-tracks pl) newlist
- (track-playlists track) (delete pl (track-playlists track)
- :test #'eq :count 1))))
-
-(defun track-with-source (source)
- (find source (store-objects-with-class 'track) :test #'string-equal :key 'track-source))
-
-;;; TRANSACTIONS
-
-(defun new-user (&key name)
- (with-transaction ()
- (make-instance 'user :name name)))
-
-(defun set-new-password (user pw)
- (with-transaction ()
- (setf (user-pwhash user)
- (hash-string pw (user-pwsalt user)))
- t))
-
-
-(defun use-invite-with-code (code username pw)
- (with-transaction ()
- (when-let (invite (invite-by-code code))
- (when (uses-remaining invite)
- (decf (uses-remaining invite))
- (unless (plusp (uses-remaining invite))
- (bknr.datastore:delete-object invite)))
- (let ((user (make-instance 'user :name username)))
- (setf (user-pwhash user)
- (hash-string pw (user-pwsalt user)))
- user))))
-
-(defun remove-editor (playlist editor)
- (with-transaction ()
- (setf (playlist-editors playlist)
- (delete editor (playlist-editors playlist)))))
-
-(defun add-editor (playlist editor)
- (with-transaction ()
- (pushnew editor (playlist-editors playlist) :test #'eq)))
-
-(defun destroy-invite (invite)
- (with-transaction ()
- (bknr.datastore:delete-object invite)))
-
-(defun make-invite (user &optional uses)
- (with-transaction ()
- (make-instance 'invite :maker user :uses-remaining uses)))
-
-(defun append-track (pl tr)
- (with-transaction ()
- (add-track tr pl)))
-
-(defun delete-track-at (pl pos)
- (when-let (tr (nth pos (playlist-tracks pl)))
- (with-transaction ()
- (setf (playlist-tracks pl)
- (delete tr (playlist-tracks pl)))
- t)))
-
-(defun swap-tracks (pl n m)
- (unless (or (minusp (min m n))
- (>= (max m n) (length (playlist-tracks pl)) ))
- (with-transaction ()
- (setf (playlist-tracks pl)
- (nswap (playlist-tracks pl) n m)))))
-
-(defun new-track (file trackinfo)
- "Trackinfo is a plist containing information about the track to create."
- (with-transaction ()
- (let ((track (apply #'make-instance 'track trackinfo)))
- (setf (track-file track) (namestring file))
- track)))
-
-(defun new-playlist (user &key title)
- (with-transaction ()
- (make-instance 'playlist :title title :user user)))
-
-(defun destroy-playlist (pl)
- (with-transaction ()
- (setf (user-playlists (playlist-user pl))
- (delete pl (user-playlists (playlist-user pl))))
- (bknr.datastore:delete-object pl)))
-
-(defun update-playlist-title (playlist title)
- (with-transaction ()
- (setf (playlist-title playlist) title)))
-
-(defun update-track-info (track new-artist new-album new-title)
- (with-transaction ()
- (with-slots (artist album title) track
- (setf artist (if (equal "" new-artist) nil new-artist)
- album (if (equal "" new-album) nil new-album)
- title (if (equal "" new-title) nil new-title)))))
diff --git a/navigation.lisp b/navigation.lisp
deleted file mode 100644
index 2e6b650..0000000
--- a/navigation.lisp
+++ /dev/null
@@ -1,11 +0,0 @@
-;;;; navigation
-
-(in-package :vampire)
-
-(defun create-navigation-header (parent)
- (with-clog-create parent
- (section (:header :class "row header")
- (div () (a (:link "/home")
- (img ( :url-src "/favicon.ico"))))
- (div () (a (:link "/explore" :content "Explore")))
- (div () (a (:link "/about" :content "About"))))))
diff --git a/new-account.lisp b/new-account.lisp
deleted file mode 100644
index 653818a..0000000
--- a/new-account.lisp
+++ /dev/null
@@ -1,75 +0,0 @@
-;;;; new-account.lisp
-
-(in-package :vampire)
-
-(defparameter +username-regex+
- (ppcre:create-scanner "^[a-zA-Z0-9\_\\-!@#$^&*]{3,25}$"))
-
-
-
-(defun new-accout-page (body)
- (include-style body)
- (with-clog-create body
- (div (:class "row")
- (div () (section (:h2 :content "Create a new account"))
- (form (:bind new-user-form)
- (form-element (:text :bind invite))
- (span (:bind invite-status))
- (br ())
- (form-element (:text :bind name))
- (span (:bind name-status))
- (br ())
- (form-element (:password :bind pw))
- (br ())
- (form-element (:password :bind pw-confirm))
- (span (:bind pw-confirm-status))
- (br ())
- (button (:content "Make Account" :bind submit))))
- (div (:bind name-help :hidden t)
- (p (:content "3-25 characters, no spaces, numbers, letters, or !@#$^&*()_-"))))
-
- (setf (place-holder invite) "Invite Code"
- (place-holder name) "Name"
- (place-holder pw) "Password"
- (place-holder pw-confirm) "Repeat Password")
-
- (set-on-blur
- invite
- (thunk*
- (setf (inner-html invite-status)
- (if (invite-by-code (value invite))
- "✔"
- "Bad Invite Code"))))
- (set-on-blur
- name
- (thunk*
- (let ((name (value name)))
- (setf (text name-status)
- (cond
- ((not (ppcre:all-matches +username-regex+ name))
- (setf (visiblep name-help) t)
- "Invalid Name.")
- ((user-with-name name)
- (setf (visiblep name-help) nil)
- "Name Already Taken")
- (t
- (setf (visiblep name-help) nil)
- "✔"))))))
-
- (set-on-key-press
- pw-confirm
- (thunk*
- (setf (text pw-confirm-status)
- (if (string-equal (value pw) (value pw-confirm))
- "✔"
- "Passwords Do Not Match"))))
-
- (set-on-click
- submit
- (thunk*
- (if (loop for status in (list pw-confirm-status name-status invite-status)
- always (string-equal "✔" (text status)))
- (if (use-invite-with-code (value invite) (value name) (value pw))
- (setf (url (location body)) "/login")
- (alert (window body) "An error occurred while making your account."))
- (alert (window body) "Plase double check your inputs."))))))
diff --git a/playlist.lisp b/playlist.lisp
deleted file mode 100644
index d5c3690..0000000
--- a/playlist.lisp
+++ /dev/null
@@ -1,544 +0,0 @@
-;;;; playlist.lisp
-
-(in-package :vampire)
-
-
-;;; CLIENT STATE
-
-(defclass/std playlist-ctl ()
- ((playlist :std nil :doc "The playlist instance.")
- (editorp :std nil)
- (tracks :std nil :doc "A list of instances of track-ctl")
- (now-playing-track :std nil :doc "An instance of track-ctl")
- (np-title np-artist np-thumb np-dur np-time np-play
- :std nil :doc "Now Playing Elements")
- (pl-title pl-tracks pl-dur pl-zip pl-download
- :std nil :doc "Playlist Elements"))
- (:documentation "Holds the complete state for this session's viewing of a particular playlist."))
-
-(defclass/std track-ctl ()
- ((track listing-line audio container info-edit-ctl edit-save-btn editing?
- artist-input album-input title-input :std nil))
- (:documentation "The state of a particular track in this session's viewing of a playlist."))
-
-(defun audio-for-track (ctl track)
- "Return the audio element associated with the track"
- (when-let (trctl (find track (tracks ctl) :test #'eq :key #'track))
- (audio trctl)))
-
-(defun track-for-audio (ctl audio)
- "Return the track instance associated with the AUDIO element."
- (when-let (trctl (find audio (tracks ctl) :test #'eq :key #'audio))
- (track trctl)))
-
-(defun track-ctl-with-audio (ctl audio)
- (find audio (tracks ctl) :key #'audio))
-
-(defun find-next-track (ctl &optional track)
- "Return the TRACK-CTL instance that appeqars after TRACK in the
- TRACKS list, or NIL. If TRACK is NIL, return the first TRACK in the
- list."
- (if (null track)
- (first (tracks ctl))
- (when-let (pos (position track (tracks ctl)))
- (nth (1+ pos) (tracks ctl)))))
-
-(defun find-previous-track (ctl &optional track)
- (when-let (pos (position track (tracks ctl)))
- (when (plusp pos)
- (nth (1- pos) (tracks ctl)))))
-
-;;; SESSION UTIL
-
-(defparameter +playlist-connection-key+ "playlist-connection-key"
- "Stored in the clog connection object")
-
-(defun cur-playlist-ctl (obj)
- (when (connection-data obj)
- (connection-data-item obj +playlist-connection-key+)))
-
-(defun (setf cur-playlist-ctl) (newval obj)
- (setf (connection-data-item obj +playlist-connection-key+) newval))
-
-(defun install-new-playlist-ctl (playlist body)
- (setf (cur-playlist-ctl body)
- (make-instance 'playlist-ctl
- :playlist playlist
- :editorp (can-edit-p (session-user body) playlist))))
-
-;;; SYNCHRONIZATION
-
-(defvar *playlist-viewers* (make-hash-table :synchronized t)
- "Holds lists of active viewers of each playlist, keyed by playlist.")
-
-(defun playlist-viewers (ctl)
- (gethash (playlist ctl) *playlist-viewers* nil))
-
-(defun add-playlist-viewer (ctl)
- "Add a new playlist-ctl instance for this connection and, while
- doing so, remove any dead controllers"
- (let ((viewers
- (playlist-viewers ctl)))
- (setf (gethash (playlist ctl) *playlist-viewers*)
- (cons ctl (remove-if-not 'controller-alive-p viewers)))))
-
-(defun controller-alive-p (ctl)
- "A controller is a live if the CLOG elements it manages are
- associated with a live connection."
- (when (pl-title ctl) (connection-data (pl-title ctl))))
-
-(defmacro for-playlist-viewers (clog-elem ctlvar &body body)
- `(dolist (,ctlvar (playlist-viewers (cur-playlist-ctl ,clog-elem)))
- (if (controller-alive-p ctl)
- (progn ,@body))))
-
-;;; PLAYBACK CONTROL
-
-(defun start-playback (ctl)
- (when-let (tr (now-playing-track ctl))
- (add-class (first-child (container tr)) "now-playing-track")
- (play-media (audio tr))
- (setf (text (np-play ctl)) "⏸")))
-
-(defun pause-playback (ctl)
- (when-let (tr (now-playing-track ctl))
- (pause-media (audio tr))
- (setf (text (np-play ctl)) "⏵")))
-
-(defun stop-playback (ctl)
- (when-let (tr (now-playing-track ctl))
- (pause-media (audio tr))
- (remove-class (first-child (container tr)) "now-playing-track")
- (setf (media-position (audio tr)) 0
- (now-playing-track ctl) nil
- (text (np-play ctl)) "⏵")))
-
-
-;;; CLIENT CONTROL
-
-(defun initialize-now-playing (elem)
- (when-let (ctl (cur-playlist-ctl elem))
- (when (tracks ctl)
- (setf (now-playing-track ctl) (first (tracks ctl)))
- (load-now-playing-display ctl (now-playing-track ctl)))))
-
-(defun load-now-playing-display (ctl track-ctl)
- (let ((tr (track track-ctl)))
- (setf (text (np-title ctl)) (track-listing-line tr nil)
- (url-src (np-thumb ctl)) (or (track-thumb-url tr) "")
- (text (np-dur ctl)) (secs-to-hms (or (track-duration tr) 0))
- (text (np-time ctl)) (secs-to-hms 0))))
-
-(defun toggle-now-playing (e)
- (when-let (ctl (cur-playlist-ctl e))
- (if-let (np (now-playing-track ctl))
- (if (pausedp (audio np))
- (start-playback ctl)
- (pause-playback ctl))
- (advance-now-playing e))))
-
-(defun advance-now-playing (e)
- (when-let ((ctl
- (cur-playlist-ctl e)))
-
- (if-let (next (find-next-track ctl (now-playing-track ctl)))
- (progn
- (stop-playback ctl)
- (setf (now-playing-track ctl) next)
- (load-now-playing-display ctl next)
- (start-playback ctl))
- (stop-playback ctl))))
-
-(defun previous-now-playing (e)
- (when-let* ((ctl
- (cur-playlist-ctl e))
- (prev
- (find-previous-track ctl (now-playing-track ctl))))
- (stop-playback ctl)
- (setf (now-playing-track ctl) prev)
- (load-now-playing-display ctl prev)
- (start-playback ctl)))
-
-(defun update-now-playing-time (e)
- (when-let* ((ctl (cur-playlist-ctl e))
- (tr (now-playing-track ctl)))
- (setf (text (np-time ctl))
- (secs-to-hms
- (media-position (audio tr))))))
-
-
-(defun play-this-audio (audio)
- (when-let (ctl (cur-playlist-ctl audio))
- (let ((np (now-playing-track ctl))
- (tr (track-ctl-with-audio ctl audio)))
- (cond
- ((and np (eq audio (audio np)) (pausedp audio))
- (start-playback ctl))
-
- (t
- (stop-playback ctl)
- (setf (now-playing-track ctl) tr)
- (start-playback ctl)
- (load-now-playing-display ctl tr))))))
-
-;;; SYNCHRONZIED CLIENT CONTROL
-
-(defun remove-track (track-ctl)
- (when-let* ((container (container track-ctl))
- (curctl (cur-playlist-ctl container))
- (pos (position track-ctl (tracks curctl))))
-
- (when (delete-track-at (playlist curctl) pos)
- (delete-zipped-playlist curctl)
- (for-playlist-viewers container ctl
- (let ((track-ctl (nth pos (tracks ctl))))
- (destroy (container track-ctl))
- (setf (tracks ctl) (delete track-ctl (tracks ctl))
- (text (pl-dur ctl)) (secs-to-hms (playlist-duration (playlist ctl)))))))))
-
-(defun move-track-down (track-ctl)
- (when-let* ((curctl (cur-playlist-ctl (container track-ctl)))
- (pos (position track-ctl (tracks curctl))))
- (when (swap-tracks (playlist curctl) pos (1+ pos))
- (delete-zipped-playlist curctl)
- (for-playlist-viewers (container track-ctl) ctl
- (let* ((cur
- (nth pos (tracks ctl)))
- (next
- (nth (1+ pos) (tracks ctl))))
- ;; swap track-ctls
- (setf (tracks ctl)
- (nswap (tracks ctl) pos (1+ pos)))
- ;; swap list items in the dom
- (place-before (container cur) (container next)))))))
-
-(defun move-track-up (track-ctl)
- (when-let* ((curctl (cur-playlist-ctl (container track-ctl)))
- (pos (position track-ctl (tracks curctl))))
- (when (swap-tracks (playlist curctl) pos (1- pos))
- (delete-zipped-playlist curctl)
- (for-playlist-viewers (container track-ctl) ctl
- (let* ((cur
- (nth pos (tracks ctl)))
- (next
- (nth (1- pos) (tracks ctl))))
- ;; swap track-ctls
- (setf (tracks ctl)
- (nswap (tracks ctl) pos (1- pos)))
- ;; swap list items in the dom
- (place-after (container cur) (container next)))))))
-
-(defun open-track-editor (track-ctl)
- (setf (display (info-edit-ctl track-ctl)) "inline"
- (text (edit-save-btn track-ctl)) "save "
- (editing? track-ctl) t)
- (with-slots (artist-input album-input title-input) track-ctl
- (with-slots (artist album title) (track track-ctl)
- (setf (place-holder artist-input) (or artist "Artist")
- (place-holder album-input) (or album "Album")
- (place-holder title-input) (or title "Title"))
- (set-on-click
- (edit-save-btn track-ctl)
- (thunk* (update-track-info
- (track track-ctl) (value artist-input) (value album-input) (value title-input))
- (close-track-editor track-ctl))
- :one-time t))))
-
-(defun close-track-editor (track-ctl)
- (setf (display (info-edit-ctl track-ctl)) "none"
- (text (listing-line track-ctl)) (track-listing-line (track track-ctl))
- (text (edit-save-btn track-ctl)) "edit "
- (editing? track-ctl) nil)
- (set-on-click
- (edit-save-btn track-ctl)
- (thunk* (open-track-editor track-ctl))
- :one-time t))
-
-(defun add-zipped-playlist-link (pl-ctl playlist)
- "Adds the link to a zipped playlist to the DOM."
- (for-playlist-viewers (pl-download pl-ctl) ctl
- (setf (pl-zip ctl) (make-zipped-playlist-link playlist (pl-download ctl)))
- (place-inside-bottom-of (pl-download ctl) (pl-zip ctl))))
-
-;;; CLIENT UI
-
-(defun playlist-title-content (playlist)
- (format nil "~a -- ~a"
- (playlist-title playlist)
- (secs-to-hms (playlist-duration playlist))))
-
-(defun create-now-playing-display (parent ctl)
- (with-clog-create parent
- (div (:class "now-playing")
- (section (:h3 :content "Now Playing"))
- (img (:bind thumb))
- (section (:h4)
- (span (:bind title))
- (span (:bind artist)))
- (p ()
- (span (:bind time))
- (span (:content " / "))
- (span (:bind dur)))
- (div (:class "controls")
- (button (:content "⏮" :bind back ))
- (button (:content "⏵" :bind play ))
- (button (:content "⏭" :bind forward ))))
- (setf (np-title ctl) title
- (np-artist ctl) artist
- (np-thumb ctl) thumb
- (np-dur ctl) dur
- (np-time ctl) time
- (np-play ctl) play)
- (setf (height thumb) "300px")
- (set-on-click back 'previous-now-playing)
- (set-on-click forward 'advance-now-playing)
- (set-on-click play 'toggle-now-playing)))
-
-(defun media-url-path (track)
- (format nil "/media/~a.~a"
- (pathname-name (track-file track))
- (pathname-type (track-file track))))
-
-(defun track-listing-line (track &optional (timep t))
- (with-slots (artist title duration) track
- (if timep
- (format nil "~50<~a~;~a~>~%~a"
- (subseq* title 0 40)
- (secs-to-hms (or duration 0))
- (if artist (concatenate 'string " by "
- (subseq* artist 0 40)) ""))
- (format nil "~a~%~a"
- (subseq* title 0 40)
- (if artist (concatenate 'string " by "
- (subseq* artist 0 40)) "")))))
-
-(defun create-track-list-item (list track ctl)
- (with-clog-create list
- (list-item (:bind container)
-
- (div (:bind item :class "track-list-item")
- (section (:pre :bind listing-line)))
- (div (:bind info-edit-ctl :class "track-list-edit")
- (div (:class "track-edit-inputs column")
- ;; (label (:content "Artist" :bind artist-label))
- (form-element (:text :bind artist-input :value (track-artist track)))
- ;; (label (:content "Album" :bind album-label))
- (form-element (:text :bind album-input :value (track-album track)))
- ;; (label (:content "Title" :bind title-label))
- (form-element (:text :bind title-input :value (track-title track)))))
- (div (:bind edit-controls)
- (button (:content "edit " :bind edit-save-btn))
- (button (:content "delete " :bind delbtn))
- (button (:content "↓" :bind downbtn))
- (button (:content "↑" :bind upbtn)))
- (audio (:source (media-url-path track) :controls nil :bind audio)))
- (let ((track-ctl
- (make-instance 'track-ctl
- :container container
- :listing-line listing-line
- :audio audio
- :track track
- :info-edit-ctl info-edit-ctl
- :edit-save-btn edit-save-btn
- :artist-input artist-input
- :album-input album-input
- :title-input title-input
- :editing? nil)))
- (setf (tracks ctl)
- (insert-nth track-ctl -1 (tracks ctl) t)
- (text listing-line) (track-listing-line track)
- (display info-edit-ctl) "none")
- (cond
- ((editorp ctl)
- (setf (attribute downbtn "title") "move track down"
- (attribute upbtn "title") "move track up")
- (set-on-click edit-save-btn (thunk* (open-track-editor track-ctl)) :one-time t)
- (set-on-click delbtn (thunk* (remove-track track-ctl)))
- (set-on-click downbtn (thunk* (move-track-down track-ctl)))
- (set-on-click upbtn (thunk* (move-track-up track-ctl))))
- (t
- (setf (display edit-controls) "none"))))
-
- (set-on-time-update audio 'update-now-playing-time)
- (set-on-ended audio 'advance-now-playing)
- (set-on-click item (thunk* (play-this-audio audio)))))
-
-(defun create-track-listing (parent pl)
- (when-let (ctl (cur-playlist-ctl parent))
- (create-section parent :h3 :content "TRACKS")
- (let ((ol (create-ordered-list parent :class "playlist-tracks")))
- (setf (pl-tracks ctl) ol)
- (dolist (track (playlist-tracks pl))
- (create-track-list-item ol track ctl)))))
-
-(defun append-track-list-item (obj track)
- (for-playlist-viewers obj ctl
- (create-track-list-item (pl-tracks ctl) track ctl)
- (setf (text (pl-dur ctl))
- (secs-to-hms (playlist-duration (playlist ctl))))))
-
-(defun create-new-track-form (parent pl)
- (when (editorp (cur-playlist-ctl parent))
- (with-clog-create parent
- (div ()
- (section (:h3 :content "Add A Track"))
- (label (:content "Paste a URL: " :bind url-label))
- (form-element (:text :bind url-input))
- (button (:content "Fetch Track" :bind button))
- (p (:content "Paste from youtube, bandcamp, vimeo... anything really. Chances are it'll work."))
- (div (:bind notice-area)))
- (label-for url-label url-input)
- (setf (size url-input) (length "https://www.youtube.com/watch?v=dQw4w9WgXcQ"))
- (setf (place-holder url-input) "https://www.youtube.com/watch?v=dQw4w9WgXcQ")
- (set-on-click
- button
- (thunk*
- (let* ((url
- (value url-input))
- (notice
- (create-p notice-area :content (format nil "... Fetching ~a" url)))
- (on-ok
- (lambda (track)
- (destroy notice)
- (delete-zipped-playlist (cur-playlist-ctl parent))
- (append-track pl track)
- (append-track-list-item parent track))))
- (setf (value url-input) "")
- (if-let (track (track-with-source url))
- (funcall on-ok track)
- (add-fetch-track-job
- url on-ok
- (lambda (err)
- (destroy notice)
- (format t "~a" err)
- (alert (window (connection-body parent))
- (format nil "Error while fetching track at: ~a~%"
- url)))))))))))
-
-(defun create-editor-managment (parent playlist)
- (when (eq (session-user parent) (playlist-user playlist))
- (with-clog-create parent
- (div ()
- (section (:h3 :content "Collaborators"))
- (unordered-list (:bind editor-list))
- (button (:content "Add Contributor" :bind addbtn))
- (form-element (:text :bind userinput))
- (span (:bind username-status)))
- (setf (place-holder userinput) "who?"
- (width userinput ) 140)
- (flet ((create-editor-item (editor)
- (with-clog-create editor-list
- (p (:content (user-name editor) :bind editor-elem)
- (button (:content "remove" :bind delbtn)))
- (set-on-click
- delbtn
- (thunk*
- (remove-editor playlist editor)
- (destroy editor-elem))))))
- (set-on-blur
- userinput
- (thunk*
- (setf (text username-status)
- (if (user-with-name (value userinput))
- "✔" "No user with that name"))))
- (set-on-click
- addbtn
- (thunk*
- (let ((user (user-with-name (value userinput))))
- (cond
- (user
- (add-editor playlist user)
- (setf (value userinput) ""
- (text username-status) "")
- (create-editor-item user))
- (t
- (setf (text username-status)
- "No user with that name"))))))
- (dolist (editor (playlist-editors playlist))
- (create-editor-item editor))))))
-
-(defun url-to-user (user)
- (format nil "/user/~a" (key user)))
-
-(defun playlist-key-from-url (url)
- (first (last (ppcre:split "/" (nth 4 (multiple-value-list (quri:parse-uri url)))))))
-
-(defun playlist-page (body)
- (when-let* ((list-id
- (playlist-key-from-url (url (location body))))
- (pl
- (object-with-key list-id)))
- (let ((ctl
- (install-new-playlist-ctl pl body)))
- (add-playlist-viewer ctl)
- (include-style body)
- (with-clog-create body
- (div (:class "container")
- (navigation-header ())
- (div (:class "player")
- (now-playing-display (ctl))
- (div (:class "playlist-display")
- (:span (:bind edit-indicator))
- (section (:h2)
- (:span (:bind title-elem :content (playlist-title pl)))
- (form-element (:text :bind input))
- (:span (:content " -- "))
- (:span (:bind dur-elem :content (secs-to-hms (playlist-duration pl)))))
- (span (:content "by ")
- (a (:link (url-to-user (playlist-user pl))
- :content (format nil "~a" (user-name (playlist-user pl))))))
- (p (:bind collaborators-elem))
- (track-listing (pl))))
-
- (div (:class "row")
- (div (:class "column" :bind dl-elem)
- (button (:content "Create Zipped Playlist" :bind zip-download-button)))
- (div ()
- (new-track-form (pl))
- (editor-managment (pl)))))
-
- (setf (pl-title ctl) title-elem
- (pl-dur ctl) dur-elem
- (pl-download ctl) dl-elem
- (display input) "none"
- (display title-elem) "inline")
-
- (when (zipped-playlist-exists-p pl)
- (setf (pl-zip ctl) (make-zipped-playlist-link pl body))
- (place-after zip-download-button (pl-zip ctl)))
-
- (set-on-click zip-download-button
- (thunk*
- (zip-playlist pl)
- (add-zipped-playlist-link ctl pl)))
-
- (when (playlist-editors pl)
- (setf (inner-html collaborators-elem)
- (with-output-to-string (out)
- (princ "with help from " out)
- (loop for (u . more) on (playlist-editors pl)
- do (format out "<a href='/user/~a'>~a</a>"
- (key u) (user-name u))
- when more do (princ ", " out)))))
-
- (when (editorp ctl)
- (setf (attribute title-elem "title") "Click to edit the title."
- (text edit-indicator) "(click the title to edit it)")
- (set-on-blur
- input
- (thunk*
- (when (plusp (length (value input)))
- (delete-zipped-playlist ctl) ;; must happen first
- (update-playlist-title pl (value input))
- (setf (text title-elem) (value input)))
- (setf (display input) "none"
- (display title-elem) "inline")))
-
- (set-on-click
- title-elem
- (thunk*
- (setf (value input) (text title-elem)
- (display title-elem) "none"
- (display input) "inline")
- (focus input))))
- (initialize-now-playing body)))))
diff --git a/session.lisp b/session.lisp
deleted file mode 100644
index d7bd937..0000000
--- a/session.lisp
+++ /dev/null
@@ -1,33 +0,0 @@
-;;;; session.lisp
-
-(in-package :vampire)
-
-;;; SESSION CLASS
-
-(defclass/bknr session (keyed)
- ((user :std (error "Sessions must be associated with users."))))
-
-(defun make-session (user)
- (with-transaction ()
- (make-instance 'session :user user)))
-
-;;; SESSION PARAMETER KEYS
-
-(defparameter +session-key+ "vampire-session-key"
- "Stored in the browser's local storage")
-
-
-;;; SESSION ACCESSORS
-
-(defun session-key (window)
- (jonathan:parse (storage-element window :local +session-key+)))
-
-(defun (setf session-key) (val window)
- (setf (storage-element window :local +session-key+) (jonathan:to-json val)))
-
-(defun session-user (clog-obj)
- (when-let (obj (object-with-key (session-key (window (connection-body clog-obj)))))
- (when (typep obj 'session)
- (user obj))))
-
-
diff --git a/src/api.lisp b/src/api.lisp
new file mode 100644
index 0000000..ad171c6
--- /dev/null
+++ b/src/api.lisp
@@ -0,0 +1,191 @@
+(defpackage #:vampire.api
+ (:import-from #:derrida #:with-plist )
+ (:import-from #:lazybones
+ #:defendpoint*)
+ (:local-nicknames
+ (#:lzb #:lazybones)
+ (#:json #:jonathan)
+ (#:a #:alexandria-2)
+ (#:util #:vampire.utilities)
+ (#:model #:vampire.model)
+ (#:downloader #:vampire.downloader)
+ (#:mail #:vampire.mailbox)
+ (#:logger #:vampire.logger))
+ (:use #:cl))
+
+(in-package #:vampire.api)
+
+;;; APP
+
+(lzb:provision-app ()
+ :prefix "/api"
+ :content-type "application/json")
+
+;;; SPECIALS
+
+(defvar *session* nil
+ "Bound per session by code expanded from SESSION-EDNPOINT")
+
+;;; MACROS
+
+(defmacro define-model-lookup (class)
+ "Defines a function called A-CLASS. These functions can be referenced
+in endpoint pathname specifications and in parameter lists to parse
+and bind parameters to model objects.
+
+Any failures result in an HTTP 404."
+ (let ((name (a:symbolicate :a- class)))
+ `(defun ,name (key)
+ (let ((,class (model:lookup key )))
+ (unless (typep ,class ',class )
+ (lzb:http-err 404
+ (format nil "No ~a with id ~a"
+ ',class key )))))))
+
+(defmacro with-json-body ((&rest var-names) &body body)
+ "VAR-NAMES should be symbols. Under the hood these names are converted
+into javascript-styled keyword symbols using
+PARENSCRIPT:SYMBOL-TO-JS-STRING, which are then passed to
+DERRIDA:WITH-PLIST."
+ (let* ((plist-bindings
+ (mapcar (lambda (var) (list var (util:jsonify-symbol var))) var-names))
+ (keywords
+ (mapcar #'second plist-bindings)))
+ `(let ((lzb:*allowed-keywords* ',keywords))
+ (with-plist ,plist-bindings (lzb:request-body)
+ ,@body))))
+
+(defmacro defendpoint/session (method path &body body)
+ (let ((full-path
+ (concatenate 'string "/session/:*session* a-session:" path)))
+ `(defendpoint* ,method ,full-path () () ,@body)))
+
+
+;;; ARGUMENT VALIDATORS
+
+(defparameter +api-token-key+ :|apiToken|)
+
+(define-model-lookup model:session)
+(define-model-lookup model:playlist)
+(define-model-lookup model:user)
+(define-model-lookup model:track)
+
+(defun an-int (str)
+ (let ((int (parse-integer str :junk-allowed t)))
+ (unless int
+ (lzb:http-err
+ 400
+ (format nil "Expected an integer, but got ~s" str)))
+ int))
+
+(defun check-title (title)
+ "Validates a string meant to be the title of something. Titles should
+be non-empty strings."
+ (unless (util:legible-line-p title)
+ (lzb:http-err 406 "Invalid Title")))
+
+;;; PERMISSIONS CHECKS
+
+(defun check-can-edit (playlist)
+ (unless (model:can-edit-p (model:user *session*) playlist)
+ (lzb:http-err 403 "\"Unauthorized\"")))
+
+(defun check-ownership (pl)
+ (unless (eq (model:user *session*) (model:user pl))
+ (lzb:http-err 403 "\Unauthorized\"")))
+
+;;; ENDPOINTS
+
+(defendpoint* :post "/session" () ()
+ "Create a new session for a user. The request body MUST contain two
+fields: \"username\" and \"password\"."
+ (with-json-body (username password)
+ (a:if-let (user (model:login-user username password))
+ (json:to-json
+ (list +api-token-key+ (model:key (model:make-session user))))
+ (lzb:http-err 403))))
+
+(defendpoint* :post "/user"
+ () ()
+ "Create a user with USERNAME and PASSWORD by redeeming an invite CODE.
+The JSON body must contain properties \"code\", \"username\", and
+\"password\"."
+ (with-json-body (code username password)
+ (json:to-json
+ (if (model:use-invite-with-code code username password)
+ (list :|status| "SUCCESS")
+ (list :|status| "INVITE_UNKNOWN")))))
+
+;;; PLAYLIST ENDPOINTS
+
+(defendpoint/session :get "/playlist/:pl a-playlist:"
+ "Return a PLAYLIST identified by its key."
+ (json:to-json pl))
+
+(defendpoint/session :post "/playlist"
+ "Create a new playlist. The request body must contain the field \"title\"."
+ (with-json-body (title)
+ (check-title title)
+ (json:to-json
+ (model:new-playlist (model:user *session*) :title title))))
+
+(defendpoint/session :patch "/playlist/:pl a-playlist:"
+ "Update a playlist with fields in the request body.
+
+Fields include \"title\" and \"trackIds\". All fields are optional.
+
+If title is provided it is validated. If trackIds is provided, each of
+its members is validated, returning ao 404 if no track can be found
+witht he given id."
+ (check-can-edit pl)
+ (with-json-body (title track-ids)
+ (when title (check-title title))
+ (let ((tracks (mapcar #'a-track track-ids)))
+ (model:update-playlist pl title tracks))
+ "true"))
+
+(defendpoint/session :post "/add-track/:pl a-playlist:"
+ (check-can-edit pl)
+ (let ((user (model:user *session*)))
+ (with-json-body (url)
+ (downloader:fetch-track
+ url
+ (lambda (track)
+ (model:append-track pl track)
+ (mail:send user (list :|newTrack| track :|playlist| (model:key pl))))
+ (lambda (e)
+ (logger:logerror (list :error e :url url))
+ (mail:send user (list :|fetchError| url)))))))
+
+(defendpoint/session :delete "/playlist/:pl a-playlist:"
+ "Owners can delete their playlists."
+ (check-ownership pl)
+ (model:destroy-playlist pl)
+ "true")
+
+(defendpoint/session :patch "/user/:user a-user:/add-editor/:pl a-playlist:"
+ "Owners can add collaborators to their playlists"
+ (check-ownership pl)
+ (model:add-editor pl user)
+ "true")
+
+(defendpoint/session :patch "/user/:user a-user:/remove-editor/:pl a-playlist:"
+ "Owners can remove collaborators from their playlists"
+ (check-ownership pl)
+ (model:remove-editor pl user)
+ "true")
+
+;;; TRACK ENDPOINTS
+
+(defendpoint/session :get "/track/:track a-track:"
+ "Fetch the metadata related to a particular track"
+ (json:to-json track))
+
+(defendpoint/session :patch "/track/:track a-track:"
+ "Any logged in user can edit track metadata"
+ (with-json-body (title artist album)
+ (model:update-track-info track new artist album title)
+ "true"))
+
+
+
diff --git a/src/config.lisp b/src/config.lisp
new file mode 100644
index 0000000..6a90322
--- /dev/null
+++ b/src/config.lisp
@@ -0,0 +1,38 @@
+
+(defpackage #:vampire.config
+ (:use #:cl)
+ (:import-from #:defclass-std #:defclass/std)
+ (:export #:config
+ #:datastore-directory*
+ #:static-directory*
+ #:swank-port*
+ #:host*
+ #:port*
+ #:downloader-threads*))
+
+(in-package #:vampire.config)
+
+(defvar *config* nil)
+
+(defclass/std config ()
+ ((datastore-directory :ir :std #P"/srv/vampire/store/")
+ (static-directory :ir :std #P"/srv/vampire/static/")
+ (swank-port :std nil :doc "If set, swank is started on this port.")
+ (host :std "0.0.0.0")
+ (port :ir :std 4919)
+ (downloader-threads :ir :std 5)))
+
+(defun static-directory* (&optional (config *config*))
+ (static-directory config))
+
+(defun datastore-directory* (&optional (config *config*))
+ (datastore-directory config))
+
+(defun swank-port* (&optional (config *config*))
+ (swank-port config))
+
+(defun host* (&optional (config *config*))
+ (host config))
+
+(defun port* (&optional (config *config*))
+ (port config))
diff --git a/downloader.lisp b/src/downloader.lisp
index cafe46b..1e08ac6 100644
--- a/downloader.lisp
+++ b/src/downloader.lisp
@@ -1,19 +1,28 @@
;;;; downloader.lisp
-(in-package #:vampire)
+(defpackage #:vampire.downloader
+ (:use #:cl)
+ (:local-nicknames
+ (#:config #:vampire.config))
+ (:import-from #:derrida #:with-plist)
+ (:export #:start
+ #:fetch-track))
+
+(in-package #:vampire.downloader)
(defvar *dl-cluster*)
(defvar *media-directory*)
-(defun start-downloader-service (config)
+(defun start (config)
(let ((media-dir
(merge-pathnames "media/" (static-directory config))))
(ensure-directories-exist media-dir)
- (setf *dl-cluster* (legion:make-cluster (downloader-threads config)
- (lambda (job) (funcall job media-dir)))))
+ (setf *dl-cluster* (legion:make-cluster
+ (downloader-threads config)
+ (lambda (job) (funcall job media-dir)))))
(legion:start *dl-cluster*))
-(defun add-fetch-track-job (url ok err)
+(defun fetch-track (url ok err)
"URL is a url to some audio track. OK is a function that accepts a
TRACK instance. ERR is a function accepting an error condition"
(legion:add-job
diff --git a/hunchentoot-handle-static-file.lisp b/src/hunchentoot/handle-static-file-monkeypatch.lisp
index 4db0425..4db0425 100644
--- a/hunchentoot-handle-static-file.lisp
+++ b/src/hunchentoot/handle-static-file-monkeypatch.lisp
diff --git a/src/log.lisp b/src/log.lisp
new file mode 100644
index 0000000..2a44b7e
--- /dev/null
+++ b/src/log.lisp
@@ -0,0 +1,10 @@
+;;;; log.lisp -- a logger
+
+(defpackage #:vampire.logger
+ (:use #:cl)
+ (:export #:logerror))
+
+(in-package :vampire.logger)
+
+(defun logerror (e)
+ (print e))
diff --git a/src/logger.lisp b/src/logger.lisp
new file mode 100644
index 0000000..2a44b7e
--- /dev/null
+++ b/src/logger.lisp
@@ -0,0 +1,10 @@
+;;;; log.lisp -- a logger
+
+(defpackage #:vampire.logger
+ (:use #:cl)
+ (:export #:logerror))
+
+(in-package :vampire.logger)
+
+(defun logerror (e)
+ (print e))
diff --git a/src/mailbox.lisp b/src/mailbox.lisp
new file mode 100644
index 0000000..8ce1acf
--- /dev/null
+++ b/src/mailbox.lisp
@@ -0,0 +1,17 @@
+;;;; mailbox.lisp -- a volatile messaging system
+
+(defpackage #:vampire.mailbox
+ (:use #:cl)
+ (:export #:send #:deliver))
+
+(in-package #:vampire.mailbox)
+
+(defvar *mailboxes* (make-hash-table :test #'eq :synchronized t))
+
+(defun send (user message)
+ (push message (gethash user *mailboxes*)))
+
+(defun deliver (user)
+ (prog1 (reverse (gethash user *mailboxes*))
+ (remhash user *mailboxes*)))
+
diff --git a/src/model.lisp b/src/model.lisp
new file mode 100644
index 0000000..984283d
--- /dev/null
+++ b/src/model.lisp
@@ -0,0 +1,260 @@
+;;;; model.lisp
+
+(defpackage #:vampire.model
+ (:use #:cl)
+ (:local-nicknames
+ (#:a #:alexandria-2)
+ (#:util #:vampire.utilities)
+ (#:config #:vampire.config))
+ (:import-from #:defclass-std #:defclass/std)
+ (:import-from #:bknr.datastore
+ #:with-transaction
+ #:store-object
+ #:persistent-class
+ #:store-objects-with-class
+ #:store-object-id
+ #:store-object-with-id
+ #:delete-object)
+ (:import-from #:bknr.indices
+ #:string-unique-index
+ #:hash-index
+ #:hash-list-index)
+ (:export
+ #:model
+ #:key
+ #:lookup
+ #:session
+ #:playlist
+ #:user
+ #:track
+
+ ;; queries (non-transactional)
+ #:login-user
+ #:can-edit-p
+ #:playlists
+
+ ;; transactions
+ #:make-session
+ #:use-invite-with-code
+ #:new-playlist
+ #:update-playlist-title
+ #:update-playlist
+ #:remove-track
+ #:swap-tracks
+ #:destroy-playlist
+ #:add-editor
+ #:remove-editor
+ #:update-track-info
+ #:append-track))
+
+(in-package :vampire.model)
+
+;;; UTILITIES
+
+(defmacro defclass/bknr (name supers slotdefs &rest options)
+ "Defines a class using defclass/std syntax. Ensures that the class
+ is a sublcas of STORE-OBJECT with metaclass PERSISTENT-CLASS."
+ (let* ((include-store-object-p
+ (notany (lambda (c) (closer-mop:subclassp c 'store-object))
+ supers))
+ (supers
+ (if include-store-object-p
+ `(store-object ,@supers)
+ supers)))
+ `(eval-when (:compile-toplevel :load-toplevel :execute)
+ (defclass/std ,name ,supers
+ ,slotdefs
+ (:metaclass persistent-class)
+ ,@options))))
+
+
+
+;;; CLASSES
+
+(defclass/bknr keyed ()
+ ((key :r :std (util:nuid)
+ :index-type string-unique-index
+ :index-reader lookup)))
+
+(defclass/bknr user (keyed)
+ ((name :index-type string-unique-index
+ :index-reader user-with-name
+ :index-initargs (:test 'equalp))
+ (playlists :std (list))
+ (pwsalt :std (util:nuid))
+ (pwhash)))
+
+(defclass/bknr invite (keyed)
+ ((maker :ri :std nil
+ :index-type hash-index
+ :index-reader invites-by-maker)
+ (uses-remaining :std nil)))
+
+(defclass/bknr session (keyed)
+ ((user :std (error "Sessions must be associated with users."))))
+
+(defun make-session (user)
+ (with-transaction ()
+ (make-instance 'session :user user)))
+
+(defclass/bknr playlist (keyed)
+ ((title :std (util:default-name "playlist"))
+ (tracks editors :std (list))
+ (cover-image :std nil :doc "A url to the cover of this album.")
+ (user :std (error "A USER is required to have created the content."))))
+
+(defmethod initialize-instance :after ((pl playlist) &key)
+ (pushnew pl (playlists (user pl)) :test #'eq))
+
+(defclass/bknr track (keyed)
+ ((source file title artist album thumb-url duration codec )
+ (playlists :std (list)
+ :doc "A list of playlists in which this track appears")))
+
+(defun track-file (track)
+ (with-slots (file) track
+ (merge-pathnames
+ (path:basename file)
+ (merge-pathnames "media/" (config:static-directory*)))))
+
+;;; MODEL OPERATIONS
+
+(defun can-edit-p (user playlist)
+ (or (eq (user playlist) user)
+ (member user (editors playlist) :test #'eq)))
+
+(defun invite-by-code (code)
+ "Returns NIL if CODE is an invalid invite code. Returns the INVITE
+ instance otherwise"
+ (a:when-let (obj (lookup code))
+ (and (typep obj 'invite)
+ (or (null (uses-remaining obj))
+ (plusp (uses-remaining obj)))
+ obj)))
+
+(defun user-with-key (key)
+ (a:when-let (obj (lookup key))
+ (when (typep obj 'user)
+ obj)))
+
+(defun login-user (username password)
+ (a:when-let (user (user-with-name username))
+ (with-slots (pwhash pwsalt) user
+ (when (equalp pwhash (util:hash-string password pwsalt))
+ user))))
+
+(defun last-change (obj)
+ (slot-value obj 'bknr.datastore::last-change))
+
+(defun recent-playlists (&optional (count 10))
+ (util:take count
+ (sort (copy-seq (store-objects-with-class 'playlist))
+ #'>
+ :key #'last-change)))
+
+(defun playlist-duration (pl)
+ (reduce #'+
+ (tracks pl)
+ :key (lambda (tr) (or (duration tr) 0))
+ :initial-value 0))
+
+(defun track-with-source (source)
+ (find source (store-objects-with-class 'track)
+ :test #'string-equal :key 'source))
+
+;;; TRANSACTIONS
+
+(defun new-user (&key name)
+ (with-transaction ()
+ (make-instance 'user :name name)))
+
+(defun set-new-password (user pw)
+ (with-transaction ()
+ (setf (pwhash user)
+ (util:hash-string pw (pwsalt user)))
+ t))
+
+
+(defun use-invite-with-code (code username password)
+ "Redeems invite token CODE, updating it's associated INVITE instance
+and creating a new user with USERNAME and PASSWORD. If everything goes
+well then the USER instance is returned. If not, then NIL is returned,
+indicating that the CODE was not associated with any known INVITE."
+ (with-transaction ()
+ (a:when-let (invite (invite-by-code code))
+ (when (uses-remaining invite)
+ (decf (uses-remaining invite))
+ (unless (plusp (uses-remaining invite))
+ (delete-object invite)))
+ (let ((user (make-instance 'user :name username)))
+ (setf (pwhash user)
+ (util:hash-string password (pwsalt user)))
+ user))))
+
+(defun remove-editor (playlist editor)
+ (with-transaction ()
+ (setf (editors playlist)
+ (delete editor (editors playlist)))))
+
+(defun add-editor (playlist editor)
+ (with-transaction ()
+ (pushnew editor (editors playlist) :test #'eq)))
+
+(defun destroy-invite (invite)
+ (with-transaction ()
+ (delete-object invite)))
+
+(defun make-invite (user &optional uses)
+ (with-transaction ()
+ (make-instance 'invite :maker user :uses-remaining uses)))
+
+(defun append-track (playlist track)
+ (with-transaction ()
+ (setf (tracks playlist) (nconc (tracks playlist) (list track)))
+ (pushnew playlist (playlists track) :test #'eq)))
+
+(defun remove-track (playlist track)
+ (with-transaction ()
+ (setf (tracks playlist) (delete track (tracks playlist))
+ (playlists track) (delete playlist (playlists track)))))
+
+(defun swap-tracks (pl n m)
+ (unless (or (minusp (min m n))
+ (>= (max m n) (length (tracks pl)) ))
+ (with-transaction ()
+ (setf (tracks pl)
+ (util:nswap (tracks pl) n m)))))
+
+(defun new-track (file trackinfo)
+ "Trackinfo is a plist containing information about the track to create."
+ (with-transaction ()
+ (let ((track (apply #'make-instance 'track trackinfo)))
+ (setf (file track) (namestring file))
+ track)))
+
+(defun new-playlist (user &key title)
+ (with-transaction ()
+ (make-instance 'playlist :title title :user user)))
+
+(defun destroy-playlist (pl)
+ (with-transaction ()
+ (setf (playlists (user pl))
+ (delete pl (playlists (user pl))))
+ (delete-object pl)))
+
+(defun update-playlist-title (playlist title)
+ (with-transaction ()
+ (setf (title playlist) title)))
+
+(defun update-playlist (pl title tracks)
+ (with-transaction ()
+ (when title (setf (title pl) title))
+ (when tracks (setf (tracks pl) tracks))
+ pl))
+
+(defun update-track-info (track new-artist new-album new-title)
+ (with-transaction ()
+ (with-slots (artist album title) track
+ (setf artist (unless (equal "" new-artist) new-artist)
+ album (unless (equal "" new-album) new-album)
+ title (unless (equal "" new-title) new-title)))))
diff --git a/package.lisp b/src/package.lisp
index c24492c..63917fc 100644
--- a/package.lisp
+++ b/src/package.lisp
@@ -1,8 +1,13 @@
;;;; package.lisp
(defpackage #:vampire
- (:use #:cl #:clog)
- (:local-nicknames (#:zippy #:org.shirakumo.zippy ))
+ (:use #:cl)
+ (:local-nicknames (#:zippy #:org.shirakumo.zippy)
+ (#:lzb #:lazybones)
+ (#:json #:jonathan)
+ (#:a #:alexandria-2))
+ (:import-from #:lazybones
+ #:defendpoint*)
(:import-from #:bknr.datastore
#:with-transaction
#:store-object
diff --git a/run.lisp b/src/run.lisp
index aa534bd..aa534bd 100644
--- a/run.lisp
+++ b/src/run.lisp
diff --git a/src/session.lisp b/src/session.lisp
new file mode 100644
index 0000000..9887581
--- /dev/null
+++ b/src/session.lisp
@@ -0,0 +1,16 @@
+;;;; session.lisp
+
+(in-package :vampire)
+
+;;; SESSION CLASS
+
+(defclass/bknr session (keyed)
+ ((user :std (error "Sessions must be associated with users."))))
+
+(defun make-session (user)
+ (with-transaction ()
+ (make-instance 'session :user user)))
+
+
+
+
diff --git a/src/site.lisp b/src/site.lisp
new file mode 100644
index 0000000..41d6c45
--- /dev/null
+++ b/src/site.lisp
@@ -0,0 +1,26 @@
+(defpackage #:vampire.site
+ (:import-from #:lazybones #:defendpoint*)
+ (:import-from #:spinneret #:with-html #:with-html-string)
+ (:local-nicknames
+ (#:lzb #:lazybones)
+ (#:json #:jonathan)
+ (#:a #:alexandria-2)
+ (#:util #:vampire.utilities)
+ (#:model #:vampire.model)
+ (#:api #:vampire.api))
+ (:use #:cl))
+
+(in-package #:vampire.site)
+
+;;; APP
+
+(lzb:provision-app ()
+ :content-type "text/html")
+
+;;; SPECIALS
+
+;;; MACROS
+
+;;; UTILITIES
+
+;;; PAGES
diff --git a/utilities.lisp b/src/utilities.lisp
index a7e90e4..7494934 100644
--- a/utilities.lisp
+++ b/src/utilities.lisp
@@ -1,6 +1,24 @@
;;;; utilities.lisp
-(in-package #:vampire)
+(defpackage #:vampire.utilities
+ (:use #:cl)
+ (:export #:nuid
+ #:hash-string
+ #:default-name
+ #:take
+ #:insert-nth
+ #:remove-nth
+ #:nswap
+ #:with-temp-dir
+ #:read-from-file
+ #:secs-to-hms
+ #:clean-filename
+ #:jsonify-symbol
+ #:whitespace-p
+ #:newline-p
+ #:legible-line-p))
+
+(in-package #:vampire.utilities)
(let ((host (uiop:hostname))
(count 0))
@@ -84,14 +102,6 @@
(nth m list) tmp)
list))
-(defmacro thunk* (&body body)
- "Returns a lambda of any number of arguments where those arguments
- are ignored."
- (let ((args (gensym)) )
- `(lambda (&rest ,args)
- (declare (ignorable ,args))
- ,@body)))
-
(defun tmp-dir-name ()
(merge-pathnames
(format nil "~a/" (gensym "tmpdir"))
@@ -122,12 +132,28 @@
(format nil "~a:~2,'0d"
mins secs))))
-(defun <?> (pred then else)
- (lambda (&rest args)
- (if (apply pred args)
- (apply then args)
- (apply else args))))
+
(defun clean-filename (str)
(let ((non-safe-chars (cl-ppcre:create-scanner "[^a-zA-Z0-9_\\-.]")))
(cl-ppcre:regex-replace-all non-safe-chars str "-")))
+
+(defun jsonify-symbol (s)
+ (alexandria:make-keyword (ps:symbol-to-js-string s)))
+
+(defparameter +whitespace-chars+
+ '(#\space #\newline #\return #\tab))
+
+(defparameter +newline-chars+
+ '(#\newline #\return))
+
+(defun whitespace-p (char)
+ (find char +whitespace-chars+))
+
+(defun newline-p (char)
+ (find char +newline-chars+))
+
+(defun legible-line-p (s)
+ (and (stringp s)
+ (plusp (count-if #'alphanumericp s))
+ (zerop (count-if #'newline-p s))))
diff --git a/src/vampire.lisp b/src/vampire.lisp
new file mode 100644
index 0000000..52eb542
--- /dev/null
+++ b/src/vampire.lisp
@@ -0,0 +1,46 @@
+;;;; vampire.lisp
+
+(in-package #:vampire)
+
+;;; SYSTEM CONFIG COMPONENT
+
+(defvar *config* nil)
+
+(defclass/std config ()
+ ((datastore-directory :ir :std #P"/srv/vampire/store/")
+ (static-directory :ir :std #P"/srv/vampire/static/")
+ (swank-port :std nil :doc "If set, swank is started on this port.")
+ (host :std "0.0.0.0")
+ (port :ir :std 4919)
+ (downloader-threads :ir :std 5)))
+
+(defun config-from-file (path)
+ "PATH should be a path to a file containing a PLIST suitable for
+ passing as the keyword arguments to (MAKE-INSTANCE 'CONFIG ...)"
+ (apply #'make-instance 'config (read-from-file path)))
+
+;;; STARTUP
+
+(defun initialize-database (config)
+ (ensure-directories-exist (datastore-directory config))
+ (make-instance
+ 'bknr.datastore:mp-store
+ :directory (datastore-directory config)
+ :subsystems (list (make-instance 'bknr.datastore:store-object-subsystem))))
+
+(defun start-vampire (config)
+ (setf *config* config)
+ (initialize-database config )
+ (start-downloader-service config)
+ (when (swank-port config)
+ (swank:create-server :port (swank-port config) :dont-close t)))
+
+(defun hacking-start ()
+ (start-vampire
+ (make-instance
+ 'config
+ :static-directory (merge-pathnames "vampire-static/" (user-homedir-pathname))
+ :datastore-directory (merge-pathnames "vampire-store/" (user-homedir-pathname)))))
+
+
+
diff --git a/zipper.lisp b/src/zipper.lisp
index 91fafba..91fafba 100644
--- a/zipper.lisp
+++ b/src/zipper.lisp
diff --git a/static/boot.html b/static/boot.html
deleted file mode 100644
index 9e19839..0000000
--- a/static/boot.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!doctype HTML>
-<HTML>
- <HEAD>
- <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
- <meta http-equiv="Pragma" content="no-cache" />
- <meta http-equiv="Expires" content="0" />
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <script src="/js/jquery.min.js" type="text/javascript"></script>
- <script src="/js/boot.js" type="text/javascript"></script>
- <noscript><%= (@ meta) %></noscript>
- </HEAD>
-<BODY>
- <noscript><%= (@ body) %></noscript>
-</BODY>
-<noscript>Your browser must support JavaScript and be HTML 5 compilant to see this site.</noscript>
-</HTML>
diff --git a/static/bootstrap.html b/static/bootstrap.html
deleted file mode 100644
index b84f5fc..0000000
--- a/static/bootstrap.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!doctype HTML>
-<HTML>
- <HEAD>
- <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
- <meta http-equiv="Pragma" content="no-cache" />
- <meta http-equiv="Expires" content="0" />
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <script src="/js/jquery.min.js" type="text/javascript"></script>
- <script src="/js/boot.js" type="text/javascript"></script>
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
- <noscript><%= (@ meta) %></noscript>
- </HEAD>
-<BODY>
- <noscript><%= (@ body) %></noscript>
-</BODY>
-<noscript>Your browser must support JavaScript and be HTML 5 compilant to see this site.</noscript>
-</HTML>
diff --git a/config.lisp b/static/config.sexp
index 966e90f..966e90f 100644
--- a/config.lisp
+++ b/static/config.sexp
diff --git a/static/css/main-2.css b/static/css/main-2.css
deleted file mode 100644
index 665eb76..0000000
--- a/static/css/main-2.css
+++ /dev/null
@@ -1,101 +0,0 @@
-
-body {
- background-color: #1c1c1c;
- color: #e8e7d5;
-}
-
-a {
- color: #d478e0;
-}
-
-h1,h2,h3,h4 {
- color: #ff9430;
-}
-
-button {
- background: #1c1c1c;
- color: #ff9430;
- border: 1px solid #ff9430;
- margin-left: 2px;
- margin-right: 2px;
-}
-
-button:hover {
- cursor: pointer;
-}
-
-.center {
- text-align: center;
-}
-
-.row {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: space-evenly;
- align-content: baseline;
-}
-
-.column {
- display: flex;
- flex-direction: column;
- flex-wrap: wrap;
- justify-content: center;
- align-content: baseline;
-}
-
-.centered-column {
- display: grid;
- grid-template-columns: 1fr minmax(300px,500px) 1fr;
- padding: 10px;
- column-gap: 40px;
-}
-
-.four-column > div {
- max-width: 50%;
-}
-
-
-.track-list-item:hover {
- cursor: pointer;
- background-color: #454545;
-}
-
-.player {
- display: flex;
- justify-content: space-evenly;
- width: 100%;
- flex-wrap: wrap;
-}
-
-.now-playing {
- display: flex;
- width: 300px;
- flex-direction: column;
-}
-
-.controls {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
-}
-
-.controls button {
- font-size: 2em;
- width: -moz-available;
- width: -webkit-fill-available;
- width: stretch;
-}
-
-.now-playing-track {
- background-color: #454545;
-}
-
-.playlist-display {
- margin-top: 2em;
- width: auto;
- display: flex;
- flex-direction: column;
- height: 600px;
- overflow-y: auto;
-}
diff --git a/static/css/main-3.css b/static/css/main-3.css
deleted file mode 100644
index 201072d..0000000
--- a/static/css/main-3.css
+++ /dev/null
@@ -1,150 +0,0 @@
-body {
- background-color: #1c1c1c;
- color: #e8e7d5;
- width: 90vw;
- display: flex;
- justify-content: center;
- margin: auto;
-}
-
-a {
- color: #d478e0;
-}
-
-h1,h2,h3,h4 {
- color: #ff9430;
-}
-
-button {
- background: #1c1c1c;
- color: #ff9430;
- border: 1px solid #ff9430;
- margin-left: 2px;
- margin-right: 2px;
-}
-
-button:hover {
- cursor: pointer;
-}
-
-.header {
- position: sticky;
- top: 0px;
- background-color: #1c1c1c;
- padding: .1rem;
- align-items: center;
- justify-content: space-around;
-}
-
-.center {
- text-align: center;
-}
-
-.row {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: space-evenly;
- align-content: baseline;
-}
-
-.column {
- display: flex;
- flex-direction: column;
- flex-wrap: wrap;
- justify-content: center;
- align-content: baseline;
-}
-
-.centered-column {
- display: grid;
- grid-template-columns: 1fr minmax(300px,500px) 1fr;
- padding: 10px;
- column-gap: 40px;
-}
-
-.four-column > div {
- max-width: 50%;
-}
-
-.track-list-item:hover {
- cursor: pointer;
- background-color: #454545;
-}
-
-.container {
- width: 100%;
-}
-
-.player {
- display: flex;
- justify-content: space-evenly;
- width: 100%;
- flex-wrap: wrap;
-}
-
-.now-playing {
- display: flex;
- width: 300px;
- flex-direction: column;
-}
-
-.controls {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
-}
-
-.controls button {
- font-size: 2em;
- width: -moz-available;
- width: -webkit-fill-available;
- width: stretch;
-}
-
-.now-playing-track {
- background-color: #454545;
-}
-
-
-.playlist-display {
- margin-top: 2rem;
- width: auto;
- display: flex;
- flex-direction: column;
-}
-
-.login {
- margin-top: 10rem;
-}
-
-
-.card {
- display: flex;
- width: 200px;
- height: 200px;
- align-items: center;
- justify-content: center;
-}
-
-.thumb {
- max-width: 180px;
-}
-
-@media (max-width: 500px) {
- body {
- font-size: small;
- width: 100vw;
- }
-
- h1 {
- font-size: medium;
- }
-}
-
-@media (min-width: 500px) {
- .playlist-display {
- height: 80vh;
- overflow-y: auto;
- }
-}
diff --git a/static/css/main-4.css b/static/css/main-4.css
deleted file mode 100644
index 49de839..0000000
--- a/static/css/main-4.css
+++ /dev/null
@@ -1,165 +0,0 @@
-body {
- background-color: #1c1c1c;
- color: #e8e7d5;
- width: 90vw;
- display: flex;
- justify-content: center;
- margin: auto;
-}
-
-a {
- color: #d478e0;
-}
-
-h1,h2,h3,h4 {
- color: #ff9430;
-}
-
-button {
- background: #1c1c1c;
- color: #ff9430;
- border: 1px solid #ff9430;
- margin-left: 2px;
- margin-right: 2px;
-}
-
-button:hover {
- cursor: pointer;
-}
-
-button:disabled {
- color: #666666;
- border: 1px solid #666666;
-}
-
-button:disabled:hover {
- cursor: not-allowed;
-}
-
-.header {
- position: sticky;
- top: 0px;
- background-color: #1c1c1c;
- padding: .1rem;
- align-items: center;
- justify-content: space-around;
-}
-
-.center {
- text-align: center;
-}
-
-.row {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: space-evenly;
- align-content: baseline;
-}
-
-.column {
- display: flex;
- flex-direction: column;
- flex-wrap: wrap;
- justify-content: center;
- align-content: baseline;
-}
-
-.centered-column {
- display: grid;
- grid-template-columns: 1fr minmax(300px,500px) 1fr;
- padding: 10px;
- column-gap: 40px;
-}
-
-.four-column > div {
- max-width: 50%;
-}
-
-.track-list-item:hover {
- cursor: pointer;
- background-color: #454545;
-}
-
-.container {
- width: 100%;
-}
-
-.player {
- display: flex;
- justify-content: space-evenly;
- width: 100%;
- flex-wrap: wrap;
-}
-
-.now-playing {
- display: flex;
- width: 300px;
- flex-direction: column;
-}
-
-.controls {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
-}
-
-.track-edit-inputs {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
-}
-
-.controls button {
- font-size: 2em;
- width: -moz-available;
- width: -webkit-fill-available;
- width: stretch;
-}
-
-.now-playing-track {
- background-color: #454545;
-}
-
-
-.playlist-display {
- margin-top: 2rem;
- width: auto;
- display: flex;
- flex-direction: column;
-}
-
-.login {
- margin-top: 10rem;
-}
-
-
-.card {
- display: flex;
- width: 200px;
- height: 200px;
- align-items: center;
- justify-content: center;
-}
-
-.thumb {
- max-width: 180px;
-}
-
-@media (max-width: 500px) {
- body {
- font-size: small;
- width: 100vw;
- }
-
- h1 {
- font-size: medium;
- }
-}
-
-@media (min-width: 500px) {
- .playlist-display {
- height: 80vh;
- overflow-y: auto;
- }
-}
diff --git a/static/css/main.css b/static/css/main.css
deleted file mode 100644
index 1303fca..0000000
--- a/static/css/main.css
+++ /dev/null
@@ -1,73 +0,0 @@
-
-body {
- background-color: #1c1c1c;
- color: #e8e7d5;
-}
-
-a {
- color: #d478e0;
-}
-
-h1,h2,h3,h4 {
- color: #ff9430;
-}
-
-button {
- background: #1c1c1c;
- color: #ff9430;
- border: 1px solid #ff9430;
- margin-left: 2px;
- margin-right: 2px;
-}
-
-button:hover {
- cursor: pointer;
-}
-
-.center {
- text-align: center;
-}
-
-.row {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: center;
- align-content: baseline;
-}
-
-.row>div {
- margin: 30px;
-}
-
-.centered-column {
- display: grid;
- grid-template-columns: 1fr minmax(300px,500px) 1fr;
- padding: 10px;
- column-gap: 40px;
-}
-
-.four-column > div {
- max-width: 50%;
-}
-
-
-.track-list-item:hover {
- cursor: pointer;
- background-color: #454545;
-}
-
-.now-playing {
- position: sticky;
- top: 2em;
- width: 300px;
-}
-
-.now-playing button {
- font-size: 2em;
-}
-
-.now-playing-track {
- background-color: #454545;
-}
-
diff --git a/static/css/reset.css b/static/css/reset.css
deleted file mode 100644
index 1bb9f7c..0000000
--- a/static/css/reset.css
+++ /dev/null
@@ -1,2 +0,0 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{ margin:0; padding:0; border:0; font-size:100%; font:inherit; vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{ display:block}body{ line-height:1}ol,ul{ list-style:none}blockquote,q{ quotes:none}blockquote:before,blockquote:after,q:before,q:after{ content:""; content:none}table{ border-collapse:collapse; border-spacing:0}html{ line-height:1.15; -webkit-text-size-adjust:100%}main{ display:block}h1{ font-size:2em; margin:0.67em 0}hr{ box-sizing:content-box; height:0; overflow:visible}pre{ font-family:monospace,monospace; font-size:1em}a{ background-color:transparent}abbr[title]{ border-bottom:none; text-decoration:underline; text-decoration:underline dotted}b,strong{ font-weight:bolder}code,kbd,samp{ font-family:monospace,monospace; font-size:1em}small{ font-size:80%}sub,sup{ font-size:75%; line-height:0; position:relative; vertical-align:baseline}sub{ bottom:-0.25em}sup{ top:-0.5em}img{ border-style:none}button,input,optgroup,select,textarea{ font-family:inherit; font-size:100%; line-height:1.15; margin:0}button,input{ overflow:visible}button,select{ text-transform:none}button,[type="button"],[type="reset"],[type="submit"]{ -webkit-appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{ border-style:none; padding:0}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{ outline:1px dotted ButtonText}fieldset{ padding:0.35em 0.75em 0.625em}legend{ box-sizing:border-box; color:inherit; display:table; max-width:100%; padding:0; white-space:normal}progress{ vertical-align:baseline}textarea{ overflow:auto}[type="checkbox"],[type="radio"]{ box-sizing:border-box; padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{ height:auto}[type="search"]{ -webkit-appearance:textfield; outline-offset:-2px}[type="search"]::-webkit-search-decoration{ -webkit-appearance:none}::-webkit-file-upload-button{ -webkit-appearance:button; font:inherit}details{ display:block}summary{ display:list-item}template{ display:none}[hidden]{ display:none}*:where(:not(iframe,canvas,img,svg,video):not(svg *,symbol *)){ all:unset; display:revert}*,*::before,*::after{ box-sizing:border-box}a,button{ cursor:revert}ol,ul,menu{ list-style:none}img{ max-width:100%}table{ border-collapse:collapse}textarea{ white-space:revert}meter{ -webkit-appearance:revert; appearance:revert}::placeholder{ color:unset}:where([hidden]){ display:none}:where([contenteditable]){ -moz-user-modify:read-write; -webkit-user-modify:read-write; overflow-wrap:break-word; -webkit-line-break:after-white-space}:where([draggable="true"]){ -webkit-user-drag:element}
-
diff --git a/static/debug.html b/static/debug.html
deleted file mode 100644
index 26e6c6f..0000000
--- a/static/debug.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!doctype HTML>
-<HTML>
- <HEAD>
- <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
- <meta http-equiv="Pragma" content="no-cache" />
- <meta http-equiv="Expires" content="0" />
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <script src="/js/jquery.min.js" type="text/javascript"></script>
- <script>var clog_debug = true;</script>
- <script src="/js/boot.js" type="text/javascript"></script>
- <noscript><%= (@ meta) %></noscript>
- </HEAD>
-<BODY>
- <noscript><%= (@ body) %></noscript>
-</BODY>
-<noscript>Your browser must support JavaScript and be HTML 5 compilant to see this site.</noscript>
-</HTML>
diff --git a/static/favicon.ico b/static/favicon.ico
deleted file mode 100644
index 80a0bf9..0000000
--- a/static/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/static/js/boot.js b/static/js/boot.js
deleted file mode 100644
index 42cd03e..0000000
--- a/static/js/boot.js
+++ /dev/null
@@ -1,121 +0,0 @@
-var ws=null;
-var adr; var adrc;
-var clog={};
-var pingerid;
-var s = document.location.search;
-var tokens;
-var r = /[?&]?([^=]+)=([^&]*)/g;
-
-clog['body']=document.body;
-clog['head']=document.head;
-clog['documentElement']=document.documentElement;
-clog['window']=window;
-clog['navigator']=navigator;
-clog['document']=window.document;
-clog['location']=window.location;
-
-if (typeof clog_debug == 'undefined') {
- clog_debug = false;
-}
-
-function Ping_ws() {
- if (ws.readyState == 1) {
- ws.send ('0');
- }
-}
-
-function Shutdown_ws(event) {
- if (ws != null) {
- ws.onerror = null;
- ws.onclose = null;
- ws.close ();
- ws = null;
- }
- clearInterval (pingerid);
- if (clog['html_on_close'] != '') {
- $(document.body).html(clog['html_on_close']);
- }
-}
-
-function Setup_ws() {
- ws.onmessage = function (event) {
- try {
- if (clog_debug == true) {
- console.log ('eval data = ' + event.data);
- }
- eval (event.data);
- } catch (e) {
- console.error (e.message);
- }
- }
-
- ws.onerror = function (event) {
- console.log ('onerror: reconnect');
- ws = null;
- ws = new WebSocket (adr + '?r=' + clog['connection_id']);
- ws.onopen = function (event) {
- console.log ('onerror: reconnect successful');
- Setup_ws();
- }
- ws.onclose = function (event) {
- console.log ('onerror: reconnect failure');
- Shutdown_ws(event);
- }
- }
-
- ws.onclose = function (event) {
- if (event.code && event.code === 1000) {
- console.log("WebSocket connection got normal close from server. Don't reconnect.");
- Shutdown_ws(event);
- } else {
- console.log ('onclose: reconnect');
- ws = null;
- ws = new WebSocket (adr + '?r=' + clog['connection_id']);
- ws.onopen = function (event) {
- console.log ('onclose: reconnect successful');
- Setup_ws();
- }
- ws.onclose = function (event) {
- console.log ('onclose: reconnect failure');
- Shutdown_ws(event);
- }
- }
- }
-}
-
-function Open_ws() {
- if (location.protocol == 'https:') {
- adr = 'wss://' + location.hostname;
- } else {
- adr = 'ws://' + location.hostname;
- }
-
- if (location.port != '') { adr = adr + ':' + location.port; }
- adr = adr + '/clog';
-
- if (clog['connection_id']) {
- adrc = adr + '?r=' + clog['connection_id'];
- } else { adrc = adr }
-
- try {
- console.log ('connecting to ' + adrc);
- ws = new WebSocket (adrc);
- } catch (e) {
- console.log ('trying again, connecting to ' + adrc);
- ws = new WebSocket (adrc);
- }
-
- if (ws != null) {
- ws.onopen = function (event) {
- console.log ('connection successful');
- Setup_ws();
- }
- pingerid = setInterval (function () {Ping_ws ();}, 10000);
- } else {
- document.writeln ('If you are seeing this your browser or your connection to the internet is blocking websockets.');
- }
-}
-
-$( document ).ready(function() {
- if (ws == null) { Open_ws(); }
-});
diff --git a/static/js/jquery-ui.js b/static/js/jquery-ui.js
deleted file mode 100644
index 5d9bfa2..0000000
--- a/static/js/jquery-ui.js
+++ /dev/null
@@ -1,19057 +0,0 @@
-/*! jQuery UI - v1.13.1 - 2022-01-20
-* http://jqueryui.com
-* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-patch.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js
-* Copyright jQuery Foundation and other contributors; Licensed MIT */
-
-( function( factory ) {
- "use strict";
-
- if ( typeof define === "function" && define.amd ) {
-
- // AMD. Register as an anonymous module.
- define( [ "jquery" ], factory );
- } else {
-
- // Browser globals
- factory( jQuery );
- }
-} )( function( $ ) {
-"use strict";
-
-$.ui = $.ui || {};
-
-var version = $.ui.version = "1.13.1";
-
-
-/*!
- * jQuery UI Widget 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Widget
-//>>group: Core
-//>>description: Provides a factory for creating stateful widgets with a common API.
-//>>docs: http://api.jqueryui.com/jQuery.widget/
-//>>demos: http://jqueryui.com/widget/
-
-
-var widgetUuid = 0;
-var widgetHasOwnProperty = Array.prototype.hasOwnProperty;
-var widgetSlice = Array.prototype.slice;
-
-$.cleanData = ( function( orig ) {
- return function( elems ) {
- var events, elem, i;
- for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
-
- // Only trigger remove when necessary to save time
- events = $._data( elem, "events" );
- if ( events && events.remove ) {
- $( elem ).triggerHandler( "remove" );
- }
- }
- orig( elems );
- };
-} )( $.cleanData );
-
-$.widget = function( name, base, prototype ) {
- var existingConstructor, constructor, basePrototype;
-
- // ProxiedPrototype allows the provided prototype to remain unmodified
- // so that it can be used as a mixin for multiple widgets (#8876)
- var proxiedPrototype = {};
-
- var namespace = name.split( "." )[ 0 ];
- name = name.split( "." )[ 1 ];
- var fullName = namespace + "-" + name;
-
- if ( !prototype ) {
- prototype = base;
- base = $.Widget;
- }
-
- if ( Array.isArray( prototype ) ) {
- prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
- }
-
- // Create selector for plugin
- $.expr.pseudos[ fullName.toLowerCase() ] = function( elem ) {
- return !!$.data( elem, fullName );
- };
-
- $[ namespace ] = $[ namespace ] || {};
- existingConstructor = $[ namespace ][ name ];
- constructor = $[ namespace ][ name ] = function( options, element ) {
-
- // Allow instantiation without "new" keyword
- if ( !this || !this._createWidget ) {
- return new constructor( options, element );
- }
-
- // Allow instantiation without initializing for simple inheritance
- // must use "new" keyword (the code above always passes args)
- if ( arguments.length ) {
- this._createWidget( options, element );
- }
- };
-
- // Extend with the existing constructor to carry over any static properties
- $.extend( constructor, existingConstructor, {
- version: prototype.version,
-
- // Copy the object used to create the prototype in case we need to
- // redefine the widget later
- _proto: $.extend( {}, prototype ),
-
- // Track widgets that inherit from this widget in case this widget is
- // redefined after a widget inherits from it
- _childConstructors: []
- } );
-
- basePrototype = new base();
-
- // We need to make the options hash a property directly on the new instance
- // otherwise we'll modify the options hash on the prototype that we're
- // inheriting from
- basePrototype.options = $.widget.extend( {}, basePrototype.options );
- $.each( prototype, function( prop, value ) {
- if ( typeof value !== "function" ) {
- proxiedPrototype[ prop ] = value;
- return;
- }
- proxiedPrototype[ prop ] = ( function() {
- function _super() {
- return base.prototype[ prop ].apply( this, arguments );
- }
-
- function _superApply( args ) {
- return base.prototype[ prop ].apply( this, args );
- }
-
- return function() {
- var __super = this._super;
- var __superApply = this._superApply;
- var returnValue;
-
- this._super = _super;
- this._superApply = _superApply;
-
- returnValue = value.apply( this, arguments );
-
- this._super = __super;
- this._superApply = __superApply;
-
- return returnValue;
- };
- } )();
- } );
- constructor.prototype = $.widget.extend( basePrototype, {
-
- // TODO: remove support for widgetEventPrefix
- // always use the name + a colon as the prefix, e.g., draggable:start
- // don't prefix for widgets that aren't DOM-based
- widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
- }, proxiedPrototype, {
- constructor: constructor,
- namespace: namespace,
- widgetName: name,
- widgetFullName: fullName
- } );
-
- // If this widget is being redefined then we need to find all widgets that
- // are inheriting from it and redefine all of them so that they inherit from
- // the new version of this widget. We're essentially trying to replace one
- // level in the prototype chain.
- if ( existingConstructor ) {
- $.each( existingConstructor._childConstructors, function( i, child ) {
- var childPrototype = child.prototype;
-
- // Redefine the child widget using the same prototype that was
- // originally used, but inherit from the new version of the base
- $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
- child._proto );
- } );
-
- // Remove the list of existing child constructors from the old constructor
- // so the old child constructors can be garbage collected
- delete existingConstructor._childConstructors;
- } else {
- base._childConstructors.push( constructor );
- }
-
- $.widget.bridge( name, constructor );
-
- return constructor;
-};
-
-$.widget.extend = function( target ) {
- var input = widgetSlice.call( arguments, 1 );
- var inputIndex = 0;
- var inputLength = input.length;
- var key;
- var value;
-
- for ( ; inputIndex < inputLength; inputIndex++ ) {
- for ( key in input[ inputIndex ] ) {
- value = input[ inputIndex ][ key ];
- if ( widgetHasOwnProperty.call( input[ inputIndex ], key ) && value !== undefined ) {
-
- // Clone objects
- if ( $.isPlainObject( value ) ) {
- target[ key ] = $.isPlainObject( target[ key ] ) ?
- $.widget.extend( {}, target[ key ], value ) :
-
- // Don't extend strings, arrays, etc. with objects
- $.widget.extend( {}, value );
-
- // Copy everything else by reference
- } else {
- target[ key ] = value;
- }
- }
- }
- }
- return target;
-};
-
-$.widget.bridge = function( name, object ) {
- var fullName = object.prototype.widgetFullName || name;
- $.fn[ name ] = function( options ) {
- var isMethodCall = typeof options === "string";
- var args = widgetSlice.call( arguments, 1 );
- var returnValue = this;
-
- if ( isMethodCall ) {
-
- // If this is an empty collection, we need to have the instance method
- // return undefined instead of the jQuery instance
- if ( !this.length && options === "instance" ) {
- returnValue = undefined;
- } else {
- this.each( function() {
- var methodValue;
- var instance = $.data( this, fullName );
-
- if ( options === "instance" ) {
- returnValue = instance;
- return false;
- }
-
- if ( !instance ) {
- return $.error( "cannot call methods on " + name +
- " prior to initialization; " +
- "attempted to call method '" + options + "'" );
- }
-
- if ( typeof instance[ options ] !== "function" ||
- options.charAt( 0 ) === "_" ) {
- return $.error( "no such method '" + options + "' for " + name +
- " widget instance" );
- }
-
- methodValue = instance[ options ].apply( instance, args );
-
- if ( methodValue !== instance && methodValue !== undefined ) {
- returnValue = methodValue && methodValue.jquery ?
- returnValue.pushStack( methodValue.get() ) :
- methodValue;
- return false;
- }
- } );
- }
- } else {
-
- // Allow multiple hashes to be passed on init
- if ( args.length ) {
- options = $.widget.extend.apply( null, [ options ].concat( args ) );
- }
-
- this.each( function() {
- var instance = $.data( this, fullName );
- if ( instance ) {
- instance.option( options || {} );
- if ( instance._init ) {
- instance._init();
- }
- } else {
- $.data( this, fullName, new object( options, this ) );
- }
- } );
- }
-
- return returnValue;
- };
-};
-
-$.Widget = function( /* options, element */ ) {};
-$.Widget._childConstructors = [];
-
-$.Widget.prototype = {
- widgetName: "widget",
- widgetEventPrefix: "",
- defaultElement: "<div>",
-
- options: {
- classes: {},
- disabled: false,
-
- // Callbacks
- create: null
- },
-
- _createWidget: function( options, element ) {
- element = $( element || this.defaultElement || this )[ 0 ];
- this.element = $( element );
- this.uuid = widgetUuid++;
- this.eventNamespace = "." + this.widgetName + this.uuid;
-
- this.bindings = $();
- this.hoverable = $();
- this.focusable = $();
- this.classesElementLookup = {};
-
- if ( element !== this ) {
- $.data( element, this.widgetFullName, this );
- this._on( true, this.element, {
- remove: function( event ) {
- if ( event.target === element ) {
- this.destroy();
- }
- }
- } );
- this.document = $( element.style ?
-
- // Element within the document
- element.ownerDocument :
-
- // Element is window or document
- element.document || element );
- this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
- }
-
- this.options = $.widget.extend( {},
- this.options,
- this._getCreateOptions(),
- options );
-
- this._create();
-
- if ( this.options.disabled ) {
- this._setOptionDisabled( this.options.disabled );
- }
-
- this._trigger( "create", null, this._getCreateEventData() );
- this._init();
- },
-
- _getCreateOptions: function() {
- return {};
- },
-
- _getCreateEventData: $.noop,
-
- _create: $.noop,
-
- _init: $.noop,
-
- destroy: function() {
- var that = this;
-
- this._destroy();
- $.each( this.classesElementLookup, function( key, value ) {
- that._removeClass( value, key );
- } );
-
- // We can probably remove the unbind calls in 2.0
- // all event bindings should go through this._on()
- this.element
- .off( this.eventNamespace )
- .removeData( this.widgetFullName );
- this.widget()
- .off( this.eventNamespace )
- .removeAttr( "aria-disabled" );
-
- // Clean up events and states
- this.bindings.off( this.eventNamespace );
- },
-
- _destroy: $.noop,
-
- widget: function() {
- return this.element;
- },
-
- option: function( key, value ) {
- var options = key;
- var parts;
- var curOption;
- var i;
-
- if ( arguments.length === 0 ) {
-
- // Don't return a reference to the internal hash
- return $.widget.extend( {}, this.options );
- }
-
- if ( typeof key === "string" ) {
-
- // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
- options = {};
- parts = key.split( "." );
- key = parts.shift();
- if ( parts.length ) {
- curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
- for ( i = 0; i < parts.length - 1; i++ ) {
- curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
- curOption = curOption[ parts[ i ] ];
- }
- key = parts.pop();
- if ( arguments.length === 1 ) {
- return curOption[ key ] === undefined ? null : curOption[ key ];
- }
- curOption[ key ] = value;
- } else {
- if ( arguments.length === 1 ) {
- return this.options[ key ] === undefined ? null : this.options[ key ];
- }
- options[ key ] = value;
- }
- }
-
- this._setOptions( options );
-
- return this;
- },
-
- _setOptions: function( options ) {
- var key;
-
- for ( key in options ) {
- this._setOption( key, options[ key ] );
- }
-
- return this;
- },
-
- _setOption: function( key, value ) {
- if ( key === "classes" ) {
- this._setOptionClasses( value );
- }
-
- this.options[ key ] = value;
-
- if ( key === "disabled" ) {
- this._setOptionDisabled( value );
- }
-
- return this;
- },
-
- _setOptionClasses: function( value ) {
- var classKey, elements, currentElements;
-
- for ( classKey in value ) {
- currentElements = this.classesElementLookup[ classKey ];
- if ( value[ classKey ] === this.options.classes[ classKey ] ||
- !currentElements ||
- !currentElements.length ) {
- continue;
- }
-
- // We are doing this to create a new jQuery object because the _removeClass() call
- // on the next line is going to destroy the reference to the current elements being
- // tracked. We need to save a copy of this collection so that we can add the new classes
- // below.
- elements = $( currentElements.get() );
- this._removeClass( currentElements, classKey );
-
- // We don't use _addClass() here, because that uses this.options.classes
- // for generating the string of classes. We want to use the value passed in from
- // _setOption(), this is the new value of the classes option which was passed to
- // _setOption(). We pass this value directly to _classes().
- elements.addClass( this._classes( {
- element: elements,
- keys: classKey,
- classes: value,
- add: true
- } ) );
- }
- },
-
- _setOptionDisabled: function( value ) {
- this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
-
- // If the widget is becoming disabled, then nothing is interactive
- if ( value ) {
- this._removeClass( this.hoverable, null, "ui-state-hover" );
- this._removeClass( this.focusable, null, "ui-state-focus" );
- }
- },
-
- enable: function() {
- return this._setOptions( { disabled: false } );
- },
-
- disable: function() {
- return this._setOptions( { disabled: true } );
- },
-
- _classes: function( options ) {
- var full = [];
- var that = this;
-
- options = $.extend( {
- element: this.element,
- classes: this.options.classes || {}
- }, options );
-
- function bindRemoveEvent() {
- var nodesToBind = [];
-
- options.element.each( function( _, element ) {
- var isTracked = $.map( that.classesElementLookup, function( elements ) {
- return elements;
- } )
- .some( function( elements ) {
- return elements.is( element );
- } );
-
- if ( !isTracked ) {
- nodesToBind.push( element );
- }
- } );
-
- that._on( $( nodesToBind ), {
- remove: "_untrackClassesElement"
- } );
- }
-
- function processClassString( classes, checkOption ) {
- var current, i;
- for ( i = 0; i < classes.length; i++ ) {
- current = that.classesElementLookup[ classes[ i ] ] || $();
- if ( options.add ) {
- bindRemoveEvent();
- current = $( $.uniqueSort( current.get().concat( options.element.get() ) ) );
- } else {
- current = $( current.not( options.element ).get() );
- }
- that.classesElementLookup[ classes[ i ] ] = current;
- full.push( classes[ i ] );
- if ( checkOption && options.classes[ classes[ i ] ] ) {
- full.push( options.classes[ classes[ i ] ] );
- }
- }
- }
-
- if ( options.keys ) {
- processClassString( options.keys.match( /\S+/g ) || [], true );
- }
- if ( options.extra ) {
- processClassString( options.extra.match( /\S+/g ) || [] );
- }
-
- return full.join( " " );
- },
-
- _untrackClassesElement: function( event ) {
- var that = this;
- $.each( that.classesElementLookup, function( key, value ) {
- if ( $.inArray( event.target, value ) !== -1 ) {
- that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
- }
- } );
-
- this._off( $( event.target ) );
- },
-
- _removeClass: function( element, keys, extra ) {
- return this._toggleClass( element, keys, extra, false );
- },
-
- _addClass: function( element, keys, extra ) {
- return this._toggleClass( element, keys, extra, true );
- },
-
- _toggleClass: function( element, keys, extra, add ) {
- add = ( typeof add === "boolean" ) ? add : extra;
- var shift = ( typeof element === "string" || element === null ),
- options = {
- extra: shift ? keys : extra,
- keys: shift ? element : keys,
- element: shift ? this.element : element,
- add: add
- };
- options.element.toggleClass( this._classes( options ), add );
- return this;
- },
-
- _on: function( suppressDisabledCheck, element, handlers ) {
- var delegateElement;
- var instance = this;
-
- // No suppressDisabledCheck flag, shuffle arguments
- if ( typeof suppressDisabledCheck !== "boolean" ) {
- handlers = element;
- element = suppressDisabledCheck;
- suppressDisabledCheck = false;
- }
-
- // No element argument, shuffle and use this.element
- if ( !handlers ) {
- handlers = element;
- element = this.element;
- delegateElement = this.widget();
- } else {
- element = delegateElement = $( element );
- this.bindings = this.bindings.add( element );
- }
-
- $.each( handlers, function( event, handler ) {
- function handlerProxy() {
-
- // Allow widgets to customize the disabled handling
- // - disabled as an array instead of boolean
- // - disabled class as method for disabling individual parts
- if ( !suppressDisabledCheck &&
- ( instance.options.disabled === true ||
- $( this ).hasClass( "ui-state-disabled" ) ) ) {
- return;
- }
- return ( typeof handler === "string" ? instance[ handler ] : handler )
- .apply( instance, arguments );
- }
-
- // Copy the guid so direct unbinding works
- if ( typeof handler !== "string" ) {
- handlerProxy.guid = handler.guid =
- handler.guid || handlerProxy.guid || $.guid++;
- }
-
- var match = event.match( /^([\w:-]*)\s*(.*)$/ );
- var eventName = match[ 1 ] + instance.eventNamespace;
- var selector = match[ 2 ];
-
- if ( selector ) {
- delegateElement.on( eventName, selector, handlerProxy );
- } else {
- element.on( eventName, handlerProxy );
- }
- } );
- },
-
- _off: function( element, eventName ) {
- eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
- this.eventNamespace;
- element.off( eventName );
-
- // Clear the stack to avoid memory leaks (#10056)
- this.bindings = $( this.bindings.not( element ).get() );
- this.focusable = $( this.focusable.not( element ).get() );
- this.hoverable = $( this.hoverable.not( element ).get() );
- },
-
- _delay: function( handler, delay ) {
- function handlerProxy() {
- return ( typeof handler === "string" ? instance[ handler ] : handler )
- .apply( instance, arguments );
- }
- var instance = this;
- return setTimeout( handlerProxy, delay || 0 );
- },
-
- _hoverable: function( element ) {
- this.hoverable = this.hoverable.add( element );
- this._on( element, {
- mouseenter: function( event ) {
- this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
- },
- mouseleave: function( event ) {
- this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
- }
- } );
- },
-
- _focusable: function( element ) {
- this.focusable = this.focusable.add( element );
- this._on( element, {
- focusin: function( event ) {
- this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
- },
- focusout: function( event ) {
- this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
- }
- } );
- },
-
- _trigger: function( type, event, data ) {
- var prop, orig;
- var callback = this.options[ type ];
-
- data = data || {};
- event = $.Event( event );
- event.type = ( type === this.widgetEventPrefix ?
- type :
- this.widgetEventPrefix + type ).toLowerCase();
-
- // The original event may come from any element
- // so we need to reset the target on the new event
- event.target = this.element[ 0 ];
-
- // Copy original event properties over to the new event
- orig = event.originalEvent;
- if ( orig ) {
- for ( prop in orig ) {
- if ( !( prop in event ) ) {
- event[ prop ] = orig[ prop ];
- }
- }
- }
-
- this.element.trigger( event, data );
- return !( typeof callback === "function" &&
- callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
- event.isDefaultPrevented() );
- }
-};
-
-$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
- $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
- if ( typeof options === "string" ) {
- options = { effect: options };
- }
-
- var hasOptions;
- var effectName = !options ?
- method :
- options === true || typeof options === "number" ?
- defaultEffect :
- options.effect || defaultEffect;
-
- options = options || {};
- if ( typeof options === "number" ) {
- options = { duration: options };
- } else if ( options === true ) {
- options = {};
- }
-
- hasOptions = !$.isEmptyObject( options );
- options.complete = callback;
-
- if ( options.delay ) {
- element.delay( options.delay );
- }
-
- if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
- element[ method ]( options );
- } else if ( effectName !== method && element[ effectName ] ) {
- element[ effectName ]( options.duration, options.easing, callback );
- } else {
- element.queue( function( next ) {
- $( this )[ method ]();
- if ( callback ) {
- callback.call( element[ 0 ] );
- }
- next();
- } );
- }
- };
-} );
-
-var widget = $.widget;
-
-
-/*!
- * jQuery UI Position 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://api.jqueryui.com/position/
- */
-
-//>>label: Position
-//>>group: Core
-//>>description: Positions elements relative to other elements.
-//>>docs: http://api.jqueryui.com/position/
-//>>demos: http://jqueryui.com/position/
-
-
-( function() {
-var cachedScrollbarWidth,
- max = Math.max,
- abs = Math.abs,
- rhorizontal = /left|center|right/,
- rvertical = /top|center|bottom/,
- roffset = /[\+\-]\d+(\.[\d]+)?%?/,
- rposition = /^\w+/,
- rpercent = /%$/,
- _position = $.fn.position;
-
-function getOffsets( offsets, width, height ) {
- return [
- parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
- parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
- ];
-}
-
-function parseCss( element, property ) {
- return parseInt( $.css( element, property ), 10 ) || 0;
-}
-
-function isWindow( obj ) {
- return obj != null && obj === obj.window;
-}
-
-function getDimensions( elem ) {
- var raw = elem[ 0 ];
- if ( raw.nodeType === 9 ) {
- return {
- width: elem.width(),
- height: elem.height(),
- offset: { top: 0, left: 0 }
- };
- }
- if ( isWindow( raw ) ) {
- return {
- width: elem.width(),
- height: elem.height(),
- offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
- };
- }
- if ( raw.preventDefault ) {
- return {
- width: 0,
- height: 0,
- offset: { top: raw.pageY, left: raw.pageX }
- };
- }
- return {
- width: elem.outerWidth(),
- height: elem.outerHeight(),
- offset: elem.offset()
- };
-}
-
-$.position = {
- scrollbarWidth: function() {
- if ( cachedScrollbarWidth !== undefined ) {
- return cachedScrollbarWidth;
- }
- var w1, w2,
- div = $( "<div style=" +
- "'display:block;position:absolute;width:200px;height:200px;overflow:hidden;'>" +
- "<div style='height:300px;width:auto;'></div></div>" ),
- innerDiv = div.children()[ 0 ];
-
- $( "body" ).append( div );
- w1 = innerDiv.offsetWidth;
- div.css( "overflow", "scroll" );
-
- w2 = innerDiv.offsetWidth;
-
- if ( w1 === w2 ) {
- w2 = div[ 0 ].clientWidth;
- }
-
- div.remove();
-
- return ( cachedScrollbarWidth = w1 - w2 );
- },
- getScrollInfo: function( within ) {
- var overflowX = within.isWindow || within.isDocument ? "" :
- within.element.css( "overflow-x" ),
- overflowY = within.isWindow || within.isDocument ? "" :
- within.element.css( "overflow-y" ),
- hasOverflowX = overflowX === "scroll" ||
- ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
- hasOverflowY = overflowY === "scroll" ||
- ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
- return {
- width: hasOverflowY ? $.position.scrollbarWidth() : 0,
- height: hasOverflowX ? $.position.scrollbarWidth() : 0
- };
- },
- getWithinInfo: function( element ) {
- var withinElement = $( element || window ),
- isElemWindow = isWindow( withinElement[ 0 ] ),
- isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
- hasOffset = !isElemWindow && !isDocument;
- return {
- element: withinElement,
- isWindow: isElemWindow,
- isDocument: isDocument,
- offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
- scrollLeft: withinElement.scrollLeft(),
- scrollTop: withinElement.scrollTop(),
- width: withinElement.outerWidth(),
- height: withinElement.outerHeight()
- };
- }
-};
-
-$.fn.position = function( options ) {
- if ( !options || !options.of ) {
- return _position.apply( this, arguments );
- }
-
- // Make a copy, we don't want to modify arguments
- options = $.extend( {}, options );
-
- var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
-
- // Make sure string options are treated as CSS selectors
- target = typeof options.of === "string" ?
- $( document ).find( options.of ) :
- $( options.of ),
-
- within = $.position.getWithinInfo( options.within ),
- scrollInfo = $.position.getScrollInfo( within ),
- collision = ( options.collision || "flip" ).split( " " ),
- offsets = {};
-
- dimensions = getDimensions( target );
- if ( target[ 0 ].preventDefault ) {
-
- // Force left top to allow flipping
- options.at = "left top";
- }
- targetWidth = dimensions.width;
- targetHeight = dimensions.height;
- targetOffset = dimensions.offset;
-
- // Clone to reuse original targetOffset later
- basePosition = $.extend( {}, targetOffset );
-
- // Force my and at to have valid horizontal and vertical positions
- // if a value is missing or invalid, it will be converted to center
- $.each( [ "my", "at" ], function() {
- var pos = ( options[ this ] || "" ).split( " " ),
- horizontalOffset,
- verticalOffset;
-
- if ( pos.length === 1 ) {
- pos = rhorizontal.test( pos[ 0 ] ) ?
- pos.concat( [ "center" ] ) :
- rvertical.test( pos[ 0 ] ) ?
- [ "center" ].concat( pos ) :
- [ "center", "center" ];
- }
- pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
- pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
-
- // Calculate offsets
- horizontalOffset = roffset.exec( pos[ 0 ] );
- verticalOffset = roffset.exec( pos[ 1 ] );
- offsets[ this ] = [
- horizontalOffset ? horizontalOffset[ 0 ] : 0,
- verticalOffset ? verticalOffset[ 0 ] : 0
- ];
-
- // Reduce to just the positions without the offsets
- options[ this ] = [
- rposition.exec( pos[ 0 ] )[ 0 ],
- rposition.exec( pos[ 1 ] )[ 0 ]
- ];
- } );
-
- // Normalize collision option
- if ( collision.length === 1 ) {
- collision[ 1 ] = collision[ 0 ];
- }
-
- if ( options.at[ 0 ] === "right" ) {
- basePosition.left += targetWidth;
- } else if ( options.at[ 0 ] === "center" ) {
- basePosition.left += targetWidth / 2;
- }
-
- if ( options.at[ 1 ] === "bottom" ) {
- basePosition.top += targetHeight;
- } else if ( options.at[ 1 ] === "center" ) {
- basePosition.top += targetHeight / 2;
- }
-
- atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
- basePosition.left += atOffset[ 0 ];
- basePosition.top += atOffset[ 1 ];
-
- return this.each( function() {
- var collisionPosition, using,
- elem = $( this ),
- elemWidth = elem.outerWidth(),
- elemHeight = elem.outerHeight(),
- marginLeft = parseCss( this, "marginLeft" ),
- marginTop = parseCss( this, "marginTop" ),
- collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
- scrollInfo.width,
- collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
- scrollInfo.height,
- position = $.extend( {}, basePosition ),
- myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
-
- if ( options.my[ 0 ] === "right" ) {
- position.left -= elemWidth;
- } else if ( options.my[ 0 ] === "center" ) {
- position.left -= elemWidth / 2;
- }
-
- if ( options.my[ 1 ] === "bottom" ) {
- position.top -= elemHeight;
- } else if ( options.my[ 1 ] === "center" ) {
- position.top -= elemHeight / 2;
- }
-
- position.left += myOffset[ 0 ];
- position.top += myOffset[ 1 ];
-
- collisionPosition = {
- marginLeft: marginLeft,
- marginTop: marginTop
- };
-
- $.each( [ "left", "top" ], function( i, dir ) {
- if ( $.ui.position[ collision[ i ] ] ) {
- $.ui.position[ collision[ i ] ][ dir ]( position, {
- targetWidth: targetWidth,
- targetHeight: targetHeight,
- elemWidth: elemWidth,
- elemHeight: elemHeight,
- collisionPosition: collisionPosition,
- collisionWidth: collisionWidth,
- collisionHeight: collisionHeight,
- offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
- my: options.my,
- at: options.at,
- within: within,
- elem: elem
- } );
- }
- } );
-
- if ( options.using ) {
-
- // Adds feedback as second argument to using callback, if present
- using = function( props ) {
- var left = targetOffset.left - position.left,
- right = left + targetWidth - elemWidth,
- top = targetOffset.top - position.top,
- bottom = top + targetHeight - elemHeight,
- feedback = {
- target: {
- element: target,
- left: targetOffset.left,
- top: targetOffset.top,
- width: targetWidth,
- height: targetHeight
- },
- element: {
- element: elem,
- left: position.left,
- top: position.top,
- width: elemWidth,
- height: elemHeight
- },
- horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
- vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
- };
- if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
- feedback.horizontal = "center";
- }
- if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
- feedback.vertical = "middle";
- }
- if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
- feedback.important = "horizontal";
- } else {
- feedback.important = "vertical";
- }
- options.using.call( this, props, feedback );
- };
- }
-
- elem.offset( $.extend( position, { using: using } ) );
- } );
-};
-
-$.ui.position = {
- fit: {
- left: function( position, data ) {
- var within = data.within,
- withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
- outerWidth = within.width,
- collisionPosLeft = position.left - data.collisionPosition.marginLeft,
- overLeft = withinOffset - collisionPosLeft,
- overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
- newOverRight;
-
- // Element is wider than within
- if ( data.collisionWidth > outerWidth ) {
-
- // Element is initially over the left side of within
- if ( overLeft > 0 && overRight <= 0 ) {
- newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
- withinOffset;
- position.left += overLeft - newOverRight;
-
- // Element is initially over right side of within
- } else if ( overRight > 0 && overLeft <= 0 ) {
- position.left = withinOffset;
-
- // Element is initially over both left and right sides of within
- } else {
- if ( overLeft > overRight ) {
- position.left = withinOffset + outerWidth - data.collisionWidth;
- } else {
- position.left = withinOffset;
- }
- }
-
- // Too far left -> align with left edge
- } else if ( overLeft > 0 ) {
- position.left += overLeft;
-
- // Too far right -> align with right edge
- } else if ( overRight > 0 ) {
- position.left -= overRight;
-
- // Adjust based on position and margin
- } else {
- position.left = max( position.left - collisionPosLeft, position.left );
- }
- },
- top: function( position, data ) {
- var within = data.within,
- withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
- outerHeight = data.within.height,
- collisionPosTop = position.top - data.collisionPosition.marginTop,
- overTop = withinOffset - collisionPosTop,
- overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
- newOverBottom;
-
- // Element is taller than within
- if ( data.collisionHeight > outerHeight ) {
-
- // Element is initially over the top of within
- if ( overTop > 0 && overBottom <= 0 ) {
- newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
- withinOffset;
- position.top += overTop - newOverBottom;
-
- // Element is initially over bottom of within
- } else if ( overBottom > 0 && overTop <= 0 ) {
- position.top = withinOffset;
-
- // Element is initially over both top and bottom of within
- } else {
- if ( overTop > overBottom ) {
- position.top = withinOffset + outerHeight - data.collisionHeight;
- } else {
- position.top = withinOffset;
- }
- }
-
- // Too far up -> align with top
- } else if ( overTop > 0 ) {
- position.top += overTop;
-
- // Too far down -> align with bottom edge
- } else if ( overBottom > 0 ) {
- position.top -= overBottom;
-
- // Adjust based on position and margin
- } else {
- position.top = max( position.top - collisionPosTop, position.top );
- }
- }
- },
- flip: {
- left: function( position, data ) {
- var within = data.within,
- withinOffset = within.offset.left + within.scrollLeft,
- outerWidth = within.width,
- offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
- collisionPosLeft = position.left - data.collisionPosition.marginLeft,
- overLeft = collisionPosLeft - offsetLeft,
- overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
- myOffset = data.my[ 0 ] === "left" ?
- -data.elemWidth :
- data.my[ 0 ] === "right" ?
- data.elemWidth :
- 0,
- atOffset = data.at[ 0 ] === "left" ?
- data.targetWidth :
- data.at[ 0 ] === "right" ?
- -data.targetWidth :
- 0,
- offset = -2 * data.offset[ 0 ],
- newOverRight,
- newOverLeft;
-
- if ( overLeft < 0 ) {
- newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
- outerWidth - withinOffset;
- if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
- position.left += myOffset + atOffset + offset;
- }
- } else if ( overRight > 0 ) {
- newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
- atOffset + offset - offsetLeft;
- if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
- position.left += myOffset + atOffset + offset;
- }
- }
- },
- top: function( position, data ) {
- var within = data.within,
- withinOffset = within.offset.top + within.scrollTop,
- outerHeight = within.height,
- offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
- collisionPosTop = position.top - data.collisionPosition.marginTop,
- overTop = collisionPosTop - offsetTop,
- overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
- top = data.my[ 1 ] === "top",
- myOffset = top ?
- -data.elemHeight :
- data.my[ 1 ] === "bottom" ?
- data.elemHeight :
- 0,
- atOffset = data.at[ 1 ] === "top" ?
- data.targetHeight :
- data.at[ 1 ] === "bottom" ?
- -data.targetHeight :
- 0,
- offset = -2 * data.offset[ 1 ],
- newOverTop,
- newOverBottom;
- if ( overTop < 0 ) {
- newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
- outerHeight - withinOffset;
- if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
- position.top += myOffset + atOffset + offset;
- }
- } else if ( overBottom > 0 ) {
- newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
- offset - offsetTop;
- if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
- position.top += myOffset + atOffset + offset;
- }
- }
- }
- },
- flipfit: {
- left: function() {
- $.ui.position.flip.left.apply( this, arguments );
- $.ui.position.fit.left.apply( this, arguments );
- },
- top: function() {
- $.ui.position.flip.top.apply( this, arguments );
- $.ui.position.fit.top.apply( this, arguments );
- }
- }
-};
-
-} )();
-
-var position = $.ui.position;
-
-
-/*!
- * jQuery UI :data 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: :data Selector
-//>>group: Core
-//>>description: Selects elements which have data stored under the specified key.
-//>>docs: http://api.jqueryui.com/data-selector/
-
-
-var data = $.extend( $.expr.pseudos, {
- data: $.expr.createPseudo ?
- $.expr.createPseudo( function( dataName ) {
- return function( elem ) {
- return !!$.data( elem, dataName );
- };
- } ) :
-
- // Support: jQuery <1.8
- function( elem, i, match ) {
- return !!$.data( elem, match[ 3 ] );
- }
-} );
-
-/*!
- * jQuery UI Disable Selection 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: disableSelection
-//>>group: Core
-//>>description: Disable selection of text content within the set of matched elements.
-//>>docs: http://api.jqueryui.com/disableSelection/
-
-// This file is deprecated
-
-var disableSelection = $.fn.extend( {
- disableSelection: ( function() {
- var eventType = "onselectstart" in document.createElement( "div" ) ?
- "selectstart" :
- "mousedown";
-
- return function() {
- return this.on( eventType + ".ui-disableSelection", function( event ) {
- event.preventDefault();
- } );
- };
- } )(),
-
- enableSelection: function() {
- return this.off( ".ui-disableSelection" );
- }
-} );
-
-
-
-// Create a local jQuery because jQuery Color relies on it and the
-// global may not exist with AMD and a custom build (#10199).
-// This module is a noop if used as a regular AMD module.
-// eslint-disable-next-line no-unused-vars
-var jQuery = $;
-
-
-/*!
- * jQuery Color Animations v2.2.0
- * https://github.com/jquery/jquery-color
- *
- * Copyright OpenJS Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * Date: Sun May 10 09:02:36 2020 +0200
- */
-
-
-
- var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
- "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
-
- class2type = {},
- toString = class2type.toString,
-
- // plusequals test for += 100 -= 100
- rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
-
- // a set of RE's that can match strings and generate color tuples.
- stringParsers = [ {
- re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
- parse: function( execResult ) {
- return [
- execResult[ 1 ],
- execResult[ 2 ],
- execResult[ 3 ],
- execResult[ 4 ]
- ];
- }
- }, {
- re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
- parse: function( execResult ) {
- return [
- execResult[ 1 ] * 2.55,
- execResult[ 2 ] * 2.55,
- execResult[ 3 ] * 2.55,
- execResult[ 4 ]
- ];
- }
- }, {
-
- // this regex ignores A-F because it's compared against an already lowercased string
- re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/,
- parse: function( execResult ) {
- return [
- parseInt( execResult[ 1 ], 16 ),
- parseInt( execResult[ 2 ], 16 ),
- parseInt( execResult[ 3 ], 16 ),
- execResult[ 4 ] ?
- ( parseInt( execResult[ 4 ], 16 ) / 255 ).toFixed( 2 ) :
- 1
- ];
- }
- }, {
-
- // this regex ignores A-F because it's compared against an already lowercased string
- re: /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?/,
- parse: function( execResult ) {
- return [
- parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
- parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
- parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ),
- execResult[ 4 ] ?
- ( parseInt( execResult[ 4 ] + execResult[ 4 ], 16 ) / 255 )
- .toFixed( 2 ) :
- 1
- ];
- }
- }, {
- re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
- space: "hsla",
- parse: function( execResult ) {
- return [
- execResult[ 1 ],
- execResult[ 2 ] / 100,
- execResult[ 3 ] / 100,
- execResult[ 4 ]
- ];
- }
- } ],
-
- // jQuery.Color( )
- color = jQuery.Color = function( color, green, blue, alpha ) {
- return new jQuery.Color.fn.parse( color, green, blue, alpha );
- },
- spaces = {
- rgba: {
- props: {
- red: {
- idx: 0,
- type: "byte"
- },
- green: {
- idx: 1,
- type: "byte"
- },
- blue: {
- idx: 2,
- type: "byte"
- }
- }
- },
-
- hsla: {
- props: {
- hue: {
- idx: 0,
- type: "degrees"
- },
- saturation: {
- idx: 1,
- type: "percent"
- },
- lightness: {
- idx: 2,
- type: "percent"
- }
- }
- }
- },
- propTypes = {
- "byte": {
- floor: true,
- max: 255
- },
- "percent": {
- max: 1
- },
- "degrees": {
- mod: 360,
- floor: true
- }
- },
- support = color.support = {},
-
- // element for support tests
- supportElem = jQuery( "<p>" )[ 0 ],
-
- // colors = jQuery.Color.names
- colors,
-
- // local aliases of functions called often
- each = jQuery.each;
-
-// determine rgba support immediately
-supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
-support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
-
-// define cache name and alpha properties
-// for rgba and hsla spaces
-each( spaces, function( spaceName, space ) {
- space.cache = "_" + spaceName;
- space.props.alpha = {
- idx: 3,
- type: "percent",
- def: 1
- };
-} );
-
-// Populate the class2type map
-jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
- function( _i, name ) {
- class2type[ "[object " + name + "]" ] = name.toLowerCase();
- } );
-
-function getType( obj ) {
- if ( obj == null ) {
- return obj + "";
- }
-
- return typeof obj === "object" ?
- class2type[ toString.call( obj ) ] || "object" :
- typeof obj;
-}
-
-function clamp( value, prop, allowEmpty ) {
- var type = propTypes[ prop.type ] || {};
-
- if ( value == null ) {
- return ( allowEmpty || !prop.def ) ? null : prop.def;
- }
-
- // ~~ is an short way of doing floor for positive numbers
- value = type.floor ? ~~value : parseFloat( value );
-
- // IE will pass in empty strings as value for alpha,
- // which will hit this case
- if ( isNaN( value ) ) {
- return prop.def;
- }
-
- if ( type.mod ) {
-
- // we add mod before modding to make sure that negatives values
- // get converted properly: -10 -> 350
- return ( value + type.mod ) % type.mod;
- }
-
- // for now all property types without mod have min and max
- return Math.min( type.max, Math.max( 0, value ) );
-}
-
-function stringParse( string ) {
- var inst = color(),
- rgba = inst._rgba = [];
-
- string = string.toLowerCase();
-
- each( stringParsers, function( _i, parser ) {
- var parsed,
- match = parser.re.exec( string ),
- values = match && parser.parse( match ),
- spaceName = parser.space || "rgba";
-
- if ( values ) {
- parsed = inst[ spaceName ]( values );
-
- // if this was an rgba parse the assignment might happen twice
- // oh well....
- inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
- rgba = inst._rgba = parsed._rgba;
-
- // exit each( stringParsers ) here because we matched
- return false;
- }
- } );
-
- // Found a stringParser that handled it
- if ( rgba.length ) {
-
- // if this came from a parsed string, force "transparent" when alpha is 0
- // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
- if ( rgba.join() === "0,0,0,0" ) {
- jQuery.extend( rgba, colors.transparent );
- }
- return inst;
- }
-
- // named colors
- return colors[ string ];
-}
-
-color.fn = jQuery.extend( color.prototype, {
- parse: function( red, green, blue, alpha ) {
- if ( red === undefined ) {
- this._rgba = [ null, null, null, null ];
- return this;
- }
- if ( red.jquery || red.nodeType ) {
- red = jQuery( red ).css( green );
- green = undefined;
- }
-
- var inst = this,
- type = getType( red ),
- rgba = this._rgba = [];
-
- // more than 1 argument specified - assume ( red, green, blue, alpha )
- if ( green !== undefined ) {
- red = [ red, green, blue, alpha ];
- type = "array";
- }
-
- if ( type === "string" ) {
- return this.parse( stringParse( red ) || colors._default );
- }
-
- if ( type === "array" ) {
- each( spaces.rgba.props, function( _key, prop ) {
- rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
- } );
- return this;
- }
-
- if ( type === "object" ) {
- if ( red instanceof color ) {
- each( spaces, function( _spaceName, space ) {
- if ( red[ space.cache ] ) {
- inst[ space.cache ] = red[ space.cache ].slice();
- }
- } );
- } else {
- each( spaces, function( _spaceName, space ) {
- var cache = space.cache;
- each( space.props, function( key, prop ) {
-
- // if the cache doesn't exist, and we know how to convert
- if ( !inst[ cache ] && space.to ) {
-
- // if the value was null, we don't need to copy it
- // if the key was alpha, we don't need to copy it either
- if ( key === "alpha" || red[ key ] == null ) {
- return;
- }
- inst[ cache ] = space.to( inst._rgba );
- }
-
- // this is the only case where we allow nulls for ALL properties.
- // call clamp with alwaysAllowEmpty
- inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
- } );
-
- // everything defined but alpha?
- if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
-
- // use the default of 1
- if ( inst[ cache ][ 3 ] == null ) {
- inst[ cache ][ 3 ] = 1;
- }
-
- if ( space.from ) {
- inst._rgba = space.from( inst[ cache ] );
- }
- }
- } );
- }
- return this;
- }
- },
- is: function( compare ) {
- var is = color( compare ),
- same = true,
- inst = this;
-
- each( spaces, function( _, space ) {
- var localCache,
- isCache = is[ space.cache ];
- if ( isCache ) {
- localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
- each( space.props, function( _, prop ) {
- if ( isCache[ prop.idx ] != null ) {
- same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
- return same;
- }
- } );
- }
- return same;
- } );
- return same;
- },
- _space: function() {
- var used = [],
- inst = this;
- each( spaces, function( spaceName, space ) {
- if ( inst[ space.cache ] ) {
- used.push( spaceName );
- }
- } );
- return used.pop();
- },
- transition: function( other, distance ) {
- var end = color( other ),
- spaceName = end._space(),
- space = spaces[ spaceName ],
- startColor = this.alpha() === 0 ? color( "transparent" ) : this,
- start = startColor[ space.cache ] || space.to( startColor._rgba ),
- result = start.slice();
-
- end = end[ space.cache ];
- each( space.props, function( _key, prop ) {
- var index = prop.idx,
- startValue = start[ index ],
- endValue = end[ index ],
- type = propTypes[ prop.type ] || {};
-
- // if null, don't override start value
- if ( endValue === null ) {
- return;
- }
-
- // if null - use end
- if ( startValue === null ) {
- result[ index ] = endValue;
- } else {
- if ( type.mod ) {
- if ( endValue - startValue > type.mod / 2 ) {
- startValue += type.mod;
- } else if ( startValue - endValue > type.mod / 2 ) {
- startValue -= type.mod;
- }
- }
- result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
- }
- } );
- return this[ spaceName ]( result );
- },
- blend: function( opaque ) {
-
- // if we are already opaque - return ourself
- if ( this._rgba[ 3 ] === 1 ) {
- return this;
- }
-
- var rgb = this._rgba.slice(),
- a = rgb.pop(),
- blend = color( opaque )._rgba;
-
- return color( jQuery.map( rgb, function( v, i ) {
- return ( 1 - a ) * blend[ i ] + a * v;
- } ) );
- },
- toRgbaString: function() {
- var prefix = "rgba(",
- rgba = jQuery.map( this._rgba, function( v, i ) {
- if ( v != null ) {
- return v;
- }
- return i > 2 ? 1 : 0;
- } );
-
- if ( rgba[ 3 ] === 1 ) {
- rgba.pop();
- prefix = "rgb(";
- }
-
- return prefix + rgba.join() + ")";
- },
- toHslaString: function() {
- var prefix = "hsla(",
- hsla = jQuery.map( this.hsla(), function( v, i ) {
- if ( v == null ) {
- v = i > 2 ? 1 : 0;
- }
-
- // catch 1 and 2
- if ( i && i < 3 ) {
- v = Math.round( v * 100 ) + "%";
- }
- return v;
- } );
-
- if ( hsla[ 3 ] === 1 ) {
- hsla.pop();
- prefix = "hsl(";
- }
- return prefix + hsla.join() + ")";
- },
- toHexString: function( includeAlpha ) {
- var rgba = this._rgba.slice(),
- alpha = rgba.pop();
-
- if ( includeAlpha ) {
- rgba.push( ~~( alpha * 255 ) );
- }
-
- return "#" + jQuery.map( rgba, function( v ) {
-
- // default to 0 when nulls exist
- v = ( v || 0 ).toString( 16 );
- return v.length === 1 ? "0" + v : v;
- } ).join( "" );
- },
- toString: function() {
- return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
- }
-} );
-color.fn.parse.prototype = color.fn;
-
-// hsla conversions adapted from:
-// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
-
-function hue2rgb( p, q, h ) {
- h = ( h + 1 ) % 1;
- if ( h * 6 < 1 ) {
- return p + ( q - p ) * h * 6;
- }
- if ( h * 2 < 1 ) {
- return q;
- }
- if ( h * 3 < 2 ) {
- return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
- }
- return p;
-}
-
-spaces.hsla.to = function( rgba ) {
- if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
- return [ null, null, null, rgba[ 3 ] ];
- }
- var r = rgba[ 0 ] / 255,
- g = rgba[ 1 ] / 255,
- b = rgba[ 2 ] / 255,
- a = rgba[ 3 ],
- max = Math.max( r, g, b ),
- min = Math.min( r, g, b ),
- diff = max - min,
- add = max + min,
- l = add * 0.5,
- h, s;
-
- if ( min === max ) {
- h = 0;
- } else if ( r === max ) {
- h = ( 60 * ( g - b ) / diff ) + 360;
- } else if ( g === max ) {
- h = ( 60 * ( b - r ) / diff ) + 120;
- } else {
- h = ( 60 * ( r - g ) / diff ) + 240;
- }
-
- // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
- // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
- if ( diff === 0 ) {
- s = 0;
- } else if ( l <= 0.5 ) {
- s = diff / add;
- } else {
- s = diff / ( 2 - add );
- }
- return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];
-};
-
-spaces.hsla.from = function( hsla ) {
- if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
- return [ null, null, null, hsla[ 3 ] ];
- }
- var h = hsla[ 0 ] / 360,
- s = hsla[ 1 ],
- l = hsla[ 2 ],
- a = hsla[ 3 ],
- q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
- p = 2 * l - q;
-
- return [
- Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
- Math.round( hue2rgb( p, q, h ) * 255 ),
- Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
- a
- ];
-};
-
-
-each( spaces, function( spaceName, space ) {
- var props = space.props,
- cache = space.cache,
- to = space.to,
- from = space.from;
-
- // makes rgba() and hsla()
- color.fn[ spaceName ] = function( value ) {
-
- // generate a cache for this space if it doesn't exist
- if ( to && !this[ cache ] ) {
- this[ cache ] = to( this._rgba );
- }
- if ( value === undefined ) {
- return this[ cache ].slice();
- }
-
- var ret,
- type = getType( value ),
- arr = ( type === "array" || type === "object" ) ? value : arguments,
- local = this[ cache ].slice();
-
- each( props, function( key, prop ) {
- var val = arr[ type === "object" ? key : prop.idx ];
- if ( val == null ) {
- val = local[ prop.idx ];
- }
- local[ prop.idx ] = clamp( val, prop );
- } );
-
- if ( from ) {
- ret = color( from( local ) );
- ret[ cache ] = local;
- return ret;
- } else {
- return color( local );
- }
- };
-
- // makes red() green() blue() alpha() hue() saturation() lightness()
- each( props, function( key, prop ) {
-
- // alpha is included in more than one space
- if ( color.fn[ key ] ) {
- return;
- }
- color.fn[ key ] = function( value ) {
- var local, cur, match, fn,
- vtype = getType( value );
-
- if ( key === "alpha" ) {
- fn = this._hsla ? "hsla" : "rgba";
- } else {
- fn = spaceName;
- }
- local = this[ fn ]();
- cur = local[ prop.idx ];
-
- if ( vtype === "undefined" ) {
- return cur;
- }
-
- if ( vtype === "function" ) {
- value = value.call( this, cur );
- vtype = getType( value );
- }
- if ( value == null && prop.empty ) {
- return this;
- }
- if ( vtype === "string" ) {
- match = rplusequals.exec( value );
- if ( match ) {
- value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
- }
- }
- local[ prop.idx ] = value;
- return this[ fn ]( local );
- };
- } );
-} );
-
-// add cssHook and .fx.step function for each named hook.
-// accept a space separated string of properties
-color.hook = function( hook ) {
- var hooks = hook.split( " " );
- each( hooks, function( _i, hook ) {
- jQuery.cssHooks[ hook ] = {
- set: function( elem, value ) {
- var parsed, curElem,
- backgroundColor = "";
-
- if ( value !== "transparent" && ( getType( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
- value = color( parsed || value );
- if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
- curElem = hook === "backgroundColor" ? elem.parentNode : elem;
- while (
- ( backgroundColor === "" || backgroundColor === "transparent" ) &&
- curElem && curElem.style
- ) {
- try {
- backgroundColor = jQuery.css( curElem, "backgroundColor" );
- curElem = curElem.parentNode;
- } catch ( e ) {
- }
- }
-
- value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
- backgroundColor :
- "_default" );
- }
-
- value = value.toRgbaString();
- }
- try {
- elem.style[ hook ] = value;
- } catch ( e ) {
-
- // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
- }
- }
- };
- jQuery.fx.step[ hook ] = function( fx ) {
- if ( !fx.colorInit ) {
- fx.start = color( fx.elem, hook );
- fx.end = color( fx.end );
- fx.colorInit = true;
- }
- jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
- };
- } );
-
-};
-
-color.hook( stepHooks );
-
-jQuery.cssHooks.borderColor = {
- expand: function( value ) {
- var expanded = {};
-
- each( [ "Top", "Right", "Bottom", "Left" ], function( _i, part ) {
- expanded[ "border" + part + "Color" ] = value;
- } );
- return expanded;
- }
-};
-
-// Basic color names only.
-// Usage of any of the other color names requires adding yourself or including
-// jquery.color.svg-names.js.
-colors = jQuery.Color.names = {
-
- // 4.1. Basic color keywords
- aqua: "#00ffff",
- black: "#000000",
- blue: "#0000ff",
- fuchsia: "#ff00ff",
- gray: "#808080",
- green: "#008000",
- lime: "#00ff00",
- maroon: "#800000",
- navy: "#000080",
- olive: "#808000",
- purple: "#800080",
- red: "#ff0000",
- silver: "#c0c0c0",
- teal: "#008080",
- white: "#ffffff",
- yellow: "#ffff00",
-
- // 4.2.3. "transparent" color keyword
- transparent: [ null, null, null, 0 ],
-
- _default: "#ffffff"
-};
-
-
-/*!
- * jQuery UI Effects 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Effects Core
-//>>group: Effects
-/* eslint-disable max-len */
-//>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.
-/* eslint-enable max-len */
-//>>docs: http://api.jqueryui.com/category/effects-core/
-//>>demos: http://jqueryui.com/effect/
-
-
-var dataSpace = "ui-effects-",
- dataSpaceStyle = "ui-effects-style",
- dataSpaceAnimated = "ui-effects-animated";
-
-$.effects = {
- effect: {}
-};
-
-/******************************************************************************/
-/****************************** CLASS ANIMATIONS ******************************/
-/******************************************************************************/
-( function() {
-
-var classAnimationActions = [ "add", "remove", "toggle" ],
- shorthandStyles = {
- border: 1,
- borderBottom: 1,
- borderColor: 1,
- borderLeft: 1,
- borderRight: 1,
- borderTop: 1,
- borderWidth: 1,
- margin: 1,
- padding: 1
- };
-
-$.each(
- [ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ],
- function( _, prop ) {
- $.fx.step[ prop ] = function( fx ) {
- if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
- jQuery.style( fx.elem, prop, fx.end );
- fx.setAttr = true;
- }
- };
- }
-);
-
-function camelCase( string ) {
- return string.replace( /-([\da-z])/gi, function( all, letter ) {
- return letter.toUpperCase();
- } );
-}
-
-function getElementStyles( elem ) {
- var key, len,
- style = elem.ownerDocument.defaultView ?
- elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
- elem.currentStyle,
- styles = {};
-
- if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
- len = style.length;
- while ( len-- ) {
- key = style[ len ];
- if ( typeof style[ key ] === "string" ) {
- styles[ camelCase( key ) ] = style[ key ];
- }
- }
-
- // Support: Opera, IE <9
- } else {
- for ( key in style ) {
- if ( typeof style[ key ] === "string" ) {
- styles[ key ] = style[ key ];
- }
- }
- }
-
- return styles;
-}
-
-function styleDifference( oldStyle, newStyle ) {
- var diff = {},
- name, value;
-
- for ( name in newStyle ) {
- value = newStyle[ name ];
- if ( oldStyle[ name ] !== value ) {
- if ( !shorthandStyles[ name ] ) {
- if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
- diff[ name ] = value;
- }
- }
- }
- }
-
- return diff;
-}
-
-// Support: jQuery <1.8
-if ( !$.fn.addBack ) {
- $.fn.addBack = function( selector ) {
- return this.add( selector == null ?
- this.prevObject : this.prevObject.filter( selector )
- );
- };
-}
-
-$.effects.animateClass = function( value, duration, easing, callback ) {
- var o = $.speed( duration, easing, callback );
-
- return this.queue( function() {
- var animated = $( this ),
- baseClass = animated.attr( "class" ) || "",
- applyClassChange,
- allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
-
- // Map the animated objects to store the original styles.
- allAnimations = allAnimations.map( function() {
- var el = $( this );
- return {
- el: el,
- start: getElementStyles( this )
- };
- } );
-
- // Apply class change
- applyClassChange = function() {
- $.each( classAnimationActions, function( i, action ) {
- if ( value[ action ] ) {
- animated[ action + "Class" ]( value[ action ] );
- }
- } );
- };
- applyClassChange();
-
- // Map all animated objects again - calculate new styles and diff
- allAnimations = allAnimations.map( function() {
- this.end = getElementStyles( this.el[ 0 ] );
- this.diff = styleDifference( this.start, this.end );
- return this;
- } );
-
- // Apply original class
- animated.attr( "class", baseClass );
-
- // Map all animated objects again - this time collecting a promise
- allAnimations = allAnimations.map( function() {
- var styleInfo = this,
- dfd = $.Deferred(),
- opts = $.extend( {}, o, {
- queue: false,
- complete: function() {
- dfd.resolve( styleInfo );
- }
- } );
-
- this.el.animate( this.diff, opts );
- return dfd.promise();
- } );
-
- // Once all animations have completed:
- $.when.apply( $, allAnimations.get() ).done( function() {
-
- // Set the final class
- applyClassChange();
-
- // For each animated element,
- // clear all css properties that were animated
- $.each( arguments, function() {
- var el = this.el;
- $.each( this.diff, function( key ) {
- el.css( key, "" );
- } );
- } );
-
- // This is guarnteed to be there if you use jQuery.speed()
- // it also handles dequeuing the next anim...
- o.complete.call( animated[ 0 ] );
- } );
- } );
-};
-
-$.fn.extend( {
- addClass: ( function( orig ) {
- return function( classNames, speed, easing, callback ) {
- return speed ?
- $.effects.animateClass.call( this,
- { add: classNames }, speed, easing, callback ) :
- orig.apply( this, arguments );
- };
- } )( $.fn.addClass ),
-
- removeClass: ( function( orig ) {
- return function( classNames, speed, easing, callback ) {
- return arguments.length > 1 ?
- $.effects.animateClass.call( this,
- { remove: classNames }, speed, easing, callback ) :
- orig.apply( this, arguments );
- };
- } )( $.fn.removeClass ),
-
- toggleClass: ( function( orig ) {
- return function( classNames, force, speed, easing, callback ) {
- if ( typeof force === "boolean" || force === undefined ) {
- if ( !speed ) {
-
- // Without speed parameter
- return orig.apply( this, arguments );
- } else {
- return $.effects.animateClass.call( this,
- ( force ? { add: classNames } : { remove: classNames } ),
- speed, easing, callback );
- }
- } else {
-
- // Without force parameter
- return $.effects.animateClass.call( this,
- { toggle: classNames }, force, speed, easing );
- }
- };
- } )( $.fn.toggleClass ),
-
- switchClass: function( remove, add, speed, easing, callback ) {
- return $.effects.animateClass.call( this, {
- add: add,
- remove: remove
- }, speed, easing, callback );
- }
-} );
-
-} )();
-
-/******************************************************************************/
-/*********************************** EFFECTS **********************************/
-/******************************************************************************/
-
-( function() {
-
-if ( $.expr && $.expr.pseudos && $.expr.pseudos.animated ) {
- $.expr.pseudos.animated = ( function( orig ) {
- return function( elem ) {
- return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
- };
- } )( $.expr.pseudos.animated );
-}
-
-if ( $.uiBackCompat !== false ) {
- $.extend( $.effects, {
-
- // Saves a set of properties in a data storage
- save: function( element, set ) {
- var i = 0, length = set.length;
- for ( ; i < length; i++ ) {
- if ( set[ i ] !== null ) {
- element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
- }
- }
- },
-
- // Restores a set of previously saved properties from a data storage
- restore: function( element, set ) {
- var val, i = 0, length = set.length;
- for ( ; i < length; i++ ) {
- if ( set[ i ] !== null ) {
- val = element.data( dataSpace + set[ i ] );
- element.css( set[ i ], val );
- }
- }
- },
-
- setMode: function( el, mode ) {
- if ( mode === "toggle" ) {
- mode = el.is( ":hidden" ) ? "show" : "hide";
- }
- return mode;
- },
-
- // Wraps the element around a wrapper that copies position properties
- createWrapper: function( element ) {
-
- // If the element is already wrapped, return it
- if ( element.parent().is( ".ui-effects-wrapper" ) ) {
- return element.parent();
- }
-
- // Wrap the element
- var props = {
- width: element.outerWidth( true ),
- height: element.outerHeight( true ),
- "float": element.css( "float" )
- },
- wrapper = $( "<div></div>" )
- .addClass( "ui-effects-wrapper" )
- .css( {
- fontSize: "100%",
- background: "transparent",
- border: "none",
- margin: 0,
- padding: 0
- } ),
-
- // Store the size in case width/height are defined in % - Fixes #5245
- size = {
- width: element.width(),
- height: element.height()
- },
- active = document.activeElement;
-
- // Support: Firefox
- // Firefox incorrectly exposes anonymous content
- // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
- try {
- // eslint-disable-next-line no-unused-expressions
- active.id;
- } catch ( e ) {
- active = document.body;
- }
-
- element.wrap( wrapper );
-
- // Fixes #7595 - Elements lose focus when wrapped.
- if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
- $( active ).trigger( "focus" );
- }
-
- // Hotfix for jQuery 1.4 since some change in wrap() seems to actually
- // lose the reference to the wrapped element
- wrapper = element.parent();
-
- // Transfer positioning properties to the wrapper
- if ( element.css( "position" ) === "static" ) {
- wrapper.css( { position: "relative" } );
- element.css( { position: "relative" } );
- } else {
- $.extend( props, {
- position: element.css( "position" ),
- zIndex: element.css( "z-index" )
- } );
- $.each( [ "top", "left", "bottom", "right" ], function( i, pos ) {
- props[ pos ] = element.css( pos );
- if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
- props[ pos ] = "auto";
- }
- } );
- element.css( {
- position: "relative",
- top: 0,
- left: 0,
- right: "auto",
- bottom: "auto"
- } );
- }
- element.css( size );
-
- return wrapper.css( props ).show();
- },
-
- removeWrapper: function( element ) {
- var active = document.activeElement;
-
- if ( element.parent().is( ".ui-effects-wrapper" ) ) {
- element.parent().replaceWith( element );
-
- // Fixes #7595 - Elements lose focus when wrapped.
- if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
- $( active ).trigger( "focus" );
- }
- }
-
- return element;
- }
- } );
-}
-
-$.extend( $.effects, {
- version: "1.13.1",
-
- define: function( name, mode, effect ) {
- if ( !effect ) {
- effect = mode;
- mode = "effect";
- }
-
- $.effects.effect[ name ] = effect;
- $.effects.effect[ name ].mode = mode;
-
- return effect;
- },
-
- scaledDimensions: function( element, percent, direction ) {
- if ( percent === 0 ) {
- return {
- height: 0,
- width: 0,
- outerHeight: 0,
- outerWidth: 0
- };
- }
-
- var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
- y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;
-
- return {
- height: element.height() * y,
- width: element.width() * x,
- outerHeight: element.outerHeight() * y,
- outerWidth: element.outerWidth() * x
- };
-
- },
-
- clipToBox: function( animation ) {
- return {
- width: animation.clip.right - animation.clip.left,
- height: animation.clip.bottom - animation.clip.top,
- left: animation.clip.left,
- top: animation.clip.top
- };
- },
-
- // Injects recently queued functions to be first in line (after "inprogress")
- unshift: function( element, queueLength, count ) {
- var queue = element.queue();
-
- if ( queueLength > 1 ) {
- queue.splice.apply( queue,
- [ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
- }
- element.dequeue();
- },
-
- saveStyle: function( element ) {
- element.data( dataSpaceStyle, element[ 0 ].style.cssText );
- },
-
- restoreStyle: function( element ) {
- element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
- element.removeData( dataSpaceStyle );
- },
-
- mode: function( element, mode ) {
- var hidden = element.is( ":hidden" );
-
- if ( mode === "toggle" ) {
- mode = hidden ? "show" : "hide";
- }
- if ( hidden ? mode === "hide" : mode === "show" ) {
- mode = "none";
- }
- return mode;
- },
-
- // Translates a [top,left] array into a baseline value
- getBaseline: function( origin, original ) {
- var y, x;
-
- switch ( origin[ 0 ] ) {
- case "top":
- y = 0;
- break;
- case "middle":
- y = 0.5;
- break;
- case "bottom":
- y = 1;
- break;
- default:
- y = origin[ 0 ] / original.height;
- }
-
- switch ( origin[ 1 ] ) {
- case "left":
- x = 0;
- break;
- case "center":
- x = 0.5;
- break;
- case "right":
- x = 1;
- break;
- default:
- x = origin[ 1 ] / original.width;
- }
-
- return {
- x: x,
- y: y
- };
- },
-
- // Creates a placeholder element so that the original element can be made absolute
- createPlaceholder: function( element ) {
- var placeholder,
- cssPosition = element.css( "position" ),
- position = element.position();
-
- // Lock in margins first to account for form elements, which
- // will change margin if you explicitly set height
- // see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
- // Support: Safari
- element.css( {
- marginTop: element.css( "marginTop" ),
- marginBottom: element.css( "marginBottom" ),
- marginLeft: element.css( "marginLeft" ),
- marginRight: element.css( "marginRight" )
- } )
- .outerWidth( element.outerWidth() )
- .outerHeight( element.outerHeight() );
-
- if ( /^(static|relative)/.test( cssPosition ) ) {
- cssPosition = "absolute";
-
- placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( {
-
- // Convert inline to inline block to account for inline elements
- // that turn to inline block based on content (like img)
- display: /^(inline|ruby)/.test( element.css( "display" ) ) ?
- "inline-block" :
- "block",
- visibility: "hidden",
-
- // Margins need to be set to account for margin collapse
- marginTop: element.css( "marginTop" ),
- marginBottom: element.css( "marginBottom" ),
- marginLeft: element.css( "marginLeft" ),
- marginRight: element.css( "marginRight" ),
- "float": element.css( "float" )
- } )
- .outerWidth( element.outerWidth() )
- .outerHeight( element.outerHeight() )
- .addClass( "ui-effects-placeholder" );
-
- element.data( dataSpace + "placeholder", placeholder );
- }
-
- element.css( {
- position: cssPosition,
- left: position.left,
- top: position.top
- } );
-
- return placeholder;
- },
-
- removePlaceholder: function( element ) {
- var dataKey = dataSpace + "placeholder",
- placeholder = element.data( dataKey );
-
- if ( placeholder ) {
- placeholder.remove();
- element.removeData( dataKey );
- }
- },
-
- // Removes a placeholder if it exists and restores
- // properties that were modified during placeholder creation
- cleanUp: function( element ) {
- $.effects.restoreStyle( element );
- $.effects.removePlaceholder( element );
- },
-
- setTransition: function( element, list, factor, value ) {
- value = value || {};
- $.each( list, function( i, x ) {
- var unit = element.cssUnit( x );
- if ( unit[ 0 ] > 0 ) {
- value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
- }
- } );
- return value;
- }
-} );
-
-// Return an effect options object for the given parameters:
-function _normalizeArguments( effect, options, speed, callback ) {
-
- // Allow passing all options as the first parameter
- if ( $.isPlainObject( effect ) ) {
- options = effect;
- effect = effect.effect;
- }
-
- // Convert to an object
- effect = { effect: effect };
-
- // Catch (effect, null, ...)
- if ( options == null ) {
- options = {};
- }
-
- // Catch (effect, callback)
- if ( typeof options === "function" ) {
- callback = options;
- speed = null;
- options = {};
- }
-
- // Catch (effect, speed, ?)
- if ( typeof options === "number" || $.fx.speeds[ options ] ) {
- callback = speed;
- speed = options;
- options = {};
- }
-
- // Catch (effect, options, callback)
- if ( typeof speed === "function" ) {
- callback = speed;
- speed = null;
- }
-
- // Add options to effect
- if ( options ) {
- $.extend( effect, options );
- }
-
- speed = speed || options.duration;
- effect.duration = $.fx.off ? 0 :
- typeof speed === "number" ? speed :
- speed in $.fx.speeds ? $.fx.speeds[ speed ] :
- $.fx.speeds._default;
-
- effect.complete = callback || options.complete;
-
- return effect;
-}
-
-function standardAnimationOption( option ) {
-
- // Valid standard speeds (nothing, number, named speed)
- if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
- return true;
- }
-
- // Invalid strings - treat as "normal" speed
- if ( typeof option === "string" && !$.effects.effect[ option ] ) {
- return true;
- }
-
- // Complete callback
- if ( typeof option === "function" ) {
- return true;
- }
-
- // Options hash (but not naming an effect)
- if ( typeof option === "object" && !option.effect ) {
- return true;
- }
-
- // Didn't match any standard API
- return false;
-}
-
-$.fn.extend( {
- effect: function( /* effect, options, speed, callback */ ) {
- var args = _normalizeArguments.apply( this, arguments ),
- effectMethod = $.effects.effect[ args.effect ],
- defaultMode = effectMethod.mode,
- queue = args.queue,
- queueName = queue || "fx",
- complete = args.complete,
- mode = args.mode,
- modes = [],
- prefilter = function( next ) {
- var el = $( this ),
- normalizedMode = $.effects.mode( el, mode ) || defaultMode;
-
- // Sentinel for duck-punching the :animated pseudo-selector
- el.data( dataSpaceAnimated, true );
-
- // Save effect mode for later use,
- // we can't just call $.effects.mode again later,
- // as the .show() below destroys the initial state
- modes.push( normalizedMode );
-
- // See $.uiBackCompat inside of run() for removal of defaultMode in 1.14
- if ( defaultMode && ( normalizedMode === "show" ||
- ( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
- el.show();
- }
-
- if ( !defaultMode || normalizedMode !== "none" ) {
- $.effects.saveStyle( el );
- }
-
- if ( typeof next === "function" ) {
- next();
- }
- };
-
- if ( $.fx.off || !effectMethod ) {
-
- // Delegate to the original method (e.g., .show()) if possible
- if ( mode ) {
- return this[ mode ]( args.duration, complete );
- } else {
- return this.each( function() {
- if ( complete ) {
- complete.call( this );
- }
- } );
- }
- }
-
- function run( next ) {
- var elem = $( this );
-
- function cleanup() {
- elem.removeData( dataSpaceAnimated );
-
- $.effects.cleanUp( elem );
-
- if ( args.mode === "hide" ) {
- elem.hide();
- }
-
- done();
- }
-
- function done() {
- if ( typeof complete === "function" ) {
- complete.call( elem[ 0 ] );
- }
-
- if ( typeof next === "function" ) {
- next();
- }
- }
-
- // Override mode option on a per element basis,
- // as toggle can be either show or hide depending on element state
- args.mode = modes.shift();
-
- if ( $.uiBackCompat !== false && !defaultMode ) {
- if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
-
- // Call the core method to track "olddisplay" properly
- elem[ mode ]();
- done();
- } else {
- effectMethod.call( elem[ 0 ], args, done );
- }
- } else {
- if ( args.mode === "none" ) {
-
- // Call the core method to track "olddisplay" properly
- elem[ mode ]();
- done();
- } else {
- effectMethod.call( elem[ 0 ], args, cleanup );
- }
- }
- }
-
- // Run prefilter on all elements first to ensure that
- // any showing or hiding happens before placeholder creation,
- // which ensures that any layout changes are correctly captured.
- return queue === false ?
- this.each( prefilter ).each( run ) :
- this.queue( queueName, prefilter ).queue( queueName, run );
- },
-
- show: ( function( orig ) {
- return function( option ) {
- if ( standardAnimationOption( option ) ) {
- return orig.apply( this, arguments );
- } else {
- var args = _normalizeArguments.apply( this, arguments );
- args.mode = "show";
- return this.effect.call( this, args );
- }
- };
- } )( $.fn.show ),
-
- hide: ( function( orig ) {
- return function( option ) {
- if ( standardAnimationOption( option ) ) {
- return orig.apply( this, arguments );
- } else {
- var args = _normalizeArguments.apply( this, arguments );
- args.mode = "hide";
- return this.effect.call( this, args );
- }
- };
- } )( $.fn.hide ),
-
- toggle: ( function( orig ) {
- return function( option ) {
- if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
- return orig.apply( this, arguments );
- } else {
- var args = _normalizeArguments.apply( this, arguments );
- args.mode = "toggle";
- return this.effect.call( this, args );
- }
- };
- } )( $.fn.toggle ),
-
- cssUnit: function( key ) {
- var style = this.css( key ),
- val = [];
-
- $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
- if ( style.indexOf( unit ) > 0 ) {
- val = [ parseFloat( style ), unit ];
- }
- } );
- return val;
- },
-
- cssClip: function( clipObj ) {
- if ( clipObj ) {
- return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " +
- clipObj.bottom + "px " + clipObj.left + "px)" );
- }
- return parseClip( this.css( "clip" ), this );
- },
-
- transfer: function( options, done ) {
- var element = $( this ),
- target = $( options.to ),
- targetFixed = target.css( "position" ) === "fixed",
- body = $( "body" ),
- fixTop = targetFixed ? body.scrollTop() : 0,
- fixLeft = targetFixed ? body.scrollLeft() : 0,
- endPosition = target.offset(),
- animation = {
- top: endPosition.top - fixTop,
- left: endPosition.left - fixLeft,
- height: target.innerHeight(),
- width: target.innerWidth()
- },
- startPosition = element.offset(),
- transfer = $( "<div class='ui-effects-transfer'></div>" );
-
- transfer
- .appendTo( "body" )
- .addClass( options.className )
- .css( {
- top: startPosition.top - fixTop,
- left: startPosition.left - fixLeft,
- height: element.innerHeight(),
- width: element.innerWidth(),
- position: targetFixed ? "fixed" : "absolute"
- } )
- .animate( animation, options.duration, options.easing, function() {
- transfer.remove();
- if ( typeof done === "function" ) {
- done();
- }
- } );
- }
-} );
-
-function parseClip( str, element ) {
- var outerWidth = element.outerWidth(),
- outerHeight = element.outerHeight(),
- clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,
- values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];
-
- return {
- top: parseFloat( values[ 1 ] ) || 0,
- right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
- bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
- left: parseFloat( values[ 4 ] ) || 0
- };
-}
-
-$.fx.step.clip = function( fx ) {
- if ( !fx.clipInit ) {
- fx.start = $( fx.elem ).cssClip();
- if ( typeof fx.end === "string" ) {
- fx.end = parseClip( fx.end, fx.elem );
- }
- fx.clipInit = true;
- }
-
- $( fx.elem ).cssClip( {
- top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,
- right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,
- bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,
- left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left
- } );
-};
-
-} )();
-
-/******************************************************************************/
-/*********************************** EASING ***********************************/
-/******************************************************************************/
-
-( function() {
-
-// Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
-
-var baseEasings = {};
-
-$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
- baseEasings[ name ] = function( p ) {
- return Math.pow( p, i + 2 );
- };
-} );
-
-$.extend( baseEasings, {
- Sine: function( p ) {
- return 1 - Math.cos( p * Math.PI / 2 );
- },
- Circ: function( p ) {
- return 1 - Math.sqrt( 1 - p * p );
- },
- Elastic: function( p ) {
- return p === 0 || p === 1 ? p :
- -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
- },
- Back: function( p ) {
- return p * p * ( 3 * p - 2 );
- },
- Bounce: function( p ) {
- var pow2,
- bounce = 4;
-
- while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
- return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
- }
-} );
-
-$.each( baseEasings, function( name, easeIn ) {
- $.easing[ "easeIn" + name ] = easeIn;
- $.easing[ "easeOut" + name ] = function( p ) {
- return 1 - easeIn( 1 - p );
- };
- $.easing[ "easeInOut" + name ] = function( p ) {
- return p < 0.5 ?
- easeIn( p * 2 ) / 2 :
- 1 - easeIn( p * -2 + 2 ) / 2;
- };
-} );
-
-} )();
-
-var effect = $.effects;
-
-
-/*!
- * jQuery UI Effects Blind 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Blind Effect
-//>>group: Effects
-//>>description: Blinds the element.
-//>>docs: http://api.jqueryui.com/blind-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) {
- var map = {
- up: [ "bottom", "top" ],
- vertical: [ "bottom", "top" ],
- down: [ "top", "bottom" ],
- left: [ "right", "left" ],
- horizontal: [ "right", "left" ],
- right: [ "left", "right" ]
- },
- element = $( this ),
- direction = options.direction || "up",
- start = element.cssClip(),
- animate = { clip: $.extend( {}, start ) },
- placeholder = $.effects.createPlaceholder( element );
-
- animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];
-
- if ( options.mode === "show" ) {
- element.cssClip( animate.clip );
- if ( placeholder ) {
- placeholder.css( $.effects.clipToBox( animate ) );
- }
-
- animate.clip = start;
- }
-
- if ( placeholder ) {
- placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
- }
-
- element.animate( animate, {
- queue: false,
- duration: options.duration,
- easing: options.easing,
- complete: done
- } );
-} );
-
-
-/*!
- * jQuery UI Effects Bounce 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Bounce Effect
-//>>group: Effects
-//>>description: Bounces an element horizontally or vertically n times.
-//>>docs: http://api.jqueryui.com/bounce-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) {
- var upAnim, downAnim, refValue,
- element = $( this ),
-
- // Defaults:
- mode = options.mode,
- hide = mode === "hide",
- show = mode === "show",
- direction = options.direction || "up",
- distance = options.distance,
- times = options.times || 5,
-
- // Number of internal animations
- anims = times * 2 + ( show || hide ? 1 : 0 ),
- speed = options.duration / anims,
- easing = options.easing,
-
- // Utility:
- ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
- motion = ( direction === "up" || direction === "left" ),
- i = 0,
-
- queuelen = element.queue().length;
-
- $.effects.createPlaceholder( element );
-
- refValue = element.css( ref );
-
- // Default distance for the BIGGEST bounce is the outer Distance / 3
- if ( !distance ) {
- distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
- }
-
- if ( show ) {
- downAnim = { opacity: 1 };
- downAnim[ ref ] = refValue;
-
- // If we are showing, force opacity 0 and set the initial position
- // then do the "first" animation
- element
- .css( "opacity", 0 )
- .css( ref, motion ? -distance * 2 : distance * 2 )
- .animate( downAnim, speed, easing );
- }
-
- // Start at the smallest distance if we are hiding
- if ( hide ) {
- distance = distance / Math.pow( 2, times - 1 );
- }
-
- downAnim = {};
- downAnim[ ref ] = refValue;
-
- // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
- for ( ; i < times; i++ ) {
- upAnim = {};
- upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
-
- element
- .animate( upAnim, speed, easing )
- .animate( downAnim, speed, easing );
-
- distance = hide ? distance * 2 : distance / 2;
- }
-
- // Last Bounce when Hiding
- if ( hide ) {
- upAnim = { opacity: 0 };
- upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
-
- element.animate( upAnim, speed, easing );
- }
-
- element.queue( done );
-
- $.effects.unshift( element, queuelen, anims + 1 );
-} );
-
-
-/*!
- * jQuery UI Effects Clip 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Clip Effect
-//>>group: Effects
-//>>description: Clips the element on and off like an old TV.
-//>>docs: http://api.jqueryui.com/clip-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) {
- var start,
- animate = {},
- element = $( this ),
- direction = options.direction || "vertical",
- both = direction === "both",
- horizontal = both || direction === "horizontal",
- vertical = both || direction === "vertical";
-
- start = element.cssClip();
- animate.clip = {
- top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
- right: horizontal ? ( start.right - start.left ) / 2 : start.right,
- bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
- left: horizontal ? ( start.right - start.left ) / 2 : start.left
- };
-
- $.effects.createPlaceholder( element );
-
- if ( options.mode === "show" ) {
- element.cssClip( animate.clip );
- animate.clip = start;
- }
-
- element.animate( animate, {
- queue: false,
- duration: options.duration,
- easing: options.easing,
- complete: done
- } );
-
-} );
-
-
-/*!
- * jQuery UI Effects Drop 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Drop Effect
-//>>group: Effects
-//>>description: Moves an element in one direction and hides it at the same time.
-//>>docs: http://api.jqueryui.com/drop-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) {
-
- var distance,
- element = $( this ),
- mode = options.mode,
- show = mode === "show",
- direction = options.direction || "left",
- ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
- motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
- oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
- animation = {
- opacity: 0
- };
-
- $.effects.createPlaceholder( element );
-
- distance = options.distance ||
- element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
-
- animation[ ref ] = motion + distance;
-
- if ( show ) {
- element.css( animation );
-
- animation[ ref ] = oppositeMotion + distance;
- animation.opacity = 1;
- }
-
- // Animate
- element.animate( animation, {
- queue: false,
- duration: options.duration,
- easing: options.easing,
- complete: done
- } );
-} );
-
-
-/*!
- * jQuery UI Effects Explode 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Explode Effect
-//>>group: Effects
-/* eslint-disable max-len */
-//>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.
-/* eslint-enable max-len */
-//>>docs: http://api.jqueryui.com/explode-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) {
-
- var i, j, left, top, mx, my,
- rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
- cells = rows,
- element = $( this ),
- mode = options.mode,
- show = mode === "show",
-
- // Show and then visibility:hidden the element before calculating offset
- offset = element.show().css( "visibility", "hidden" ).offset(),
-
- // Width and height of a piece
- width = Math.ceil( element.outerWidth() / cells ),
- height = Math.ceil( element.outerHeight() / rows ),
- pieces = [];
-
- // Children animate complete:
- function childComplete() {
- pieces.push( this );
- if ( pieces.length === rows * cells ) {
- animComplete();
- }
- }
-
- // Clone the element for each row and cell.
- for ( i = 0; i < rows; i++ ) { // ===>
- top = offset.top + i * height;
- my = i - ( rows - 1 ) / 2;
-
- for ( j = 0; j < cells; j++ ) { // |||
- left = offset.left + j * width;
- mx = j - ( cells - 1 ) / 2;
-
- // Create a clone of the now hidden main element that will be absolute positioned
- // within a wrapper div off the -left and -top equal to size of our pieces
- element
- .clone()
- .appendTo( "body" )
- .wrap( "<div></div>" )
- .css( {
- position: "absolute",
- visibility: "visible",
- left: -j * width,
- top: -i * height
- } )
-
- // Select the wrapper - make it overflow: hidden and absolute positioned based on
- // where the original was located +left and +top equal to the size of pieces
- .parent()
- .addClass( "ui-effects-explode" )
- .css( {
- position: "absolute",
- overflow: "hidden",
- width: width,
- height: height,
- left: left + ( show ? mx * width : 0 ),
- top: top + ( show ? my * height : 0 ),
- opacity: show ? 0 : 1
- } )
- .animate( {
- left: left + ( show ? 0 : mx * width ),
- top: top + ( show ? 0 : my * height ),
- opacity: show ? 1 : 0
- }, options.duration || 500, options.easing, childComplete );
- }
- }
-
- function animComplete() {
- element.css( {
- visibility: "visible"
- } );
- $( pieces ).remove();
- done();
- }
-} );
-
-
-/*!
- * jQuery UI Effects Fade 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Fade Effect
-//>>group: Effects
-//>>description: Fades the element.
-//>>docs: http://api.jqueryui.com/fade-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) {
- var show = options.mode === "show";
-
- $( this )
- .css( "opacity", show ? 0 : 1 )
- .animate( {
- opacity: show ? 1 : 0
- }, {
- queue: false,
- duration: options.duration,
- easing: options.easing,
- complete: done
- } );
-} );
-
-
-/*!
- * jQuery UI Effects Fold 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Fold Effect
-//>>group: Effects
-//>>description: Folds an element first horizontally and then vertically.
-//>>docs: http://api.jqueryui.com/fold-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) {
-
- // Create element
- var element = $( this ),
- mode = options.mode,
- show = mode === "show",
- hide = mode === "hide",
- size = options.size || 15,
- percent = /([0-9]+)%/.exec( size ),
- horizFirst = !!options.horizFirst,
- ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
- duration = options.duration / 2,
-
- placeholder = $.effects.createPlaceholder( element ),
-
- start = element.cssClip(),
- animation1 = { clip: $.extend( {}, start ) },
- animation2 = { clip: $.extend( {}, start ) },
-
- distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],
-
- queuelen = element.queue().length;
-
- if ( percent ) {
- size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
- }
- animation1.clip[ ref[ 0 ] ] = size;
- animation2.clip[ ref[ 0 ] ] = size;
- animation2.clip[ ref[ 1 ] ] = 0;
-
- if ( show ) {
- element.cssClip( animation2.clip );
- if ( placeholder ) {
- placeholder.css( $.effects.clipToBox( animation2 ) );
- }
-
- animation2.clip = start;
- }
-
- // Animate
- element
- .queue( function( next ) {
- if ( placeholder ) {
- placeholder
- .animate( $.effects.clipToBox( animation1 ), duration, options.easing )
- .animate( $.effects.clipToBox( animation2 ), duration, options.easing );
- }
-
- next();
- } )
- .animate( animation1, duration, options.easing )
- .animate( animation2, duration, options.easing )
- .queue( done );
-
- $.effects.unshift( element, queuelen, 4 );
-} );
-
-
-/*!
- * jQuery UI Effects Highlight 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Highlight Effect
-//>>group: Effects
-//>>description: Highlights the background of an element in a defined color for a custom duration.
-//>>docs: http://api.jqueryui.com/highlight-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) {
- var element = $( this ),
- animation = {
- backgroundColor: element.css( "backgroundColor" )
- };
-
- if ( options.mode === "hide" ) {
- animation.opacity = 0;
- }
-
- $.effects.saveStyle( element );
-
- element
- .css( {
- backgroundImage: "none",
- backgroundColor: options.color || "#ffff99"
- } )
- .animate( animation, {
- queue: false,
- duration: options.duration,
- easing: options.easing,
- complete: done
- } );
-} );
-
-
-/*!
- * jQuery UI Effects Size 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Size Effect
-//>>group: Effects
-//>>description: Resize an element to a specified width and height.
-//>>docs: http://api.jqueryui.com/size-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectSize = $.effects.define( "size", function( options, done ) {
-
- // Create element
- var baseline, factor, temp,
- element = $( this ),
-
- // Copy for children
- cProps = [ "fontSize" ],
- vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
- hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
-
- // Set options
- mode = options.mode,
- restore = mode !== "effect",
- scale = options.scale || "both",
- origin = options.origin || [ "middle", "center" ],
- position = element.css( "position" ),
- pos = element.position(),
- original = $.effects.scaledDimensions( element ),
- from = options.from || original,
- to = options.to || $.effects.scaledDimensions( element, 0 );
-
- $.effects.createPlaceholder( element );
-
- if ( mode === "show" ) {
- temp = from;
- from = to;
- to = temp;
- }
-
- // Set scaling factor
- factor = {
- from: {
- y: from.height / original.height,
- x: from.width / original.width
- },
- to: {
- y: to.height / original.height,
- x: to.width / original.width
- }
- };
-
- // Scale the css box
- if ( scale === "box" || scale === "both" ) {
-
- // Vertical props scaling
- if ( factor.from.y !== factor.to.y ) {
- from = $.effects.setTransition( element, vProps, factor.from.y, from );
- to = $.effects.setTransition( element, vProps, factor.to.y, to );
- }
-
- // Horizontal props scaling
- if ( factor.from.x !== factor.to.x ) {
- from = $.effects.setTransition( element, hProps, factor.from.x, from );
- to = $.effects.setTransition( element, hProps, factor.to.x, to );
- }
- }
-
- // Scale the content
- if ( scale === "content" || scale === "both" ) {
-
- // Vertical props scaling
- if ( factor.from.y !== factor.to.y ) {
- from = $.effects.setTransition( element, cProps, factor.from.y, from );
- to = $.effects.setTransition( element, cProps, factor.to.y, to );
- }
- }
-
- // Adjust the position properties based on the provided origin points
- if ( origin ) {
- baseline = $.effects.getBaseline( origin, original );
- from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
- from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
- to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
- to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
- }
- delete from.outerHeight;
- delete from.outerWidth;
- element.css( from );
-
- // Animate the children if desired
- if ( scale === "content" || scale === "both" ) {
-
- vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps );
- hProps = hProps.concat( [ "marginLeft", "marginRight" ] );
-
- // Only animate children with width attributes specified
- // TODO: is this right? should we include anything with css width specified as well
- element.find( "*[width]" ).each( function() {
- var child = $( this ),
- childOriginal = $.effects.scaledDimensions( child ),
- childFrom = {
- height: childOriginal.height * factor.from.y,
- width: childOriginal.width * factor.from.x,
- outerHeight: childOriginal.outerHeight * factor.from.y,
- outerWidth: childOriginal.outerWidth * factor.from.x
- },
- childTo = {
- height: childOriginal.height * factor.to.y,
- width: childOriginal.width * factor.to.x,
- outerHeight: childOriginal.height * factor.to.y,
- outerWidth: childOriginal.width * factor.to.x
- };
-
- // Vertical props scaling
- if ( factor.from.y !== factor.to.y ) {
- childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
- childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
- }
-
- // Horizontal props scaling
- if ( factor.from.x !== factor.to.x ) {
- childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
- childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
- }
-
- if ( restore ) {
- $.effects.saveStyle( child );
- }
-
- // Animate children
- child.css( childFrom );
- child.animate( childTo, options.duration, options.easing, function() {
-
- // Restore children
- if ( restore ) {
- $.effects.restoreStyle( child );
- }
- } );
- } );
- }
-
- // Animate
- element.animate( to, {
- queue: false,
- duration: options.duration,
- easing: options.easing,
- complete: function() {
-
- var offset = element.offset();
-
- if ( to.opacity === 0 ) {
- element.css( "opacity", from.opacity );
- }
-
- if ( !restore ) {
- element
- .css( "position", position === "static" ? "relative" : position )
- .offset( offset );
-
- // Need to save style here so that automatic style restoration
- // doesn't restore to the original styles from before the animation.
- $.effects.saveStyle( element );
- }
-
- done();
- }
- } );
-
-} );
-
-
-/*!
- * jQuery UI Effects Scale 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Scale Effect
-//>>group: Effects
-//>>description: Grows or shrinks an element and its content.
-//>>docs: http://api.jqueryui.com/scale-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectScale = $.effects.define( "scale", function( options, done ) {
-
- // Create element
- var el = $( this ),
- mode = options.mode,
- percent = parseInt( options.percent, 10 ) ||
- ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),
-
- newOptions = $.extend( true, {
- from: $.effects.scaledDimensions( el ),
- to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
- origin: options.origin || [ "middle", "center" ]
- }, options );
-
- // Fade option to support puff
- if ( options.fade ) {
- newOptions.from.opacity = 1;
- newOptions.to.opacity = 0;
- }
-
- $.effects.effect.size.call( this, newOptions, done );
-} );
-
-
-/*!
- * jQuery UI Effects Puff 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Puff Effect
-//>>group: Effects
-//>>description: Creates a puff effect by scaling the element up and hiding it at the same time.
-//>>docs: http://api.jqueryui.com/puff-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) {
- var newOptions = $.extend( true, {}, options, {
- fade: true,
- percent: parseInt( options.percent, 10 ) || 150
- } );
-
- $.effects.effect.scale.call( this, newOptions, done );
-} );
-
-
-/*!
- * jQuery UI Effects Pulsate 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Pulsate Effect
-//>>group: Effects
-//>>description: Pulsates an element n times by changing the opacity to zero and back.
-//>>docs: http://api.jqueryui.com/pulsate-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) {
- var element = $( this ),
- mode = options.mode,
- show = mode === "show",
- hide = mode === "hide",
- showhide = show || hide,
-
- // Showing or hiding leaves off the "last" animation
- anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
- duration = options.duration / anims,
- animateTo = 0,
- i = 1,
- queuelen = element.queue().length;
-
- if ( show || !element.is( ":visible" ) ) {
- element.css( "opacity", 0 ).show();
- animateTo = 1;
- }
-
- // Anims - 1 opacity "toggles"
- for ( ; i < anims; i++ ) {
- element.animate( { opacity: animateTo }, duration, options.easing );
- animateTo = 1 - animateTo;
- }
-
- element.animate( { opacity: animateTo }, duration, options.easing );
-
- element.queue( done );
-
- $.effects.unshift( element, queuelen, anims + 1 );
-} );
-
-
-/*!
- * jQuery UI Effects Shake 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Shake Effect
-//>>group: Effects
-//>>description: Shakes an element horizontally or vertically n times.
-//>>docs: http://api.jqueryui.com/shake-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectShake = $.effects.define( "shake", function( options, done ) {
-
- var i = 1,
- element = $( this ),
- direction = options.direction || "left",
- distance = options.distance || 20,
- times = options.times || 3,
- anims = times * 2 + 1,
- speed = Math.round( options.duration / anims ),
- ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
- positiveMotion = ( direction === "up" || direction === "left" ),
- animation = {},
- animation1 = {},
- animation2 = {},
-
- queuelen = element.queue().length;
-
- $.effects.createPlaceholder( element );
-
- // Animation
- animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
- animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
- animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
-
- // Animate
- element.animate( animation, speed, options.easing );
-
- // Shakes
- for ( ; i < times; i++ ) {
- element
- .animate( animation1, speed, options.easing )
- .animate( animation2, speed, options.easing );
- }
-
- element
- .animate( animation1, speed, options.easing )
- .animate( animation, speed / 2, options.easing )
- .queue( done );
-
- $.effects.unshift( element, queuelen, anims + 1 );
-} );
-
-
-/*!
- * jQuery UI Effects Slide 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Slide Effect
-//>>group: Effects
-//>>description: Slides an element in and out of the viewport.
-//>>docs: http://api.jqueryui.com/slide-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) {
- var startClip, startRef,
- element = $( this ),
- map = {
- up: [ "bottom", "top" ],
- down: [ "top", "bottom" ],
- left: [ "right", "left" ],
- right: [ "left", "right" ]
- },
- mode = options.mode,
- direction = options.direction || "left",
- ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
- positiveMotion = ( direction === "up" || direction === "left" ),
- distance = options.distance ||
- element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
- animation = {};
-
- $.effects.createPlaceholder( element );
-
- startClip = element.cssClip();
- startRef = element.position()[ ref ];
-
- // Define hide animation
- animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
- animation.clip = element.cssClip();
- animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];
-
- // Reverse the animation if we're showing
- if ( mode === "show" ) {
- element.cssClip( animation.clip );
- element.css( ref, animation[ ref ] );
- animation.clip = startClip;
- animation[ ref ] = startRef;
- }
-
- // Actually animate
- element.animate( animation, {
- queue: false,
- duration: options.duration,
- easing: options.easing,
- complete: done
- } );
-} );
-
-
-/*!
- * jQuery UI Effects Transfer 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Transfer Effect
-//>>group: Effects
-//>>description: Displays a transfer effect from one element to another.
-//>>docs: http://api.jqueryui.com/transfer-effect/
-//>>demos: http://jqueryui.com/effect/
-
-
-var effect;
-if ( $.uiBackCompat !== false ) {
- effect = $.effects.define( "transfer", function( options, done ) {
- $( this ).transfer( options, done );
- } );
-}
-var effectsEffectTransfer = effect;
-
-
-/*!
- * jQuery UI Focusable 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: :focusable Selector
-//>>group: Core
-//>>description: Selects elements which can be focused.
-//>>docs: http://api.jqueryui.com/focusable-selector/
-
-
-// Selectors
-$.ui.focusable = function( element, hasTabindex ) {
- var map, mapName, img, focusableIfVisible, fieldset,
- nodeName = element.nodeName.toLowerCase();
-
- if ( "area" === nodeName ) {
- map = element.parentNode;
- mapName = map.name;
- if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
- return false;
- }
- img = $( "img[usemap='#" + mapName + "']" );
- return img.length > 0 && img.is( ":visible" );
- }
-
- if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {
- focusableIfVisible = !element.disabled;
-
- if ( focusableIfVisible ) {
-
- // Form controls within a disabled fieldset are disabled.
- // However, controls within the fieldset's legend do not get disabled.
- // Since controls generally aren't placed inside legends, we skip
- // this portion of the check.
- fieldset = $( element ).closest( "fieldset" )[ 0 ];
- if ( fieldset ) {
- focusableIfVisible = !fieldset.disabled;
- }
- }
- } else if ( "a" === nodeName ) {
- focusableIfVisible = element.href || hasTabindex;
- } else {
- focusableIfVisible = hasTabindex;
- }
-
- return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) );
-};
-
-// Support: IE 8 only
-// IE 8 doesn't resolve inherit to visible/hidden for computed values
-function visible( element ) {
- var visibility = element.css( "visibility" );
- while ( visibility === "inherit" ) {
- element = element.parent();
- visibility = element.css( "visibility" );
- }
- return visibility === "visible";
-}
-
-$.extend( $.expr.pseudos, {
- focusable: function( element ) {
- return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );
- }
-} );
-
-var focusable = $.ui.focusable;
-
-
-
-// Support: IE8 Only
-// IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
-// with a string, so we need to find the proper form.
-var form = $.fn._form = function() {
- return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
-};
-
-
-/*!
- * jQuery UI Form Reset Mixin 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Form Reset Mixin
-//>>group: Core
-//>>description: Refresh input widgets when their form is reset
-//>>docs: http://api.jqueryui.com/form-reset-mixin/
-
-
-var formResetMixin = $.ui.formResetMixin = {
- _formResetHandler: function() {
- var form = $( this );
-
- // Wait for the form reset to actually happen before refreshing
- setTimeout( function() {
- var instances = form.data( "ui-form-reset-instances" );
- $.each( instances, function() {
- this.refresh();
- } );
- } );
- },
-
- _bindFormResetHandler: function() {
- this.form = this.element._form();
- if ( !this.form.length ) {
- return;
- }
-
- var instances = this.form.data( "ui-form-reset-instances" ) || [];
- if ( !instances.length ) {
-
- // We don't use _on() here because we use a single event handler per form
- this.form.on( "reset.ui-form-reset", this._formResetHandler );
- }
- instances.push( this );
- this.form.data( "ui-form-reset-instances", instances );
- },
-
- _unbindFormResetHandler: function() {
- if ( !this.form.length ) {
- return;
- }
-
- var instances = this.form.data( "ui-form-reset-instances" );
- instances.splice( $.inArray( this, instances ), 1 );
- if ( instances.length ) {
- this.form.data( "ui-form-reset-instances", instances );
- } else {
- this.form
- .removeData( "ui-form-reset-instances" )
- .off( "reset.ui-form-reset" );
- }
- }
-};
-
-
-/*!
- * jQuery UI Support for jQuery core 1.8.x and newer 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- */
-
-//>>label: jQuery 1.8+ Support
-//>>group: Core
-//>>description: Support version 1.8.x and newer of jQuery core
-
-
-// Support: jQuery 1.9.x or older
-// $.expr[ ":" ] is deprecated.
-if ( !$.expr.pseudos ) {
- $.expr.pseudos = $.expr[ ":" ];
-}
-
-// Support: jQuery 1.11.x or older
-// $.unique has been renamed to $.uniqueSort
-if ( !$.uniqueSort ) {
- $.uniqueSort = $.unique;
-}
-
-// Support: jQuery 2.2.x or older.
-// This method has been defined in jQuery 3.0.0.
-// Code from https://github.com/jquery/jquery/blob/e539bac79e666bba95bba86d690b4e609dca2286/src/selector/escapeSelector.js
-if ( !$.escapeSelector ) {
-
- // CSS string/identifier serialization
- // https://drafts.csswg.org/cssom/#common-serializing-idioms
- var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
-
- var fcssescape = function( ch, asCodePoint ) {
- if ( asCodePoint ) {
-
- // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
- if ( ch === "\0" ) {
- return "\uFFFD";
- }
-
- // Control characters and (dependent upon position) numbers get escaped as code points
- return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
- }
-
- // Other potentially-special ASCII characters get backslash-escaped
- return "\\" + ch;
- };
-
- $.escapeSelector = function( sel ) {
- return ( sel + "" ).replace( rcssescape, fcssescape );
- };
-}
-
-// Support: jQuery 3.4.x or older
-// These methods have been defined in jQuery 3.5.0.
-if ( !$.fn.even || !$.fn.odd ) {
- $.fn.extend( {
- even: function() {
- return this.filter( function( i ) {
- return i % 2 === 0;
- } );
- },
- odd: function() {
- return this.filter( function( i ) {
- return i % 2 === 1;
- } );
- }
- } );
-}
-
-;
-/*!
- * jQuery UI Keycode 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Keycode
-//>>group: Core
-//>>description: Provide keycodes as keynames
-//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
-
-
-var keycode = $.ui.keyCode = {
- BACKSPACE: 8,
- COMMA: 188,
- DELETE: 46,
- DOWN: 40,
- END: 35,
- ENTER: 13,
- ESCAPE: 27,
- HOME: 36,
- LEFT: 37,
- PAGE_DOWN: 34,
- PAGE_UP: 33,
- PERIOD: 190,
- RIGHT: 39,
- SPACE: 32,
- TAB: 9,
- UP: 38
-};
-
-
-/*!
- * jQuery UI Labels 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: labels
-//>>group: Core
-//>>description: Find all the labels associated with a given input
-//>>docs: http://api.jqueryui.com/labels/
-
-
-var labels = $.fn.labels = function() {
- var ancestor, selector, id, labels, ancestors;
-
- if ( !this.length ) {
- return this.pushStack( [] );
- }
-
- // Check control.labels first
- if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
- return this.pushStack( this[ 0 ].labels );
- }
-
- // Support: IE <= 11, FF <= 37, Android <= 2.3 only
- // Above browsers do not support control.labels. Everything below is to support them
- // as well as document fragments. control.labels does not work on document fragments
- labels = this.eq( 0 ).parents( "label" );
-
- // Look for the label based on the id
- id = this.attr( "id" );
- if ( id ) {
-
- // We don't search against the document in case the element
- // is disconnected from the DOM
- ancestor = this.eq( 0 ).parents().last();
-
- // Get a full set of top level ancestors
- ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
-
- // Create a selector for the label based on the id
- selector = "label[for='" + $.escapeSelector( id ) + "']";
-
- labels = labels.add( ancestors.find( selector ).addBack( selector ) );
-
- }
-
- // Return whatever we have found for labels
- return this.pushStack( labels );
-};
-
-
-/*!
- * jQuery UI Scroll Parent 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: scrollParent
-//>>group: Core
-//>>description: Get the closest ancestor element that is scrollable.
-//>>docs: http://api.jqueryui.com/scrollParent/
-
-
-var scrollParent = $.fn.scrollParent = function( includeHidden ) {
- var position = this.css( "position" ),
- excludeStaticParent = position === "absolute",
- overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
- scrollParent = this.parents().filter( function() {
- var parent = $( this );
- if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
- return false;
- }
- return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
- parent.css( "overflow-x" ) );
- } ).eq( 0 );
-
- return position === "fixed" || !scrollParent.length ?
- $( this[ 0 ].ownerDocument || document ) :
- scrollParent;
-};
-
-
-/*!
- * jQuery UI Tabbable 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: :tabbable Selector
-//>>group: Core
-//>>description: Selects elements which can be tabbed to.
-//>>docs: http://api.jqueryui.com/tabbable-selector/
-
-
-var tabbable = $.extend( $.expr.pseudos, {
- tabbable: function( element ) {
- var tabIndex = $.attr( element, "tabindex" ),
- hasTabindex = tabIndex != null;
- return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex );
- }
-} );
-
-
-/*!
- * jQuery UI Unique ID 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: uniqueId
-//>>group: Core
-//>>description: Functions to generate and remove uniqueId's
-//>>docs: http://api.jqueryui.com/uniqueId/
-
-
-var uniqueId = $.fn.extend( {
- uniqueId: ( function() {
- var uuid = 0;
-
- return function() {
- return this.each( function() {
- if ( !this.id ) {
- this.id = "ui-id-" + ( ++uuid );
- }
- } );
- };
- } )(),
-
- removeUniqueId: function() {
- return this.each( function() {
- if ( /^ui-id-\d+$/.test( this.id ) ) {
- $( this ).removeAttr( "id" );
- }
- } );
- }
-} );
-
-
-/*!
- * jQuery UI Accordion 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Accordion
-//>>group: Widgets
-/* eslint-disable max-len */
-//>>description: Displays collapsible content panels for presenting information in a limited amount of space.
-/* eslint-enable max-len */
-//>>docs: http://api.jqueryui.com/accordion/
-//>>demos: http://jqueryui.com/accordion/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/accordion.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-var widgetsAccordion = $.widget( "ui.accordion", {
- version: "1.13.1",
- options: {
- active: 0,
- animate: {},
- classes: {
- "ui-accordion-header": "ui-corner-top",
- "ui-accordion-header-collapsed": "ui-corner-all",
- "ui-accordion-content": "ui-corner-bottom"
- },
- collapsible: false,
- event: "click",
- header: function( elem ) {
- return elem.find( "> li > :first-child" ).add( elem.find( "> :not(li)" ).even() );
- },
- heightStyle: "auto",
- icons: {
- activeHeader: "ui-icon-triangle-1-s",
- header: "ui-icon-triangle-1-e"
- },
-
- // Callbacks
- activate: null,
- beforeActivate: null
- },
-
- hideProps: {
- borderTopWidth: "hide",
- borderBottomWidth: "hide",
- paddingTop: "hide",
- paddingBottom: "hide",
- height: "hide"
- },
-
- showProps: {
- borderTopWidth: "show",
- borderBottomWidth: "show",
- paddingTop: "show",
- paddingBottom: "show",
- height: "show"
- },
-
- _create: function() {
- var options = this.options;
-
- this.prevShow = this.prevHide = $();
- this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
- this.element.attr( "role", "tablist" );
-
- // Don't allow collapsible: false and active: false / null
- if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
- options.active = 0;
- }
-
- this._processPanels();
-
- // handle negative values
- if ( options.active < 0 ) {
- options.active += this.headers.length;
- }
- this._refresh();
- },
-
- _getCreateEventData: function() {
- return {
- header: this.active,
- panel: !this.active.length ? $() : this.active.next()
- };
- },
-
- _createIcons: function() {
- var icon, children,
- icons = this.options.icons;
-
- if ( icons ) {
- icon = $( "<span>" );
- this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
- icon.prependTo( this.headers );
- children = this.active.children( ".ui-accordion-header-icon" );
- this._removeClass( children, icons.header )
- ._addClass( children, null, icons.activeHeader )
- ._addClass( this.headers, "ui-accordion-icons" );
- }
- },
-
- _destroyIcons: function() {
- this._removeClass( this.headers, "ui-accordion-icons" );
- this.headers.children( ".ui-accordion-header-icon" ).remove();
- },
-
- _destroy: function() {
- var contents;
-
- // Clean up main element
- this.element.removeAttr( "role" );
-
- // Clean up headers
- this.headers
- .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
- .removeUniqueId();
-
- this._destroyIcons();
-
- // Clean up content panels
- contents = this.headers.next()
- .css( "display", "" )
- .removeAttr( "role aria-hidden aria-labelledby" )
- .removeUniqueId();
-
- if ( this.options.heightStyle !== "content" ) {
- contents.css( "height", "" );
- }
- },
-
- _setOption: function( key, value ) {
- if ( key === "active" ) {
-
- // _activate() will handle invalid values and update this.options
- this._activate( value );
- return;
- }
-
- if ( key === "event" ) {
- if ( this.options.event ) {
- this._off( this.headers, this.options.event );
- }
- this._setupEvents( value );
- }
-
- this._super( key, value );
-
- // Setting collapsible: false while collapsed; open first panel
- if ( key === "collapsible" && !value && this.options.active === false ) {
- this._activate( 0 );
- }
-
- if ( key === "icons" ) {
- this._destroyIcons();
- if ( value ) {
- this._createIcons();
- }
- }
- },
-
- _setOptionDisabled: function( value ) {
- this._super( value );
-
- this.element.attr( "aria-disabled", value );
-
- // Support: IE8 Only
- // #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
- // so we need to add the disabled class to the headers and panels
- this._toggleClass( null, "ui-state-disabled", !!value );
- this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
- !!value );
- },
-
- _keydown: function( event ) {
- if ( event.altKey || event.ctrlKey ) {
- return;
- }
-
- var keyCode = $.ui.keyCode,
- length = this.headers.length,
- currentIndex = this.headers.index( event.target ),
- toFocus = false;
-
- switch ( event.keyCode ) {
- case keyCode.RIGHT:
- case keyCode.DOWN:
- toFocus = this.headers[ ( currentIndex + 1 ) % length ];
- break;
- case keyCode.LEFT:
- case keyCode.UP:
- toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
- break;
- case keyCode.SPACE:
- case keyCode.ENTER:
- this._eventHandler( event );
- break;
- case keyCode.HOME:
- toFocus = this.headers[ 0 ];
- break;
- case keyCode.END:
- toFocus = this.headers[ length - 1 ];
- break;
- }
-
- if ( toFocus ) {
- $( event.target ).attr( "tabIndex", -1 );
- $( toFocus ).attr( "tabIndex", 0 );
- $( toFocus ).trigger( "focus" );
- event.preventDefault();
- }
- },
-
- _panelKeyDown: function( event ) {
- if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
- $( event.currentTarget ).prev().trigger( "focus" );
- }
- },
-
- refresh: function() {
- var options = this.options;
- this._processPanels();
-
- // Was collapsed or no panel
- if ( ( options.active === false && options.collapsible === true ) ||
- !this.headers.length ) {
- options.active = false;
- this.active = $();
-
- // active false only when collapsible is true
- } else if ( options.active === false ) {
- this._activate( 0 );
-
- // was active, but active panel is gone
- } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
-
- // all remaining panel are disabled
- if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
- options.active = false;
- this.active = $();
-
- // activate previous panel
- } else {
- this._activate( Math.max( 0, options.active - 1 ) );
- }
-
- // was active, active panel still exists
- } else {
-
- // make sure active index is correct
- options.active = this.headers.index( this.active );
- }
-
- this._destroyIcons();
-
- this._refresh();
- },
-
- _processPanels: function() {
- var prevHeaders = this.headers,
- prevPanels = this.panels;
-
- if ( typeof this.options.header === "function" ) {
- this.headers = this.options.header( this.element );
- } else {
- this.headers = this.element.find( this.options.header );
- }
- this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
- "ui-state-default" );
-
- this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
- this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );
-
- // Avoid memory leaks (#10056)
- if ( prevPanels ) {
- this._off( prevHeaders.not( this.headers ) );
- this._off( prevPanels.not( this.panels ) );
- }
- },
-
- _refresh: function() {
- var maxHeight,
- options = this.options,
- heightStyle = options.heightStyle,
- parent = this.element.parent();
-
- this.active = this._findActive( options.active );
- this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
- ._removeClass( this.active, "ui-accordion-header-collapsed" );
- this._addClass( this.active.next(), "ui-accordion-content-active" );
- this.active.next().show();
-
- this.headers
- .attr( "role", "tab" )
- .each( function() {
- var header = $( this ),
- headerId = header.uniqueId().attr( "id" ),
- panel = header.next(),
- panelId = panel.uniqueId().attr( "id" );
- header.attr( "aria-controls", panelId );
- panel.attr( "aria-labelledby", headerId );
- } )
- .next()
- .attr( "role", "tabpanel" );
-
- this.headers
- .not( this.active )
- .attr( {
- "aria-selected": "false",
- "aria-expanded": "false",
- tabIndex: -1
- } )
- .next()
- .attr( {
- "aria-hidden": "true"
- } )
- .hide();
-
- // Make sure at least one header is in the tab order
- if ( !this.active.length ) {
- this.headers.eq( 0 ).attr( "tabIndex", 0 );
- } else {
- this.active.attr( {
- "aria-selected": "true",
- "aria-expanded": "true",
- tabIndex: 0
- } )
- .next()
- .attr( {
- "aria-hidden": "false"
- } );
- }
-
- this._createIcons();
-
- this._setupEvents( options.event );
-
- if ( heightStyle === "fill" ) {
- maxHeight = parent.height();
- this.element.siblings( ":visible" ).each( function() {
- var elem = $( this ),
- position = elem.css( "position" );
-
- if ( position === "absolute" || position === "fixed" ) {
- return;
- }
- maxHeight -= elem.outerHeight( true );
- } );
-
- this.headers.each( function() {
- maxHeight -= $( this ).outerHeight( true );
- } );
-
- this.headers.next()
- .each( function() {
- $( this ).height( Math.max( 0, maxHeight -
- $( this ).innerHeight() + $( this ).height() ) );
- } )
- .css( "overflow", "auto" );
- } else if ( heightStyle === "auto" ) {
- maxHeight = 0;
- this.headers.next()
- .each( function() {
- var isVisible = $( this ).is( ":visible" );
- if ( !isVisible ) {
- $( this ).show();
- }
- maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
- if ( !isVisible ) {
- $( this ).hide();
- }
- } )
- .height( maxHeight );
- }
- },
-
- _activate: function( index ) {
- var active = this._findActive( index )[ 0 ];
-
- // Trying to activate the already active panel
- if ( active === this.active[ 0 ] ) {
- return;
- }
-
- // Trying to collapse, simulate a click on the currently active header
- active = active || this.active[ 0 ];
-
- this._eventHandler( {
- target: active,
- currentTarget: active,
- preventDefault: $.noop
- } );
- },
-
- _findActive: function( selector ) {
- return typeof selector === "number" ? this.headers.eq( selector ) : $();
- },
-
- _setupEvents: function( event ) {
- var events = {
- keydown: "_keydown"
- };
- if ( event ) {
- $.each( event.split( " " ), function( index, eventName ) {
- events[ eventName ] = "_eventHandler";
- } );
- }
-
- this._off( this.headers.add( this.headers.next() ) );
- this._on( this.headers, events );
- this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
- this._hoverable( this.headers );
- this._focusable( this.headers );
- },
-
- _eventHandler: function( event ) {
- var activeChildren, clickedChildren,
- options = this.options,
- active = this.active,
- clicked = $( event.currentTarget ),
- clickedIsActive = clicked[ 0 ] === active[ 0 ],
- collapsing = clickedIsActive && options.collapsible,
- toShow = collapsing ? $() : clicked.next(),
- toHide = active.next(),
- eventData = {
- oldHeader: active,
- oldPanel: toHide,
- newHeader: collapsing ? $() : clicked,
- newPanel: toShow
- };
-
- event.preventDefault();
-
- if (
-
- // click on active header, but not collapsible
- ( clickedIsActive && !options.collapsible ) ||
-
- // allow canceling activation
- ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
- return;
- }
-
- options.active = collapsing ? false : this.headers.index( clicked );
-
- // When the call to ._toggle() comes after the class changes
- // it causes a very odd bug in IE 8 (see #6720)
- this.active = clickedIsActive ? $() : clicked;
- this._toggle( eventData );
-
- // Switch classes
- // corner classes on the previously active header stay after the animation
- this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
- if ( options.icons ) {
- activeChildren = active.children( ".ui-accordion-header-icon" );
- this._removeClass( activeChildren, null, options.icons.activeHeader )
- ._addClass( activeChildren, null, options.icons.header );
- }
-
- if ( !clickedIsActive ) {
- this._removeClass( clicked, "ui-accordion-header-collapsed" )
- ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
- if ( options.icons ) {
- clickedChildren = clicked.children( ".ui-accordion-header-icon" );
- this._removeClass( clickedChildren, null, options.icons.header )
- ._addClass( clickedChildren, null, options.icons.activeHeader );
- }
-
- this._addClass( clicked.next(), "ui-accordion-content-active" );
- }
- },
-
- _toggle: function( data ) {
- var toShow = data.newPanel,
- toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
-
- // Handle activating a panel during the animation for another activation
- this.prevShow.add( this.prevHide ).stop( true, true );
- this.prevShow = toShow;
- this.prevHide = toHide;
-
- if ( this.options.animate ) {
- this._animate( toShow, toHide, data );
- } else {
- toHide.hide();
- toShow.show();
- this._toggleComplete( data );
- }
-
- toHide.attr( {
- "aria-hidden": "true"
- } );
- toHide.prev().attr( {
- "aria-selected": "false",
- "aria-expanded": "false"
- } );
-
- // if we're switching panels, remove the old header from the tab order
- // if we're opening from collapsed state, remove the previous header from the tab order
- // if we're collapsing, then keep the collapsing header in the tab order
- if ( toShow.length && toHide.length ) {
- toHide.prev().attr( {
- "tabIndex": -1,
- "aria-expanded": "false"
- } );
- } else if ( toShow.length ) {
- this.headers.filter( function() {
- return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
- } )
- .attr( "tabIndex", -1 );
- }
-
- toShow
- .attr( "aria-hidden", "false" )
- .prev()
- .attr( {
- "aria-selected": "true",
- "aria-expanded": "true",
- tabIndex: 0
- } );
- },
-
- _animate: function( toShow, toHide, data ) {
- var total, easing, duration,
- that = this,
- adjust = 0,
- boxSizing = toShow.css( "box-sizing" ),
- down = toShow.length &&
- ( !toHide.length || ( toShow.index() < toHide.index() ) ),
- animate = this.options.animate || {},
- options = down && animate.down || animate,
- complete = function() {
- that._toggleComplete( data );
- };
-
- if ( typeof options === "number" ) {
- duration = options;
- }
- if ( typeof options === "string" ) {
- easing = options;
- }
-
- // fall back from options to animation in case of partial down settings
- easing = easing || options.easing || animate.easing;
- duration = duration || options.duration || animate.duration;
-
- if ( !toHide.length ) {
- return toShow.animate( this.showProps, duration, easing, complete );
- }
- if ( !toShow.length ) {
- return toHide.animate( this.hideProps, duration, easing, complete );
- }
-
- total = toShow.show().outerHeight();
- toHide.animate( this.hideProps, {
- duration: duration,
- easing: easing,
- step: function( now, fx ) {
- fx.now = Math.round( now );
- }
- } );
- toShow
- .hide()
- .animate( this.showProps, {
- duration: duration,
- easing: easing,
- complete: complete,
- step: function( now, fx ) {
- fx.now = Math.round( now );
- if ( fx.prop !== "height" ) {
- if ( boxSizing === "content-box" ) {
- adjust += fx.now;
- }
- } else if ( that.options.heightStyle !== "content" ) {
- fx.now = Math.round( total - toHide.outerHeight() - adjust );
- adjust = 0;
- }
- }
- } );
- },
-
- _toggleComplete: function( data ) {
- var toHide = data.oldPanel,
- prev = toHide.prev();
-
- this._removeClass( toHide, "ui-accordion-content-active" );
- this._removeClass( prev, "ui-accordion-header-active" )
- ._addClass( prev, "ui-accordion-header-collapsed" );
-
- // Work around for rendering bug in IE (#5421)
- if ( toHide.length ) {
- toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
- }
- this._trigger( "activate", null, data );
- }
-} );
-
-
-
-var safeActiveElement = $.ui.safeActiveElement = function( document ) {
- var activeElement;
-
- // Support: IE 9 only
- // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
- try {
- activeElement = document.activeElement;
- } catch ( error ) {
- activeElement = document.body;
- }
-
- // Support: IE 9 - 11 only
- // IE may return null instead of an element
- // Interestingly, this only seems to occur when NOT in an iframe
- if ( !activeElement ) {
- activeElement = document.body;
- }
-
- // Support: IE 11 only
- // IE11 returns a seemingly empty object in some cases when accessing
- // document.activeElement from an <iframe>
- if ( !activeElement.nodeName ) {
- activeElement = document.body;
- }
-
- return activeElement;
-};
-
-
-/*!
- * jQuery UI Menu 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Menu
-//>>group: Widgets
-//>>description: Creates nestable menus.
-//>>docs: http://api.jqueryui.com/menu/
-//>>demos: http://jqueryui.com/menu/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/menu.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-var widgetsMenu = $.widget( "ui.menu", {
- version: "1.13.1",
- defaultElement: "<ul>",
- delay: 300,
- options: {
- icons: {
- submenu: "ui-icon-caret-1-e"
- },
- items: "> *",
- menus: "ul",
- position: {
- my: "left top",
- at: "right top"
- },
- role: "menu",
-
- // Callbacks
- blur: null,
- focus: null,
- select: null
- },
-
- _create: function() {
- this.activeMenu = this.element;
-
- // Flag used to prevent firing of the click handler
- // as the event bubbles up through nested menus
- this.mouseHandled = false;
- this.lastMousePosition = { x: null, y: null };
- this.element
- .uniqueId()
- .attr( {
- role: this.options.role,
- tabIndex: 0
- } );
-
- this._addClass( "ui-menu", "ui-widget ui-widget-content" );
- this._on( {
-
- // Prevent focus from sticking to links inside menu after clicking
- // them (focus should always stay on UL during navigation).
- "mousedown .ui-menu-item": function( event ) {
- event.preventDefault();
-
- this._activateItem( event );
- },
- "click .ui-menu-item": function( event ) {
- var target = $( event.target );
- var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
- if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
- this.select( event );
-
- // Only set the mouseHandled flag if the event will bubble, see #9469.
- if ( !event.isPropagationStopped() ) {
- this.mouseHandled = true;
- }
-
- // Open submenu on click
- if ( target.has( ".ui-menu" ).length ) {
- this.expand( event );
- } else if ( !this.element.is( ":focus" ) &&
- active.closest( ".ui-menu" ).length ) {
-
- // Redirect focus to the menu
- this.element.trigger( "focus", [ true ] );
-
- // If the active item is on the top level, let it stay active.
- // Otherwise, blur the active item since it is no longer visible.
- if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
- clearTimeout( this.timer );
- }
- }
- }
- },
- "mouseenter .ui-menu-item": "_activateItem",
- "mousemove .ui-menu-item": "_activateItem",
- mouseleave: "collapseAll",
- "mouseleave .ui-menu": "collapseAll",
- focus: function( event, keepActiveItem ) {
-
- // If there's already an active item, keep it active
- // If not, activate the first item
- var item = this.active || this._menuItems().first();
-
- if ( !keepActiveItem ) {
- this.focus( event, item );
- }
- },
- blur: function( event ) {
- this._delay( function() {
- var notContained = !$.contains(
- this.element[ 0 ],
- $.ui.safeActiveElement( this.document[ 0 ] )
- );
- if ( notContained ) {
- this.collapseAll( event );
- }
- } );
- },
- keydown: "_keydown"
- } );
-
- this.refresh();
-
- // Clicks outside of a menu collapse any open menus
- this._on( this.document, {
- click: function( event ) {
- if ( this._closeOnDocumentClick( event ) ) {
- this.collapseAll( event, true );
- }
-
- // Reset the mouseHandled flag
- this.mouseHandled = false;
- }
- } );
- },
-
- _activateItem: function( event ) {
-
- // Ignore mouse events while typeahead is active, see #10458.
- // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
- // is over an item in the menu
- if ( this.previousFilter ) {
- return;
- }
-
- // If the mouse didn't actually move, but the page was scrolled, ignore the event (#9356)
- if ( event.clientX === this.lastMousePosition.x &&
- event.clientY === this.lastMousePosition.y ) {
- return;
- }
-
- this.lastMousePosition = {
- x: event.clientX,
- y: event.clientY
- };
-
- var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
- target = $( event.currentTarget );
-
- // Ignore bubbled events on parent items, see #11641
- if ( actualTarget[ 0 ] !== target[ 0 ] ) {
- return;
- }
-
- // If the item is already active, there's nothing to do
- if ( target.is( ".ui-state-active" ) ) {
- return;
- }
-
- // Remove ui-state-active class from siblings of the newly focused menu item
- // to avoid a jump caused by adjacent elements both having a class with a border
- this._removeClass( target.siblings().children( ".ui-state-active" ),
- null, "ui-state-active" );
- this.focus( event, target );
- },
-
- _destroy: function() {
- var items = this.element.find( ".ui-menu-item" )
- .removeAttr( "role aria-disabled" ),
- submenus = items.children( ".ui-menu-item-wrapper" )
- .removeUniqueId()
- .removeAttr( "tabIndex role aria-haspopup" );
-
- // Destroy (sub)menus
- this.element
- .removeAttr( "aria-activedescendant" )
- .find( ".ui-menu" ).addBack()
- .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
- "tabIndex" )
- .removeUniqueId()
- .show();
-
- submenus.children().each( function() {
- var elem = $( this );
- if ( elem.data( "ui-menu-submenu-caret" ) ) {
- elem.remove();
- }
- } );
- },
-
- _keydown: function( event ) {
- var match, prev, character, skip,
- preventDefault = true;
-
- switch ( event.keyCode ) {
- case $.ui.keyCode.PAGE_UP:
- this.previousPage( event );
- break;
- case $.ui.keyCode.PAGE_DOWN:
- this.nextPage( event );
- break;
- case $.ui.keyCode.HOME:
- this._move( "first", "first", event );
- break;
- case $.ui.keyCode.END:
- this._move( "last", "last", event );
- break;
- case $.ui.keyCode.UP:
- this.previous( event );
- break;
- case $.ui.keyCode.DOWN:
- this.next( event );
- break;
- case $.ui.keyCode.LEFT:
- this.collapse( event );
- break;
- case $.ui.keyCode.RIGHT:
- if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
- this.expand( event );
- }
- break;
- case $.ui.keyCode.ENTER:
- case $.ui.keyCode.SPACE:
- this._activate( event );
- break;
- case $.ui.keyCode.ESCAPE:
- this.collapse( event );
- break;
- default:
- preventDefault = false;
- prev = this.previousFilter || "";
- skip = false;
-
- // Support number pad values
- character = event.keyCode >= 96 && event.keyCode <= 105 ?
- ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
-
- clearTimeout( this.filterTimer );
-
- if ( character === prev ) {
- skip = true;
- } else {
- character = prev + character;
- }
-
- match = this._filterMenuItems( character );
- match = skip && match.index( this.active.next() ) !== -1 ?
- this.active.nextAll( ".ui-menu-item" ) :
- match;
-
- // If no matches on the current filter, reset to the last character pressed
- // to move down the menu to the first item that starts with that character
- if ( !match.length ) {
- character = String.fromCharCode( event.keyCode );
- match = this._filterMenuItems( character );
- }
-
- if ( match.length ) {
- this.focus( event, match );
- this.previousFilter = character;
- this.filterTimer = this._delay( function() {
- delete this.previousFilter;
- }, 1000 );
- } else {
- delete this.previousFilter;
- }
- }
-
- if ( preventDefault ) {
- event.preventDefault();
- }
- },
-
- _activate: function( event ) {
- if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
- if ( this.active.children( "[aria-haspopup='true']" ).length ) {
- this.expand( event );
- } else {
- this.select( event );
- }
- }
- },
-
- refresh: function() {
- var menus, items, newSubmenus, newItems, newWrappers,
- that = this,
- icon = this.options.icons.submenu,
- submenus = this.element.find( this.options.menus );
-
- this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
-
- // Initialize nested menus
- newSubmenus = submenus.filter( ":not(.ui-menu)" )
- .hide()
- .attr( {
- role: this.options.role,
- "aria-hidden": "true",
- "aria-expanded": "false"
- } )
- .each( function() {
- var menu = $( this ),
- item = menu.prev(),
- submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
-
- that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
- item
- .attr( "aria-haspopup", "true" )
- .prepend( submenuCaret );
- menu.attr( "aria-labelledby", item.attr( "id" ) );
- } );
-
- this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
-
- menus = submenus.add( this.element );
- items = menus.find( this.options.items );
-
- // Initialize menu-items containing spaces and/or dashes only as dividers
- items.not( ".ui-menu-item" ).each( function() {
- var item = $( this );
- if ( that._isDivider( item ) ) {
- that._addClass( item, "ui-menu-divider", "ui-widget-content" );
- }
- } );
-
- // Don't refresh list items that are already adapted
- newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
- newWrappers = newItems.children()
- .not( ".ui-menu" )
- .uniqueId()
- .attr( {
- tabIndex: -1,
- role: this._itemRole()
- } );
- this._addClass( newItems, "ui-menu-item" )
- ._addClass( newWrappers, "ui-menu-item-wrapper" );
-
- // Add aria-disabled attribute to any disabled menu item
- items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
-
- // If the active item has been removed, blur the menu
- if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
- this.blur();
- }
- },
-
- _itemRole: function() {
- return {
- menu: "menuitem",
- listbox: "option"
- }[ this.options.role ];
- },
-
- _setOption: function( key, value ) {
- if ( key === "icons" ) {
- var icons = this.element.find( ".ui-menu-icon" );
- this._removeClass( icons, null, this.options.icons.submenu )
- ._addClass( icons, null, value.submenu );
- }
- this._super( key, value );
- },
-
- _setOptionDisabled: function( value ) {
- this._super( value );
-
- this.element.attr( "aria-disabled", String( value ) );
- this._toggleClass( null, "ui-state-disabled", !!value );
- },
-
- focus: function( event, item ) {
- var nested, focused, activeParent;
- this.blur( event, event && event.type === "focus" );
-
- this._scrollIntoView( item );
-
- this.active = item.first();
-
- focused = this.active.children( ".ui-menu-item-wrapper" );
- this._addClass( focused, null, "ui-state-active" );
-
- // Only update aria-activedescendant if there's a role
- // otherwise we assume focus is managed elsewhere
- if ( this.options.role ) {
- this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
- }
-
- // Highlight active parent menu item, if any
- activeParent = this.active
- .parent()
- .closest( ".ui-menu-item" )
- .children( ".ui-menu-item-wrapper" );
- this._addClass( activeParent, null, "ui-state-active" );
-
- if ( event && event.type === "keydown" ) {
- this._close();
- } else {
- this.timer = this._delay( function() {
- this._close();
- }, this.delay );
- }
-
- nested = item.children( ".ui-menu" );
- if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
- this._startOpening( nested );
- }
- this.activeMenu = item.parent();
-
- this._trigger( "focus", event, { item: item } );
- },
-
- _scrollIntoView: function( item ) {
- var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
- if ( this._hasScroll() ) {
- borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
- paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
- offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
- scroll = this.activeMenu.scrollTop();
- elementHeight = this.activeMenu.height();
- itemHeight = item.outerHeight();
-
- if ( offset < 0 ) {
- this.activeMenu.scrollTop( scroll + offset );
- } else if ( offset + itemHeight > elementHeight ) {
- this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
- }
- }
- },
-
- blur: function( event, fromFocus ) {
- if ( !fromFocus ) {
- clearTimeout( this.timer );
- }
-
- if ( !this.active ) {
- return;
- }
-
- this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
- null, "ui-state-active" );
-
- this._trigger( "blur", event, { item: this.active } );
- this.active = null;
- },
-
- _startOpening: function( submenu ) {
- clearTimeout( this.timer );
-
- // Don't open if already open fixes a Firefox bug that caused a .5 pixel
- // shift in the submenu position when mousing over the caret icon
- if ( submenu.attr( "aria-hidden" ) !== "true" ) {
- return;
- }
-
- this.timer = this._delay( function() {
- this._close();
- this._open( submenu );
- }, this.delay );
- },
-
- _open: function( submenu ) {
- var position = $.extend( {
- of: this.active
- }, this.options.position );
-
- clearTimeout( this.timer );
- this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
- .hide()
- .attr( "aria-hidden", "true" );
-
- submenu
- .show()
- .removeAttr( "aria-hidden" )
- .attr( "aria-expanded", "true" )
- .position( position );
- },
-
- collapseAll: function( event, all ) {
- clearTimeout( this.timer );
- this.timer = this._delay( function() {
-
- // If we were passed an event, look for the submenu that contains the event
- var currentMenu = all ? this.element :
- $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
-
- // If we found no valid submenu ancestor, use the main menu to close all
- // sub menus anyway
- if ( !currentMenu.length ) {
- currentMenu = this.element;
- }
-
- this._close( currentMenu );
-
- this.blur( event );
-
- // Work around active item staying active after menu is blurred
- this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
-
- this.activeMenu = currentMenu;
- }, all ? 0 : this.delay );
- },
-
- // With no arguments, closes the currently active menu - if nothing is active
- // it closes all menus. If passed an argument, it will search for menus BELOW
- _close: function( startMenu ) {
- if ( !startMenu ) {
- startMenu = this.active ? this.active.parent() : this.element;
- }
-
- startMenu.find( ".ui-menu" )
- .hide()
- .attr( "aria-hidden", "true" )
- .attr( "aria-expanded", "false" );
- },
-
- _closeOnDocumentClick: function( event ) {
- return !$( event.target ).closest( ".ui-menu" ).length;
- },
-
- _isDivider: function( item ) {
-
- // Match hyphen, em dash, en dash
- return !/[^\-\u2014\u2013\s]/.test( item.text() );
- },
-
- collapse: function( event ) {
- var newItem = this.active &&
- this.active.parent().closest( ".ui-menu-item", this.element );
- if ( newItem && newItem.length ) {
- this._close();
- this.focus( event, newItem );
- }
- },
-
- expand: function( event ) {
- var newItem = this.active && this._menuItems( this.active.children( ".ui-menu" ) ).first();
-
- if ( newItem && newItem.length ) {
- this._open( newItem.parent() );
-
- // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
- this._delay( function() {
- this.focus( event, newItem );
- } );
- }
- },
-
- next: function( event ) {
- this._move( "next", "first", event );
- },
-
- previous: function( event ) {
- this._move( "prev", "last", event );
- },
-
- isFirstItem: function() {
- return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
- },
-
- isLastItem: function() {
- return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
- },
-
- _menuItems: function( menu ) {
- return ( menu || this.element )
- .find( this.options.items )
- .filter( ".ui-menu-item" );
- },
-
- _move: function( direction, filter, event ) {
- var next;
- if ( this.active ) {
- if ( direction === "first" || direction === "last" ) {
- next = this.active
- [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
- .last();
- } else {
- next = this.active
- [ direction + "All" ]( ".ui-menu-item" )
- .first();
- }
- }
- if ( !next || !next.length || !this.active ) {
- next = this._menuItems( this.activeMenu )[ filter ]();
- }
-
- this.focus( event, next );
- },
-
- nextPage: function( event ) {
- var item, base, height;
-
- if ( !this.active ) {
- this.next( event );
- return;
- }
- if ( this.isLastItem() ) {
- return;
- }
- if ( this._hasScroll() ) {
- base = this.active.offset().top;
- height = this.element.innerHeight();
-
- // jQuery 3.2 doesn't include scrollbars in innerHeight, add it back.
- if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) {
- height += this.element[ 0 ].offsetHeight - this.element.outerHeight();
- }
-
- this.active.nextAll( ".ui-menu-item" ).each( function() {
- item = $( this );
- return item.offset().top - base - height < 0;
- } );
-
- this.focus( event, item );
- } else {
- this.focus( event, this._menuItems( this.activeMenu )
- [ !this.active ? "first" : "last" ]() );
- }
- },
-
- previousPage: function( event ) {
- var item, base, height;
- if ( !this.active ) {
- this.next( event );
- return;
- }
- if ( this.isFirstItem() ) {
- return;
- }
- if ( this._hasScroll() ) {
- base = this.active.offset().top;
- height = this.element.innerHeight();
-
- // jQuery 3.2 doesn't include scrollbars in innerHeight, add it back.
- if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) {
- height += this.element[ 0 ].offsetHeight - this.element.outerHeight();
- }
-
- this.active.prevAll( ".ui-menu-item" ).each( function() {
- item = $( this );
- return item.offset().top - base + height > 0;
- } );
-
- this.focus( event, item );
- } else {
- this.focus( event, this._menuItems( this.activeMenu ).first() );
- }
- },
-
- _hasScroll: function() {
- return this.element.outerHeight() < this.element.prop( "scrollHeight" );
- },
-
- select: function( event ) {
-
- // TODO: It should never be possible to not have an active item at this
- // point, but the tests don't trigger mouseenter before click.
- this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
- var ui = { item: this.active };
- if ( !this.active.has( ".ui-menu" ).length ) {
- this.collapseAll( event, true );
- }
- this._trigger( "select", event, ui );
- },
-
- _filterMenuItems: function( character ) {
- var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
- regex = new RegExp( "^" + escapedCharacter, "i" );
-
- return this.activeMenu
- .find( this.options.items )
-
- // Only match on items, not dividers or other content (#10571)
- .filter( ".ui-menu-item" )
- .filter( function() {
- return regex.test(
- String.prototype.trim.call(
- $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
- } );
- }
-} );
-
-
-/*!
- * jQuery UI Autocomplete 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Autocomplete
-//>>group: Widgets
-//>>description: Lists suggested words as the user is typing.
-//>>docs: http://api.jqueryui.com/autocomplete/
-//>>demos: http://jqueryui.com/autocomplete/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/autocomplete.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-$.widget( "ui.autocomplete", {
- version: "1.13.1",
- defaultElement: "<input>",
- options: {
- appendTo: null,
- autoFocus: false,
- delay: 300,
- minLength: 1,
- position: {
- my: "left top",
- at: "left bottom",
- collision: "none"
- },
- source: null,
-
- // Callbacks
- change: null,
- close: null,
- focus: null,
- open: null,
- response: null,
- search: null,
- select: null
- },
-
- requestIndex: 0,
- pending: 0,
- liveRegionTimer: null,
-
- _create: function() {
-
- // Some browsers only repeat keydown events, not keypress events,
- // so we use the suppressKeyPress flag to determine if we've already
- // handled the keydown event. #7269
- // Unfortunately the code for & in keypress is the same as the up arrow,
- // so we use the suppressKeyPressRepeat flag to avoid handling keypress
- // events when we know the keydown event was used to modify the
- // search term. #7799
- var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
- nodeName = this.element[ 0 ].nodeName.toLowerCase(),
- isTextarea = nodeName === "textarea",
- isInput = nodeName === "input";
-
- // Textareas are always multi-line
- // Inputs are always single-line, even if inside a contentEditable element
- // IE also treats inputs as contentEditable
- // All other element types are determined by whether or not they're contentEditable
- this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
-
- this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
- this.isNewMenu = true;
-
- this._addClass( "ui-autocomplete-input" );
- this.element.attr( "autocomplete", "off" );
-
- this._on( this.element, {
- keydown: function( event ) {
- if ( this.element.prop( "readOnly" ) ) {
- suppressKeyPress = true;
- suppressInput = true;
- suppressKeyPressRepeat = true;
- return;
- }
-
- suppressKeyPress = false;
- suppressInput = false;
- suppressKeyPressRepeat = false;
- var keyCode = $.ui.keyCode;
- switch ( event.keyCode ) {
- case keyCode.PAGE_UP:
- suppressKeyPress = true;
- this._move( "previousPage", event );
- break;
- case keyCode.PAGE_DOWN:
- suppressKeyPress = true;
- this._move( "nextPage", event );
- break;
- case keyCode.UP:
- suppressKeyPress = true;
- this._keyEvent( "previous", event );
- break;
- case keyCode.DOWN:
- suppressKeyPress = true;
- this._keyEvent( "next", event );
- break;
- case keyCode.ENTER:
-
- // when menu is open and has focus
- if ( this.menu.active ) {
-
- // #6055 - Opera still allows the keypress to occur
- // which causes forms to submit
- suppressKeyPress = true;
- event.preventDefault();
- this.menu.select( event );
- }
- break;
- case keyCode.TAB:
- if ( this.menu.active ) {
- this.menu.select( event );
- }
- break;
- case keyCode.ESCAPE:
- if ( this.menu.element.is( ":visible" ) ) {
- if ( !this.isMultiLine ) {
- this._value( this.term );
- }
- this.close( event );
-
- // Different browsers have different default behavior for escape
- // Single press can mean undo or clear
- // Double press in IE means clear the whole form
- event.preventDefault();
- }
- break;
- default:
- suppressKeyPressRepeat = true;
-
- // search timeout should be triggered before the input value is changed
- this._searchTimeout( event );
- break;
- }
- },
- keypress: function( event ) {
- if ( suppressKeyPress ) {
- suppressKeyPress = false;
- if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
- event.preventDefault();
- }
- return;
- }
- if ( suppressKeyPressRepeat ) {
- return;
- }
-
- // Replicate some key handlers to allow them to repeat in Firefox and Opera
- var keyCode = $.ui.keyCode;
- switch ( event.keyCode ) {
- case keyCode.PAGE_UP:
- this._move( "previousPage", event );
- break;
- case keyCode.PAGE_DOWN:
- this._move( "nextPage", event );
- break;
- case keyCode.UP:
- this._keyEvent( "previous", event );
- break;
- case keyCode.DOWN:
- this._keyEvent( "next", event );
- break;
- }
- },
- input: function( event ) {
- if ( suppressInput ) {
- suppressInput = false;
- event.preventDefault();
- return;
- }
- this._searchTimeout( event );
- },
- focus: function() {
- this.selectedItem = null;
- this.previous = this._value();
- },
- blur: function( event ) {
- clearTimeout( this.searching );
- this.close( event );
- this._change( event );
- }
- } );
-
- this._initSource();
- this.menu = $( "<ul>" )
- .appendTo( this._appendTo() )
- .menu( {
-
- // disable ARIA support, the live region takes care of that
- role: null
- } )
- .hide()
-
- // Support: IE 11 only, Edge <= 14
- // For other browsers, we preventDefault() on the mousedown event
- // to keep the dropdown from taking focus from the input. This doesn't
- // work for IE/Edge, causing problems with selection and scrolling (#9638)
- // Happily, IE and Edge support an "unselectable" attribute that
- // prevents an element from receiving focus, exactly what we want here.
- .attr( {
- "unselectable": "on"
- } )
- .menu( "instance" );
-
- this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
- this._on( this.menu.element, {
- mousedown: function( event ) {
-
- // Prevent moving focus out of the text field
- event.preventDefault();
- },
- menufocus: function( event, ui ) {
- var label, item;
-
- // support: Firefox
- // Prevent accidental activation of menu items in Firefox (#7024 #9118)
- if ( this.isNewMenu ) {
- this.isNewMenu = false;
- if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
- this.menu.blur();
-
- this.document.one( "mousemove", function() {
- $( event.target ).trigger( event.originalEvent );
- } );
-
- return;
- }
- }
-
- item = ui.item.data( "ui-autocomplete-item" );
- if ( false !== this._trigger( "focus", event, { item: item } ) ) {
-
- // use value to match what will end up in the input, if it was a key event
- if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
- this._value( item.value );
- }
- }
-
- // Announce the value in the liveRegion
- label = ui.item.attr( "aria-label" ) || item.value;
- if ( label && String.prototype.trim.call( label ).length ) {
- clearTimeout( this.liveRegionTimer );
- this.liveRegionTimer = this._delay( function() {
- this.liveRegion.html( $( "<div>" ).text( label ) );
- }, 100 );
- }
- },
- menuselect: function( event, ui ) {
- var item = ui.item.data( "ui-autocomplete-item" ),
- previous = this.previous;
-
- // Only trigger when focus was lost (click on menu)
- if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
- this.element.trigger( "focus" );
- this.previous = previous;
-
- // #6109 - IE triggers two focus events and the second
- // is asynchronous, so we need to reset the previous
- // term synchronously and asynchronously :-(
- this._delay( function() {
- this.previous = previous;
- this.selectedItem = item;
- } );
- }
-
- if ( false !== this._trigger( "select", event, { item: item } ) ) {
- this._value( item.value );
- }
-
- // reset the term after the select event
- // this allows custom select handling to work properly
- this.term = this._value();
-
- this.close( event );
- this.selectedItem = item;
- }
- } );
-
- this.liveRegion = $( "<div>", {
- role: "status",
- "aria-live": "assertive",
- "aria-relevant": "additions"
- } )
- .appendTo( this.document[ 0 ].body );
-
- this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
-
- // Turning off autocomplete prevents the browser from remembering the
- // value when navigating through history, so we re-enable autocomplete
- // if the page is unloaded before the widget is destroyed. #7790
- this._on( this.window, {
- beforeunload: function() {
- this.element.removeAttr( "autocomplete" );
- }
- } );
- },
-
- _destroy: function() {
- clearTimeout( this.searching );
- this.element.removeAttr( "autocomplete" );
- this.menu.element.remove();
- this.liveRegion.remove();
- },
-
- _setOption: function( key, value ) {
- this._super( key, value );
- if ( key === "source" ) {
- this._initSource();
- }
- if ( key === "appendTo" ) {
- this.menu.element.appendTo( this._appendTo() );
- }
- if ( key === "disabled" && value && this.xhr ) {
- this.xhr.abort();
- }
- },
-
- _isEventTargetInWidget: function( event ) {
- var menuElement = this.menu.element[ 0 ];
-
- return event.target === this.element[ 0 ] ||
- event.target === menuElement ||
- $.contains( menuElement, event.target );
- },
-
- _closeOnClickOutside: function( event ) {
- if ( !this._isEventTargetInWidget( event ) ) {
- this.close();
- }
- },
-
- _appendTo: function() {
- var element = this.options.appendTo;
-
- if ( element ) {
- element = element.jquery || element.nodeType ?
- $( element ) :
- this.document.find( element ).eq( 0 );
- }
-
- if ( !element || !element[ 0 ] ) {
- element = this.element.closest( ".ui-front, dialog" );
- }
-
- if ( !element.length ) {
- element = this.document[ 0 ].body;
- }
-
- return element;
- },
-
- _initSource: function() {
- var array, url,
- that = this;
- if ( Array.isArray( this.options.source ) ) {
- array = this.options.source;
- this.source = function( request, response ) {
- response( $.ui.autocomplete.filter( array, request.term ) );
- };
- } else if ( typeof this.options.source === "string" ) {
- url = this.options.source;
- this.source = function( request, response ) {
- if ( that.xhr ) {
- that.xhr.abort();
- }
- that.xhr = $.ajax( {
- url: url,
- data: request,
- dataType: "json",
- success: function( data ) {
- response( data );
- },
- error: function() {
- response( [] );
- }
- } );
- };
- } else {
- this.source = this.options.source;
- }
- },
-
- _searchTimeout: function( event ) {
- clearTimeout( this.searching );
- this.searching = this._delay( function() {
-
- // Search if the value has changed, or if the user retypes the same value (see #7434)
- var equalValues = this.term === this._value(),
- menuVisible = this.menu.element.is( ":visible" ),
- modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
-
- if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
- this.selectedItem = null;
- this.search( null, event );
- }
- }, this.options.delay );
- },
-
- search: function( value, event ) {
- value = value != null ? value : this._value();
-
- // Always save the actual value, not the one passed as an argument
- this.term = this._value();
-
- if ( value.length < this.options.minLength ) {
- return this.close( event );
- }
-
- if ( this._trigger( "search", event ) === false ) {
- return;
- }
-
- return this._search( value );
- },
-
- _search: function( value ) {
- this.pending++;
- this._addClass( "ui-autocomplete-loading" );
- this.cancelSearch = false;
-
- this.source( { term: value }, this._response() );
- },
-
- _response: function() {
- var index = ++this.requestIndex;
-
- return function( content ) {
- if ( index === this.requestIndex ) {
- this.__response( content );
- }
-
- this.pending--;
- if ( !this.pending ) {
- this._removeClass( "ui-autocomplete-loading" );
- }
- }.bind( this );
- },
-
- __response: function( content ) {
- if ( content ) {
- content = this._normalize( content );
- }
- this._trigger( "response", null, { content: content } );
- if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
- this._suggest( content );
- this._trigger( "open" );
- } else {
-
- // use ._close() instead of .close() so we don't cancel future searches
- this._close();
- }
- },
-
- close: function( event ) {
- this.cancelSearch = true;
- this._close( event );
- },
-
- _close: function( event ) {
-
- // Remove the handler that closes the menu on outside clicks
- this._off( this.document, "mousedown" );
-
- if ( this.menu.element.is( ":visible" ) ) {
- this.menu.element.hide();
- this.menu.blur();
- this.isNewMenu = true;
- this._trigger( "close", event );
- }
- },
-
- _change: function( event ) {
- if ( this.previous !== this._value() ) {
- this._trigger( "change", event, { item: this.selectedItem } );
- }
- },
-
- _normalize: function( items ) {
-
- // assume all items have the right format when the first item is complete
- if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
- return items;
- }
- return $.map( items, function( item ) {
- if ( typeof item === "string" ) {
- return {
- label: item,
- value: item
- };
- }
- return $.extend( {}, item, {
- label: item.label || item.value,
- value: item.value || item.label
- } );
- } );
- },
-
- _suggest: function( items ) {
- var ul = this.menu.element.empty();
- this._renderMenu( ul, items );
- this.isNewMenu = true;
- this.menu.refresh();
-
- // Size and position menu
- ul.show();
- this._resizeMenu();
- ul.position( $.extend( {
- of: this.element
- }, this.options.position ) );
-
- if ( this.options.autoFocus ) {
- this.menu.next();
- }
-
- // Listen for interactions outside of the widget (#6642)
- this._on( this.document, {
- mousedown: "_closeOnClickOutside"
- } );
- },
-
- _resizeMenu: function() {
- var ul = this.menu.element;
- ul.outerWidth( Math.max(
-
- // Firefox wraps long text (possibly a rounding bug)
- // so we add 1px to avoid the wrapping (#7513)
- ul.width( "" ).outerWidth() + 1,
- this.element.outerWidth()
- ) );
- },
-
- _renderMenu: function( ul, items ) {
- var that = this;
- $.each( items, function( index, item ) {
- that._renderItemData( ul, item );
- } );
- },
-
- _renderItemData: function( ul, item ) {
- return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
- },
-
- _renderItem: function( ul, item ) {
- return $( "<li>" )
- .append( $( "<div>" ).text( item.label ) )
- .appendTo( ul );
- },
-
- _move: function( direction, event ) {
- if ( !this.menu.element.is( ":visible" ) ) {
- this.search( null, event );
- return;
- }
- if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
- this.menu.isLastItem() && /^next/.test( direction ) ) {
-
- if ( !this.isMultiLine ) {
- this._value( this.term );
- }
-
- this.menu.blur();
- return;
- }
- this.menu[ direction ]( event );
- },
-
- widget: function() {
- return this.menu.element;
- },
-
- _value: function() {
- return this.valueMethod.apply( this.element, arguments );
- },
-
- _keyEvent: function( keyEvent, event ) {
- if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
- this._move( keyEvent, event );
-
- // Prevents moving cursor to beginning/end of the text field in some browsers
- event.preventDefault();
- }
- },
-
- // Support: Chrome <=50
- // We should be able to just use this.element.prop( "isContentEditable" )
- // but hidden elements always report false in Chrome.
- // https://code.google.com/p/chromium/issues/detail?id=313082
- _isContentEditable: function( element ) {
- if ( !element.length ) {
- return false;
- }
-
- var editable = element.prop( "contentEditable" );
-
- if ( editable === "inherit" ) {
- return this._isContentEditable( element.parent() );
- }
-
- return editable === "true";
- }
-} );
-
-$.extend( $.ui.autocomplete, {
- escapeRegex: function( value ) {
- return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
- },
- filter: function( array, term ) {
- var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
- return $.grep( array, function( value ) {
- return matcher.test( value.label || value.value || value );
- } );
- }
-} );
-
-// Live region extension, adding a `messages` option
-// NOTE: This is an experimental API. We are still investigating
-// a full solution for string manipulation and internationalization.
-$.widget( "ui.autocomplete", $.ui.autocomplete, {
- options: {
- messages: {
- noResults: "No search results.",
- results: function( amount ) {
- return amount + ( amount > 1 ? " results are" : " result is" ) +
- " available, use up and down arrow keys to navigate.";
- }
- }
- },
-
- __response: function( content ) {
- var message;
- this._superApply( arguments );
- if ( this.options.disabled || this.cancelSearch ) {
- return;
- }
- if ( content && content.length ) {
- message = this.options.messages.results( content.length );
- } else {
- message = this.options.messages.noResults;
- }
- clearTimeout( this.liveRegionTimer );
- this.liveRegionTimer = this._delay( function() {
- this.liveRegion.html( $( "<div>" ).text( message ) );
- }, 100 );
- }
-} );
-
-var widgetsAutocomplete = $.ui.autocomplete;
-
-
-/*!
- * jQuery UI Controlgroup 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Controlgroup
-//>>group: Widgets
-//>>description: Visually groups form control widgets
-//>>docs: http://api.jqueryui.com/controlgroup/
-//>>demos: http://jqueryui.com/controlgroup/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/controlgroup.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;
-
-var widgetsControlgroup = $.widget( "ui.controlgroup", {
- version: "1.13.1",
- defaultElement: "<div>",
- options: {
- direction: "horizontal",
- disabled: null,
- onlyVisible: true,
- items: {
- "button": "input[type=button], input[type=submit], input[type=reset], button, a",
- "controlgroupLabel": ".ui-controlgroup-label",
- "checkboxradio": "input[type='checkbox'], input[type='radio']",
- "selectmenu": "select",
- "spinner": ".ui-spinner-input"
- }
- },
-
- _create: function() {
- this._enhance();
- },
-
- // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
- _enhance: function() {
- this.element.attr( "role", "toolbar" );
- this.refresh();
- },
-
- _destroy: function() {
- this._callChildMethod( "destroy" );
- this.childWidgets.removeData( "ui-controlgroup-data" );
- this.element.removeAttr( "role" );
- if ( this.options.items.controlgroupLabel ) {
- this.element
- .find( this.options.items.controlgroupLabel )
- .find( ".ui-controlgroup-label-contents" )
- .contents().unwrap();
- }
- },
-
- _initWidgets: function() {
- var that = this,
- childWidgets = [];
-
- // First we iterate over each of the items options
- $.each( this.options.items, function( widget, selector ) {
- var labels;
- var options = {};
-
- // Make sure the widget has a selector set
- if ( !selector ) {
- return;
- }
-
- if ( widget === "controlgroupLabel" ) {
- labels = that.element.find( selector );
- labels.each( function() {
- var element = $( this );
-
- if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
- return;
- }
- element.contents()
- .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
- } );
- that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
- childWidgets = childWidgets.concat( labels.get() );
- return;
- }
-
- // Make sure the widget actually exists
- if ( !$.fn[ widget ] ) {
- return;
- }
-
- // We assume everything is in the middle to start because we can't determine
- // first / last elements until all enhancments are done.
- if ( that[ "_" + widget + "Options" ] ) {
- options = that[ "_" + widget + "Options" ]( "middle" );
- } else {
- options = { classes: {} };
- }
-
- // Find instances of this widget inside controlgroup and init them
- that.element
- .find( selector )
- .each( function() {
- var element = $( this );
- var instance = element[ widget ]( "instance" );
-
- // We need to clone the default options for this type of widget to avoid
- // polluting the variable options which has a wider scope than a single widget.
- var instanceOptions = $.widget.extend( {}, options );
-
- // If the button is the child of a spinner ignore it
- // TODO: Find a more generic solution
- if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
- return;
- }
-
- // Create the widget if it doesn't exist
- if ( !instance ) {
- instance = element[ widget ]()[ widget ]( "instance" );
- }
- if ( instance ) {
- instanceOptions.classes =
- that._resolveClassesValues( instanceOptions.classes, instance );
- }
- element[ widget ]( instanceOptions );
-
- // Store an instance of the controlgroup to be able to reference
- // from the outermost element for changing options and refresh
- var widgetElement = element[ widget ]( "widget" );
- $.data( widgetElement[ 0 ], "ui-controlgroup-data",
- instance ? instance : element[ widget ]( "instance" ) );
-
- childWidgets.push( widgetElement[ 0 ] );
- } );
- } );
-
- this.childWidgets = $( $.uniqueSort( childWidgets ) );
- this._addClass( this.childWidgets, "ui-controlgroup-item" );
- },
-
- _callChildMethod: function( method ) {
- this.childWidgets.each( function() {
- var element = $( this ),
- data = element.data( "ui-controlgroup-data" );
- if ( data && data[ method ] ) {
- data[ method ]();
- }
- } );
- },
-
- _updateCornerClass: function( element, position ) {
- var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
- var add = this._buildSimpleOptions( position, "label" ).classes.label;
-
- this._removeClass( element, null, remove );
- this._addClass( element, null, add );
- },
-
- _buildSimpleOptions: function( position, key ) {
- var direction = this.options.direction === "vertical";
- var result = {
- classes: {}
- };
- result.classes[ key ] = {
- "middle": "",
- "first": "ui-corner-" + ( direction ? "top" : "left" ),
- "last": "ui-corner-" + ( direction ? "bottom" : "right" ),
- "only": "ui-corner-all"
- }[ position ];
-
- return result;
- },
-
- _spinnerOptions: function( position ) {
- var options = this._buildSimpleOptions( position, "ui-spinner" );
-
- options.classes[ "ui-spinner-up" ] = "";
- options.classes[ "ui-spinner-down" ] = "";
-
- return options;
- },
-
- _buttonOptions: function( position ) {
- return this._buildSimpleOptions( position, "ui-button" );
- },
-
- _checkboxradioOptions: function( position ) {
- return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
- },
-
- _selectmenuOptions: function( position ) {
- var direction = this.options.direction === "vertical";
- return {
- width: direction ? "auto" : false,
- classes: {
- middle: {
- "ui-selectmenu-button-open": "",
- "ui-selectmenu-button-closed": ""
- },
- first: {
- "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
- "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
- },
- last: {
- "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
- "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
- },
- only: {
- "ui-selectmenu-button-open": "ui-corner-top",
- "ui-selectmenu-button-closed": "ui-corner-all"
- }
-
- }[ position ]
- };
- },
-
- _resolveClassesValues: function( classes, instance ) {
- var result = {};
- $.each( classes, function( key ) {
- var current = instance.options.classes[ key ] || "";
- current = String.prototype.trim.call( current.replace( controlgroupCornerRegex, "" ) );
- result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
- } );
- return result;
- },
-
- _setOption: function( key, value ) {
- if ( key === "direction" ) {
- this._removeClass( "ui-controlgroup-" + this.options.direction );
- }
-
- this._super( key, value );
- if ( key === "disabled" ) {
- this._callChildMethod( value ? "disable" : "enable" );
- return;
- }
-
- this.refresh();
- },
-
- refresh: function() {
- var children,
- that = this;
-
- this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );
-
- if ( this.options.direction === "horizontal" ) {
- this._addClass( null, "ui-helper-clearfix" );
- }
- this._initWidgets();
-
- children = this.childWidgets;
-
- // We filter here because we need to track all childWidgets not just the visible ones
- if ( this.options.onlyVisible ) {
- children = children.filter( ":visible" );
- }
-
- if ( children.length ) {
-
- // We do this last because we need to make sure all enhancment is done
- // before determining first and last
- $.each( [ "first", "last" ], function( index, value ) {
- var instance = children[ value ]().data( "ui-controlgroup-data" );
-
- if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
- var options = that[ "_" + instance.widgetName + "Options" ](
- children.length === 1 ? "only" : value
- );
- options.classes = that._resolveClassesValues( options.classes, instance );
- instance.element[ instance.widgetName ]( options );
- } else {
- that._updateCornerClass( children[ value ](), value );
- }
- } );
-
- // Finally call the refresh method on each of the child widgets.
- this._callChildMethod( "refresh" );
- }
- }
-} );
-
-/*!
- * jQuery UI Checkboxradio 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Checkboxradio
-//>>group: Widgets
-//>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
-//>>docs: http://api.jqueryui.com/checkboxradio/
-//>>demos: http://jqueryui.com/checkboxradio/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/button.css
-//>>css.structure: ../../themes/base/checkboxradio.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-$.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
- version: "1.13.1",
- options: {
- disabled: null,
- label: null,
- icon: true,
- classes: {
- "ui-checkboxradio-label": "ui-corner-all",
- "ui-checkboxradio-icon": "ui-corner-all"
- }
- },
-
- _getCreateOptions: function() {
- var disabled, labels;
- var that = this;
- var options = this._super() || {};
-
- // We read the type here, because it makes more sense to throw a element type error first,
- // rather then the error for lack of a label. Often if its the wrong type, it
- // won't have a label (e.g. calling on a div, btn, etc)
- this._readType();
-
- labels = this.element.labels();
-
- // If there are multiple labels, use the last one
- this.label = $( labels[ labels.length - 1 ] );
- if ( !this.label.length ) {
- $.error( "No label found for checkboxradio widget" );
- }
-
- this.originalLabel = "";
-
- // We need to get the label text but this may also need to make sure it does not contain the
- // input itself.
- this.label.contents().not( this.element[ 0 ] ).each( function() {
-
- // The label contents could be text, html, or a mix. We concat each element to get a
- // string representation of the label, without the input as part of it.
- that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
- } );
-
- // Set the label option if we found label text
- if ( this.originalLabel ) {
- options.label = this.originalLabel;
- }
-
- disabled = this.element[ 0 ].disabled;
- if ( disabled != null ) {
- options.disabled = disabled;
- }
- return options;
- },
-
- _create: function() {
- var checked = this.element[ 0 ].checked;
-
- this._bindFormResetHandler();
-
- if ( this.options.disabled == null ) {
- this.options.disabled = this.element[ 0 ].disabled;
- }
-
- this._setOption( "disabled", this.options.disabled );
- this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
- this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );
-
- if ( this.type === "radio" ) {
- this._addClass( this.label, "ui-checkboxradio-radio-label" );
- }
-
- if ( this.options.label && this.options.label !== this.originalLabel ) {
- this._updateLabel();
- } else if ( this.originalLabel ) {
- this.options.label = this.originalLabel;
- }
-
- this._enhance();
-
- if ( checked ) {
- this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
- }
-
- this._on( {
- change: "_toggleClasses",
- focus: function() {
- this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
- },
- blur: function() {
- this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
- }
- } );
- },
-
- _readType: function() {
- var nodeName = this.element[ 0 ].nodeName.toLowerCase();
- this.type = this.element[ 0 ].type;
- if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
- $.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
- " and element.type=" + this.type );
- }
- },
-
- // Support jQuery Mobile enhanced option
- _enhance: function() {
- this._updateIcon( this.element[ 0 ].checked );
- },
-
- widget: function() {
- return this.label;
- },
-
- _getRadioGroup: function() {
- var group;
- var name = this.element[ 0 ].name;
- var nameSelector = "input[name='" + $.escapeSelector( name ) + "']";
-
- if ( !name ) {
- return $( [] );
- }
-
- if ( this.form.length ) {
- group = $( this.form[ 0 ].elements ).filter( nameSelector );
- } else {
-
- // Not inside a form, check all inputs that also are not inside a form
- group = $( nameSelector ).filter( function() {
- return $( this )._form().length === 0;
- } );
- }
-
- return group.not( this.element );
- },
-
- _toggleClasses: function() {
- var checked = this.element[ 0 ].checked;
- this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
-
- if ( this.options.icon && this.type === "checkbox" ) {
- this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
- ._toggleClass( this.icon, null, "ui-icon-blank", !checked );
- }
-
- if ( this.type === "radio" ) {
- this._getRadioGroup()
- .each( function() {
- var instance = $( this ).checkboxradio( "instance" );
-
- if ( instance ) {
- instance._removeClass( instance.label,
- "ui-checkboxradio-checked", "ui-state-active" );
- }
- } );
- }
- },
-
- _destroy: function() {
- this._unbindFormResetHandler();
-
- if ( this.icon ) {
- this.icon.remove();
- this.iconSpace.remove();
- }
- },
-
- _setOption: function( key, value ) {
-
- // We don't allow the value to be set to nothing
- if ( key === "label" && !value ) {
- return;
- }
-
- this._super( key, value );
-
- if ( key === "disabled" ) {
- this._toggleClass( this.label, null, "ui-state-disabled", value );
- this.element[ 0 ].disabled = value;
-
- // Don't refresh when setting disabled
- return;
- }
- this.refresh();
- },
-
- _updateIcon: function( checked ) {
- var toAdd = "ui-icon ui-icon-background ";
-
- if ( this.options.icon ) {
- if ( !this.icon ) {
- this.icon = $( "<span>" );
- this.iconSpace = $( "<span> </span>" );
- this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
- }
-
- if ( this.type === "checkbox" ) {
- toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
- this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
- } else {
- toAdd += "ui-icon-blank";
- }
- this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
- if ( !checked ) {
- this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
- }
- this.icon.prependTo( this.label ).after( this.iconSpace );
- } else if ( this.icon !== undefined ) {
- this.icon.remove();
- this.iconSpace.remove();
- delete this.icon;
- }
- },
-
- _updateLabel: function() {
-
- // Remove the contents of the label ( minus the icon, icon space, and input )
- var contents = this.label.contents().not( this.element[ 0 ] );
- if ( this.icon ) {
- contents = contents.not( this.icon[ 0 ] );
- }
- if ( this.iconSpace ) {
- contents = contents.not( this.iconSpace[ 0 ] );
- }
- contents.remove();
-
- this.label.append( this.options.label );
- },
-
- refresh: function() {
- var checked = this.element[ 0 ].checked,
- isDisabled = this.element[ 0 ].disabled;
-
- this._updateIcon( checked );
- this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
- if ( this.options.label !== null ) {
- this._updateLabel();
- }
-
- if ( isDisabled !== this.options.disabled ) {
- this._setOptions( { "disabled": isDisabled } );
- }
- }
-
-} ] );
-
-var widgetsCheckboxradio = $.ui.checkboxradio;
-
-
-/*!
- * jQuery UI Button 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Button
-//>>group: Widgets
-//>>description: Enhances a form with themeable buttons.
-//>>docs: http://api.jqueryui.com/button/
-//>>demos: http://jqueryui.com/button/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/button.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-$.widget( "ui.button", {
- version: "1.13.1",
- defaultElement: "<button>",
- options: {
- classes: {
- "ui-button": "ui-corner-all"
- },
- disabled: null,
- icon: null,
- iconPosition: "beginning",
- label: null,
- showLabel: true
- },
-
- _getCreateOptions: function() {
- var disabled,
-
- // This is to support cases like in jQuery Mobile where the base widget does have
- // an implementation of _getCreateOptions
- options = this._super() || {};
-
- this.isInput = this.element.is( "input" );
-
- disabled = this.element[ 0 ].disabled;
- if ( disabled != null ) {
- options.disabled = disabled;
- }
-
- this.originalLabel = this.isInput ? this.element.val() : this.element.html();
- if ( this.originalLabel ) {
- options.label = this.originalLabel;
- }
-
- return options;
- },
-
- _create: function() {
- if ( !this.option.showLabel & !this.options.icon ) {
- this.options.showLabel = true;
- }
-
- // We have to check the option again here even though we did in _getCreateOptions,
- // because null may have been passed on init which would override what was set in
- // _getCreateOptions
- if ( this.options.disabled == null ) {
- this.options.disabled = this.element[ 0 ].disabled || false;
- }
-
- this.hasTitle = !!this.element.attr( "title" );
-
- // Check to see if the label needs to be set or if its already correct
- if ( this.options.label && this.options.label !== this.originalLabel ) {
- if ( this.isInput ) {
- this.element.val( this.options.label );
- } else {
- this.element.html( this.options.label );
- }
- }
- this._addClass( "ui-button", "ui-widget" );
- this._setOption( "disabled", this.options.disabled );
- this._enhance();
-
- if ( this.element.is( "a" ) ) {
- this._on( {
- "keyup": function( event ) {
- if ( event.keyCode === $.ui.keyCode.SPACE ) {
- event.preventDefault();
-
- // Support: PhantomJS <= 1.9, IE 8 Only
- // If a native click is available use it so we actually cause navigation
- // otherwise just trigger a click event
- if ( this.element[ 0 ].click ) {
- this.element[ 0 ].click();
- } else {
- this.element.trigger( "click" );
- }
- }
- }
- } );
- }
- },
-
- _enhance: function() {
- if ( !this.element.is( "button" ) ) {
- this.element.attr( "role", "button" );
- }
-
- if ( this.options.icon ) {
- this._updateIcon( "icon", this.options.icon );
- this._updateTooltip();
- }
- },
-
- _updateTooltip: function() {
- this.title = this.element.attr( "title" );
-
- if ( !this.options.showLabel && !this.title ) {
- this.element.attr( "title", this.options.label );
- }
- },
-
- _updateIcon: function( option, value ) {
- var icon = option !== "iconPosition",
- position = icon ? this.options.iconPosition : value,
- displayBlock = position === "top" || position === "bottom";
-
- // Create icon
- if ( !this.icon ) {
- this.icon = $( "<span>" );
-
- this._addClass( this.icon, "ui-button-icon", "ui-icon" );
-
- if ( !this.options.showLabel ) {
- this._addClass( "ui-button-icon-only" );
- }
- } else if ( icon ) {
-
- // If we are updating the icon remove the old icon class
- this._removeClass( this.icon, null, this.options.icon );
- }
-
- // If we are updating the icon add the new icon class
- if ( icon ) {
- this._addClass( this.icon, null, value );
- }
-
- this._attachIcon( position );
-
- // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
- // the iconSpace if there is one.
- if ( displayBlock ) {
- this._addClass( this.icon, null, "ui-widget-icon-block" );
- if ( this.iconSpace ) {
- this.iconSpace.remove();
- }
- } else {
-
- // Position is beginning or end so remove the ui-widget-icon-block class and add the
- // space if it does not exist
- if ( !this.iconSpace ) {
- this.iconSpace = $( "<span> </span>" );
- this._addClass( this.iconSpace, "ui-button-icon-space" );
- }
- this._removeClass( this.icon, null, "ui-wiget-icon-block" );
- this._attachIconSpace( position );
- }
- },
-
- _destroy: function() {
- this.element.removeAttr( "role" );
-
- if ( this.icon ) {
- this.icon.remove();
- }
- if ( this.iconSpace ) {
- this.iconSpace.remove();
- }
- if ( !this.hasTitle ) {
- this.element.removeAttr( "title" );
- }
- },
-
- _attachIconSpace: function( iconPosition ) {
- this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
- },
-
- _attachIcon: function( iconPosition ) {
- this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
- },
-
- _setOptions: function( options ) {
- var newShowLabel = options.showLabel === undefined ?
- this.options.showLabel :
- options.showLabel,
- newIcon = options.icon === undefined ? this.options.icon : options.icon;
-
- if ( !newShowLabel && !newIcon ) {
- options.showLabel = true;
- }
- this._super( options );
- },
-
- _setOption: function( key, value ) {
- if ( key === "icon" ) {
- if ( value ) {
- this._updateIcon( key, value );
- } else if ( this.icon ) {
- this.icon.remove();
- if ( this.iconSpace ) {
- this.iconSpace.remove();
- }
- }
- }
-
- if ( key === "iconPosition" ) {
- this._updateIcon( key, value );
- }
-
- // Make sure we can't end up with a button that has neither text nor icon
- if ( key === "showLabel" ) {
- this._toggleClass( "ui-button-icon-only", null, !value );
- this._updateTooltip();
- }
-
- if ( key === "label" ) {
- if ( this.isInput ) {
- this.element.val( value );
- } else {
-
- // If there is an icon, append it, else nothing then append the value
- // this avoids removal of the icon when setting label text
- this.element.html( value );
- if ( this.icon ) {
- this._attachIcon( this.options.iconPosition );
- this._attachIconSpace( this.options.iconPosition );
- }
- }
- }
-
- this._super( key, value );
-
- if ( key === "disabled" ) {
- this._toggleClass( null, "ui-state-disabled", value );
- this.element[ 0 ].disabled = value;
- if ( value ) {
- this.element.trigger( "blur" );
- }
- }
- },
-
- refresh: function() {
-
- // Make sure to only check disabled if its an element that supports this otherwise
- // check for the disabled class to determine state
- var isDisabled = this.element.is( "input, button" ) ?
- this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
-
- if ( isDisabled !== this.options.disabled ) {
- this._setOptions( { disabled: isDisabled } );
- }
-
- this._updateTooltip();
- }
-} );
-
-// DEPRECATED
-if ( $.uiBackCompat !== false ) {
-
- // Text and Icons options
- $.widget( "ui.button", $.ui.button, {
- options: {
- text: true,
- icons: {
- primary: null,
- secondary: null
- }
- },
-
- _create: function() {
- if ( this.options.showLabel && !this.options.text ) {
- this.options.showLabel = this.options.text;
- }
- if ( !this.options.showLabel && this.options.text ) {
- this.options.text = this.options.showLabel;
- }
- if ( !this.options.icon && ( this.options.icons.primary ||
- this.options.icons.secondary ) ) {
- if ( this.options.icons.primary ) {
- this.options.icon = this.options.icons.primary;
- } else {
- this.options.icon = this.options.icons.secondary;
- this.options.iconPosition = "end";
- }
- } else if ( this.options.icon ) {
- this.options.icons.primary = this.options.icon;
- }
- this._super();
- },
-
- _setOption: function( key, value ) {
- if ( key === "text" ) {
- this._super( "showLabel", value );
- return;
- }
- if ( key === "showLabel" ) {
- this.options.text = value;
- }
- if ( key === "icon" ) {
- this.options.icons.primary = value;
- }
- if ( key === "icons" ) {
- if ( value.primary ) {
- this._super( "icon", value.primary );
- this._super( "iconPosition", "beginning" );
- } else if ( value.secondary ) {
- this._super( "icon", value.secondary );
- this._super( "iconPosition", "end" );
- }
- }
- this._superApply( arguments );
- }
- } );
-
- $.fn.button = ( function( orig ) {
- return function( options ) {
- var isMethodCall = typeof options === "string";
- var args = Array.prototype.slice.call( arguments, 1 );
- var returnValue = this;
-
- if ( isMethodCall ) {
-
- // If this is an empty collection, we need to have the instance method
- // return undefined instead of the jQuery instance
- if ( !this.length && options === "instance" ) {
- returnValue = undefined;
- } else {
- this.each( function() {
- var methodValue;
- var type = $( this ).attr( "type" );
- var name = type !== "checkbox" && type !== "radio" ?
- "button" :
- "checkboxradio";
- var instance = $.data( this, "ui-" + name );
-
- if ( options === "instance" ) {
- returnValue = instance;
- return false;
- }
-
- if ( !instance ) {
- return $.error( "cannot call methods on button" +
- " prior to initialization; " +
- "attempted to call method '" + options + "'" );
- }
-
- if ( typeof instance[ options ] !== "function" ||
- options.charAt( 0 ) === "_" ) {
- return $.error( "no such method '" + options + "' for button" +
- " widget instance" );
- }
-
- methodValue = instance[ options ].apply( instance, args );
-
- if ( methodValue !== instance && methodValue !== undefined ) {
- returnValue = methodValue && methodValue.jquery ?
- returnValue.pushStack( methodValue.get() ) :
- methodValue;
- return false;
- }
- } );
- }
- } else {
-
- // Allow multiple hashes to be passed on init
- if ( args.length ) {
- options = $.widget.extend.apply( null, [ options ].concat( args ) );
- }
-
- this.each( function() {
- var type = $( this ).attr( "type" );
- var name = type !== "checkbox" && type !== "radio" ? "button" : "checkboxradio";
- var instance = $.data( this, "ui-" + name );
-
- if ( instance ) {
- instance.option( options || {} );
- if ( instance._init ) {
- instance._init();
- }
- } else {
- if ( name === "button" ) {
- orig.call( $( this ), options );
- return;
- }
-
- $( this ).checkboxradio( $.extend( { icon: false }, options ) );
- }
- } );
- }
-
- return returnValue;
- };
- } )( $.fn.button );
-
- $.fn.buttonset = function() {
- if ( !$.ui.controlgroup ) {
- $.error( "Controlgroup widget missing" );
- }
- if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
- return this.controlgroup.apply( this,
- [ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
- }
- if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
- return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
- }
- if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
- arguments[ 0 ].items = {
- button: arguments[ 0 ].items
- };
- }
- return this.controlgroup.apply( this, arguments );
- };
-}
-
-var widgetsButton = $.ui.button;
-
-
-/* eslint-disable max-len, camelcase */
-/*!
- * jQuery UI Datepicker 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Datepicker
-//>>group: Widgets
-//>>description: Displays a calendar from an input or inline for selecting dates.
-//>>docs: http://api.jqueryui.com/datepicker/
-//>>demos: http://jqueryui.com/datepicker/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/datepicker.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-$.extend( $.ui, { datepicker: { version: "1.13.1" } } );
-
-var datepicker_instActive;
-
-function datepicker_getZindex( elem ) {
- var position, value;
- while ( elem.length && elem[ 0 ] !== document ) {
-
- // Ignore z-index if position is set to a value where z-index is ignored by the browser
- // This makes behavior of this function consistent across browsers
- // WebKit always returns auto if the element is positioned
- position = elem.css( "position" );
- if ( position === "absolute" || position === "relative" || position === "fixed" ) {
-
- // IE returns 0 when zIndex is not specified
- // other browsers return a string
- // we ignore the case of nested elements with an explicit value of 0
- // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
- value = parseInt( elem.css( "zIndex" ), 10 );
- if ( !isNaN( value ) && value !== 0 ) {
- return value;
- }
- }
- elem = elem.parent();
- }
-
- return 0;
-}
-
-/* Date picker manager.
- Use the singleton instance of this class, $.datepicker, to interact with the date picker.
- Settings for (groups of) date pickers are maintained in an instance object,
- allowing multiple different settings on the same page. */
-
-function Datepicker() {
- this._curInst = null; // The current instance in use
- this._keyEvent = false; // If the last event was a key event
- this._disabledInputs = []; // List of date picker inputs that have been disabled
- this._datepickerShowing = false; // True if the popup picker is showing , false if not
- this._inDialog = false; // True if showing within a "dialog", false if not
- this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
- this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
- this._appendClass = "ui-datepicker-append"; // The name of the append marker class
- this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
- this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
- this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
- this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
- this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
- this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
- this.regional = []; // Available regional settings, indexed by language code
- this.regional[ "" ] = { // Default regional settings
- closeText: "Done", // Display text for close link
- prevText: "Prev", // Display text for previous month link
- nextText: "Next", // Display text for next month link
- currentText: "Today", // Display text for current month link
- monthNames: [ "January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December" ], // Names of months for drop-down and formatting
- monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
- dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
- dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
- dayNamesMin: [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" ], // Column headings for days starting at Sunday
- weekHeader: "Wk", // Column header for week of the year
- dateFormat: "mm/dd/yy", // See format options on parseDate
- firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
- isRTL: false, // True if right-to-left language, false if left-to-right
- showMonthAfterYear: false, // True if the year select precedes month, false for month then year
- yearSuffix: "", // Additional text to append to the year in the month headers,
- selectMonthLabel: "Select month", // Invisible label for month selector
- selectYearLabel: "Select year" // Invisible label for year selector
- };
- this._defaults = { // Global defaults for all the date picker instances
- showOn: "focus", // "focus" for popup on focus,
- // "button" for trigger button, or "both" for either
- showAnim: "fadeIn", // Name of jQuery animation for popup
- showOptions: {}, // Options for enhanced animations
- defaultDate: null, // Used when field is blank: actual date,
- // +/-number for offset from today, null for today
- appendText: "", // Display text following the input box, e.g. showing the format
- buttonText: "...", // Text for trigger button
- buttonImage: "", // URL for trigger button image
- buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
- hideIfNoPrevNext: false, // True to hide next/previous month links
- // if not applicable, false to just disable them
- navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
- gotoCurrent: false, // True if today link goes back to current selection instead
- changeMonth: false, // True if month can be selected directly, false if only prev/next
- changeYear: false, // True if year can be selected directly, false if only prev/next
- yearRange: "c-10:c+10", // Range of years to display in drop-down,
- // either relative to today's year (-nn:+nn), relative to currently displayed year
- // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
- showOtherMonths: false, // True to show dates in other months, false to leave blank
- selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
- showWeek: false, // True to show week of the year, false to not show it
- calculateWeek: this.iso8601Week, // How to calculate the week of the year,
- // takes a Date and returns the number of the week for it
- shortYearCutoff: "+10", // Short year values < this are in the current century,
- // > this are in the previous century,
- // string value starting with "+" for current year + value
- minDate: null, // The earliest selectable date, or null for no limit
- maxDate: null, // The latest selectable date, or null for no limit
- duration: "fast", // Duration of display/closure
- beforeShowDay: null, // Function that takes a date and returns an array with
- // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
- // [2] = cell title (optional), e.g. $.datepicker.noWeekends
- beforeShow: null, // Function that takes an input field and
- // returns a set of custom settings for the date picker
- onSelect: null, // Define a callback function when a date is selected
- onChangeMonthYear: null, // Define a callback function when the month or year is changed
- onClose: null, // Define a callback function when the datepicker is closed
- onUpdateDatepicker: null, // Define a callback function when the datepicker is updated
- numberOfMonths: 1, // Number of months to show at a time
- showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
- stepMonths: 1, // Number of months to step back/forward
- stepBigMonths: 12, // Number of months to step back/forward for the big links
- altField: "", // Selector for an alternate field to store selected dates into
- altFormat: "", // The date format to use for the alternate field
- constrainInput: true, // The input is constrained by the current date format
- showButtonPanel: false, // True to show button panel, false to not show it
- autoSize: false, // True to size the input for the date format, false to leave as is
- disabled: false // The initial disabled state
- };
- $.extend( this._defaults, this.regional[ "" ] );
- this.regional.en = $.extend( true, {}, this.regional[ "" ] );
- this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
- this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
-}
-
-$.extend( Datepicker.prototype, {
-
- /* Class name added to elements to indicate already configured with a date picker. */
- markerClassName: "hasDatepicker",
-
- //Keep track of the maximum number of rows displayed (see #7043)
- maxRows: 4,
-
- // TODO rename to "widget" when switching to widget factory
- _widgetDatepicker: function() {
- return this.dpDiv;
- },
-
- /* Override the default settings for all instances of the date picker.
- * @param settings object - the new settings to use as defaults (anonymous object)
- * @return the manager object
- */
- setDefaults: function( settings ) {
- datepicker_extendRemove( this._defaults, settings || {} );
- return this;
- },
-
- /* Attach the date picker to a jQuery selection.
- * @param target element - the target input field or division or span
- * @param settings object - the new settings to use for this date picker instance (anonymous)
- */
- _attachDatepicker: function( target, settings ) {
- var nodeName, inline, inst;
- nodeName = target.nodeName.toLowerCase();
- inline = ( nodeName === "div" || nodeName === "span" );
- if ( !target.id ) {
- this.uuid += 1;
- target.id = "dp" + this.uuid;
- }
- inst = this._newInst( $( target ), inline );
- inst.settings = $.extend( {}, settings || {} );
- if ( nodeName === "input" ) {
- this._connectDatepicker( target, inst );
- } else if ( inline ) {
- this._inlineDatepicker( target, inst );
- }
- },
-
- /* Create a new instance object. */
- _newInst: function( target, inline ) {
- var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
- return { id: id, input: target, // associated target
- selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
- drawMonth: 0, drawYear: 0, // month being drawn
- inline: inline, // is datepicker inline or not
- dpDiv: ( !inline ? this.dpDiv : // presentation div
- datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
- },
-
- /* Attach the date picker to an input field. */
- _connectDatepicker: function( target, inst ) {
- var input = $( target );
- inst.append = $( [] );
- inst.trigger = $( [] );
- if ( input.hasClass( this.markerClassName ) ) {
- return;
- }
- this._attachments( input, inst );
- input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
- on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
- this._autoSize( inst );
- $.data( target, "datepicker", inst );
-
- //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
- if ( inst.settings.disabled ) {
- this._disableDatepicker( target );
- }
- },
-
- /* Make attachments based on settings. */
- _attachments: function( input, inst ) {
- var showOn, buttonText, buttonImage,
- appendText = this._get( inst, "appendText" ),
- isRTL = this._get( inst, "isRTL" );
-
- if ( inst.append ) {
- inst.append.remove();
- }
- if ( appendText ) {
- inst.append = $( "<span>" )
- .addClass( this._appendClass )
- .text( appendText );
- input[ isRTL ? "before" : "after" ]( inst.append );
- }
-
- input.off( "focus", this._showDatepicker );
-
- if ( inst.trigger ) {
- inst.trigger.remove();
- }
-
- showOn = this._get( inst, "showOn" );
- if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
- input.on( "focus", this._showDatepicker );
- }
- if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
- buttonText = this._get( inst, "buttonText" );
- buttonImage = this._get( inst, "buttonImage" );
-
- if ( this._get( inst, "buttonImageOnly" ) ) {
- inst.trigger = $( "<img>" )
- .addClass( this._triggerClass )
- .attr( {
- src: buttonImage,
- alt: buttonText,
- title: buttonText
- } );
- } else {
- inst.trigger = $( "<button type='button'>" )
- .addClass( this._triggerClass );
- if ( buttonImage ) {
- inst.trigger.html(
- $( "<img>" )
- .attr( {
- src: buttonImage,
- alt: buttonText,
- title: buttonText
- } )
- );
- } else {
- inst.trigger.text( buttonText );
- }
- }
-
- input[ isRTL ? "before" : "after" ]( inst.trigger );
- inst.trigger.on( "click", function() {
- if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
- $.datepicker._hideDatepicker();
- } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
- $.datepicker._hideDatepicker();
- $.datepicker._showDatepicker( input[ 0 ] );
- } else {
- $.datepicker._showDatepicker( input[ 0 ] );
- }
- return false;
- } );
- }
- },
-
- /* Apply the maximum length for the date format. */
- _autoSize: function( inst ) {
- if ( this._get( inst, "autoSize" ) && !inst.inline ) {
- var findMax, max, maxI, i,
- date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
- dateFormat = this._get( inst, "dateFormat" );
-
- if ( dateFormat.match( /[DM]/ ) ) {
- findMax = function( names ) {
- max = 0;
- maxI = 0;
- for ( i = 0; i < names.length; i++ ) {
- if ( names[ i ].length > max ) {
- max = names[ i ].length;
- maxI = i;
- }
- }
- return maxI;
- };
- date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
- "monthNames" : "monthNamesShort" ) ) ) );
- date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
- "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
- }
- inst.input.attr( "size", this._formatDate( inst, date ).length );
- }
- },
-
- /* Attach an inline date picker to a div. */
- _inlineDatepicker: function( target, inst ) {
- var divSpan = $( target );
- if ( divSpan.hasClass( this.markerClassName ) ) {
- return;
- }
- divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
- $.data( target, "datepicker", inst );
- this._setDate( inst, this._getDefaultDate( inst ), true );
- this._updateDatepicker( inst );
- this._updateAlternate( inst );
-
- //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
- if ( inst.settings.disabled ) {
- this._disableDatepicker( target );
- }
-
- // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
- // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
- inst.dpDiv.css( "display", "block" );
- },
-
- /* Pop-up the date picker in a "dialog" box.
- * @param input element - ignored
- * @param date string or Date - the initial date to display
- * @param onSelect function - the function to call when a date is selected
- * @param settings object - update the dialog date picker instance's settings (anonymous object)
- * @param pos int[2] - coordinates for the dialog's position within the screen or
- * event - with x/y coordinates or
- * leave empty for default (screen centre)
- * @return the manager object
- */
- _dialogDatepicker: function( input, date, onSelect, settings, pos ) {
- var id, browserWidth, browserHeight, scrollX, scrollY,
- inst = this._dialogInst; // internal instance
-
- if ( !inst ) {
- this.uuid += 1;
- id = "dp" + this.uuid;
- this._dialogInput = $( "<input type='text' id='" + id +
- "' style='position: absolute; top: -100px; width: 0px;'/>" );
- this._dialogInput.on( "keydown", this._doKeyDown );
- $( "body" ).append( this._dialogInput );
- inst = this._dialogInst = this._newInst( this._dialogInput, false );
- inst.settings = {};
- $.data( this._dialogInput[ 0 ], "datepicker", inst );
- }
- datepicker_extendRemove( inst.settings, settings || {} );
- date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
- this._dialogInput.val( date );
-
- this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
- if ( !this._pos ) {
- browserWidth = document.documentElement.clientWidth;
- browserHeight = document.documentElement.clientHeight;
- scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
- scrollY = document.documentElement.scrollTop || document.body.scrollTop;
- this._pos = // should use actual width/height below
- [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
- }
-
- // Move input on screen for focus, but hidden behind dialog
- this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
- inst.settings.onSelect = onSelect;
- this._inDialog = true;
- this.dpDiv.addClass( this._dialogClass );
- this._showDatepicker( this._dialogInput[ 0 ] );
- if ( $.blockUI ) {
- $.blockUI( this.dpDiv );
- }
- $.data( this._dialogInput[ 0 ], "datepicker", inst );
- return this;
- },
-
- /* Detach a datepicker from its control.
- * @param target element - the target input field or division or span
- */
- _destroyDatepicker: function( target ) {
- var nodeName,
- $target = $( target ),
- inst = $.data( target, "datepicker" );
-
- if ( !$target.hasClass( this.markerClassName ) ) {
- return;
- }
-
- nodeName = target.nodeName.toLowerCase();
- $.removeData( target, "datepicker" );
- if ( nodeName === "input" ) {
- inst.append.remove();
- inst.trigger.remove();
- $target.removeClass( this.markerClassName ).
- off( "focus", this._showDatepicker ).
- off( "keydown", this._doKeyDown ).
- off( "keypress", this._doKeyPress ).
- off( "keyup", this._doKeyUp );
- } else if ( nodeName === "div" || nodeName === "span" ) {
- $target.removeClass( this.markerClassName ).empty();
- }
-
- if ( datepicker_instActive === inst ) {
- datepicker_instActive = null;
- this._curInst = null;
- }
- },
-
- /* Enable the date picker to a jQuery selection.
- * @param target element - the target input field or division or span
- */
- _enableDatepicker: function( target ) {
- var nodeName, inline,
- $target = $( target ),
- inst = $.data( target, "datepicker" );
-
- if ( !$target.hasClass( this.markerClassName ) ) {
- return;
- }
-
- nodeName = target.nodeName.toLowerCase();
- if ( nodeName === "input" ) {
- target.disabled = false;
- inst.trigger.filter( "button" ).
- each( function() {
- this.disabled = false;
- } ).end().
- filter( "img" ).css( { opacity: "1.0", cursor: "" } );
- } else if ( nodeName === "div" || nodeName === "span" ) {
- inline = $target.children( "." + this._inlineClass );
- inline.children().removeClass( "ui-state-disabled" );
- inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
- prop( "disabled", false );
- }
- this._disabledInputs = $.map( this._disabledInputs,
-
- // Delete entry
- function( value ) {
- return ( value === target ? null : value );
- } );
- },
-
- /* Disable the date picker to a jQuery selection.
- * @param target element - the target input field or division or span
- */
- _disableDatepicker: function( target ) {
- var nodeName, inline,
- $target = $( target ),
- inst = $.data( target, "datepicker" );
-
- if ( !$target.hasClass( this.markerClassName ) ) {
- return;
- }
-
- nodeName = target.nodeName.toLowerCase();
- if ( nodeName === "input" ) {
- target.disabled = true;
- inst.trigger.filter( "button" ).
- each( function() {
- this.disabled = true;
- } ).end().
- filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
- } else if ( nodeName === "div" || nodeName === "span" ) {
- inline = $target.children( "." + this._inlineClass );
- inline.children().addClass( "ui-state-disabled" );
- inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
- prop( "disabled", true );
- }
- this._disabledInputs = $.map( this._disabledInputs,
-
- // Delete entry
- function( value ) {
- return ( value === target ? null : value );
- } );
- this._disabledInputs[ this._disabledInputs.length ] = target;
- },
-
- /* Is the first field in a jQuery collection disabled as a datepicker?
- * @param target element - the target input field or division or span
- * @return boolean - true if disabled, false if enabled
- */
- _isDisabledDatepicker: function( target ) {
- if ( !target ) {
- return false;
- }
- for ( var i = 0; i < this._disabledInputs.length; i++ ) {
- if ( this._disabledInputs[ i ] === target ) {
- return true;
- }
- }
- return false;
- },
-
- /* Retrieve the instance data for the target control.
- * @param target element - the target input field or division or span
- * @return object - the associated instance data
- * @throws error if a jQuery problem getting data
- */
- _getInst: function( target ) {
- try {
- return $.data( target, "datepicker" );
- } catch ( err ) {
- throw "Missing instance data for this datepicker";
- }
- },
-
- /* Update or retrieve the settings for a date picker attached to an input field or division.
- * @param target element - the target input field or division or span
- * @param name object - the new settings to update or
- * string - the name of the setting to change or retrieve,
- * when retrieving also "all" for all instance settings or
- * "defaults" for all global defaults
- * @param value any - the new value for the setting
- * (omit if above is an object or to retrieve a value)
- */
- _optionDatepicker: function( target, name, value ) {
- var settings, date, minDate, maxDate,
- inst = this._getInst( target );
-
- if ( arguments.length === 2 && typeof name === "string" ) {
- return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
- ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
- this._get( inst, name ) ) : null ) );
- }
-
- settings = name || {};
- if ( typeof name === "string" ) {
- settings = {};
- settings[ name ] = value;
- }
-
- if ( inst ) {
- if ( this._curInst === inst ) {
- this._hideDatepicker();
- }
-
- date = this._getDateDatepicker( target, true );
- minDate = this._getMinMaxDate( inst, "min" );
- maxDate = this._getMinMaxDate( inst, "max" );
- datepicker_extendRemove( inst.settings, settings );
-
- // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
- if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
- inst.settings.minDate = this._formatDate( inst, minDate );
- }
- if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
- inst.settings.maxDate = this._formatDate( inst, maxDate );
- }
- if ( "disabled" in settings ) {
- if ( settings.disabled ) {
- this._disableDatepicker( target );
- } else {
- this._enableDatepicker( target );
- }
- }
- this._attachments( $( target ), inst );
- this._autoSize( inst );
- this._setDate( inst, date );
- this._updateAlternate( inst );
- this._updateDatepicker( inst );
- }
- },
-
- // Change method deprecated
- _changeDatepicker: function( target, name, value ) {
- this._optionDatepicker( target, name, value );
- },
-
- /* Redraw the date picker attached to an input field or division.
- * @param target element - the target input field or division or span
- */
- _refreshDatepicker: function( target ) {
- var inst = this._getInst( target );
- if ( inst ) {
- this._updateDatepicker( inst );
- }
- },
-
- /* Set the dates for a jQuery selection.
- * @param target element - the target input field or division or span
- * @param date Date - the new date
- */
- _setDateDatepicker: function( target, date ) {
- var inst = this._getInst( target );
- if ( inst ) {
- this._setDate( inst, date );
- this._updateDatepicker( inst );
- this._updateAlternate( inst );
- }
- },
-
- /* Get the date(s) for the first entry in a jQuery selection.
- * @param target element - the target input field or division or span
- * @param noDefault boolean - true if no default date is to be used
- * @return Date - the current date
- */
- _getDateDatepicker: function( target, noDefault ) {
- var inst = this._getInst( target );
- if ( inst && !inst.inline ) {
- this._setDateFromField( inst, noDefault );
- }
- return ( inst ? this._getDate( inst ) : null );
- },
-
- /* Handle keystrokes. */
- _doKeyDown: function( event ) {
- var onSelect, dateStr, sel,
- inst = $.datepicker._getInst( event.target ),
- handled = true,
- isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
-
- inst._keyEvent = true;
- if ( $.datepicker._datepickerShowing ) {
- switch ( event.keyCode ) {
- case 9: $.datepicker._hideDatepicker();
- handled = false;
- break; // hide on tab out
- case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
- $.datepicker._currentClass + ")", inst.dpDiv );
- if ( sel[ 0 ] ) {
- $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
- }
-
- onSelect = $.datepicker._get( inst, "onSelect" );
- if ( onSelect ) {
- dateStr = $.datepicker._formatDate( inst );
-
- // Trigger custom callback
- onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
- } else {
- $.datepicker._hideDatepicker();
- }
-
- return false; // don't submit the form
- case 27: $.datepicker._hideDatepicker();
- break; // hide on escape
- case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
- -$.datepicker._get( inst, "stepBigMonths" ) :
- -$.datepicker._get( inst, "stepMonths" ) ), "M" );
- break; // previous month/year on page up/+ ctrl
- case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
- +$.datepicker._get( inst, "stepBigMonths" ) :
- +$.datepicker._get( inst, "stepMonths" ) ), "M" );
- break; // next month/year on page down/+ ctrl
- case 35: if ( event.ctrlKey || event.metaKey ) {
- $.datepicker._clearDate( event.target );
- }
- handled = event.ctrlKey || event.metaKey;
- break; // clear on ctrl or command +end
- case 36: if ( event.ctrlKey || event.metaKey ) {
- $.datepicker._gotoToday( event.target );
- }
- handled = event.ctrlKey || event.metaKey;
- break; // current on ctrl or command +home
- case 37: if ( event.ctrlKey || event.metaKey ) {
- $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
- }
- handled = event.ctrlKey || event.metaKey;
-
- // -1 day on ctrl or command +left
- if ( event.originalEvent.altKey ) {
- $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
- -$.datepicker._get( inst, "stepBigMonths" ) :
- -$.datepicker._get( inst, "stepMonths" ) ), "M" );
- }
-
- // next month/year on alt +left on Mac
- break;
- case 38: if ( event.ctrlKey || event.metaKey ) {
- $.datepicker._adjustDate( event.target, -7, "D" );
- }
- handled = event.ctrlKey || event.metaKey;
- break; // -1 week on ctrl or command +up
- case 39: if ( event.ctrlKey || event.metaKey ) {
- $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
- }
- handled = event.ctrlKey || event.metaKey;
-
- // +1 day on ctrl or command +right
- if ( event.originalEvent.altKey ) {
- $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
- +$.datepicker._get( inst, "stepBigMonths" ) :
- +$.datepicker._get( inst, "stepMonths" ) ), "M" );
- }
-
- // next month/year on alt +right
- break;
- case 40: if ( event.ctrlKey || event.metaKey ) {
- $.datepicker._adjustDate( event.target, +7, "D" );
- }
- handled = event.ctrlKey || event.metaKey;
- break; // +1 week on ctrl or command +down
- default: handled = false;
- }
- } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
- $.datepicker._showDatepicker( this );
- } else {
- handled = false;
- }
-
- if ( handled ) {
- event.preventDefault();
- event.stopPropagation();
- }
- },
-
- /* Filter entered characters - based on date format. */
- _doKeyPress: function( event ) {
- var chars, chr,
- inst = $.datepicker._getInst( event.target );
-
- if ( $.datepicker._get( inst, "constrainInput" ) ) {
- chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
- chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
- return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
- }
- },
-
- /* Synchronise manual entry and field/alternate field. */
- _doKeyUp: function( event ) {
- var date,
- inst = $.datepicker._getInst( event.target );
-
- if ( inst.input.val() !== inst.lastVal ) {
- try {
- date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
- ( inst.input ? inst.input.val() : null ),
- $.datepicker._getFormatConfig( inst ) );
-
- if ( date ) { // only if valid
- $.datepicker._setDateFromField( inst );
- $.datepicker._updateAlternate( inst );
- $.datepicker._updateDatepicker( inst );
- }
- } catch ( err ) {
- }
- }
- return true;
- },
-
- /* Pop-up the date picker for a given input field.
- * If false returned from beforeShow event handler do not show.
- * @param input element - the input field attached to the date picker or
- * event - if triggered by focus
- */
- _showDatepicker: function( input ) {
- input = input.target || input;
- if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
- input = $( "input", input.parentNode )[ 0 ];
- }
-
- if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
- return;
- }
-
- var inst, beforeShow, beforeShowSettings, isFixed,
- offset, showAnim, duration;
-
- inst = $.datepicker._getInst( input );
- if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
- $.datepicker._curInst.dpDiv.stop( true, true );
- if ( inst && $.datepicker._datepickerShowing ) {
- $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
- }
- }
-
- beforeShow = $.datepicker._get( inst, "beforeShow" );
- beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
- if ( beforeShowSettings === false ) {
- return;
- }
- datepicker_extendRemove( inst.settings, beforeShowSettings );
-
- inst.lastVal = null;
- $.datepicker._lastInput = input;
- $.datepicker._setDateFromField( inst );
-
- if ( $.datepicker._inDialog ) { // hide cursor
- input.value = "";
- }
- if ( !$.datepicker._pos ) { // position below input
- $.datepicker._pos = $.datepicker._findPos( input );
- $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
- }
-
- isFixed = false;
- $( input ).parents().each( function() {
- isFixed |= $( this ).css( "position" ) === "fixed";
- return !isFixed;
- } );
-
- offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
- $.datepicker._pos = null;
-
- //to avoid flashes on Firefox
- inst.dpDiv.empty();
-
- // determine sizing offscreen
- inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
- $.datepicker._updateDatepicker( inst );
-
- // fix width for dynamic number of date pickers
- // and adjust position before showing
- offset = $.datepicker._checkOffset( inst, offset, isFixed );
- inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
- "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
- left: offset.left + "px", top: offset.top + "px" } );
-
- if ( !inst.inline ) {
- showAnim = $.datepicker._get( inst, "showAnim" );
- duration = $.datepicker._get( inst, "duration" );
- inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
- $.datepicker._datepickerShowing = true;
-
- if ( $.effects && $.effects.effect[ showAnim ] ) {
- inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
- } else {
- inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
- }
-
- if ( $.datepicker._shouldFocusInput( inst ) ) {
- inst.input.trigger( "focus" );
- }
-
- $.datepicker._curInst = inst;
- }
- },
-
- /* Generate the date picker content. */
- _updateDatepicker: function( inst ) {
- this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
- datepicker_instActive = inst; // for delegate hover events
- inst.dpDiv.empty().append( this._generateHTML( inst ) );
- this._attachHandlers( inst );
-
- var origyearshtml,
- numMonths = this._getNumberOfMonths( inst ),
- cols = numMonths[ 1 ],
- width = 17,
- activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ),
- onUpdateDatepicker = $.datepicker._get( inst, "onUpdateDatepicker" );
-
- if ( activeCell.length > 0 ) {
- datepicker_handleMouseover.apply( activeCell.get( 0 ) );
- }
-
- inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
- if ( cols > 1 ) {
- inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
- }
- inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
- "Class" ]( "ui-datepicker-multi" );
- inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
- "Class" ]( "ui-datepicker-rtl" );
-
- if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
- inst.input.trigger( "focus" );
- }
-
- // Deffered render of the years select (to avoid flashes on Firefox)
- if ( inst.yearshtml ) {
- origyearshtml = inst.yearshtml;
- setTimeout( function() {
-
- //assure that inst.yearshtml didn't change.
- if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
- inst.dpDiv.find( "select.ui-datepicker-year" ).first().replaceWith( inst.yearshtml );
- }
- origyearshtml = inst.yearshtml = null;
- }, 0 );
- }
-
- if ( onUpdateDatepicker ) {
- onUpdateDatepicker.apply( ( inst.input ? inst.input[ 0 ] : null ), [ inst ] );
- }
- },
-
- // #6694 - don't focus the input if it's already focused
- // this breaks the change event in IE
- // Support: IE and jQuery <1.9
- _shouldFocusInput: function( inst ) {
- return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
- },
-
- /* Check positioning to remain on screen. */
- _checkOffset: function( inst, offset, isFixed ) {
- var dpWidth = inst.dpDiv.outerWidth(),
- dpHeight = inst.dpDiv.outerHeight(),
- inputWidth = inst.input ? inst.input.outerWidth() : 0,
- inputHeight = inst.input ? inst.input.outerHeight() : 0,
- viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
- viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
-
- offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
- offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
- offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
-
- // Now check if datepicker is showing outside window viewport - move to a better place if so.
- offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
- Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
- offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
- Math.abs( dpHeight + inputHeight ) : 0 );
-
- return offset;
- },
-
- /* Find an object's position on the screen. */
- _findPos: function( obj ) {
- var position,
- inst = this._getInst( obj ),
- isRTL = this._get( inst, "isRTL" );
-
- while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.pseudos.hidden( obj ) ) ) {
- obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
- }
-
- position = $( obj ).offset();
- return [ position.left, position.top ];
- },
-
- /* Hide the date picker from view.
- * @param input element - the input field attached to the date picker
- */
- _hideDatepicker: function( input ) {
- var showAnim, duration, postProcess, onClose,
- inst = this._curInst;
-
- if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
- return;
- }
-
- if ( this._datepickerShowing ) {
- showAnim = this._get( inst, "showAnim" );
- duration = this._get( inst, "duration" );
- postProcess = function() {
- $.datepicker._tidyDialog( inst );
- };
-
- // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
- if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
- inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
- } else {
- inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
- ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
- }
-
- if ( !showAnim ) {
- postProcess();
- }
- this._datepickerShowing = false;
-
- onClose = this._get( inst, "onClose" );
- if ( onClose ) {
- onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
- }
-
- this._lastInput = null;
- if ( this._inDialog ) {
- this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
- if ( $.blockUI ) {
- $.unblockUI();
- $( "body" ).append( this.dpDiv );
- }
- }
- this._inDialog = false;
- }
- },
-
- /* Tidy up after a dialog display. */
- _tidyDialog: function( inst ) {
- inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
- },
-
- /* Close date picker if clicked elsewhere. */
- _checkExternalClick: function( event ) {
- if ( !$.datepicker._curInst ) {
- return;
- }
-
- var $target = $( event.target ),
- inst = $.datepicker._getInst( $target[ 0 ] );
-
- if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
- $target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
- !$target.hasClass( $.datepicker.markerClassName ) &&
- !$target.closest( "." + $.datepicker._triggerClass ).length &&
- $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
- ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
- $.datepicker._hideDatepicker();
- }
- },
-
- /* Adjust one of the date sub-fields. */
- _adjustDate: function( id, offset, period ) {
- var target = $( id ),
- inst = this._getInst( target[ 0 ] );
-
- if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
- return;
- }
- this._adjustInstDate( inst, offset, period );
- this._updateDatepicker( inst );
- },
-
- /* Action for current link. */
- _gotoToday: function( id ) {
- var date,
- target = $( id ),
- inst = this._getInst( target[ 0 ] );
-
- if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
- inst.selectedDay = inst.currentDay;
- inst.drawMonth = inst.selectedMonth = inst.currentMonth;
- inst.drawYear = inst.selectedYear = inst.currentYear;
- } else {
- date = new Date();
- inst.selectedDay = date.getDate();
- inst.drawMonth = inst.selectedMonth = date.getMonth();
- inst.drawYear = inst.selectedYear = date.getFullYear();
- }
- this._notifyChange( inst );
- this._adjustDate( target );
- },
-
- /* Action for selecting a new month/year. */
- _selectMonthYear: function( id, select, period ) {
- var target = $( id ),
- inst = this._getInst( target[ 0 ] );
-
- inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
- inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
- parseInt( select.options[ select.selectedIndex ].value, 10 );
-
- this._notifyChange( inst );
- this._adjustDate( target );
- },
-
- /* Action for selecting a day. */
- _selectDay: function( id, month, year, td ) {
- var inst,
- target = $( id );
-
- if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
- return;
- }
-
- inst = this._getInst( target[ 0 ] );
- inst.selectedDay = inst.currentDay = parseInt( $( "a", td ).attr( "data-date" ) );
- inst.selectedMonth = inst.currentMonth = month;
- inst.selectedYear = inst.currentYear = year;
- this._selectDate( id, this._formatDate( inst,
- inst.currentDay, inst.currentMonth, inst.currentYear ) );
- },
-
- /* Erase the input field and hide the date picker. */
- _clearDate: function( id ) {
- var target = $( id );
- this._selectDate( target, "" );
- },
-
- /* Update the input field with the selected date. */
- _selectDate: function( id, dateStr ) {
- var onSelect,
- target = $( id ),
- inst = this._getInst( target[ 0 ] );
-
- dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
- if ( inst.input ) {
- inst.input.val( dateStr );
- }
- this._updateAlternate( inst );
-
- onSelect = this._get( inst, "onSelect" );
- if ( onSelect ) {
- onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback
- } else if ( inst.input ) {
- inst.input.trigger( "change" ); // fire the change event
- }
-
- if ( inst.inline ) {
- this._updateDatepicker( inst );
- } else {
- this._hideDatepicker();
- this._lastInput = inst.input[ 0 ];
- if ( typeof( inst.input[ 0 ] ) !== "object" ) {
- inst.input.trigger( "focus" ); // restore focus
- }
- this._lastInput = null;
- }
- },
-
- /* Update any alternate field to synchronise with the main field. */
- _updateAlternate: function( inst ) {
- var altFormat, date, dateStr,
- altField = this._get( inst, "altField" );
-
- if ( altField ) { // update alternate field too
- altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
- date = this._getDate( inst );
- dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
- $( document ).find( altField ).val( dateStr );
- }
- },
-
- /* Set as beforeShowDay function to prevent selection of weekends.
- * @param date Date - the date to customise
- * @return [boolean, string] - is this date selectable?, what is its CSS class?
- */
- noWeekends: function( date ) {
- var day = date.getDay();
- return [ ( day > 0 && day < 6 ), "" ];
- },
-
- /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
- * @param date Date - the date to get the week for
- * @return number - the number of the week within the year that contains this date
- */
- iso8601Week: function( date ) {
- var time,
- checkDate = new Date( date.getTime() );
-
- // Find Thursday of this week starting on Monday
- checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
-
- time = checkDate.getTime();
- checkDate.setMonth( 0 ); // Compare with Jan 1
- checkDate.setDate( 1 );
- return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
- },
-
- /* Parse a string value into a date object.
- * See formatDate below for the possible formats.
- *
- * @param format string - the expected format of the date
- * @param value string - the date in the above format
- * @param settings Object - attributes include:
- * shortYearCutoff number - the cutoff year for determining the century (optional)
- * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
- * dayNames string[7] - names of the days from Sunday (optional)
- * monthNamesShort string[12] - abbreviated names of the months (optional)
- * monthNames string[12] - names of the months (optional)
- * @return Date - the extracted date value or null if value is blank
- */
- parseDate: function( format, value, settings ) {
- if ( format == null || value == null ) {
- throw "Invalid arguments";
- }
-
- value = ( typeof value === "object" ? value.toString() : value + "" );
- if ( value === "" ) {
- return null;
- }
-
- var iFormat, dim, extra,
- iValue = 0,
- shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
- shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
- new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
- dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
- dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
- monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
- monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
- year = -1,
- month = -1,
- day = -1,
- doy = -1,
- literal = false,
- date,
-
- // Check whether a format character is doubled
- lookAhead = function( match ) {
- var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
- if ( matches ) {
- iFormat++;
- }
- return matches;
- },
-
- // Extract a number from the string value
- getNumber = function( match ) {
- var isDoubled = lookAhead( match ),
- size = ( match === "@" ? 14 : ( match === "!" ? 20 :
- ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
- minSize = ( match === "y" ? size : 1 ),
- digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
- num = value.substring( iValue ).match( digits );
- if ( !num ) {
- throw "Missing number at position " + iValue;
- }
- iValue += num[ 0 ].length;
- return parseInt( num[ 0 ], 10 );
- },
-
- // Extract a name from the string value and convert to an index
- getName = function( match, shortNames, longNames ) {
- var index = -1,
- names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
- return [ [ k, v ] ];
- } ).sort( function( a, b ) {
- return -( a[ 1 ].length - b[ 1 ].length );
- } );
-
- $.each( names, function( i, pair ) {
- var name = pair[ 1 ];
- if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
- index = pair[ 0 ];
- iValue += name.length;
- return false;
- }
- } );
- if ( index !== -1 ) {
- return index + 1;
- } else {
- throw "Unknown name at position " + iValue;
- }
- },
-
- // Confirm that a literal character matches the string value
- checkLiteral = function() {
- if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
- throw "Unexpected literal at position " + iValue;
- }
- iValue++;
- };
-
- for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
- if ( literal ) {
- if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
- literal = false;
- } else {
- checkLiteral();
- }
- } else {
- switch ( format.charAt( iFormat ) ) {
- case "d":
- day = getNumber( "d" );
- break;
- case "D":
- getName( "D", dayNamesShort, dayNames );
- break;
- case "o":
- doy = getNumber( "o" );
- break;
- case "m":
- month = getNumber( "m" );
- break;
- case "M":
- month = getName( "M", monthNamesShort, monthNames );
- break;
- case "y":
- year = getNumber( "y" );
- break;
- case "@":
- date = new Date( getNumber( "@" ) );
- year = date.getFullYear();
- month = date.getMonth() + 1;
- day = date.getDate();
- break;
- case "!":
- date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
- year = date.getFullYear();
- month = date.getMonth() + 1;
- day = date.getDate();
- break;
- case "'":
- if ( lookAhead( "'" ) ) {
- checkLiteral();
- } else {
- literal = true;
- }
- break;
- default:
- checkLiteral();
- }
- }
- }
-
- if ( iValue < value.length ) {
- extra = value.substr( iValue );
- if ( !/^\s+/.test( extra ) ) {
- throw "Extra/unparsed characters found in date: " + extra;
- }
- }
-
- if ( year === -1 ) {
- year = new Date().getFullYear();
- } else if ( year < 100 ) {
- year += new Date().getFullYear() - new Date().getFullYear() % 100 +
- ( year <= shortYearCutoff ? 0 : -100 );
- }
-
- if ( doy > -1 ) {
- month = 1;
- day = doy;
- do {
- dim = this._getDaysInMonth( year, month - 1 );
- if ( day <= dim ) {
- break;
- }
- month++;
- day -= dim;
- } while ( true );
- }
-
- date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
- if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
- throw "Invalid date"; // E.g. 31/02/00
- }
- return date;
- },
-
- /* Standard date formats. */
- ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
- COOKIE: "D, dd M yy",
- ISO_8601: "yy-mm-dd",
- RFC_822: "D, d M y",
- RFC_850: "DD, dd-M-y",
- RFC_1036: "D, d M y",
- RFC_1123: "D, d M yy",
- RFC_2822: "D, d M yy",
- RSS: "D, d M y", // RFC 822
- TICKS: "!",
- TIMESTAMP: "@",
- W3C: "yy-mm-dd", // ISO 8601
-
- _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
- Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
-
- /* Format a date object into a string value.
- * The format can be combinations of the following:
- * d - day of month (no leading zero)
- * dd - day of month (two digit)
- * o - day of year (no leading zeros)
- * oo - day of year (three digit)
- * D - day name short
- * DD - day name long
- * m - month of year (no leading zero)
- * mm - month of year (two digit)
- * M - month name short
- * MM - month name long
- * y - year (two digit)
- * yy - year (four digit)
- * @ - Unix timestamp (ms since 01/01/1970)
- * ! - Windows ticks (100ns since 01/01/0001)
- * "..." - literal text
- * '' - single quote
- *
- * @param format string - the desired format of the date
- * @param date Date - the date value to format
- * @param settings Object - attributes include:
- * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
- * dayNames string[7] - names of the days from Sunday (optional)
- * monthNamesShort string[12] - abbreviated names of the months (optional)
- * monthNames string[12] - names of the months (optional)
- * @return string - the date in the above format
- */
- formatDate: function( format, date, settings ) {
- if ( !date ) {
- return "";
- }
-
- var iFormat,
- dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
- dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
- monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
- monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
-
- // Check whether a format character is doubled
- lookAhead = function( match ) {
- var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
- if ( matches ) {
- iFormat++;
- }
- return matches;
- },
-
- // Format a number, with leading zero if necessary
- formatNumber = function( match, value, len ) {
- var num = "" + value;
- if ( lookAhead( match ) ) {
- while ( num.length < len ) {
- num = "0" + num;
- }
- }
- return num;
- },
-
- // Format a name, short or long as requested
- formatName = function( match, value, shortNames, longNames ) {
- return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
- },
- output = "",
- literal = false;
-
- if ( date ) {
- for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
- if ( literal ) {
- if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
- literal = false;
- } else {
- output += format.charAt( iFormat );
- }
- } else {
- switch ( format.charAt( iFormat ) ) {
- case "d":
- output += formatNumber( "d", date.getDate(), 2 );
- break;
- case "D":
- output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
- break;
- case "o":
- output += formatNumber( "o",
- Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
- break;
- case "m":
- output += formatNumber( "m", date.getMonth() + 1, 2 );
- break;
- case "M":
- output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
- break;
- case "y":
- output += ( lookAhead( "y" ) ? date.getFullYear() :
- ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
- break;
- case "@":
- output += date.getTime();
- break;
- case "!":
- output += date.getTime() * 10000 + this._ticksTo1970;
- break;
- case "'":
- if ( lookAhead( "'" ) ) {
- output += "'";
- } else {
- literal = true;
- }
- break;
- default:
- output += format.charAt( iFormat );
- }
- }
- }
- }
- return output;
- },
-
- /* Extract all possible characters from the date format. */
- _possibleChars: function( format ) {
- var iFormat,
- chars = "",
- literal = false,
-
- // Check whether a format character is doubled
- lookAhead = function( match ) {
- var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
- if ( matches ) {
- iFormat++;
- }
- return matches;
- };
-
- for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
- if ( literal ) {
- if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
- literal = false;
- } else {
- chars += format.charAt( iFormat );
- }
- } else {
- switch ( format.charAt( iFormat ) ) {
- case "d": case "m": case "y": case "@":
- chars += "0123456789";
- break;
- case "D": case "M":
- return null; // Accept anything
- case "'":
- if ( lookAhead( "'" ) ) {
- chars += "'";
- } else {
- literal = true;
- }
- break;
- default:
- chars += format.charAt( iFormat );
- }
- }
- }
- return chars;
- },
-
- /* Get a setting value, defaulting if necessary. */
- _get: function( inst, name ) {
- return inst.settings[ name ] !== undefined ?
- inst.settings[ name ] : this._defaults[ name ];
- },
-
- /* Parse existing date and initialise date picker. */
- _setDateFromField: function( inst, noDefault ) {
- if ( inst.input.val() === inst.lastVal ) {
- return;
- }
-
- var dateFormat = this._get( inst, "dateFormat" ),
- dates = inst.lastVal = inst.input ? inst.input.val() : null,
- defaultDate = this._getDefaultDate( inst ),
- date = defaultDate,
- settings = this._getFormatConfig( inst );
-
- try {
- date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
- } catch ( event ) {
- dates = ( noDefault ? "" : dates );
- }
- inst.selectedDay = date.getDate();
- inst.drawMonth = inst.selectedMonth = date.getMonth();
- inst.drawYear = inst.selectedYear = date.getFullYear();
- inst.currentDay = ( dates ? date.getDate() : 0 );
- inst.currentMonth = ( dates ? date.getMonth() : 0 );
- inst.currentYear = ( dates ? date.getFullYear() : 0 );
- this._adjustInstDate( inst );
- },
-
- /* Retrieve the default date shown on opening. */
- _getDefaultDate: function( inst ) {
- return this._restrictMinMax( inst,
- this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
- },
-
- /* A date may be specified as an exact value or a relative one. */
- _determineDate: function( inst, date, defaultDate ) {
- var offsetNumeric = function( offset ) {
- var date = new Date();
- date.setDate( date.getDate() + offset );
- return date;
- },
- offsetString = function( offset ) {
- try {
- return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
- offset, $.datepicker._getFormatConfig( inst ) );
- } catch ( e ) {
-
- // Ignore
- }
-
- var date = ( offset.toLowerCase().match( /^c/ ) ?
- $.datepicker._getDate( inst ) : null ) || new Date(),
- year = date.getFullYear(),
- month = date.getMonth(),
- day = date.getDate(),
- pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
- matches = pattern.exec( offset );
-
- while ( matches ) {
- switch ( matches[ 2 ] || "d" ) {
- case "d" : case "D" :
- day += parseInt( matches[ 1 ], 10 ); break;
- case "w" : case "W" :
- day += parseInt( matches[ 1 ], 10 ) * 7; break;
- case "m" : case "M" :
- month += parseInt( matches[ 1 ], 10 );
- day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
- break;
- case "y": case "Y" :
- year += parseInt( matches[ 1 ], 10 );
- day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
- break;
- }
- matches = pattern.exec( offset );
- }
- return new Date( year, month, day );
- },
- newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
- ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
-
- newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
- if ( newDate ) {
- newDate.setHours( 0 );
- newDate.setMinutes( 0 );
- newDate.setSeconds( 0 );
- newDate.setMilliseconds( 0 );
- }
- return this._daylightSavingAdjust( newDate );
- },
-
- /* Handle switch to/from daylight saving.
- * Hours may be non-zero on daylight saving cut-over:
- * > 12 when midnight changeover, but then cannot generate
- * midnight datetime, so jump to 1AM, otherwise reset.
- * @param date (Date) the date to check
- * @return (Date) the corrected date
- */
- _daylightSavingAdjust: function( date ) {
- if ( !date ) {
- return null;
- }
- date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
- return date;
- },
-
- /* Set the date(s) directly. */
- _setDate: function( inst, date, noChange ) {
- var clear = !date,
- origMonth = inst.selectedMonth,
- origYear = inst.selectedYear,
- newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
-
- inst.selectedDay = inst.currentDay = newDate.getDate();
- inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
- inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
- if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
- this._notifyChange( inst );
- }
- this._adjustInstDate( inst );
- if ( inst.input ) {
- inst.input.val( clear ? "" : this._formatDate( inst ) );
- }
- },
-
- /* Retrieve the date(s) directly. */
- _getDate: function( inst ) {
- var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
- this._daylightSavingAdjust( new Date(
- inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
- return startDate;
- },
-
- /* Attach the onxxx handlers. These are declared statically so
- * they work with static code transformers like Caja.
- */
- _attachHandlers: function( inst ) {
- var stepMonths = this._get( inst, "stepMonths" ),
- id = "#" + inst.id.replace( /\\\\/g, "\\" );
- inst.dpDiv.find( "[data-handler]" ).map( function() {
- var handler = {
- prev: function() {
- $.datepicker._adjustDate( id, -stepMonths, "M" );
- },
- next: function() {
- $.datepicker._adjustDate( id, +stepMonths, "M" );
- },
- hide: function() {
- $.datepicker._hideDatepicker();
- },
- today: function() {
- $.datepicker._gotoToday( id );
- },
- selectDay: function() {
- $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
- return false;
- },
- selectMonth: function() {
- $.datepicker._selectMonthYear( id, this, "M" );
- return false;
- },
- selectYear: function() {
- $.datepicker._selectMonthYear( id, this, "Y" );
- return false;
- }
- };
- $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
- } );
- },
-
- /* Generate the HTML for the current state of the date picker. */
- _generateHTML: function( inst ) {
- var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
- controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
- monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
- selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
- cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
- printDate, dRow, tbody, daySettings, otherMonth, unselectable,
- tempDate = new Date(),
- today = this._daylightSavingAdjust(
- new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
- isRTL = this._get( inst, "isRTL" ),
- showButtonPanel = this._get( inst, "showButtonPanel" ),
- hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
- navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
- numMonths = this._getNumberOfMonths( inst ),
- showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
- stepMonths = this._get( inst, "stepMonths" ),
- isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
- currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
- new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
- minDate = this._getMinMaxDate( inst, "min" ),
- maxDate = this._getMinMaxDate( inst, "max" ),
- drawMonth = inst.drawMonth - showCurrentAtPos,
- drawYear = inst.drawYear;
-
- if ( drawMonth < 0 ) {
- drawMonth += 12;
- drawYear--;
- }
- if ( maxDate ) {
- maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
- maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
- maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
- while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
- drawMonth--;
- if ( drawMonth < 0 ) {
- drawMonth = 11;
- drawYear--;
- }
- }
- }
- inst.drawMonth = drawMonth;
- inst.drawYear = drawYear;
-
- prevText = this._get( inst, "prevText" );
- prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
- this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
- this._getFormatConfig( inst ) ) );
-
- if ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ) {
- prev = $( "<a>" )
- .attr( {
- "class": "ui-datepicker-prev ui-corner-all",
- "data-handler": "prev",
- "data-event": "click",
- title: prevText
- } )
- .append(
- $( "<span>" )
- .addClass( "ui-icon ui-icon-circle-triangle-" +
- ( isRTL ? "e" : "w" ) )
- .text( prevText )
- )[ 0 ].outerHTML;
- } else if ( hideIfNoPrevNext ) {
- prev = "";
- } else {
- prev = $( "<a>" )
- .attr( {
- "class": "ui-datepicker-prev ui-corner-all ui-state-disabled",
- title: prevText
- } )
- .append(
- $( "<span>" )
- .addClass( "ui-icon ui-icon-circle-triangle-" +
- ( isRTL ? "e" : "w" ) )
- .text( prevText )
- )[ 0 ].outerHTML;
- }
-
- nextText = this._get( inst, "nextText" );
- nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
- this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
- this._getFormatConfig( inst ) ) );
-
- if ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ) {
- next = $( "<a>" )
- .attr( {
- "class": "ui-datepicker-next ui-corner-all",
- "data-handler": "next",
- "data-event": "click",
- title: nextText
- } )
- .append(
- $( "<span>" )
- .addClass( "ui-icon ui-icon-circle-triangle-" +
- ( isRTL ? "w" : "e" ) )
- .text( nextText )
- )[ 0 ].outerHTML;
- } else if ( hideIfNoPrevNext ) {
- next = "";
- } else {
- next = $( "<a>" )
- .attr( {
- "class": "ui-datepicker-next ui-corner-all ui-state-disabled",
- title: nextText
- } )
- .append(
- $( "<span>" )
- .attr( "class", "ui-icon ui-icon-circle-triangle-" +
- ( isRTL ? "w" : "e" ) )
- .text( nextText )
- )[ 0 ].outerHTML;
- }
-
- currentText = this._get( inst, "currentText" );
- gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
- currentText = ( !navigationAsDateFormat ? currentText :
- this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
-
- controls = "";
- if ( !inst.inline ) {
- controls = $( "<button>" )
- .attr( {
- type: "button",
- "class": "ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all",
- "data-handler": "hide",
- "data-event": "click"
- } )
- .text( this._get( inst, "closeText" ) )[ 0 ].outerHTML;
- }
-
- buttonPanel = "";
- if ( showButtonPanel ) {
- buttonPanel = $( "<div class='ui-datepicker-buttonpane ui-widget-content'>" )
- .append( isRTL ? controls : "" )
- .append( this._isInRange( inst, gotoDate ) ?
- $( "<button>" )
- .attr( {
- type: "button",
- "class": "ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all",
- "data-handler": "today",
- "data-event": "click"
- } )
- .text( currentText ) :
- "" )
- .append( isRTL ? "" : controls )[ 0 ].outerHTML;
- }
-
- firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
- firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
-
- showWeek = this._get( inst, "showWeek" );
- dayNames = this._get( inst, "dayNames" );
- dayNamesMin = this._get( inst, "dayNamesMin" );
- monthNames = this._get( inst, "monthNames" );
- monthNamesShort = this._get( inst, "monthNamesShort" );
- beforeShowDay = this._get( inst, "beforeShowDay" );
- showOtherMonths = this._get( inst, "showOtherMonths" );
- selectOtherMonths = this._get( inst, "selectOtherMonths" );
- defaultDate = this._getDefaultDate( inst );
- html = "";
-
- for ( row = 0; row < numMonths[ 0 ]; row++ ) {
- group = "";
- this.maxRows = 4;
- for ( col = 0; col < numMonths[ 1 ]; col++ ) {
- selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
- cornerClass = " ui-corner-all";
- calender = "";
- if ( isMultiMonth ) {
- calender += "<div class='ui-datepicker-group";
- if ( numMonths[ 1 ] > 1 ) {
- switch ( col ) {
- case 0: calender += " ui-datepicker-group-first";
- cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
- case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
- cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
- default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
- }
- }
- calender += "'>";
- }
- calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
- ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
- ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
- this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
- row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
- "</div><table class='ui-datepicker-calendar'><thead>" +
- "<tr>";
- thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
- for ( dow = 0; dow < 7; dow++ ) { // days of the week
- day = ( dow + firstDay ) % 7;
- thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
- "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
- }
- calender += thead + "</tr></thead><tbody>";
- daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
- if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
- inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
- }
- leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
- curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
- numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
- this.maxRows = numRows;
- printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
- for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
- calender += "<tr>";
- tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
- this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
- for ( dow = 0; dow < 7; dow++ ) { // create date picker days
- daySettings = ( beforeShowDay ?
- beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
- otherMonth = ( printDate.getMonth() !== drawMonth );
- unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
- ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
- tbody += "<td class='" +
- ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
- ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
- ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
- ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
-
- // or defaultDate is current printedDate and defaultDate is selectedDate
- " " + this._dayOverClass : "" ) + // highlight selected day
- ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days
- ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
- ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
- ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
- ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
- ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
- ( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
- ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
- ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
- ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
- ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
- "' href='#' aria-current='" + ( printDate.getTime() === currentDate.getTime() ? "true" : "false" ) + // mark date as selected for screen reader
- "' data-date='" + printDate.getDate() + // store date as data
- "'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
- printDate.setDate( printDate.getDate() + 1 );
- printDate = this._daylightSavingAdjust( printDate );
- }
- calender += tbody + "</tr>";
- }
- drawMonth++;
- if ( drawMonth > 11 ) {
- drawMonth = 0;
- drawYear++;
- }
- calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
- ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
- group += calender;
- }
- html += group;
- }
- html += buttonPanel;
- inst._keyEvent = false;
- return html;
- },
-
- /* Generate the month and year header. */
- _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
- secondary, monthNames, monthNamesShort ) {
-
- var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
- changeMonth = this._get( inst, "changeMonth" ),
- changeYear = this._get( inst, "changeYear" ),
- showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
- selectMonthLabel = this._get( inst, "selectMonthLabel" ),
- selectYearLabel = this._get( inst, "selectYearLabel" ),
- html = "<div class='ui-datepicker-title'>",
- monthHtml = "";
-
- // Month selection
- if ( secondary || !changeMonth ) {
- monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
- } else {
- inMinYear = ( minDate && minDate.getFullYear() === drawYear );
- inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
- monthHtml += "<select class='ui-datepicker-month' aria-label='" + selectMonthLabel + "' data-handler='selectMonth' data-event='change'>";
- for ( month = 0; month < 12; month++ ) {
- if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
- monthHtml += "<option value='" + month + "'" +
- ( month === drawMonth ? " selected='selected'" : "" ) +
- ">" + monthNamesShort[ month ] + "</option>";
- }
- }
- monthHtml += "</select>";
- }
-
- if ( !showMonthAfterYear ) {
- html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
- }
-
- // Year selection
- if ( !inst.yearshtml ) {
- inst.yearshtml = "";
- if ( secondary || !changeYear ) {
- html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
- } else {
-
- // determine range of years to display
- years = this._get( inst, "yearRange" ).split( ":" );
- thisYear = new Date().getFullYear();
- determineYear = function( value ) {
- var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
- ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
- parseInt( value, 10 ) ) );
- return ( isNaN( year ) ? thisYear : year );
- };
- year = determineYear( years[ 0 ] );
- endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
- year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
- endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
- inst.yearshtml += "<select class='ui-datepicker-year' aria-label='" + selectYearLabel + "' data-handler='selectYear' data-event='change'>";
- for ( ; year <= endYear; year++ ) {
- inst.yearshtml += "<option value='" + year + "'" +
- ( year === drawYear ? " selected='selected'" : "" ) +
- ">" + year + "</option>";
- }
- inst.yearshtml += "</select>";
-
- html += inst.yearshtml;
- inst.yearshtml = null;
- }
- }
-
- html += this._get( inst, "yearSuffix" );
- if ( showMonthAfterYear ) {
- html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
- }
- html += "</div>"; // Close datepicker_header
- return html;
- },
-
- /* Adjust one of the date sub-fields. */
- _adjustInstDate: function( inst, offset, period ) {
- var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
- month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
- day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
- date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
-
- inst.selectedDay = date.getDate();
- inst.drawMonth = inst.selectedMonth = date.getMonth();
- inst.drawYear = inst.selectedYear = date.getFullYear();
- if ( period === "M" || period === "Y" ) {
- this._notifyChange( inst );
- }
- },
-
- /* Ensure a date is within any min/max bounds. */
- _restrictMinMax: function( inst, date ) {
- var minDate = this._getMinMaxDate( inst, "min" ),
- maxDate = this._getMinMaxDate( inst, "max" ),
- newDate = ( minDate && date < minDate ? minDate : date );
- return ( maxDate && newDate > maxDate ? maxDate : newDate );
- },
-
- /* Notify change of month/year. */
- _notifyChange: function( inst ) {
- var onChange = this._get( inst, "onChangeMonthYear" );
- if ( onChange ) {
- onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
- [ inst.selectedYear, inst.selectedMonth + 1, inst ] );
- }
- },
-
- /* Determine the number of months to show. */
- _getNumberOfMonths: function( inst ) {
- var numMonths = this._get( inst, "numberOfMonths" );
- return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
- },
-
- /* Determine the current maximum date - ensure no time components are set. */
- _getMinMaxDate: function( inst, minMax ) {
- return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
- },
-
- /* Find the number of days in a given month. */
- _getDaysInMonth: function( year, month ) {
- return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
- },
-
- /* Find the day of the week of the first of a month. */
- _getFirstDayOfMonth: function( year, month ) {
- return new Date( year, month, 1 ).getDay();
- },
-
- /* Determines if we should allow a "next/prev" month display change. */
- _canAdjustMonth: function( inst, offset, curYear, curMonth ) {
- var numMonths = this._getNumberOfMonths( inst ),
- date = this._daylightSavingAdjust( new Date( curYear,
- curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
-
- if ( offset < 0 ) {
- date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
- }
- return this._isInRange( inst, date );
- },
-
- /* Is the given date in the accepted range? */
- _isInRange: function( inst, date ) {
- var yearSplit, currentYear,
- minDate = this._getMinMaxDate( inst, "min" ),
- maxDate = this._getMinMaxDate( inst, "max" ),
- minYear = null,
- maxYear = null,
- years = this._get( inst, "yearRange" );
- if ( years ) {
- yearSplit = years.split( ":" );
- currentYear = new Date().getFullYear();
- minYear = parseInt( yearSplit[ 0 ], 10 );
- maxYear = parseInt( yearSplit[ 1 ], 10 );
- if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
- minYear += currentYear;
- }
- if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
- maxYear += currentYear;
- }
- }
-
- return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
- ( !maxDate || date.getTime() <= maxDate.getTime() ) &&
- ( !minYear || date.getFullYear() >= minYear ) &&
- ( !maxYear || date.getFullYear() <= maxYear ) );
- },
-
- /* Provide the configuration settings for formatting/parsing. */
- _getFormatConfig: function( inst ) {
- var shortYearCutoff = this._get( inst, "shortYearCutoff" );
- shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
- new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
- return { shortYearCutoff: shortYearCutoff,
- dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
- monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
- },
-
- /* Format the given date for display. */
- _formatDate: function( inst, day, month, year ) {
- if ( !day ) {
- inst.currentDay = inst.selectedDay;
- inst.currentMonth = inst.selectedMonth;
- inst.currentYear = inst.selectedYear;
- }
- var date = ( day ? ( typeof day === "object" ? day :
- this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
- this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
- return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
- }
-} );
-
-/*
- * Bind hover events for datepicker elements.
- * Done via delegate so the binding only occurs once in the lifetime of the parent div.
- * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
- */
-function datepicker_bindHover( dpDiv ) {
- var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
- return dpDiv.on( "mouseout", selector, function() {
- $( this ).removeClass( "ui-state-hover" );
- if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
- $( this ).removeClass( "ui-datepicker-prev-hover" );
- }
- if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
- $( this ).removeClass( "ui-datepicker-next-hover" );
- }
- } )
- .on( "mouseover", selector, datepicker_handleMouseover );
-}
-
-function datepicker_handleMouseover() {
- if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
- $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
- $( this ).addClass( "ui-state-hover" );
- if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
- $( this ).addClass( "ui-datepicker-prev-hover" );
- }
- if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
- $( this ).addClass( "ui-datepicker-next-hover" );
- }
- }
-}
-
-/* jQuery extend now ignores nulls! */
-function datepicker_extendRemove( target, props ) {
- $.extend( target, props );
- for ( var name in props ) {
- if ( props[ name ] == null ) {
- target[ name ] = props[ name ];
- }
- }
- return target;
-}
-
-/* Invoke the datepicker functionality.
- @param options string - a command, optionally followed by additional parameters or
- Object - settings for attaching new datepicker functionality
- @return jQuery object */
-$.fn.datepicker = function( options ) {
-
- /* Verify an empty collection wasn't passed - Fixes #6976 */
- if ( !this.length ) {
- return this;
- }
-
- /* Initialise the date picker. */
- if ( !$.datepicker.initialized ) {
- $( document ).on( "mousedown", $.datepicker._checkExternalClick );
- $.datepicker.initialized = true;
- }
-
- /* Append datepicker main container to body if not exist. */
- if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
- $( "body" ).append( $.datepicker.dpDiv );
- }
-
- var otherArgs = Array.prototype.slice.call( arguments, 1 );
- if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
- return $.datepicker[ "_" + options + "Datepicker" ].
- apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
- }
- if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
- return $.datepicker[ "_" + options + "Datepicker" ].
- apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
- }
- return this.each( function() {
- if ( typeof options === "string" ) {
- $.datepicker[ "_" + options + "Datepicker" ]
- .apply( $.datepicker, [ this ].concat( otherArgs ) );
- } else {
- $.datepicker._attachDatepicker( this, options );
- }
- } );
-};
-
-$.datepicker = new Datepicker(); // singleton instance
-$.datepicker.initialized = false;
-$.datepicker.uuid = new Date().getTime();
-$.datepicker.version = "1.13.1";
-
-var widgetsDatepicker = $.datepicker;
-
-
-
-// This file is deprecated
-var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
-
-/*!
- * jQuery UI Mouse 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Mouse
-//>>group: Widgets
-//>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
-//>>docs: http://api.jqueryui.com/mouse/
-
-
-var mouseHandled = false;
-$( document ).on( "mouseup", function() {
- mouseHandled = false;
-} );
-
-var widgetsMouse = $.widget( "ui.mouse", {
- version: "1.13.1",
- options: {
- cancel: "input, textarea, button, select, option",
- distance: 1,
- delay: 0
- },
- _mouseInit: function() {
- var that = this;
-
- this.element
- .on( "mousedown." + this.widgetName, function( event ) {
- return that._mouseDown( event );
- } )
- .on( "click." + this.widgetName, function( event ) {
- if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
- $.removeData( event.target, that.widgetName + ".preventClickEvent" );
- event.stopImmediatePropagation();
- return false;
- }
- } );
-
- this.started = false;
- },
-
- // TODO: make sure destroying one instance of mouse doesn't mess with
- // other instances of mouse
- _mouseDestroy: function() {
- this.element.off( "." + this.widgetName );
- if ( this._mouseMoveDelegate ) {
- this.document
- .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
- .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
- }
- },
-
- _mouseDown: function( event ) {
-
- // don't let more than one widget handle mouseStart
- if ( mouseHandled ) {
- return;
- }
-
- this._mouseMoved = false;
-
- // We may have missed mouseup (out of window)
- if ( this._mouseStarted ) {
- this._mouseUp( event );
- }
-
- this._mouseDownEvent = event;
-
- var that = this,
- btnIsLeft = ( event.which === 1 ),
-
- // event.target.nodeName works around a bug in IE 8 with
- // disabled inputs (#7620)
- elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
- $( event.target ).closest( this.options.cancel ).length : false );
- if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
- return true;
- }
-
- this.mouseDelayMet = !this.options.delay;
- if ( !this.mouseDelayMet ) {
- this._mouseDelayTimer = setTimeout( function() {
- that.mouseDelayMet = true;
- }, this.options.delay );
- }
-
- if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
- this._mouseStarted = ( this._mouseStart( event ) !== false );
- if ( !this._mouseStarted ) {
- event.preventDefault();
- return true;
- }
- }
-
- // Click event may never have fired (Gecko & Opera)
- if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
- $.removeData( event.target, this.widgetName + ".preventClickEvent" );
- }
-
- // These delegates are required to keep context
- this._mouseMoveDelegate = function( event ) {
- return that._mouseMove( event );
- };
- this._mouseUpDelegate = function( event ) {
- return that._mouseUp( event );
- };
-
- this.document
- .on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
- .on( "mouseup." + this.widgetName, this._mouseUpDelegate );
-
- event.preventDefault();
-
- mouseHandled = true;
- return true;
- },
-
- _mouseMove: function( event ) {
-
- // Only check for mouseups outside the document if you've moved inside the document
- // at least once. This prevents the firing of mouseup in the case of IE<9, which will
- // fire a mousemove event if content is placed under the cursor. See #7778
- // Support: IE <9
- if ( this._mouseMoved ) {
-
- // IE mouseup check - mouseup happened when mouse was out of window
- if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
- !event.button ) {
- return this._mouseUp( event );
-
- // Iframe mouseup check - mouseup occurred in another document
- } else if ( !event.which ) {
-
- // Support: Safari <=8 - 9
- // Safari sets which to 0 if you press any of the following keys
- // during a drag (#14461)
- if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
- event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
- this.ignoreMissingWhich = true;
- } else if ( !this.ignoreMissingWhich ) {
- return this._mouseUp( event );
- }
- }
- }
-
- if ( event.which || event.button ) {
- this._mouseMoved = true;
- }
-
- if ( this._mouseStarted ) {
- this._mouseDrag( event );
- return event.preventDefault();
- }
-
- if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
- this._mouseStarted =
- ( this._mouseStart( this._mouseDownEvent, event ) !== false );
- if ( this._mouseStarted ) {
- this._mouseDrag( event );
- } else {
- this._mouseUp( event );
- }
- }
-
- return !this._mouseStarted;
- },
-
- _mouseUp: function( event ) {
- this.document
- .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
- .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
-
- if ( this._mouseStarted ) {
- this._mouseStarted = false;
-
- if ( event.target === this._mouseDownEvent.target ) {
- $.data( event.target, this.widgetName + ".preventClickEvent", true );
- }
-
- this._mouseStop( event );
- }
-
- if ( this._mouseDelayTimer ) {
- clearTimeout( this._mouseDelayTimer );
- delete this._mouseDelayTimer;
- }
-
- this.ignoreMissingWhich = false;
- mouseHandled = false;
- event.preventDefault();
- },
-
- _mouseDistanceMet: function( event ) {
- return ( Math.max(
- Math.abs( this._mouseDownEvent.pageX - event.pageX ),
- Math.abs( this._mouseDownEvent.pageY - event.pageY )
- ) >= this.options.distance
- );
- },
-
- _mouseDelayMet: function( /* event */ ) {
- return this.mouseDelayMet;
- },
-
- // These are placeholder methods, to be overriden by extending plugin
- _mouseStart: function( /* event */ ) {},
- _mouseDrag: function( /* event */ ) {},
- _mouseStop: function( /* event */ ) {},
- _mouseCapture: function( /* event */ ) {
- return true;
- }
-} );
-
-
-
-// $.ui.plugin is deprecated. Use $.widget() extensions instead.
-var plugin = $.ui.plugin = {
- add: function( module, option, set ) {
- var i,
- proto = $.ui[ module ].prototype;
- for ( i in set ) {
- proto.plugins[ i ] = proto.plugins[ i ] || [];
- proto.plugins[ i ].push( [ option, set[ i ] ] );
- }
- },
- call: function( instance, name, args, allowDisconnected ) {
- var i,
- set = instance.plugins[ name ];
-
- if ( !set ) {
- return;
- }
-
- if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
- instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
- return;
- }
-
- for ( i = 0; i < set.length; i++ ) {
- if ( instance.options[ set[ i ][ 0 ] ] ) {
- set[ i ][ 1 ].apply( instance.element, args );
- }
- }
- }
-};
-
-
-
-var safeBlur = $.ui.safeBlur = function( element ) {
-
- // Support: IE9 - 10 only
- // If the <body> is blurred, IE will switch windows, see #9420
- if ( element && element.nodeName.toLowerCase() !== "body" ) {
- $( element ).trigger( "blur" );
- }
-};
-
-
-/*!
- * jQuery UI Draggable 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Draggable
-//>>group: Interactions
-//>>description: Enables dragging functionality for any element.
-//>>docs: http://api.jqueryui.com/draggable/
-//>>demos: http://jqueryui.com/draggable/
-//>>css.structure: ../../themes/base/draggable.css
-
-
-$.widget( "ui.draggable", $.ui.mouse, {
- version: "1.13.1",
- widgetEventPrefix: "drag",
- options: {
- addClasses: true,
- appendTo: "parent",
- axis: false,
- connectToSortable: false,
- containment: false,
- cursor: "auto",
- cursorAt: false,
- grid: false,
- handle: false,
- helper: "original",
- iframeFix: false,
- opacity: false,
- refreshPositions: false,
- revert: false,
- revertDuration: 500,
- scope: "default",
- scroll: true,
- scrollSensitivity: 20,
- scrollSpeed: 20,
- snap: false,
- snapMode: "both",
- snapTolerance: 20,
- stack: false,
- zIndex: false,
-
- // Callbacks
- drag: null,
- start: null,
- stop: null
- },
- _create: function() {
-
- if ( this.options.helper === "original" ) {
- this._setPositionRelative();
- }
- if ( this.options.addClasses ) {
- this._addClass( "ui-draggable" );
- }
- this._setHandleClassName();
-
- this._mouseInit();
- },
-
- _setOption: function( key, value ) {
- this._super( key, value );
- if ( key === "handle" ) {
- this._removeHandleClassName();
- this._setHandleClassName();
- }
- },
-
- _destroy: function() {
- if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
- this.destroyOnClear = true;
- return;
- }
- this._removeHandleClassName();
- this._mouseDestroy();
- },
-
- _mouseCapture: function( event ) {
- var o = this.options;
-
- // Among others, prevent a drag on a resizable-handle
- if ( this.helper || o.disabled ||
- $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
- return false;
- }
-
- //Quit if we're not on a valid handle
- this.handle = this._getHandle( event );
- if ( !this.handle ) {
- return false;
- }
-
- this._blurActiveElement( event );
-
- this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
-
- return true;
-
- },
-
- _blockFrames: function( selector ) {
- this.iframeBlocks = this.document.find( selector ).map( function() {
- var iframe = $( this );
-
- return $( "<div>" )
- .css( "position", "absolute" )
- .appendTo( iframe.parent() )
- .outerWidth( iframe.outerWidth() )
- .outerHeight( iframe.outerHeight() )
- .offset( iframe.offset() )[ 0 ];
- } );
- },
-
- _unblockFrames: function() {
- if ( this.iframeBlocks ) {
- this.iframeBlocks.remove();
- delete this.iframeBlocks;
- }
- },
-
- _blurActiveElement: function( event ) {
- var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
- target = $( event.target );
-
- // Don't blur if the event occurred on an element that is within
- // the currently focused element
- // See #10527, #12472
- if ( target.closest( activeElement ).length ) {
- return;
- }
-
- // Blur any element that currently has focus, see #4261
- $.ui.safeBlur( activeElement );
- },
-
- _mouseStart: function( event ) {
-
- var o = this.options;
-
- //Create and append the visible helper
- this.helper = this._createHelper( event );
-
- this._addClass( this.helper, "ui-draggable-dragging" );
-
- //Cache the helper size
- this._cacheHelperProportions();
-
- //If ddmanager is used for droppables, set the global draggable
- if ( $.ui.ddmanager ) {
- $.ui.ddmanager.current = this;
- }
-
- /*
- * - Position generation -
- * This block generates everything position related - it's the core of draggables.
- */
-
- //Cache the margins of the original element
- this._cacheMargins();
-
- //Store the helper's css position
- this.cssPosition = this.helper.css( "position" );
- this.scrollParent = this.helper.scrollParent( true );
- this.offsetParent = this.helper.offsetParent();
- this.hasFixedAncestor = this.helper.parents().filter( function() {
- return $( this ).css( "position" ) === "fixed";
- } ).length > 0;
-
- //The element's absolute position on the page minus margins
- this.positionAbs = this.element.offset();
- this._refreshOffsets( event );
-
- //Generate the original position
- this.originalPosition = this.position = this._generatePosition( event, false );
- this.originalPageX = event.pageX;
- this.originalPageY = event.pageY;
-
- //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
- if ( o.cursorAt ) {
- this._adjustOffsetFromHelper( o.cursorAt );
- }
-
- //Set a containment if given in the options
- this._setContainment();
-
- //Trigger event + callbacks
- if ( this._trigger( "start", event ) === false ) {
- this._clear();
- return false;
- }
-
- //Recache the helper size
- this._cacheHelperProportions();
-
- //Prepare the droppable offsets
- if ( $.ui.ddmanager && !o.dropBehaviour ) {
- $.ui.ddmanager.prepareOffsets( this, event );
- }
-
- // Execute the drag once - this causes the helper not to be visible before getting its
- // correct position
- this._mouseDrag( event, true );
-
- // If the ddmanager is used for droppables, inform the manager that dragging has started
- // (see #5003)
- if ( $.ui.ddmanager ) {
- $.ui.ddmanager.dragStart( this, event );
- }
-
- return true;
- },
-
- _refreshOffsets: function( event ) {
- this.offset = {
- top: this.positionAbs.top - this.margins.top,
- left: this.positionAbs.left - this.margins.left,
- scroll: false,
- parent: this._getParentOffset(),
- relative: this._getRelativeOffset()
- };
-
- this.offset.click = {
- left: event.pageX - this.offset.left,
- top: event.pageY - this.offset.top
- };
- },
-
- _mouseDrag: function( event, noPropagation ) {
-
- // reset any necessary cached properties (see #5009)
- if ( this.hasFixedAncestor ) {
- this.offset.parent = this._getParentOffset();
- }
-
- //Compute the helpers position
- this.position = this._generatePosition( event, true );
- this.positionAbs = this._convertPositionTo( "absolute" );
-
- //Call plugins and callbacks and use the resulting position if something is returned
- if ( !noPropagation ) {
- var ui = this._uiHash();
- if ( this._trigger( "drag", event, ui ) === false ) {
- this._mouseUp( new $.Event( "mouseup", event ) );
- return false;
- }
- this.position = ui.position;
- }
-
- this.helper[ 0 ].style.left = this.position.left + "px";
- this.helper[ 0 ].style.top = this.position.top + "px";
-
- if ( $.ui.ddmanager ) {
- $.ui.ddmanager.drag( this, event );
- }
-
- return false;
- },
-
- _mouseStop: function( event ) {
-
- //If we are using droppables, inform the manager about the drop
- var that = this,
- dropped = false;
- if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
- dropped = $.ui.ddmanager.drop( this, event );
- }
-
- //if a drop comes from outside (a sortable)
- if ( this.dropped ) {
- dropped = this.dropped;
- this.dropped = false;
- }
-
- if ( ( this.options.revert === "invalid" && !dropped ) ||
- ( this.options.revert === "valid" && dropped ) ||
- this.options.revert === true || ( typeof this.options.revert === "function" &&
- this.options.revert.call( this.element, dropped ) )
- ) {
- $( this.helper ).animate(
- this.originalPosition,
- parseInt( this.options.revertDuration, 10 ),
- function() {
- if ( that._trigger( "stop", event ) !== false ) {
- that._clear();
- }
- }
- );
- } else {
- if ( this._trigger( "stop", event ) !== false ) {
- this._clear();
- }
- }
-
- return false;
- },
-
- _mouseUp: function( event ) {
- this._unblockFrames();
-
- // If the ddmanager is used for droppables, inform the manager that dragging has stopped
- // (see #5003)
- if ( $.ui.ddmanager ) {
- $.ui.ddmanager.dragStop( this, event );
- }
-
- // Only need to focus if the event occurred on the draggable itself, see #10527
- if ( this.handleElement.is( event.target ) ) {
-
- // The interaction is over; whether or not the click resulted in a drag,
- // focus the element
- this.element.trigger( "focus" );
- }
-
- return $.ui.mouse.prototype._mouseUp.call( this, event );
- },
-
- cancel: function() {
-
- if ( this.helper.is( ".ui-draggable-dragging" ) ) {
- this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
- } else {
- this._clear();
- }
-
- return this;
-
- },
-
- _getHandle: function( event ) {
- return this.options.handle ?
- !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
- true;
- },
-
- _setHandleClassName: function() {
- this.handleElement = this.options.handle ?
- this.element.find( this.options.handle ) : this.element;
- this._addClass( this.handleElement, "ui-draggable-handle" );
- },
-
- _removeHandleClassName: function() {
- this._removeClass( this.handleElement, "ui-draggable-handle" );
- },
-
- _createHelper: function( event ) {
-
- var o = this.options,
- helperIsFunction = typeof o.helper === "function",
- helper = helperIsFunction ?
- $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
- ( o.helper === "clone" ?
- this.element.clone().removeAttr( "id" ) :
- this.element );
-
- if ( !helper.parents( "body" ).length ) {
- helper.appendTo( ( o.appendTo === "parent" ?
- this.element[ 0 ].parentNode :
- o.appendTo ) );
- }
-
- // Http://bugs.jqueryui.com/ticket/9446
- // a helper function can return the original element
- // which wouldn't have been set to relative in _create
- if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
- this._setPositionRelative();
- }
-
- if ( helper[ 0 ] !== this.element[ 0 ] &&
- !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
- helper.css( "position", "absolute" );
- }
-
- return helper;
-
- },
-
- _setPositionRelative: function() {
- if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
- this.element[ 0 ].style.position = "relative";
- }
- },
-
- _adjustOffsetFromHelper: function( obj ) {
- if ( typeof obj === "string" ) {
- obj = obj.split( " " );
- }
- if ( Array.isArray( obj ) ) {
- obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
- }
- if ( "left" in obj ) {
- this.offset.click.left = obj.left + this.margins.left;
- }
- if ( "right" in obj ) {
- this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
- }
- if ( "top" in obj ) {
- this.offset.click.top = obj.top + this.margins.top;
- }
- if ( "bottom" in obj ) {
- this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
- }
- },
-
- _isRootNode: function( element ) {
- return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
- },
-
- _getParentOffset: function() {
-
- //Get the offsetParent and cache its position
- var po = this.offsetParent.offset(),
- document = this.document[ 0 ];
-
- // This is a special case where we need to modify a offset calculated on start, since the
- // following happened:
- // 1. The position of the helper is absolute, so it's position is calculated based on the
- // next positioned parent
- // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
- // the document, which means that the scroll is included in the initial calculation of the
- // offset of the parent, and never recalculated upon drag
- if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
- $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
- po.left += this.scrollParent.scrollLeft();
- po.top += this.scrollParent.scrollTop();
- }
-
- if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
- po = { top: 0, left: 0 };
- }
-
- return {
- top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
- left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
- };
-
- },
-
- _getRelativeOffset: function() {
- if ( this.cssPosition !== "relative" ) {
- return { top: 0, left: 0 };
- }
-
- var p = this.element.position(),
- scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
-
- return {
- top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
- ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
- left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
- ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
- };
-
- },
-
- _cacheMargins: function() {
- this.margins = {
- left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
- top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
- right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
- bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
- };
- },
-
- _cacheHelperProportions: function() {
- this.helperProportions = {
- width: this.helper.outerWidth(),
- height: this.helper.outerHeight()
- };
- },
-
- _setContainment: function() {
-
- var isUserScrollable, c, ce,
- o = this.options,
- document = this.document[ 0 ];
-
- this.relativeContainer = null;
-
- if ( !o.containment ) {
- this.containment = null;
- return;
- }
-
- if ( o.containment === "window" ) {
- this.containment = [
- $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
- $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
- $( window ).scrollLeft() + $( window ).width() -
- this.helperProportions.width - this.margins.left,
- $( window ).scrollTop() +
- ( $( window ).height() || document.body.parentNode.scrollHeight ) -
- this.helperProportions.height - this.margins.top
- ];
- return;
- }
-
- if ( o.containment === "document" ) {
- this.containment = [
- 0,
- 0,
- $( document ).width() - this.helperProportions.width - this.margins.left,
- ( $( document ).height() || document.body.parentNode.scrollHeight ) -
- this.helperProportions.height - this.margins.top
- ];
- return;
- }
-
- if ( o.containment.constructor === Array ) {
- this.containment = o.containment;
- return;
- }
-
- if ( o.containment === "parent" ) {
- o.containment = this.helper[ 0 ].parentNode;
- }
-
- c = $( o.containment );
- ce = c[ 0 ];
-
- if ( !ce ) {
- return;
- }
-
- isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
-
- this.containment = [
- ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
- ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
- ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
- ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
- ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
- ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
- ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
- this.helperProportions.width -
- this.margins.left -
- this.margins.right,
- ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
- ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
- ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
- this.helperProportions.height -
- this.margins.top -
- this.margins.bottom
- ];
- this.relativeContainer = c;
- },
-
- _convertPositionTo: function( d, pos ) {
-
- if ( !pos ) {
- pos = this.position;
- }
-
- var mod = d === "absolute" ? 1 : -1,
- scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
-
- return {
- top: (
-
- // The absolute mouse position
- pos.top +
-
- // Only for relative positioned nodes: Relative offset from element to offset parent
- this.offset.relative.top * mod +
-
- // The offsetParent's offset without borders (offset + border)
- this.offset.parent.top * mod -
- ( ( this.cssPosition === "fixed" ?
- -this.offset.scroll.top :
- ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
- ),
- left: (
-
- // The absolute mouse position
- pos.left +
-
- // Only for relative positioned nodes: Relative offset from element to offset parent
- this.offset.relative.left * mod +
-
- // The offsetParent's offset without borders (offset + border)
- this.offset.parent.left * mod -
- ( ( this.cssPosition === "fixed" ?
- -this.offset.scroll.left :
- ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
- )
- };
-
- },
-
- _generatePosition: function( event, constrainPosition ) {
-
- var containment, co, top, left,
- o = this.options,
- scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
- pageX = event.pageX,
- pageY = event.pageY;
-
- // Cache the scroll
- if ( !scrollIsRootNode || !this.offset.scroll ) {
- this.offset.scroll = {
- top: this.scrollParent.scrollTop(),
- left: this.scrollParent.scrollLeft()
- };
- }
-
- /*
- * - Position constraining -
- * Constrain the position to a mix of grid, containment.
- */
-
- // If we are not dragging yet, we won't check for options
- if ( constrainPosition ) {
- if ( this.containment ) {
- if ( this.relativeContainer ) {
- co = this.relativeContainer.offset();
- containment = [
- this.containment[ 0 ] + co.left,
- this.containment[ 1 ] + co.top,
- this.containment[ 2 ] + co.left,
- this.containment[ 3 ] + co.top
- ];
- } else {
- containment = this.containment;
- }
-
- if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
- pageX = containment[ 0 ] + this.offset.click.left;
- }
- if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
- pageY = containment[ 1 ] + this.offset.click.top;
- }
- if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
- pageX = containment[ 2 ] + this.offset.click.left;
- }
- if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
- pageY = containment[ 3 ] + this.offset.click.top;
- }
- }
-
- if ( o.grid ) {
-
- //Check for grid elements set to 0 to prevent divide by 0 error causing invalid
- // argument errors in IE (see ticket #6950)
- top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
- this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
- pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
- top - this.offset.click.top > containment[ 3 ] ) ?
- top :
- ( ( top - this.offset.click.top >= containment[ 1 ] ) ?
- top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
-
- left = o.grid[ 0 ] ? this.originalPageX +
- Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
- this.originalPageX;
- pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
- left - this.offset.click.left > containment[ 2 ] ) ?
- left :
- ( ( left - this.offset.click.left >= containment[ 0 ] ) ?
- left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
- }
-
- if ( o.axis === "y" ) {
- pageX = this.originalPageX;
- }
-
- if ( o.axis === "x" ) {
- pageY = this.originalPageY;
- }
- }
-
- return {
- top: (
-
- // The absolute mouse position
- pageY -
-
- // Click offset (relative to the element)
- this.offset.click.top -
-
- // Only for relative positioned nodes: Relative offset from element to offset parent
- this.offset.relative.top -
-
- // The offsetParent's offset without borders (offset + border)
- this.offset.parent.top +
- ( this.cssPosition === "fixed" ?
- -this.offset.scroll.top :
- ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
- ),
- left: (
-
- // The absolute mouse position
- pageX -
-
- // Click offset (relative to the element)
- this.offset.click.left -
-
- // Only for relative positioned nodes: Relative offset from element to offset parent
- this.offset.relative.left -
-
- // The offsetParent's offset without borders (offset + border)
- this.offset.parent.left +
- ( this.cssPosition === "fixed" ?
- -this.offset.scroll.left :
- ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
- )
- };
-
- },
-
- _clear: function() {
- this._removeClass( this.helper, "ui-draggable-dragging" );
- if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
- this.helper.remove();
- }
- this.helper = null;
- this.cancelHelperRemoval = false;
- if ( this.destroyOnClear ) {
- this.destroy();
- }
- },
-
- // From now on bulk stuff - mainly helpers
-
- _trigger: function( type, event, ui ) {
- ui = ui || this._uiHash();
- $.ui.plugin.call( this, type, [ event, ui, this ], true );
-
- // Absolute position and offset (see #6884 ) have to be recalculated after plugins
- if ( /^(drag|start|stop)/.test( type ) ) {
- this.positionAbs = this._convertPositionTo( "absolute" );
- ui.offset = this.positionAbs;
- }
- return $.Widget.prototype._trigger.call( this, type, event, ui );
- },
-
- plugins: {},
-
- _uiHash: function() {
- return {
- helper: this.helper,
- position: this.position,
- originalPosition: this.originalPosition,
- offset: this.positionAbs
- };
- }
-
-} );
-
-$.ui.plugin.add( "draggable", "connectToSortable", {
- start: function( event, ui, draggable ) {
- var uiSortable = $.extend( {}, ui, {
- item: draggable.element
- } );
-
- draggable.sortables = [];
- $( draggable.options.connectToSortable ).each( function() {
- var sortable = $( this ).sortable( "instance" );
-
- if ( sortable && !sortable.options.disabled ) {
- draggable.sortables.push( sortable );
-
- // RefreshPositions is called at drag start to refresh the containerCache
- // which is used in drag. This ensures it's initialized and synchronized
- // with any changes that might have happened on the page since initialization.
- sortable.refreshPositions();
- sortable._trigger( "activate", event, uiSortable );
- }
- } );
- },
- stop: function( event, ui, draggable ) {
- var uiSortable = $.extend( {}, ui, {
- item: draggable.element
- } );
-
- draggable.cancelHelperRemoval = false;
-
- $.each( draggable.sortables, function() {
- var sortable = this;
-
- if ( sortable.isOver ) {
- sortable.isOver = 0;
-
- // Allow this sortable to handle removing the helper
- draggable.cancelHelperRemoval = true;
- sortable.cancelHelperRemoval = false;
-
- // Use _storedCSS To restore properties in the sortable,
- // as this also handles revert (#9675) since the draggable
- // may have modified them in unexpected ways (#8809)
- sortable._storedCSS = {
- position: sortable.placeholder.css( "position" ),
- top: sortable.placeholder.css( "top" ),
- left: sortable.placeholder.css( "left" )
- };
-
- sortable._mouseStop( event );
-
- // Once drag has ended, the sortable should return to using
- // its original helper, not the shared helper from draggable
- sortable.options.helper = sortable.options._helper;
- } else {
-
- // Prevent this Sortable from removing the helper.
- // However, don't set the draggable to remove the helper
- // either as another connected Sortable may yet handle the removal.
- sortable.cancelHelperRemoval = true;
-
- sortable._trigger( "deactivate", event, uiSortable );
- }
- } );
- },
- drag: function( event, ui, draggable ) {
- $.each( draggable.sortables, function() {
- var innermostIntersecting = false,
- sortable = this;
-
- // Copy over variables that sortable's _intersectsWith uses
- sortable.positionAbs = draggable.positionAbs;
- sortable.helperProportions = draggable.helperProportions;
- sortable.offset.click = draggable.offset.click;
-
- if ( sortable._intersectsWith( sortable.containerCache ) ) {
- innermostIntersecting = true;
-
- $.each( draggable.sortables, function() {
-
- // Copy over variables that sortable's _intersectsWith uses
- this.positionAbs = draggable.positionAbs;
- this.helperProportions = draggable.helperProportions;
- this.offset.click = draggable.offset.click;
-
- if ( this !== sortable &&
- this._intersectsWith( this.containerCache ) &&
- $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
- innermostIntersecting = false;
- }
-
- return innermostIntersecting;
- } );
- }
-
- if ( innermostIntersecting ) {
-
- // If it intersects, we use a little isOver variable and set it once,
- // so that the move-in stuff gets fired only once.
- if ( !sortable.isOver ) {
- sortable.isOver = 1;
-
- // Store draggable's parent in case we need to reappend to it later.
- draggable._parent = ui.helper.parent();
-
- sortable.currentItem = ui.helper
- .appendTo( sortable.element )
- .data( "ui-sortable-item", true );
-
- // Store helper option to later restore it
- sortable.options._helper = sortable.options.helper;
-
- sortable.options.helper = function() {
- return ui.helper[ 0 ];
- };
-
- // Fire the start events of the sortable with our passed browser event,
- // and our own helper (so it doesn't create a new one)
- event.target = sortable.currentItem[ 0 ];
- sortable._mouseCapture( event, true );
- sortable._mouseStart( event, true, true );
-
- // Because the browser event is way off the new appended portlet,
- // modify necessary variables to reflect the changes
- sortable.offset.click.top = draggable.offset.click.top;
- sortable.offset.click.left = draggable.offset.click.left;
- sortable.offset.parent.left -= draggable.offset.parent.left -
- sortable.offset.parent.left;
- sortable.offset.parent.top -= draggable.offset.parent.top -
- sortable.offset.parent.top;
-
- draggable._trigger( "toSortable", event );
-
- // Inform draggable that the helper is in a valid drop zone,
- // used solely in the revert option to handle "valid/invalid".
- draggable.dropped = sortable.element;
-
- // Need to refreshPositions of all sortables in the case that
- // adding to one sortable changes the location of the other sortables (#9675)
- $.each( draggable.sortables, function() {
- this.refreshPositions();
- } );
-
- // Hack so receive/update callbacks work (mostly)
- draggable.currentItem = draggable.element;
- sortable.fromOutside = draggable;
- }
-
- if ( sortable.currentItem ) {
- sortable._mouseDrag( event );
-
- // Copy the sortable's position because the draggable's can potentially reflect
- // a relative position, while sortable is always absolute, which the dragged
- // element has now become. (#8809)
- ui.position = sortable.position;
- }
- } else {
-
- // If it doesn't intersect with the sortable, and it intersected before,
- // we fake the drag stop of the sortable, but make sure it doesn't remove
- // the helper by using cancelHelperRemoval.
- if ( sortable.isOver ) {
-
- sortable.isOver = 0;
- sortable.cancelHelperRemoval = true;
-
- // Calling sortable's mouseStop would trigger a revert,
- // so revert must be temporarily false until after mouseStop is called.
- sortable.options._revert = sortable.options.revert;
- sortable.options.revert = false;
-
- sortable._trigger( "out", event, sortable._uiHash( sortable ) );
- sortable._mouseStop( event, true );
-
- // Restore sortable behaviors that were modfied
- // when the draggable entered the sortable area (#9481)
- sortable.options.revert = sortable.options._revert;
- sortable.options.helper = sortable.options._helper;
-
- if ( sortable.placeholder ) {
- sortable.placeholder.remove();
- }
-
- // Restore and recalculate the draggable's offset considering the sortable
- // may have modified them in unexpected ways. (#8809, #10669)
- ui.helper.appendTo( draggable._parent );
- draggable._refreshOffsets( event );
- ui.position = draggable._generatePosition( event, true );
-
- draggable._trigger( "fromSortable", event );
-
- // Inform draggable that the helper is no longer in a valid drop zone
- draggable.dropped = false;
-
- // Need to refreshPositions of all sortables just in case removing
- // from one sortable changes the location of other sortables (#9675)
- $.each( draggable.sortables, function() {
- this.refreshPositions();
- } );
- }
- }
- } );
- }
-} );
-
-$.ui.plugin.add( "draggable", "cursor", {
- start: function( event, ui, instance ) {
- var t = $( "body" ),
- o = instance.options;
-
- if ( t.css( "cursor" ) ) {
- o._cursor = t.css( "cursor" );
- }
- t.css( "cursor", o.cursor );
- },
- stop: function( event, ui, instance ) {
- var o = instance.options;
- if ( o._cursor ) {
- $( "body" ).css( "cursor", o._cursor );
- }
- }
-} );
-
-$.ui.plugin.add( "draggable", "opacity", {
- start: function( event, ui, instance ) {
- var t = $( ui.helper ),
- o = instance.options;
- if ( t.css( "opacity" ) ) {
- o._opacity = t.css( "opacity" );
- }
- t.css( "opacity", o.opacity );
- },
- stop: function( event, ui, instance ) {
- var o = instance.options;
- if ( o._opacity ) {
- $( ui.helper ).css( "opacity", o._opacity );
- }
- }
-} );
-
-$.ui.plugin.add( "draggable", "scroll", {
- start: function( event, ui, i ) {
- if ( !i.scrollParentNotHidden ) {
- i.scrollParentNotHidden = i.helper.scrollParent( false );
- }
-
- if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
- i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
- i.overflowOffset = i.scrollParentNotHidden.offset();
- }
- },
- drag: function( event, ui, i ) {
-
- var o = i.options,
- scrolled = false,
- scrollParent = i.scrollParentNotHidden[ 0 ],
- document = i.document[ 0 ];
-
- if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
- if ( !o.axis || o.axis !== "x" ) {
- if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
- o.scrollSensitivity ) {
- scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
- } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
- scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
- }
- }
-
- if ( !o.axis || o.axis !== "y" ) {
- if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
- o.scrollSensitivity ) {
- scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
- } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
- scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
- }
- }
-
- } else {
-
- if ( !o.axis || o.axis !== "x" ) {
- if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
- scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
- } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
- o.scrollSensitivity ) {
- scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
- }
- }
-
- if ( !o.axis || o.axis !== "y" ) {
- if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
- scrolled = $( document ).scrollLeft(
- $( document ).scrollLeft() - o.scrollSpeed
- );
- } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
- o.scrollSensitivity ) {
- scrolled = $( document ).scrollLeft(
- $( document ).scrollLeft() + o.scrollSpeed
- );
- }
- }
-
- }
-
- if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
- $.ui.ddmanager.prepareOffsets( i, event );
- }
-
- }
-} );
-
-$.ui.plugin.add( "draggable", "snap", {
- start: function( event, ui, i ) {
-
- var o = i.options;
-
- i.snapElements = [];
-
- $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
- .each( function() {
- var $t = $( this ),
- $o = $t.offset();
- if ( this !== i.element[ 0 ] ) {
- i.snapElements.push( {
- item: this,
- width: $t.outerWidth(), height: $t.outerHeight(),
- top: $o.top, left: $o.left
- } );
- }
- } );
-
- },
- drag: function( event, ui, inst ) {
-
- var ts, bs, ls, rs, l, r, t, b, i, first,
- o = inst.options,
- d = o.snapTolerance,
- x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
- y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
-
- for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {
-
- l = inst.snapElements[ i ].left - inst.margins.left;
- r = l + inst.snapElements[ i ].width;
- t = inst.snapElements[ i ].top - inst.margins.top;
- b = t + inst.snapElements[ i ].height;
-
- if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
- !$.contains( inst.snapElements[ i ].item.ownerDocument,
- inst.snapElements[ i ].item ) ) {
- if ( inst.snapElements[ i ].snapping ) {
- if ( inst.options.snap.release ) {
- inst.options.snap.release.call(
- inst.element,
- event,
- $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
- );
- }
- }
- inst.snapElements[ i ].snapping = false;
- continue;
- }
-
- if ( o.snapMode !== "inner" ) {
- ts = Math.abs( t - y2 ) <= d;
- bs = Math.abs( b - y1 ) <= d;
- ls = Math.abs( l - x2 ) <= d;
- rs = Math.abs( r - x1 ) <= d;
- if ( ts ) {
- ui.position.top = inst._convertPositionTo( "relative", {
- top: t - inst.helperProportions.height,
- left: 0
- } ).top;
- }
- if ( bs ) {
- ui.position.top = inst._convertPositionTo( "relative", {
- top: b,
- left: 0
- } ).top;
- }
- if ( ls ) {
- ui.position.left = inst._convertPositionTo( "relative", {
- top: 0,
- left: l - inst.helperProportions.width
- } ).left;
- }
- if ( rs ) {
- ui.position.left = inst._convertPositionTo( "relative", {
- top: 0,
- left: r
- } ).left;
- }
- }
-
- first = ( ts || bs || ls || rs );
-
- if ( o.snapMode !== "outer" ) {
- ts = Math.abs( t - y1 ) <= d;
- bs = Math.abs( b - y2 ) <= d;
- ls = Math.abs( l - x1 ) <= d;
- rs = Math.abs( r - x2 ) <= d;
- if ( ts ) {
- ui.position.top = inst._convertPositionTo( "relative", {
- top: t,
- left: 0
- } ).top;
- }
- if ( bs ) {
- ui.position.top = inst._convertPositionTo( "relative", {
- top: b - inst.helperProportions.height,
- left: 0
- } ).top;
- }
- if ( ls ) {
- ui.position.left = inst._convertPositionTo( "relative", {
- top: 0,
- left: l
- } ).left;
- }
- if ( rs ) {
- ui.position.left = inst._convertPositionTo( "relative", {
- top: 0,
- left: r - inst.helperProportions.width
- } ).left;
- }
- }
-
- if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
- if ( inst.options.snap.snap ) {
- inst.options.snap.snap.call(
- inst.element,
- event,
- $.extend( inst._uiHash(), {
- snapItem: inst.snapElements[ i ].item
- } ) );
- }
- }
- inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );
-
- }
-
- }
-} );
-
-$.ui.plugin.add( "draggable", "stack", {
- start: function( event, ui, instance ) {
- var min,
- o = instance.options,
- group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
- return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
- ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
- } );
-
- if ( !group.length ) {
- return;
- }
-
- min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
- $( group ).each( function( i ) {
- $( this ).css( "zIndex", min + i );
- } );
- this.css( "zIndex", ( min + group.length ) );
- }
-} );
-
-$.ui.plugin.add( "draggable", "zIndex", {
- start: function( event, ui, instance ) {
- var t = $( ui.helper ),
- o = instance.options;
-
- if ( t.css( "zIndex" ) ) {
- o._zIndex = t.css( "zIndex" );
- }
- t.css( "zIndex", o.zIndex );
- },
- stop: function( event, ui, instance ) {
- var o = instance.options;
-
- if ( o._zIndex ) {
- $( ui.helper ).css( "zIndex", o._zIndex );
- }
- }
-} );
-
-var widgetsDraggable = $.ui.draggable;
-
-
-/*!
- * jQuery UI Resizable 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Resizable
-//>>group: Interactions
-//>>description: Enables resize functionality for any element.
-//>>docs: http://api.jqueryui.com/resizable/
-//>>demos: http://jqueryui.com/resizable/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/resizable.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-$.widget( "ui.resizable", $.ui.mouse, {
- version: "1.13.1",
- widgetEventPrefix: "resize",
- options: {
- alsoResize: false,
- animate: false,
- animateDuration: "slow",
- animateEasing: "swing",
- aspectRatio: false,
- autoHide: false,
- classes: {
- "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
- },
- containment: false,
- ghost: false,
- grid: false,
- handles: "e,s,se",
- helper: false,
- maxHeight: null,
- maxWidth: null,
- minHeight: 10,
- minWidth: 10,
-
- // See #7960
- zIndex: 90,
-
- // Callbacks
- resize: null,
- start: null,
- stop: null
- },
-
- _num: function( value ) {
- return parseFloat( value ) || 0;
- },
-
- _isNumber: function( value ) {
- return !isNaN( parseFloat( value ) );
- },
-
- _hasScroll: function( el, a ) {
-
- if ( $( el ).css( "overflow" ) === "hidden" ) {
- return false;
- }
-
- var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
- has = false;
-
- if ( el[ scroll ] > 0 ) {
- return true;
- }
-
- // TODO: determine which cases actually cause this to happen
- // if the element doesn't have the scroll set, see if it's possible to
- // set the scroll
- try {
- el[ scroll ] = 1;
- has = ( el[ scroll ] > 0 );
- el[ scroll ] = 0;
- } catch ( e ) {
-
- // `el` might be a string, then setting `scroll` will throw
- // an error in strict mode; ignore it.
- }
- return has;
- },
-
- _create: function() {
-
- var margins,
- o = this.options,
- that = this;
- this._addClass( "ui-resizable" );
-
- $.extend( this, {
- _aspectRatio: !!( o.aspectRatio ),
- aspectRatio: o.aspectRatio,
- originalElement: this.element,
- _proportionallyResizeElements: [],
- _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
- } );
-
- // Wrap the element if it cannot hold child nodes
- if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
-
- this.element.wrap(
- $( "<div class='ui-wrapper'></div>" ).css( {
- overflow: "hidden",
- position: this.element.css( "position" ),
- width: this.element.outerWidth(),
- height: this.element.outerHeight(),
- top: this.element.css( "top" ),
- left: this.element.css( "left" )
- } )
- );
-
- this.element = this.element.parent().data(
- "ui-resizable", this.element.resizable( "instance" )
- );
-
- this.elementIsWrapper = true;
-
- margins = {
- marginTop: this.originalElement.css( "marginTop" ),
- marginRight: this.originalElement.css( "marginRight" ),
- marginBottom: this.originalElement.css( "marginBottom" ),
- marginLeft: this.originalElement.css( "marginLeft" )
- };
-
- this.element.css( margins );
- this.originalElement.css( "margin", 0 );
-
- // support: Safari
- // Prevent Safari textarea resize
- this.originalResizeStyle = this.originalElement.css( "resize" );
- this.originalElement.css( "resize", "none" );
-
- this._proportionallyResizeElements.push( this.originalElement.css( {
- position: "static",
- zoom: 1,
- display: "block"
- } ) );
-
- // Support: IE9
- // avoid IE jump (hard set the margin)
- this.originalElement.css( margins );
-
- this._proportionallyResize();
- }
-
- this._setupHandles();
-
- if ( o.autoHide ) {
- $( this.element )
- .on( "mouseenter", function() {
- if ( o.disabled ) {
- return;
- }
- that._removeClass( "ui-resizable-autohide" );
- that._handles.show();
- } )
- .on( "mouseleave", function() {
- if ( o.disabled ) {
- return;
- }
- if ( !that.resizing ) {
- that._addClass( "ui-resizable-autohide" );
- that._handles.hide();
- }
- } );
- }
-
- this._mouseInit();
- },
-
- _destroy: function() {
-
- this._mouseDestroy();
- this._addedHandles.remove();
-
- var wrapper,
- _destroy = function( exp ) {
- $( exp )
- .removeData( "resizable" )
- .removeData( "ui-resizable" )
- .off( ".resizable" );
- };
-
- // TODO: Unwrap at same DOM position
- if ( this.elementIsWrapper ) {
- _destroy( this.element );
- wrapper = this.element;
- this.originalElement.css( {
- position: wrapper.css( "position" ),
- width: wrapper.outerWidth(),
- height: wrapper.outerHeight(),
- top: wrapper.css( "top" ),
- left: wrapper.css( "left" )
- } ).insertAfter( wrapper );
- wrapper.remove();
- }
-
- this.originalElement.css( "resize", this.originalResizeStyle );
- _destroy( this.originalElement );
-
- return this;
- },
-
- _setOption: function( key, value ) {
- this._super( key, value );
-
- switch ( key ) {
- case "handles":
- this._removeHandles();
- this._setupHandles();
- break;
- case "aspectRatio":
- this._aspectRatio = !!value;
- break;
- default:
- break;
- }
- },
-
- _setupHandles: function() {
- var o = this.options, handle, i, n, hname, axis, that = this;
- this.handles = o.handles ||
- ( !$( ".ui-resizable-handle", this.element ).length ?
- "e,s,se" : {
- n: ".ui-resizable-n",
- e: ".ui-resizable-e",
- s: ".ui-resizable-s",
- w: ".ui-resizable-w",
- se: ".ui-resizable-se",
- sw: ".ui-resizable-sw",
- ne: ".ui-resizable-ne",
- nw: ".ui-resizable-nw"
- } );
-
- this._handles = $();
- this._addedHandles = $();
- if ( this.handles.constructor === String ) {
-
- if ( this.handles === "all" ) {
- this.handles = "n,e,s,w,se,sw,ne,nw";
- }
-
- n = this.handles.split( "," );
- this.handles = {};
-
- for ( i = 0; i < n.length; i++ ) {
-
- handle = String.prototype.trim.call( n[ i ] );
- hname = "ui-resizable-" + handle;
- axis = $( "<div>" );
- this._addClass( axis, "ui-resizable-handle " + hname );
-
- axis.css( { zIndex: o.zIndex } );
-
- this.handles[ handle ] = ".ui-resizable-" + handle;
- if ( !this.element.children( this.handles[ handle ] ).length ) {
- this.element.append( axis );
- this._addedHandles = this._addedHandles.add( axis );
- }
- }
-
- }
-
- this._renderAxis = function( target ) {
-
- var i, axis, padPos, padWrapper;
-
- target = target || this.element;
-
- for ( i in this.handles ) {
-
- if ( this.handles[ i ].constructor === String ) {
- this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
- } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
- this.handles[ i ] = $( this.handles[ i ] );
- this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
- }
-
- if ( this.elementIsWrapper &&
- this.originalElement[ 0 ]
- .nodeName
- .match( /^(textarea|input|select|button)$/i ) ) {
- axis = $( this.handles[ i ], this.element );
-
- padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
- axis.outerHeight() :
- axis.outerWidth();
-
- padPos = [ "padding",
- /ne|nw|n/.test( i ) ? "Top" :
- /se|sw|s/.test( i ) ? "Bottom" :
- /^e$/.test( i ) ? "Right" : "Left" ].join( "" );
-
- target.css( padPos, padWrapper );
-
- this._proportionallyResize();
- }
-
- this._handles = this._handles.add( this.handles[ i ] );
- }
- };
-
- // TODO: make renderAxis a prototype function
- this._renderAxis( this.element );
-
- this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
- this._handles.disableSelection();
-
- this._handles.on( "mouseover", function() {
- if ( !that.resizing ) {
- if ( this.className ) {
- axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
- }
- that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
- }
- } );
-
- if ( o.autoHide ) {
- this._handles.hide();
- this._addClass( "ui-resizable-autohide" );
- }
- },
-
- _removeHandles: function() {
- this._addedHandles.remove();
- },
-
- _mouseCapture: function( event ) {
- var i, handle,
- capture = false;
-
- for ( i in this.handles ) {
- handle = $( this.handles[ i ] )[ 0 ];
- if ( handle === event.target || $.contains( handle, event.target ) ) {
- capture = true;
- }
- }
-
- return !this.options.disabled && capture;
- },
-
- _mouseStart: function( event ) {
-
- var curleft, curtop, cursor,
- o = this.options,
- el = this.element;
-
- this.resizing = true;
-
- this._renderProxy();
-
- curleft = this._num( this.helper.css( "left" ) );
- curtop = this._num( this.helper.css( "top" ) );
-
- if ( o.containment ) {
- curleft += $( o.containment ).scrollLeft() || 0;
- curtop += $( o.containment ).scrollTop() || 0;
- }
-
- this.offset = this.helper.offset();
- this.position = { left: curleft, top: curtop };
-
- this.size = this._helper ? {
- width: this.helper.width(),
- height: this.helper.height()
- } : {
- width: el.width(),
- height: el.height()
- };
-
- this.originalSize = this._helper ? {
- width: el.outerWidth(),
- height: el.outerHeight()
- } : {
- width: el.width(),
- height: el.height()
- };
-
- this.sizeDiff = {
- width: el.outerWidth() - el.width(),
- height: el.outerHeight() - el.height()
- };
-
- this.originalPosition = { left: curleft, top: curtop };
- this.originalMousePosition = { left: event.pageX, top: event.pageY };
-
- this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
- o.aspectRatio :
- ( ( this.originalSize.width / this.originalSize.height ) || 1 );
-
- cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
- $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
-
- this._addClass( "ui-resizable-resizing" );
- this._propagate( "start", event );
- return true;
- },
-
- _mouseDrag: function( event ) {
-
- var data, props,
- smp = this.originalMousePosition,
- a = this.axis,
- dx = ( event.pageX - smp.left ) || 0,
- dy = ( event.pageY - smp.top ) || 0,
- trigger = this._change[ a ];
-
- this._updatePrevProperties();
-
- if ( !trigger ) {
- return false;
- }
-
- data = trigger.apply( this, [ event, dx, dy ] );
-
- this._updateVirtualBoundaries( event.shiftKey );
- if ( this._aspectRatio || event.shiftKey ) {
- data = this._updateRatio( data, event );
- }
-
- data = this._respectSize( data, event );
-
- this._updateCache( data );
-
- this._propagate( "resize", event );
-
- props = this._applyChanges();
-
- if ( !this._helper && this._proportionallyResizeElements.length ) {
- this._proportionallyResize();
- }
-
- if ( !$.isEmptyObject( props ) ) {
- this._updatePrevProperties();
- this._trigger( "resize", event, this.ui() );
- this._applyChanges();
- }
-
- return false;
- },
-
- _mouseStop: function( event ) {
-
- this.resizing = false;
- var pr, ista, soffseth, soffsetw, s, left, top,
- o = this.options, that = this;
-
- if ( this._helper ) {
-
- pr = this._proportionallyResizeElements;
- ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
- soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
- soffsetw = ista ? 0 : that.sizeDiff.width;
-
- s = {
- width: ( that.helper.width() - soffsetw ),
- height: ( that.helper.height() - soffseth )
- };
- left = ( parseFloat( that.element.css( "left" ) ) +
- ( that.position.left - that.originalPosition.left ) ) || null;
- top = ( parseFloat( that.element.css( "top" ) ) +
- ( that.position.top - that.originalPosition.top ) ) || null;
-
- if ( !o.animate ) {
- this.element.css( $.extend( s, { top: top, left: left } ) );
- }
-
- that.helper.height( that.size.height );
- that.helper.width( that.size.width );
-
- if ( this._helper && !o.animate ) {
- this._proportionallyResize();
- }
- }
-
- $( "body" ).css( "cursor", "auto" );
-
- this._removeClass( "ui-resizable-resizing" );
-
- this._propagate( "stop", event );
-
- if ( this._helper ) {
- this.helper.remove();
- }
-
- return false;
-
- },
-
- _updatePrevProperties: function() {
- this.prevPosition = {
- top: this.position.top,
- left: this.position.left
- };
- this.prevSize = {
- width: this.size.width,
- height: this.size.height
- };
- },
-
- _applyChanges: function() {
- var props = {};
-
- if ( this.position.top !== this.prevPosition.top ) {
- props.top = this.position.top + "px";
- }
- if ( this.position.left !== this.prevPosition.left ) {
- props.left = this.position.left + "px";
- }
- if ( this.size.width !== this.prevSize.width ) {
- props.width = this.size.width + "px";
- }
- if ( this.size.height !== this.prevSize.height ) {
- props.height = this.size.height + "px";
- }
-
- this.helper.css( props );
-
- return props;
- },
-
- _updateVirtualBoundaries: function( forceAspectRatio ) {
- var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
- o = this.options;
-
- b = {
- minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
- maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
- minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
- maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
- };
-
- if ( this._aspectRatio || forceAspectRatio ) {
- pMinWidth = b.minHeight * this.aspectRatio;
- pMinHeight = b.minWidth / this.aspectRatio;
- pMaxWidth = b.maxHeight * this.aspectRatio;
- pMaxHeight = b.maxWidth / this.aspectRatio;
-
- if ( pMinWidth > b.minWidth ) {
- b.minWidth = pMinWidth;
- }
- if ( pMinHeight > b.minHeight ) {
- b.minHeight = pMinHeight;
- }
- if ( pMaxWidth < b.maxWidth ) {
- b.maxWidth = pMaxWidth;
- }
- if ( pMaxHeight < b.maxHeight ) {
- b.maxHeight = pMaxHeight;
- }
- }
- this._vBoundaries = b;
- },
-
- _updateCache: function( data ) {
- this.offset = this.helper.offset();
- if ( this._isNumber( data.left ) ) {
- this.position.left = data.left;
- }
- if ( this._isNumber( data.top ) ) {
- this.position.top = data.top;
- }
- if ( this._isNumber( data.height ) ) {
- this.size.height = data.height;
- }
- if ( this._isNumber( data.width ) ) {
- this.size.width = data.width;
- }
- },
-
- _updateRatio: function( data ) {
-
- var cpos = this.position,
- csize = this.size,
- a = this.axis;
-
- if ( this._isNumber( data.height ) ) {
- data.width = ( data.height * this.aspectRatio );
- } else if ( this._isNumber( data.width ) ) {
- data.height = ( data.width / this.aspectRatio );
- }
-
- if ( a === "sw" ) {
- data.left = cpos.left + ( csize.width - data.width );
- data.top = null;
- }
- if ( a === "nw" ) {
- data.top = cpos.top + ( csize.height - data.height );
- data.left = cpos.left + ( csize.width - data.width );
- }
-
- return data;
- },
-
- _respectSize: function( data ) {
-
- var o = this._vBoundaries,
- a = this.axis,
- ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
- ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
- isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
- isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
- dw = this.originalPosition.left + this.originalSize.width,
- dh = this.originalPosition.top + this.originalSize.height,
- cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
- if ( isminw ) {
- data.width = o.minWidth;
- }
- if ( isminh ) {
- data.height = o.minHeight;
- }
- if ( ismaxw ) {
- data.width = o.maxWidth;
- }
- if ( ismaxh ) {
- data.height = o.maxHeight;
- }
-
- if ( isminw && cw ) {
- data.left = dw - o.minWidth;
- }
- if ( ismaxw && cw ) {
- data.left = dw - o.maxWidth;
- }
- if ( isminh && ch ) {
- data.top = dh - o.minHeight;
- }
- if ( ismaxh && ch ) {
- data.top = dh - o.maxHeight;
- }
-
- // Fixing jump error on top/left - bug #2330
- if ( !data.width && !data.height && !data.left && data.top ) {
- data.top = null;
- } else if ( !data.width && !data.height && !data.top && data.left ) {
- data.left = null;
- }
-
- return data;
- },
-
- _getPaddingPlusBorderDimensions: function( element ) {
- var i = 0,
- widths = [],
- borders = [
- element.css( "borderTopWidth" ),
- element.css( "borderRightWidth" ),
- element.css( "borderBottomWidth" ),
- element.css( "borderLeftWidth" )
- ],
- paddings = [
- element.css( "paddingTop" ),
- element.css( "paddingRight" ),
- element.css( "paddingBottom" ),
- element.css( "paddingLeft" )
- ];
-
- for ( ; i < 4; i++ ) {
- widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
- widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
- }
-
- return {
- height: widths[ 0 ] + widths[ 2 ],
- width: widths[ 1 ] + widths[ 3 ]
- };
- },
-
- _proportionallyResize: function() {
-
- if ( !this._proportionallyResizeElements.length ) {
- return;
- }
-
- var prel,
- i = 0,
- element = this.helper || this.element;
-
- for ( ; i < this._proportionallyResizeElements.length; i++ ) {
-
- prel = this._proportionallyResizeElements[ i ];
-
- // TODO: Seems like a bug to cache this.outerDimensions
- // considering that we are in a loop.
- if ( !this.outerDimensions ) {
- this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
- }
-
- prel.css( {
- height: ( element.height() - this.outerDimensions.height ) || 0,
- width: ( element.width() - this.outerDimensions.width ) || 0
- } );
-
- }
-
- },
-
- _renderProxy: function() {
-
- var el = this.element, o = this.options;
- this.elementOffset = el.offset();
-
- if ( this._helper ) {
-
- this.helper = this.helper || $( "<div></div>" ).css( { overflow: "hidden" } );
-
- this._addClass( this.helper, this._helper );
- this.helper.css( {
- width: this.element.outerWidth(),
- height: this.element.outerHeight(),
- position: "absolute",
- left: this.elementOffset.left + "px",
- top: this.elementOffset.top + "px",
- zIndex: ++o.zIndex //TODO: Don't modify option
- } );
-
- this.helper
- .appendTo( "body" )
- .disableSelection();
-
- } else {
- this.helper = this.element;
- }
-
- },
-
- _change: {
- e: function( event, dx ) {
- return { width: this.originalSize.width + dx };
- },
- w: function( event, dx ) {
- var cs = this.originalSize, sp = this.originalPosition;
- return { left: sp.left + dx, width: cs.width - dx };
- },
- n: function( event, dx, dy ) {
- var cs = this.originalSize, sp = this.originalPosition;
- return { top: sp.top + dy, height: cs.height - dy };
- },
- s: function( event, dx, dy ) {
- return { height: this.originalSize.height + dy };
- },
- se: function( event, dx, dy ) {
- return $.extend( this._change.s.apply( this, arguments ),
- this._change.e.apply( this, [ event, dx, dy ] ) );
- },
- sw: function( event, dx, dy ) {
- return $.extend( this._change.s.apply( this, arguments ),
- this._change.w.apply( this, [ event, dx, dy ] ) );
- },
- ne: function( event, dx, dy ) {
- return $.extend( this._change.n.apply( this, arguments ),
- this._change.e.apply( this, [ event, dx, dy ] ) );
- },
- nw: function( event, dx, dy ) {
- return $.extend( this._change.n.apply( this, arguments ),
- this._change.w.apply( this, [ event, dx, dy ] ) );
- }
- },
-
- _propagate: function( n, event ) {
- $.ui.plugin.call( this, n, [ event, this.ui() ] );
- if ( n !== "resize" ) {
- this._trigger( n, event, this.ui() );
- }
- },
-
- plugins: {},
-
- ui: function() {
- return {
- originalElement: this.originalElement,
- element: this.element,
- helper: this.helper,
- position: this.position,
- size: this.size,
- originalSize: this.originalSize,
- originalPosition: this.originalPosition
- };
- }
-
-} );
-
-/*
- * Resizable Extensions
- */
-
-$.ui.plugin.add( "resizable", "animate", {
-
- stop: function( event ) {
- var that = $( this ).resizable( "instance" ),
- o = that.options,
- pr = that._proportionallyResizeElements,
- ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
- soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
- soffsetw = ista ? 0 : that.sizeDiff.width,
- style = {
- width: ( that.size.width - soffsetw ),
- height: ( that.size.height - soffseth )
- },
- left = ( parseFloat( that.element.css( "left" ) ) +
- ( that.position.left - that.originalPosition.left ) ) || null,
- top = ( parseFloat( that.element.css( "top" ) ) +
- ( that.position.top - that.originalPosition.top ) ) || null;
-
- that.element.animate(
- $.extend( style, top && left ? { top: top, left: left } : {} ), {
- duration: o.animateDuration,
- easing: o.animateEasing,
- step: function() {
-
- var data = {
- width: parseFloat( that.element.css( "width" ) ),
- height: parseFloat( that.element.css( "height" ) ),
- top: parseFloat( that.element.css( "top" ) ),
- left: parseFloat( that.element.css( "left" ) )
- };
-
- if ( pr && pr.length ) {
- $( pr[ 0 ] ).css( { width: data.width, height: data.height } );
- }
-
- // Propagating resize, and updating values for each animation step
- that._updateCache( data );
- that._propagate( "resize", event );
-
- }
- }
- );
- }
-
-} );
-
-$.ui.plugin.add( "resizable", "containment", {
-
- start: function() {
- var element, p, co, ch, cw, width, height,
- that = $( this ).resizable( "instance" ),
- o = that.options,
- el = that.element,
- oc = o.containment,
- ce = ( oc instanceof $ ) ?
- oc.get( 0 ) :
- ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
-
- if ( !ce ) {
- return;
- }
-
- that.containerElement = $( ce );
-
- if ( /document/.test( oc ) || oc === document ) {
- that.containerOffset = {
- left: 0,
- top: 0
- };
- that.containerPosition = {
- left: 0,
- top: 0
- };
-
- that.parentData = {
- element: $( document ),
- left: 0,
- top: 0,
- width: $( document ).width(),
- height: $( document ).height() || document.body.parentNode.scrollHeight
- };
- } else {
- element = $( ce );
- p = [];
- $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
- p[ i ] = that._num( element.css( "padding" + name ) );
- } );
-
- that.containerOffset = element.offset();
- that.containerPosition = element.position();
- that.containerSize = {
- height: ( element.innerHeight() - p[ 3 ] ),
- width: ( element.innerWidth() - p[ 1 ] )
- };
-
- co = that.containerOffset;
- ch = that.containerSize.height;
- cw = that.containerSize.width;
- width = ( that._hasScroll( ce, "left" ) ? ce.scrollWidth : cw );
- height = ( that._hasScroll( ce ) ? ce.scrollHeight : ch );
-
- that.parentData = {
- element: ce,
- left: co.left,
- top: co.top,
- width: width,
- height: height
- };
- }
- },
-
- resize: function( event ) {
- var woset, hoset, isParent, isOffsetRelative,
- that = $( this ).resizable( "instance" ),
- o = that.options,
- co = that.containerOffset,
- cp = that.position,
- pRatio = that._aspectRatio || event.shiftKey,
- cop = {
- top: 0,
- left: 0
- },
- ce = that.containerElement,
- continueResize = true;
-
- if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
- cop = co;
- }
-
- if ( cp.left < ( that._helper ? co.left : 0 ) ) {
- that.size.width = that.size.width +
- ( that._helper ?
- ( that.position.left - co.left ) :
- ( that.position.left - cop.left ) );
-
- if ( pRatio ) {
- that.size.height = that.size.width / that.aspectRatio;
- continueResize = false;
- }
- that.position.left = o.helper ? co.left : 0;
- }
-
- if ( cp.top < ( that._helper ? co.top : 0 ) ) {
- that.size.height = that.size.height +
- ( that._helper ?
- ( that.position.top - co.top ) :
- that.position.top );
-
- if ( pRatio ) {
- that.size.width = that.size.height * that.aspectRatio;
- continueResize = false;
- }
- that.position.top = that._helper ? co.top : 0;
- }
-
- isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
- isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
-
- if ( isParent && isOffsetRelative ) {
- that.offset.left = that.parentData.left + that.position.left;
- that.offset.top = that.parentData.top + that.position.top;
- } else {
- that.offset.left = that.element.offset().left;
- that.offset.top = that.element.offset().top;
- }
-
- woset = Math.abs( that.sizeDiff.width +
- ( that._helper ?
- that.offset.left - cop.left :
- ( that.offset.left - co.left ) ) );
-
- hoset = Math.abs( that.sizeDiff.height +
- ( that._helper ?
- that.offset.top - cop.top :
- ( that.offset.top - co.top ) ) );
-
- if ( woset + that.size.width >= that.parentData.width ) {
- that.size.width = that.parentData.width - woset;
- if ( pRatio ) {
- that.size.height = that.size.width / that.aspectRatio;
- continueResize = false;
- }
- }
-
- if ( hoset + that.size.height >= that.parentData.height ) {
- that.size.height = that.parentData.height - hoset;
- if ( pRatio ) {
- that.size.width = that.size.height * that.aspectRatio;
- continueResize = false;
- }
- }
-
- if ( !continueResize ) {
- that.position.left = that.prevPosition.left;
- that.position.top = that.prevPosition.top;
- that.size.width = that.prevSize.width;
- that.size.height = that.prevSize.height;
- }
- },
-
- stop: function() {
- var that = $( this ).resizable( "instance" ),
- o = that.options,
- co = that.containerOffset,
- cop = that.containerPosition,
- ce = that.containerElement,
- helper = $( that.helper ),
- ho = helper.offset(),
- w = helper.outerWidth() - that.sizeDiff.width,
- h = helper.outerHeight() - that.sizeDiff.height;
-
- if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
- $( this ).css( {
- left: ho.left - cop.left - co.left,
- width: w,
- height: h
- } );
- }
-
- if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
- $( this ).css( {
- left: ho.left - cop.left - co.left,
- width: w,
- height: h
- } );
- }
- }
-} );
-
-$.ui.plugin.add( "resizable", "alsoResize", {
-
- start: function() {
- var that = $( this ).resizable( "instance" ),
- o = that.options;
-
- $( o.alsoResize ).each( function() {
- var el = $( this );
- el.data( "ui-resizable-alsoresize", {
- width: parseFloat( el.width() ), height: parseFloat( el.height() ),
- left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
- } );
- } );
- },
-
- resize: function( event, ui ) {
- var that = $( this ).resizable( "instance" ),
- o = that.options,
- os = that.originalSize,
- op = that.originalPosition,
- delta = {
- height: ( that.size.height - os.height ) || 0,
- width: ( that.size.width - os.width ) || 0,
- top: ( that.position.top - op.top ) || 0,
- left: ( that.position.left - op.left ) || 0
- };
-
- $( o.alsoResize ).each( function() {
- var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
- css = el.parents( ui.originalElement[ 0 ] ).length ?
- [ "width", "height" ] :
- [ "width", "height", "top", "left" ];
-
- $.each( css, function( i, prop ) {
- var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
- if ( sum && sum >= 0 ) {
- style[ prop ] = sum || null;
- }
- } );
-
- el.css( style );
- } );
- },
-
- stop: function() {
- $( this ).removeData( "ui-resizable-alsoresize" );
- }
-} );
-
-$.ui.plugin.add( "resizable", "ghost", {
-
- start: function() {
-
- var that = $( this ).resizable( "instance" ), cs = that.size;
-
- that.ghost = that.originalElement.clone();
- that.ghost.css( {
- opacity: 0.25,
- display: "block",
- position: "relative",
- height: cs.height,
- width: cs.width,
- margin: 0,
- left: 0,
- top: 0
- } );
-
- that._addClass( that.ghost, "ui-resizable-ghost" );
-
- // DEPRECATED
- // TODO: remove after 1.12
- if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {
-
- // Ghost option
- that.ghost.addClass( this.options.ghost );
- }
-
- that.ghost.appendTo( that.helper );
-
- },
-
- resize: function() {
- var that = $( this ).resizable( "instance" );
- if ( that.ghost ) {
- that.ghost.css( {
- position: "relative",
- height: that.size.height,
- width: that.size.width
- } );
- }
- },
-
- stop: function() {
- var that = $( this ).resizable( "instance" );
- if ( that.ghost && that.helper ) {
- that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
- }
- }
-
-} );
-
-$.ui.plugin.add( "resizable", "grid", {
-
- resize: function() {
- var outerDimensions,
- that = $( this ).resizable( "instance" ),
- o = that.options,
- cs = that.size,
- os = that.originalSize,
- op = that.originalPosition,
- a = that.axis,
- grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
- gridX = ( grid[ 0 ] || 1 ),
- gridY = ( grid[ 1 ] || 1 ),
- ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
- oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
- newWidth = os.width + ox,
- newHeight = os.height + oy,
- isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
- isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
- isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
- isMinHeight = o.minHeight && ( o.minHeight > newHeight );
-
- o.grid = grid;
-
- if ( isMinWidth ) {
- newWidth += gridX;
- }
- if ( isMinHeight ) {
- newHeight += gridY;
- }
- if ( isMaxWidth ) {
- newWidth -= gridX;
- }
- if ( isMaxHeight ) {
- newHeight -= gridY;
- }
-
- if ( /^(se|s|e)$/.test( a ) ) {
- that.size.width = newWidth;
- that.size.height = newHeight;
- } else if ( /^(ne)$/.test( a ) ) {
- that.size.width = newWidth;
- that.size.height = newHeight;
- that.position.top = op.top - oy;
- } else if ( /^(sw)$/.test( a ) ) {
- that.size.width = newWidth;
- that.size.height = newHeight;
- that.position.left = op.left - ox;
- } else {
- if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
- outerDimensions = that._getPaddingPlusBorderDimensions( this );
- }
-
- if ( newHeight - gridY > 0 ) {
- that.size.height = newHeight;
- that.position.top = op.top - oy;
- } else {
- newHeight = gridY - outerDimensions.height;
- that.size.height = newHeight;
- that.position.top = op.top + os.height - newHeight;
- }
- if ( newWidth - gridX > 0 ) {
- that.size.width = newWidth;
- that.position.left = op.left - ox;
- } else {
- newWidth = gridX - outerDimensions.width;
- that.size.width = newWidth;
- that.position.left = op.left + os.width - newWidth;
- }
- }
- }
-
-} );
-
-var widgetsResizable = $.ui.resizable;
-
-
-/*!
- * jQuery UI Dialog 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Dialog
-//>>group: Widgets
-//>>description: Displays customizable dialog windows.
-//>>docs: http://api.jqueryui.com/dialog/
-//>>demos: http://jqueryui.com/dialog/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/dialog.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-$.widget( "ui.dialog", {
- version: "1.13.1",
- options: {
- appendTo: "body",
- autoOpen: true,
- buttons: [],
- classes: {
- "ui-dialog": "ui-corner-all",
- "ui-dialog-titlebar": "ui-corner-all"
- },
- closeOnEscape: true,
- closeText: "Close",
- draggable: true,
- hide: null,
- height: "auto",
- maxHeight: null,
- maxWidth: null,
- minHeight: 150,
- minWidth: 150,
- modal: false,
- position: {
- my: "center",
- at: "center",
- of: window,
- collision: "fit",
-
- // Ensure the titlebar is always visible
- using: function( pos ) {
- var topOffset = $( this ).css( pos ).offset().top;
- if ( topOffset < 0 ) {
- $( this ).css( "top", pos.top - topOffset );
- }
- }
- },
- resizable: true,
- show: null,
- title: null,
- width: 300,
-
- // Callbacks
- beforeClose: null,
- close: null,
- drag: null,
- dragStart: null,
- dragStop: null,
- focus: null,
- open: null,
- resize: null,
- resizeStart: null,
- resizeStop: null
- },
-
- sizeRelatedOptions: {
- buttons: true,
- height: true,
- maxHeight: true,
- maxWidth: true,
- minHeight: true,
- minWidth: true,
- width: true
- },
-
- resizableRelatedOptions: {
- maxHeight: true,
- maxWidth: true,
- minHeight: true,
- minWidth: true
- },
-
- _create: function() {
- this.originalCss = {
- display: this.element[ 0 ].style.display,
- width: this.element[ 0 ].style.width,
- minHeight: this.element[ 0 ].style.minHeight,
- maxHeight: this.element[ 0 ].style.maxHeight,
- height: this.element[ 0 ].style.height
- };
- this.originalPosition = {
- parent: this.element.parent(),
- index: this.element.parent().children().index( this.element )
- };
- this.originalTitle = this.element.attr( "title" );
- if ( this.options.title == null && this.originalTitle != null ) {
- this.options.title = this.originalTitle;
- }
-
- // Dialogs can't be disabled
- if ( this.options.disabled ) {
- this.options.disabled = false;
- }
-
- this._createWrapper();
-
- this.element
- .show()
- .removeAttr( "title" )
- .appendTo( this.uiDialog );
-
- this._addClass( "ui-dialog-content", "ui-widget-content" );
-
- this._createTitlebar();
- this._createButtonPane();
-
- if ( this.options.draggable && $.fn.draggable ) {
- this._makeDraggable();
- }
- if ( this.options.resizable && $.fn.resizable ) {
- this._makeResizable();
- }
-
- this._isOpen = false;
-
- this._trackFocus();
- },
-
- _init: function() {
- if ( this.options.autoOpen ) {
- this.open();
- }
- },
-
- _appendTo: function() {
- var element = this.options.appendTo;
- if ( element && ( element.jquery || element.nodeType ) ) {
- return $( element );
- }
- return this.document.find( element || "body" ).eq( 0 );
- },
-
- _destroy: function() {
- var next,
- originalPosition = this.originalPosition;
-
- this._untrackInstance();
- this._destroyOverlay();
-
- this.element
- .removeUniqueId()
- .css( this.originalCss )
-
- // Without detaching first, the following becomes really slow
- .detach();
-
- this.uiDialog.remove();
-
- if ( this.originalTitle ) {
- this.element.attr( "title", this.originalTitle );
- }
-
- next = originalPosition.parent.children().eq( originalPosition.index );
-
- // Don't try to place the dialog next to itself (#8613)
- if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
- next.before( this.element );
- } else {
- originalPosition.parent.append( this.element );
- }
- },
-
- widget: function() {
- return this.uiDialog;
- },
-
- disable: $.noop,
- enable: $.noop,
-
- close: function( event ) {
- var that = this;
-
- if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
- return;
- }
-
- this._isOpen = false;
- this._focusedElement = null;
- this._destroyOverlay();
- this._untrackInstance();
-
- if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) {
-
- // Hiding a focused element doesn't trigger blur in WebKit
- // so in case we have nothing to focus on, explicitly blur the active element
- // https://bugs.webkit.org/show_bug.cgi?id=47182
- $.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) );
- }
-
- this._hide( this.uiDialog, this.options.hide, function() {
- that._trigger( "close", event );
- } );
- },
-
- isOpen: function() {
- return this._isOpen;
- },
-
- moveToTop: function() {
- this._moveToTop();
- },
-
- _moveToTop: function( event, silent ) {
- var moved = false,
- zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() {
- return +$( this ).css( "z-index" );
- } ).get(),
- zIndexMax = Math.max.apply( null, zIndices );
-
- if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
- this.uiDialog.css( "z-index", zIndexMax + 1 );
- moved = true;
- }
-
- if ( moved && !silent ) {
- this._trigger( "focus", event );
- }
- return moved;
- },
-
- open: function() {
- var that = this;
- if ( this._isOpen ) {
- if ( this._moveToTop() ) {
- this._focusTabbable();
- }
- return;
- }
-
- this._isOpen = true;
- this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
-
- this._size();
- this._position();
- this._createOverlay();
- this._moveToTop( null, true );
-
- // Ensure the overlay is moved to the top with the dialog, but only when
- // opening. The overlay shouldn't move after the dialog is open so that
- // modeless dialogs opened after the modal dialog stack properly.
- if ( this.overlay ) {
- this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
- }
-
- this._show( this.uiDialog, this.options.show, function() {
- that._focusTabbable();
- that._trigger( "focus" );
- } );
-
- // Track the dialog immediately upon opening in case a focus event
- // somehow occurs outside of the dialog before an element inside the
- // dialog is focused (#10152)
- this._makeFocusTarget();
-
- this._trigger( "open" );
- },
-
- _focusTabbable: function() {
-
- // Set focus to the first match:
- // 1. An element that was focused previously
- // 2. First element inside the dialog matching [autofocus]
- // 3. Tabbable element inside the content element
- // 4. Tabbable element inside the buttonpane
- // 5. The close button
- // 6. The dialog itself
- var hasFocus = this._focusedElement;
- if ( !hasFocus ) {
- hasFocus = this.element.find( "[autofocus]" );
- }
- if ( !hasFocus.length ) {
- hasFocus = this.element.find( ":tabbable" );
- }
- if ( !hasFocus.length ) {
- hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
- }
- if ( !hasFocus.length ) {
- hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
- }
- if ( !hasFocus.length ) {
- hasFocus = this.uiDialog;
- }
- hasFocus.eq( 0 ).trigger( "focus" );
- },
-
- _restoreTabbableFocus: function() {
- var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
- isActive = this.uiDialog[ 0 ] === activeElement ||
- $.contains( this.uiDialog[ 0 ], activeElement );
- if ( !isActive ) {
- this._focusTabbable();
- }
- },
-
- _keepFocus: function( event ) {
- event.preventDefault();
- this._restoreTabbableFocus();
-
- // support: IE
- // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
- // so we check again later
- this._delay( this._restoreTabbableFocus );
- },
-
- _createWrapper: function() {
- this.uiDialog = $( "<div>" )
- .hide()
- .attr( {
-
- // Setting tabIndex makes the div focusable
- tabIndex: -1,
- role: "dialog"
- } )
- .appendTo( this._appendTo() );
-
- this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" );
- this._on( this.uiDialog, {
- keydown: function( event ) {
- if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
- event.keyCode === $.ui.keyCode.ESCAPE ) {
- event.preventDefault();
- this.close( event );
- return;
- }
-
- // Prevent tabbing out of dialogs
- if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
- return;
- }
- var tabbables = this.uiDialog.find( ":tabbable" ),
- first = tabbables.first(),
- last = tabbables.last();
-
- if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) &&
- !event.shiftKey ) {
- this._delay( function() {
- first.trigger( "focus" );
- } );
- event.preventDefault();
- } else if ( ( event.target === first[ 0 ] ||
- event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) {
- this._delay( function() {
- last.trigger( "focus" );
- } );
- event.preventDefault();
- }
- },
- mousedown: function( event ) {
- if ( this._moveToTop( event ) ) {
- this._focusTabbable();
- }
- }
- } );
-
- // We assume that any existing aria-describedby attribute means
- // that the dialog content is marked up properly
- // otherwise we brute force the content as the description
- if ( !this.element.find( "[aria-describedby]" ).length ) {
- this.uiDialog.attr( {
- "aria-describedby": this.element.uniqueId().attr( "id" )
- } );
- }
- },
-
- _createTitlebar: function() {
- var uiDialogTitle;
-
- this.uiDialogTitlebar = $( "<div>" );
- this._addClass( this.uiDialogTitlebar,
- "ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" );
- this._on( this.uiDialogTitlebar, {
- mousedown: function( event ) {
-
- // Don't prevent click on close button (#8838)
- // Focusing a dialog that is partially scrolled out of view
- // causes the browser to scroll it into view, preventing the click event
- if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
-
- // Dialog isn't getting focus when dragging (#8063)
- this.uiDialog.trigger( "focus" );
- }
- }
- } );
-
- // Support: IE
- // Use type="button" to prevent enter keypresses in textboxes from closing the
- // dialog in IE (#9312)
- this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
- .button( {
- label: $( "<a>" ).text( this.options.closeText ).html(),
- icon: "ui-icon-closethick",
- showLabel: false
- } )
- .appendTo( this.uiDialogTitlebar );
-
- this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" );
- this._on( this.uiDialogTitlebarClose, {
- click: function( event ) {
- event.preventDefault();
- this.close( event );
- }
- } );
-
- uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
- this._addClass( uiDialogTitle, "ui-dialog-title" );
- this._title( uiDialogTitle );
-
- this.uiDialogTitlebar.prependTo( this.uiDialog );
-
- this.uiDialog.attr( {
- "aria-labelledby": uiDialogTitle.attr( "id" )
- } );
- },
-
- _title: function( title ) {
- if ( this.options.title ) {
- title.text( this.options.title );
- } else {
- title.html( "&#160;" );
- }
- },
-
- _createButtonPane: function() {
- this.uiDialogButtonPane = $( "<div>" );
- this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane",
- "ui-widget-content ui-helper-clearfix" );
-
- this.uiButtonSet = $( "<div>" )
- .appendTo( this.uiDialogButtonPane );
- this._addClass( this.uiButtonSet, "ui-dialog-buttonset" );
-
- this._createButtons();
- },
-
- _createButtons: function() {
- var that = this,
- buttons = this.options.buttons;
-
- // If we already have a button pane, remove it
- this.uiDialogButtonPane.remove();
- this.uiButtonSet.empty();
-
- if ( $.isEmptyObject( buttons ) || ( Array.isArray( buttons ) && !buttons.length ) ) {
- this._removeClass( this.uiDialog, "ui-dialog-buttons" );
- return;
- }
-
- $.each( buttons, function( name, props ) {
- var click, buttonOptions;
- props = typeof props === "function" ?
- { click: props, text: name } :
- props;
-
- // Default to a non-submitting button
- props = $.extend( { type: "button" }, props );
-
- // Change the context for the click callback to be the main element
- click = props.click;
- buttonOptions = {
- icon: props.icon,
- iconPosition: props.iconPosition,
- showLabel: props.showLabel,
-
- // Deprecated options
- icons: props.icons,
- text: props.text
- };
-
- delete props.click;
- delete props.icon;
- delete props.iconPosition;
- delete props.showLabel;
-
- // Deprecated options
- delete props.icons;
- if ( typeof props.text === "boolean" ) {
- delete props.text;
- }
-
- $( "<button></button>", props )
- .button( buttonOptions )
- .appendTo( that.uiButtonSet )
- .on( "click", function() {
- click.apply( that.element[ 0 ], arguments );
- } );
- } );
- this._addClass( this.uiDialog, "ui-dialog-buttons" );
- this.uiDialogButtonPane.appendTo( this.uiDialog );
- },
-
- _makeDraggable: function() {
- var that = this,
- options = this.options;
-
- function filteredUi( ui ) {
- return {
- position: ui.position,
- offset: ui.offset
- };
- }
-
- this.uiDialog.draggable( {
- cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
- handle: ".ui-dialog-titlebar",
- containment: "document",
- start: function( event, ui ) {
- that._addClass( $( this ), "ui-dialog-dragging" );
- that._blockFrames();
- that._trigger( "dragStart", event, filteredUi( ui ) );
- },
- drag: function( event, ui ) {
- that._trigger( "drag", event, filteredUi( ui ) );
- },
- stop: function( event, ui ) {
- var left = ui.offset.left - that.document.scrollLeft(),
- top = ui.offset.top - that.document.scrollTop();
-
- options.position = {
- my: "left top",
- at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
- "top" + ( top >= 0 ? "+" : "" ) + top,
- of: that.window
- };
- that._removeClass( $( this ), "ui-dialog-dragging" );
- that._unblockFrames();
- that._trigger( "dragStop", event, filteredUi( ui ) );
- }
- } );
- },
-
- _makeResizable: function() {
- var that = this,
- options = this.options,
- handles = options.resizable,
-
- // .ui-resizable has position: relative defined in the stylesheet
- // but dialogs have to use absolute or fixed positioning
- position = this.uiDialog.css( "position" ),
- resizeHandles = typeof handles === "string" ?
- handles :
- "n,e,s,w,se,sw,ne,nw";
-
- function filteredUi( ui ) {
- return {
- originalPosition: ui.originalPosition,
- originalSize: ui.originalSize,
- position: ui.position,
- size: ui.size
- };
- }
-
- this.uiDialog.resizable( {
- cancel: ".ui-dialog-content",
- containment: "document",
- alsoResize: this.element,
- maxWidth: options.maxWidth,
- maxHeight: options.maxHeight,
- minWidth: options.minWidth,
- minHeight: this._minHeight(),
- handles: resizeHandles,
- start: function( event, ui ) {
- that._addClass( $( this ), "ui-dialog-resizing" );
- that._blockFrames();
- that._trigger( "resizeStart", event, filteredUi( ui ) );
- },
- resize: function( event, ui ) {
- that._trigger( "resize", event, filteredUi( ui ) );
- },
- stop: function( event, ui ) {
- var offset = that.uiDialog.offset(),
- left = offset.left - that.document.scrollLeft(),
- top = offset.top - that.document.scrollTop();
-
- options.height = that.uiDialog.height();
- options.width = that.uiDialog.width();
- options.position = {
- my: "left top",
- at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
- "top" + ( top >= 0 ? "+" : "" ) + top,
- of: that.window
- };
- that._removeClass( $( this ), "ui-dialog-resizing" );
- that._unblockFrames();
- that._trigger( "resizeStop", event, filteredUi( ui ) );
- }
- } )
- .css( "position", position );
- },
-
- _trackFocus: function() {
- this._on( this.widget(), {
- focusin: function( event ) {
- this._makeFocusTarget();
- this._focusedElement = $( event.target );
- }
- } );
- },
-
- _makeFocusTarget: function() {
- this._untrackInstance();
- this._trackingInstances().unshift( this );
- },
-
- _untrackInstance: function() {
- var instances = this._trackingInstances(),
- exists = $.inArray( this, instances );
- if ( exists !== -1 ) {
- instances.splice( exists, 1 );
- }
- },
-
- _trackingInstances: function() {
- var instances = this.document.data( "ui-dialog-instances" );
- if ( !instances ) {
- instances = [];
- this.document.data( "ui-dialog-instances", instances );
- }
- return instances;
- },
-
- _minHeight: function() {
- var options = this.options;
-
- return options.height === "auto" ?
- options.minHeight :
- Math.min( options.minHeight, options.height );
- },
-
- _position: function() {
-
- // Need to show the dialog to get the actual offset in the position plugin
- var isVisible = this.uiDialog.is( ":visible" );
- if ( !isVisible ) {
- this.uiDialog.show();
- }
- this.uiDialog.position( this.options.position );
- if ( !isVisible ) {
- this.uiDialog.hide();
- }
- },
-
- _setOptions: function( options ) {
- var that = this,
- resize = false,
- resizableOptions = {};
-
- $.each( options, function( key, value ) {
- that._setOption( key, value );
-
- if ( key in that.sizeRelatedOptions ) {
- resize = true;
- }
- if ( key in that.resizableRelatedOptions ) {
- resizableOptions[ key ] = value;
- }
- } );
-
- if ( resize ) {
- this._size();
- this._position();
- }
- if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
- this.uiDialog.resizable( "option", resizableOptions );
- }
- },
-
- _setOption: function( key, value ) {
- var isDraggable, isResizable,
- uiDialog = this.uiDialog;
-
- if ( key === "disabled" ) {
- return;
- }
-
- this._super( key, value );
-
- if ( key === "appendTo" ) {
- this.uiDialog.appendTo( this._appendTo() );
- }
-
- if ( key === "buttons" ) {
- this._createButtons();
- }
-
- if ( key === "closeText" ) {
- this.uiDialogTitlebarClose.button( {
-
- // Ensure that we always pass a string
- label: $( "<a>" ).text( "" + this.options.closeText ).html()
- } );
- }
-
- if ( key === "draggable" ) {
- isDraggable = uiDialog.is( ":data(ui-draggable)" );
- if ( isDraggable && !value ) {
- uiDialog.draggable( "destroy" );
- }
-
- if ( !isDraggable && value ) {
- this._makeDraggable();
- }
- }
-
- if ( key === "position" ) {
- this._position();
- }
-
- if ( key === "resizable" ) {
-
- // currently resizable, becoming non-resizable
- isResizable = uiDialog.is( ":data(ui-resizable)" );
- if ( isResizable && !value ) {
- uiDialog.resizable( "destroy" );
- }
-
- // Currently resizable, changing handles
- if ( isResizable && typeof value === "string" ) {
- uiDialog.resizable( "option", "handles", value );
- }
-
- // Currently non-resizable, becoming resizable
- if ( !isResizable && value !== false ) {
- this._makeResizable();
- }
- }
-
- if ( key === "title" ) {
- this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
- }
- },
-
- _size: function() {
-
- // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
- // divs will both have width and height set, so we need to reset them
- var nonContentHeight, minContentHeight, maxContentHeight,
- options = this.options;
-
- // Reset content sizing
- this.element.show().css( {
- width: "auto",
- minHeight: 0,
- maxHeight: "none",
- height: 0
- } );
-
- if ( options.minWidth > options.width ) {
- options.width = options.minWidth;
- }
-
- // Reset wrapper sizing
- // determine the height of all the non-content elements
- nonContentHeight = this.uiDialog.css( {
- height: "auto",
- width: options.width
- } )
- .outerHeight();
- minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
- maxContentHeight = typeof options.maxHeight === "number" ?
- Math.max( 0, options.maxHeight - nonContentHeight ) :
- "none";
-
- if ( options.height === "auto" ) {
- this.element.css( {
- minHeight: minContentHeight,
- maxHeight: maxContentHeight,
- height: "auto"
- } );
- } else {
- this.element.height( Math.max( 0, options.height - nonContentHeight ) );
- }
-
- if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
- this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
- }
- },
-
- _blockFrames: function() {
- this.iframeBlocks = this.document.find( "iframe" ).map( function() {
- var iframe = $( this );
-
- return $( "<div>" )
- .css( {
- position: "absolute",
- width: iframe.outerWidth(),
- height: iframe.outerHeight()
- } )
- .appendTo( iframe.parent() )
- .offset( iframe.offset() )[ 0 ];
- } );
- },
-
- _unblockFrames: function() {
- if ( this.iframeBlocks ) {
- this.iframeBlocks.remove();
- delete this.iframeBlocks;
- }
- },
-
- _allowInteraction: function( event ) {
- if ( $( event.target ).closest( ".ui-dialog" ).length ) {
- return true;
- }
-
- // TODO: Remove hack when datepicker implements
- // the .ui-front logic (#8989)
- return !!$( event.target ).closest( ".ui-datepicker" ).length;
- },
-
- _createOverlay: function() {
- if ( !this.options.modal ) {
- return;
- }
-
- var jqMinor = $.fn.jquery.substring( 0, 4 );
-
- // We use a delay in case the overlay is created from an
- // event that we're going to be cancelling (#2804)
- var isOpening = true;
- this._delay( function() {
- isOpening = false;
- } );
-
- if ( !this.document.data( "ui-dialog-overlays" ) ) {
-
- // Prevent use of anchors and inputs
- // This doesn't use `_on()` because it is a shared event handler
- // across all open modal dialogs.
- this.document.on( "focusin.ui-dialog", function( event ) {
- if ( isOpening ) {
- return;
- }
-
- var instance = this._trackingInstances()[ 0 ];
- if ( !instance._allowInteraction( event ) ) {
- event.preventDefault();
- instance._focusTabbable();
-
- // Support: jQuery >=3.4 <3.6 only
- // Focus re-triggering in jQuery 3.4/3.5 makes the original element
- // have its focus event propagated last, breaking the re-targeting.
- // Trigger focus in a delay in addition if needed to avoid the issue
- // See https://github.com/jquery/jquery/issues/4382
- if ( jqMinor === "3.4." || jqMinor === "3.5." ) {
- instance._delay( instance._restoreTabbableFocus );
- }
- }
- }.bind( this ) );
- }
-
- this.overlay = $( "<div>" )
- .appendTo( this._appendTo() );
-
- this._addClass( this.overlay, null, "ui-widget-overlay ui-front" );
- this._on( this.overlay, {
- mousedown: "_keepFocus"
- } );
- this.document.data( "ui-dialog-overlays",
- ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 );
- },
-
- _destroyOverlay: function() {
- if ( !this.options.modal ) {
- return;
- }
-
- if ( this.overlay ) {
- var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
-
- if ( !overlays ) {
- this.document.off( "focusin.ui-dialog" );
- this.document.removeData( "ui-dialog-overlays" );
- } else {
- this.document.data( "ui-dialog-overlays", overlays );
- }
-
- this.overlay.remove();
- this.overlay = null;
- }
- }
-} );
-
-// DEPRECATED
-// TODO: switch return back to widget declaration at top of file when this is removed
-if ( $.uiBackCompat !== false ) {
-
- // Backcompat for dialogClass option
- $.widget( "ui.dialog", $.ui.dialog, {
- options: {
- dialogClass: ""
- },
- _createWrapper: function() {
- this._super();
- this.uiDialog.addClass( this.options.dialogClass );
- },
- _setOption: function( key, value ) {
- if ( key === "dialogClass" ) {
- this.uiDialog
- .removeClass( this.options.dialogClass )
- .addClass( value );
- }
- this._superApply( arguments );
- }
- } );
-}
-
-var widgetsDialog = $.ui.dialog;
-
-
-/*!
- * jQuery UI Droppable 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Droppable
-//>>group: Interactions
-//>>description: Enables drop targets for draggable elements.
-//>>docs: http://api.jqueryui.com/droppable/
-//>>demos: http://jqueryui.com/droppable/
-
-
-$.widget( "ui.droppable", {
- version: "1.13.1",
- widgetEventPrefix: "drop",
- options: {
- accept: "*",
- addClasses: true,
- greedy: false,
- scope: "default",
- tolerance: "intersect",
-
- // Callbacks
- activate: null,
- deactivate: null,
- drop: null,
- out: null,
- over: null
- },
- _create: function() {
-
- var proportions,
- o = this.options,
- accept = o.accept;
-
- this.isover = false;
- this.isout = true;
-
- this.accept = typeof accept === "function" ? accept : function( d ) {
- return d.is( accept );
- };
-
- this.proportions = function( /* valueToWrite */ ) {
- if ( arguments.length ) {
-
- // Store the droppable's proportions
- proportions = arguments[ 0 ];
- } else {
-
- // Retrieve or derive the droppable's proportions
- return proportions ?
- proportions :
- proportions = {
- width: this.element[ 0 ].offsetWidth,
- height: this.element[ 0 ].offsetHeight
- };
- }
- };
-
- this._addToManager( o.scope );
-
- if ( o.addClasses ) {
- this._addClass( "ui-droppable" );
- }
-
- },
-
- _addToManager: function( scope ) {
-
- // Add the reference and positions to the manager
- $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
- $.ui.ddmanager.droppables[ scope ].push( this );
- },
-
- _splice: function( drop ) {
- var i = 0;
- for ( ; i < drop.length; i++ ) {
- if ( drop[ i ] === this ) {
- drop.splice( i, 1 );
- }
- }
- },
-
- _destroy: function() {
- var drop = $.ui.ddmanager.droppables[ this.options.scope ];
-
- this._splice( drop );
- },
-
- _setOption: function( key, value ) {
-
- if ( key === "accept" ) {
- this.accept = typeof value === "function" ? value : function( d ) {
- return d.is( value );
- };
- } else if ( key === "scope" ) {
- var drop = $.ui.ddmanager.droppables[ this.options.scope ];
-
- this._splice( drop );
- this._addToManager( value );
- }
-
- this._super( key, value );
- },
-
- _activate: function( event ) {
- var draggable = $.ui.ddmanager.current;
-
- this._addActiveClass();
- if ( draggable ) {
- this._trigger( "activate", event, this.ui( draggable ) );
- }
- },
-
- _deactivate: function( event ) {
- var draggable = $.ui.ddmanager.current;
-
- this._removeActiveClass();
- if ( draggable ) {
- this._trigger( "deactivate", event, this.ui( draggable ) );
- }
- },
-
- _over: function( event ) {
-
- var draggable = $.ui.ddmanager.current;
-
- // Bail if draggable and droppable are same element
- if ( !draggable || ( draggable.currentItem ||
- draggable.element )[ 0 ] === this.element[ 0 ] ) {
- return;
- }
-
- if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
- draggable.element ) ) ) {
- this._addHoverClass();
- this._trigger( "over", event, this.ui( draggable ) );
- }
-
- },
-
- _out: function( event ) {
-
- var draggable = $.ui.ddmanager.current;
-
- // Bail if draggable and droppable are same element
- if ( !draggable || ( draggable.currentItem ||
- draggable.element )[ 0 ] === this.element[ 0 ] ) {
- return;
- }
-
- if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
- draggable.element ) ) ) {
- this._removeHoverClass();
- this._trigger( "out", event, this.ui( draggable ) );
- }
-
- },
-
- _drop: function( event, custom ) {
-
- var draggable = custom || $.ui.ddmanager.current,
- childrenIntersection = false;
-
- // Bail if draggable and droppable are same element
- if ( !draggable || ( draggable.currentItem ||
- draggable.element )[ 0 ] === this.element[ 0 ] ) {
- return false;
- }
-
- this.element
- .find( ":data(ui-droppable)" )
- .not( ".ui-draggable-dragging" )
- .each( function() {
- var inst = $( this ).droppable( "instance" );
- if (
- inst.options.greedy &&
- !inst.options.disabled &&
- inst.options.scope === draggable.options.scope &&
- inst.accept.call(
- inst.element[ 0 ], ( draggable.currentItem || draggable.element )
- ) &&
- $.ui.intersect(
- draggable,
- $.extend( inst, { offset: inst.element.offset() } ),
- inst.options.tolerance, event
- )
- ) {
- childrenIntersection = true;
- return false;
- }
- } );
- if ( childrenIntersection ) {
- return false;
- }
-
- if ( this.accept.call( this.element[ 0 ],
- ( draggable.currentItem || draggable.element ) ) ) {
- this._removeActiveClass();
- this._removeHoverClass();
-
- this._trigger( "drop", event, this.ui( draggable ) );
- return this.element;
- }
-
- return false;
-
- },
-
- ui: function( c ) {
- return {
- draggable: ( c.currentItem || c.element ),
- helper: c.helper,
- position: c.position,
- offset: c.positionAbs
- };
- },
-
- // Extension points just to make backcompat sane and avoid duplicating logic
- // TODO: Remove in 1.14 along with call to it below
- _addHoverClass: function() {
- this._addClass( "ui-droppable-hover" );
- },
-
- _removeHoverClass: function() {
- this._removeClass( "ui-droppable-hover" );
- },
-
- _addActiveClass: function() {
- this._addClass( "ui-droppable-active" );
- },
-
- _removeActiveClass: function() {
- this._removeClass( "ui-droppable-active" );
- }
-} );
-
-$.ui.intersect = ( function() {
- function isOverAxis( x, reference, size ) {
- return ( x >= reference ) && ( x < ( reference + size ) );
- }
-
- return function( draggable, droppable, toleranceMode, event ) {
-
- if ( !droppable.offset ) {
- return false;
- }
-
- var x1 = ( draggable.positionAbs ||
- draggable.position.absolute ).left + draggable.margins.left,
- y1 = ( draggable.positionAbs ||
- draggable.position.absolute ).top + draggable.margins.top,
- x2 = x1 + draggable.helperProportions.width,
- y2 = y1 + draggable.helperProportions.height,
- l = droppable.offset.left,
- t = droppable.offset.top,
- r = l + droppable.proportions().width,
- b = t + droppable.proportions().height;
-
- switch ( toleranceMode ) {
- case "fit":
- return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
- case "intersect":
- return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
- x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
- t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
- y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
- case "pointer":
- return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
- isOverAxis( event.pageX, l, droppable.proportions().width );
- case "touch":
- return (
- ( y1 >= t && y1 <= b ) || // Top edge touching
- ( y2 >= t && y2 <= b ) || // Bottom edge touching
- ( y1 < t && y2 > b ) // Surrounded vertically
- ) && (
- ( x1 >= l && x1 <= r ) || // Left edge touching
- ( x2 >= l && x2 <= r ) || // Right edge touching
- ( x1 < l && x2 > r ) // Surrounded horizontally
- );
- default:
- return false;
- }
- };
-} )();
-
-/*
- This manager tracks offsets of draggables and droppables
-*/
-$.ui.ddmanager = {
- current: null,
- droppables: { "default": [] },
- prepareOffsets: function( t, event ) {
-
- var i, j,
- m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
- type = event ? event.type : null, // workaround for #2317
- list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
-
- droppablesLoop: for ( i = 0; i < m.length; i++ ) {
-
- // No disabled and non-accepted
- if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
- ( t.currentItem || t.element ) ) ) ) {
- continue;
- }
-
- // Filter out elements in the current dragged item
- for ( j = 0; j < list.length; j++ ) {
- if ( list[ j ] === m[ i ].element[ 0 ] ) {
- m[ i ].proportions().height = 0;
- continue droppablesLoop;
- }
- }
-
- m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
- if ( !m[ i ].visible ) {
- continue;
- }
-
- // Activate the droppable if used directly from draggables
- if ( type === "mousedown" ) {
- m[ i ]._activate.call( m[ i ], event );
- }
-
- m[ i ].offset = m[ i ].element.offset();
- m[ i ].proportions( {
- width: m[ i ].element[ 0 ].offsetWidth,
- height: m[ i ].element[ 0 ].offsetHeight
- } );
-
- }
-
- },
- drop: function( draggable, event ) {
-
- var dropped = false;
-
- // Create a copy of the droppables in case the list changes during the drop (#9116)
- $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
-
- if ( !this.options ) {
- return;
- }
- if ( !this.options.disabled && this.visible &&
- $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
- dropped = this._drop.call( this, event ) || dropped;
- }
-
- if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
- ( draggable.currentItem || draggable.element ) ) ) {
- this.isout = true;
- this.isover = false;
- this._deactivate.call( this, event );
- }
-
- } );
- return dropped;
-
- },
- dragStart: function( draggable, event ) {
-
- // Listen for scrolling so that if the dragging causes scrolling the position of the
- // droppables can be recalculated (see #5003)
- draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
- if ( !draggable.options.refreshPositions ) {
- $.ui.ddmanager.prepareOffsets( draggable, event );
- }
- } );
- },
- drag: function( draggable, event ) {
-
- // If you have a highly dynamic page, you might try this option. It renders positions
- // every time you move the mouse.
- if ( draggable.options.refreshPositions ) {
- $.ui.ddmanager.prepareOffsets( draggable, event );
- }
-
- // Run through all droppables and check their positions based on specific tolerance options
- $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
-
- if ( this.options.disabled || this.greedyChild || !this.visible ) {
- return;
- }
-
- var parentInstance, scope, parent,
- intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
- c = !intersects && this.isover ?
- "isout" :
- ( intersects && !this.isover ? "isover" : null );
- if ( !c ) {
- return;
- }
-
- if ( this.options.greedy ) {
-
- // find droppable parents with same scope
- scope = this.options.scope;
- parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
- return $( this ).droppable( "instance" ).options.scope === scope;
- } );
-
- if ( parent.length ) {
- parentInstance = $( parent[ 0 ] ).droppable( "instance" );
- parentInstance.greedyChild = ( c === "isover" );
- }
- }
-
- // We just moved into a greedy child
- if ( parentInstance && c === "isover" ) {
- parentInstance.isover = false;
- parentInstance.isout = true;
- parentInstance._out.call( parentInstance, event );
- }
-
- this[ c ] = true;
- this[ c === "isout" ? "isover" : "isout" ] = false;
- this[ c === "isover" ? "_over" : "_out" ].call( this, event );
-
- // We just moved out of a greedy child
- if ( parentInstance && c === "isout" ) {
- parentInstance.isout = false;
- parentInstance.isover = true;
- parentInstance._over.call( parentInstance, event );
- }
- } );
-
- },
- dragStop: function( draggable, event ) {
- draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );
-
- // Call prepareOffsets one final time since IE does not fire return scroll events when
- // overflow was caused by drag (see #5003)
- if ( !draggable.options.refreshPositions ) {
- $.ui.ddmanager.prepareOffsets( draggable, event );
- }
- }
-};
-
-// DEPRECATED
-// TODO: switch return back to widget declaration at top of file when this is removed
-if ( $.uiBackCompat !== false ) {
-
- // Backcompat for activeClass and hoverClass options
- $.widget( "ui.droppable", $.ui.droppable, {
- options: {
- hoverClass: false,
- activeClass: false
- },
- _addActiveClass: function() {
- this._super();
- if ( this.options.activeClass ) {
- this.element.addClass( this.options.activeClass );
- }
- },
- _removeActiveClass: function() {
- this._super();
- if ( this.options.activeClass ) {
- this.element.removeClass( this.options.activeClass );
- }
- },
- _addHoverClass: function() {
- this._super();
- if ( this.options.hoverClass ) {
- this.element.addClass( this.options.hoverClass );
- }
- },
- _removeHoverClass: function() {
- this._super();
- if ( this.options.hoverClass ) {
- this.element.removeClass( this.options.hoverClass );
- }
- }
- } );
-}
-
-var widgetsDroppable = $.ui.droppable;
-
-
-/*!
- * jQuery UI Progressbar 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Progressbar
-//>>group: Widgets
-/* eslint-disable max-len */
-//>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators.
-/* eslint-enable max-len */
-//>>docs: http://api.jqueryui.com/progressbar/
-//>>demos: http://jqueryui.com/progressbar/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/progressbar.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-var widgetsProgressbar = $.widget( "ui.progressbar", {
- version: "1.13.1",
- options: {
- classes: {
- "ui-progressbar": "ui-corner-all",
- "ui-progressbar-value": "ui-corner-left",
- "ui-progressbar-complete": "ui-corner-right"
- },
- max: 100,
- value: 0,
-
- change: null,
- complete: null
- },
-
- min: 0,
-
- _create: function() {
-
- // Constrain initial value
- this.oldValue = this.options.value = this._constrainedValue();
-
- this.element.attr( {
-
- // Only set static values; aria-valuenow and aria-valuemax are
- // set inside _refreshValue()
- role: "progressbar",
- "aria-valuemin": this.min
- } );
- this._addClass( "ui-progressbar", "ui-widget ui-widget-content" );
-
- this.valueDiv = $( "<div>" ).appendTo( this.element );
- this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" );
- this._refreshValue();
- },
-
- _destroy: function() {
- this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" );
-
- this.valueDiv.remove();
- },
-
- value: function( newValue ) {
- if ( newValue === undefined ) {
- return this.options.value;
- }
-
- this.options.value = this._constrainedValue( newValue );
- this._refreshValue();
- },
-
- _constrainedValue: function( newValue ) {
- if ( newValue === undefined ) {
- newValue = this.options.value;
- }
-
- this.indeterminate = newValue === false;
-
- // Sanitize value
- if ( typeof newValue !== "number" ) {
- newValue = 0;
- }
-
- return this.indeterminate ? false :
- Math.min( this.options.max, Math.max( this.min, newValue ) );
- },
-
- _setOptions: function( options ) {
-
- // Ensure "value" option is set after other values (like max)
- var value = options.value;
- delete options.value;
-
- this._super( options );
-
- this.options.value = this._constrainedValue( value );
- this._refreshValue();
- },
-
- _setOption: function( key, value ) {
- if ( key === "max" ) {
-
- // Don't allow a max less than min
- value = Math.max( this.min, value );
- }
- this._super( key, value );
- },
-
- _setOptionDisabled: function( value ) {
- this._super( value );
-
- this.element.attr( "aria-disabled", value );
- this._toggleClass( null, "ui-state-disabled", !!value );
- },
-
- _percentage: function() {
- return this.indeterminate ?
- 100 :
- 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
- },
-
- _refreshValue: function() {
- var value = this.options.value,
- percentage = this._percentage();
-
- this.valueDiv
- .toggle( this.indeterminate || value > this.min )
- .width( percentage.toFixed( 0 ) + "%" );
-
- this
- ._toggleClass( this.valueDiv, "ui-progressbar-complete", null,
- value === this.options.max )
- ._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate );
-
- if ( this.indeterminate ) {
- this.element.removeAttr( "aria-valuenow" );
- if ( !this.overlayDiv ) {
- this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv );
- this._addClass( this.overlayDiv, "ui-progressbar-overlay" );
- }
- } else {
- this.element.attr( {
- "aria-valuemax": this.options.max,
- "aria-valuenow": value
- } );
- if ( this.overlayDiv ) {
- this.overlayDiv.remove();
- this.overlayDiv = null;
- }
- }
-
- if ( this.oldValue !== value ) {
- this.oldValue = value;
- this._trigger( "change" );
- }
- if ( value === this.options.max ) {
- this._trigger( "complete" );
- }
- }
-} );
-
-
-/*!
- * jQuery UI Selectable 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Selectable
-//>>group: Interactions
-//>>description: Allows groups of elements to be selected with the mouse.
-//>>docs: http://api.jqueryui.com/selectable/
-//>>demos: http://jqueryui.com/selectable/
-//>>css.structure: ../../themes/base/selectable.css
-
-
-var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, {
- version: "1.13.1",
- options: {
- appendTo: "body",
- autoRefresh: true,
- distance: 0,
- filter: "*",
- tolerance: "touch",
-
- // Callbacks
- selected: null,
- selecting: null,
- start: null,
- stop: null,
- unselected: null,
- unselecting: null
- },
- _create: function() {
- var that = this;
-
- this._addClass( "ui-selectable" );
-
- this.dragged = false;
-
- // Cache selectee children based on filter
- this.refresh = function() {
- that.elementPos = $( that.element[ 0 ] ).offset();
- that.selectees = $( that.options.filter, that.element[ 0 ] );
- that._addClass( that.selectees, "ui-selectee" );
- that.selectees.each( function() {
- var $this = $( this ),
- selecteeOffset = $this.offset(),
- pos = {
- left: selecteeOffset.left - that.elementPos.left,
- top: selecteeOffset.top - that.elementPos.top
- };
- $.data( this, "selectable-item", {
- element: this,
- $element: $this,
- left: pos.left,
- top: pos.top,
- right: pos.left + $this.outerWidth(),
- bottom: pos.top + $this.outerHeight(),
- startselected: false,
- selected: $this.hasClass( "ui-selected" ),
- selecting: $this.hasClass( "ui-selecting" ),
- unselecting: $this.hasClass( "ui-unselecting" )
- } );
- } );
- };
- this.refresh();
-
- this._mouseInit();
-
- this.helper = $( "<div>" );
- this._addClass( this.helper, "ui-selectable-helper" );
- },
-
- _destroy: function() {
- this.selectees.removeData( "selectable-item" );
- this._mouseDestroy();
- },
-
- _mouseStart: function( event ) {
- var that = this,
- options = this.options;
-
- this.opos = [ event.pageX, event.pageY ];
- this.elementPos = $( this.element[ 0 ] ).offset();
-
- if ( this.options.disabled ) {
- return;
- }
-
- this.selectees = $( options.filter, this.element[ 0 ] );
-
- this._trigger( "start", event );
-
- $( options.appendTo ).append( this.helper );
-
- // position helper (lasso)
- this.helper.css( {
- "left": event.pageX,
- "top": event.pageY,
- "width": 0,
- "height": 0
- } );
-
- if ( options.autoRefresh ) {
- this.refresh();
- }
-
- this.selectees.filter( ".ui-selected" ).each( function() {
- var selectee = $.data( this, "selectable-item" );
- selectee.startselected = true;
- if ( !event.metaKey && !event.ctrlKey ) {
- that._removeClass( selectee.$element, "ui-selected" );
- selectee.selected = false;
- that._addClass( selectee.$element, "ui-unselecting" );
- selectee.unselecting = true;
-
- // selectable UNSELECTING callback
- that._trigger( "unselecting", event, {
- unselecting: selectee.element
- } );
- }
- } );
-
- $( event.target ).parents().addBack().each( function() {
- var doSelect,
- selectee = $.data( this, "selectable-item" );
- if ( selectee ) {
- doSelect = ( !event.metaKey && !event.ctrlKey ) ||
- !selectee.$element.hasClass( "ui-selected" );
- that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
- ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
- selectee.unselecting = !doSelect;
- selectee.selecting = doSelect;
- selectee.selected = doSelect;
-
- // selectable (UN)SELECTING callback
- if ( doSelect ) {
- that._trigger( "selecting", event, {
- selecting: selectee.element
- } );
- } else {
- that._trigger( "unselecting", event, {
- unselecting: selectee.element
- } );
- }
- return false;
- }
- } );
-
- },
-
- _mouseDrag: function( event ) {
-
- this.dragged = true;
-
- if ( this.options.disabled ) {
- return;
- }
-
- var tmp,
- that = this,
- options = this.options,
- x1 = this.opos[ 0 ],
- y1 = this.opos[ 1 ],
- x2 = event.pageX,
- y2 = event.pageY;
-
- if ( x1 > x2 ) {
- tmp = x2; x2 = x1; x1 = tmp;
- }
- if ( y1 > y2 ) {
- tmp = y2; y2 = y1; y1 = tmp;
- }
- this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );
-
- this.selectees.each( function() {
- var selectee = $.data( this, "selectable-item" ),
- hit = false,
- offset = {};
-
- //prevent helper from being selected if appendTo: selectable
- if ( !selectee || selectee.element === that.element[ 0 ] ) {
- return;
- }
-
- offset.left = selectee.left + that.elementPos.left;
- offset.right = selectee.right + that.elementPos.left;
- offset.top = selectee.top + that.elementPos.top;
- offset.bottom = selectee.bottom + that.elementPos.top;
-
- if ( options.tolerance === "touch" ) {
- hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
- offset.bottom < y1 ) );
- } else if ( options.tolerance === "fit" ) {
- hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
- offset.bottom < y2 );
- }
-
- if ( hit ) {
-
- // SELECT
- if ( selectee.selected ) {
- that._removeClass( selectee.$element, "ui-selected" );
- selectee.selected = false;
- }
- if ( selectee.unselecting ) {
- that._removeClass( selectee.$element, "ui-unselecting" );
- selectee.unselecting = false;
- }
- if ( !selectee.selecting ) {
- that._addClass( selectee.$element, "ui-selecting" );
- selectee.selecting = true;
-
- // selectable SELECTING callback
- that._trigger( "selecting", event, {
- selecting: selectee.element
- } );
- }
- } else {
-
- // UNSELECT
- if ( selectee.selecting ) {
- if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
- that._removeClass( selectee.$element, "ui-selecting" );
- selectee.selecting = false;
- that._addClass( selectee.$element, "ui-selected" );
- selectee.selected = true;
- } else {
- that._removeClass( selectee.$element, "ui-selecting" );
- selectee.selecting = false;
- if ( selectee.startselected ) {
- that._addClass( selectee.$element, "ui-unselecting" );
- selectee.unselecting = true;
- }
-
- // selectable UNSELECTING callback
- that._trigger( "unselecting", event, {
- unselecting: selectee.element
- } );
- }
- }
- if ( selectee.selected ) {
- if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
- that._removeClass( selectee.$element, "ui-selected" );
- selectee.selected = false;
-
- that._addClass( selectee.$element, "ui-unselecting" );
- selectee.unselecting = true;
-
- // selectable UNSELECTING callback
- that._trigger( "unselecting", event, {
- unselecting: selectee.element
- } );
- }
- }
- }
- } );
-
- return false;
- },
-
- _mouseStop: function( event ) {
- var that = this;
-
- this.dragged = false;
-
- $( ".ui-unselecting", this.element[ 0 ] ).each( function() {
- var selectee = $.data( this, "selectable-item" );
- that._removeClass( selectee.$element, "ui-unselecting" );
- selectee.unselecting = false;
- selectee.startselected = false;
- that._trigger( "unselected", event, {
- unselected: selectee.element
- } );
- } );
- $( ".ui-selecting", this.element[ 0 ] ).each( function() {
- var selectee = $.data( this, "selectable-item" );
- that._removeClass( selectee.$element, "ui-selecting" )
- ._addClass( selectee.$element, "ui-selected" );
- selectee.selecting = false;
- selectee.selected = true;
- selectee.startselected = true;
- that._trigger( "selected", event, {
- selected: selectee.element
- } );
- } );
- this._trigger( "stop", event );
-
- this.helper.remove();
-
- return false;
- }
-
-} );
-
-
-/*!
- * jQuery UI Selectmenu 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Selectmenu
-//>>group: Widgets
-/* eslint-disable max-len */
-//>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select.
-/* eslint-enable max-len */
-//>>docs: http://api.jqueryui.com/selectmenu/
-//>>demos: http://jqueryui.com/selectmenu/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
- version: "1.13.1",
- defaultElement: "<select>",
- options: {
- appendTo: null,
- classes: {
- "ui-selectmenu-button-open": "ui-corner-top",
- "ui-selectmenu-button-closed": "ui-corner-all"
- },
- disabled: null,
- icons: {
- button: "ui-icon-triangle-1-s"
- },
- position: {
- my: "left top",
- at: "left bottom",
- collision: "none"
- },
- width: false,
-
- // Callbacks
- change: null,
- close: null,
- focus: null,
- open: null,
- select: null
- },
-
- _create: function() {
- var selectmenuId = this.element.uniqueId().attr( "id" );
- this.ids = {
- element: selectmenuId,
- button: selectmenuId + "-button",
- menu: selectmenuId + "-menu"
- };
-
- this._drawButton();
- this._drawMenu();
- this._bindFormResetHandler();
-
- this._rendered = false;
- this.menuItems = $();
- },
-
- _drawButton: function() {
- var icon,
- that = this,
- item = this._parseOption(
- this.element.find( "option:selected" ),
- this.element[ 0 ].selectedIndex
- );
-
- // Associate existing label with the new button
- this.labels = this.element.labels().attr( "for", this.ids.button );
- this._on( this.labels, {
- click: function( event ) {
- this.button.trigger( "focus" );
- event.preventDefault();
- }
- } );
-
- // Hide original select element
- this.element.hide();
-
- // Create button
- this.button = $( "<span>", {
- tabindex: this.options.disabled ? -1 : 0,
- id: this.ids.button,
- role: "combobox",
- "aria-expanded": "false",
- "aria-autocomplete": "list",
- "aria-owns": this.ids.menu,
- "aria-haspopup": "true",
- title: this.element.attr( "title" )
- } )
- .insertAfter( this.element );
-
- this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
- "ui-button ui-widget" );
-
- icon = $( "<span>" ).appendTo( this.button );
- this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button );
- this.buttonItem = this._renderButtonItem( item )
- .appendTo( this.button );
-
- if ( this.options.width !== false ) {
- this._resizeButton();
- }
-
- this._on( this.button, this._buttonEvents );
- this.button.one( "focusin", function() {
-
- // Delay rendering the menu items until the button receives focus.
- // The menu may have already been rendered via a programmatic open.
- if ( !that._rendered ) {
- that._refreshMenu();
- }
- } );
- },
-
- _drawMenu: function() {
- var that = this;
-
- // Create menu
- this.menu = $( "<ul>", {
- "aria-hidden": "true",
- "aria-labelledby": this.ids.button,
- id: this.ids.menu
- } );
-
- // Wrap menu
- this.menuWrap = $( "<div>" ).append( this.menu );
- this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
- this.menuWrap.appendTo( this._appendTo() );
-
- // Initialize menu widget
- this.menuInstance = this.menu
- .menu( {
- classes: {
- "ui-menu": "ui-corner-bottom"
- },
- role: "listbox",
- select: function( event, ui ) {
- event.preventDefault();
-
- // Support: IE8
- // If the item was selected via a click, the text selection
- // will be destroyed in IE
- that._setSelection();
-
- that._select( ui.item.data( "ui-selectmenu-item" ), event );
- },
- focus: function( event, ui ) {
- var item = ui.item.data( "ui-selectmenu-item" );
-
- // Prevent inital focus from firing and check if its a newly focused item
- if ( that.focusIndex != null && item.index !== that.focusIndex ) {
- that._trigger( "focus", event, { item: item } );
- if ( !that.isOpen ) {
- that._select( item, event );
- }
- }
- that.focusIndex = item.index;
-
- that.button.attr( "aria-activedescendant",
- that.menuItems.eq( item.index ).attr( "id" ) );
- }
- } )
- .menu( "instance" );
-
- // Don't close the menu on mouseleave
- this.menuInstance._off( this.menu, "mouseleave" );
-
- // Cancel the menu's collapseAll on document click
- this.menuInstance._closeOnDocumentClick = function() {
- return false;
- };
-
- // Selects often contain empty items, but never contain dividers
- this.menuInstance._isDivider = function() {
- return false;
- };
- },
-
- refresh: function() {
- this._refreshMenu();
- this.buttonItem.replaceWith(
- this.buttonItem = this._renderButtonItem(
-
- // Fall back to an empty object in case there are no options
- this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
- )
- );
- if ( this.options.width === null ) {
- this._resizeButton();
- }
- },
-
- _refreshMenu: function() {
- var item,
- options = this.element.find( "option" );
-
- this.menu.empty();
-
- this._parseOptions( options );
- this._renderMenu( this.menu, this.items );
-
- this.menuInstance.refresh();
- this.menuItems = this.menu.find( "li" )
- .not( ".ui-selectmenu-optgroup" )
- .find( ".ui-menu-item-wrapper" );
-
- this._rendered = true;
-
- if ( !options.length ) {
- return;
- }
-
- item = this._getSelectedItem();
-
- // Update the menu to have the correct item focused
- this.menuInstance.focus( null, item );
- this._setAria( item.data( "ui-selectmenu-item" ) );
-
- // Set disabled state
- this._setOption( "disabled", this.element.prop( "disabled" ) );
- },
-
- open: function( event ) {
- if ( this.options.disabled ) {
- return;
- }
-
- // If this is the first time the menu is being opened, render the items
- if ( !this._rendered ) {
- this._refreshMenu();
- } else {
-
- // Menu clears focus on close, reset focus to selected item
- this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
- this.menuInstance.focus( null, this._getSelectedItem() );
- }
-
- // If there are no options, don't open the menu
- if ( !this.menuItems.length ) {
- return;
- }
-
- this.isOpen = true;
- this._toggleAttr();
- this._resizeMenu();
- this._position();
-
- this._on( this.document, this._documentClick );
-
- this._trigger( "open", event );
- },
-
- _position: function() {
- this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
- },
-
- close: function( event ) {
- if ( !this.isOpen ) {
- return;
- }
-
- this.isOpen = false;
- this._toggleAttr();
-
- this.range = null;
- this._off( this.document );
-
- this._trigger( "close", event );
- },
-
- widget: function() {
- return this.button;
- },
-
- menuWidget: function() {
- return this.menu;
- },
-
- _renderButtonItem: function( item ) {
- var buttonItem = $( "<span>" );
-
- this._setText( buttonItem, item.label );
- this._addClass( buttonItem, "ui-selectmenu-text" );
-
- return buttonItem;
- },
-
- _renderMenu: function( ul, items ) {
- var that = this,
- currentOptgroup = "";
-
- $.each( items, function( index, item ) {
- var li;
-
- if ( item.optgroup !== currentOptgroup ) {
- li = $( "<li>", {
- text: item.optgroup
- } );
- that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
- ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
- " ui-state-disabled" :
- "" ) );
-
- li.appendTo( ul );
-
- currentOptgroup = item.optgroup;
- }
-
- that._renderItemData( ul, item );
- } );
- },
-
- _renderItemData: function( ul, item ) {
- return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
- },
-
- _renderItem: function( ul, item ) {
- var li = $( "<li>" ),
- wrapper = $( "<div>", {
- title: item.element.attr( "title" )
- } );
-
- if ( item.disabled ) {
- this._addClass( li, null, "ui-state-disabled" );
- }
- this._setText( wrapper, item.label );
-
- return li.append( wrapper ).appendTo( ul );
- },
-
- _setText: function( element, value ) {
- if ( value ) {
- element.text( value );
- } else {
- element.html( "&#160;" );
- }
- },
-
- _move: function( direction, event ) {
- var item, next,
- filter = ".ui-menu-item";
-
- if ( this.isOpen ) {
- item = this.menuItems.eq( this.focusIndex ).parent( "li" );
- } else {
- item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
- filter += ":not(.ui-state-disabled)";
- }
-
- if ( direction === "first" || direction === "last" ) {
- next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
- } else {
- next = item[ direction + "All" ]( filter ).eq( 0 );
- }
-
- if ( next.length ) {
- this.menuInstance.focus( event, next );
- }
- },
-
- _getSelectedItem: function() {
- return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
- },
-
- _toggle: function( event ) {
- this[ this.isOpen ? "close" : "open" ]( event );
- },
-
- _setSelection: function() {
- var selection;
-
- if ( !this.range ) {
- return;
- }
-
- if ( window.getSelection ) {
- selection = window.getSelection();
- selection.removeAllRanges();
- selection.addRange( this.range );
-
- // Support: IE8
- } else {
- this.range.select();
- }
-
- // Support: IE
- // Setting the text selection kills the button focus in IE, but
- // restoring the focus doesn't kill the selection.
- this.button.focus();
- },
-
- _documentClick: {
- mousedown: function( event ) {
- if ( !this.isOpen ) {
- return;
- }
-
- if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
- $.escapeSelector( this.ids.button ) ).length ) {
- this.close( event );
- }
- }
- },
-
- _buttonEvents: {
-
- // Prevent text selection from being reset when interacting with the selectmenu (#10144)
- mousedown: function() {
- var selection;
-
- if ( window.getSelection ) {
- selection = window.getSelection();
- if ( selection.rangeCount ) {
- this.range = selection.getRangeAt( 0 );
- }
-
- // Support: IE8
- } else {
- this.range = document.selection.createRange();
- }
- },
-
- click: function( event ) {
- this._setSelection();
- this._toggle( event );
- },
-
- keydown: function( event ) {
- var preventDefault = true;
- switch ( event.keyCode ) {
- case $.ui.keyCode.TAB:
- case $.ui.keyCode.ESCAPE:
- this.close( event );
- preventDefault = false;
- break;
- case $.ui.keyCode.ENTER:
- if ( this.isOpen ) {
- this._selectFocusedItem( event );
- }
- break;
- case $.ui.keyCode.UP:
- if ( event.altKey ) {
- this._toggle( event );
- } else {
- this._move( "prev", event );
- }
- break;
- case $.ui.keyCode.DOWN:
- if ( event.altKey ) {
- this._toggle( event );
- } else {
- this._move( "next", event );
- }
- break;
- case $.ui.keyCode.SPACE:
- if ( this.isOpen ) {
- this._selectFocusedItem( event );
- } else {
- this._toggle( event );
- }
- break;
- case $.ui.keyCode.LEFT:
- this._move( "prev", event );
- break;
- case $.ui.keyCode.RIGHT:
- this._move( "next", event );
- break;
- case $.ui.keyCode.HOME:
- case $.ui.keyCode.PAGE_UP:
- this._move( "first", event );
- break;
- case $.ui.keyCode.END:
- case $.ui.keyCode.PAGE_DOWN:
- this._move( "last", event );
- break;
- default:
- this.menu.trigger( event );
- preventDefault = false;
- }
-
- if ( preventDefault ) {
- event.preventDefault();
- }
- }
- },
-
- _selectFocusedItem: function( event ) {
- var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
- if ( !item.hasClass( "ui-state-disabled" ) ) {
- this._select( item.data( "ui-selectmenu-item" ), event );
- }
- },
-
- _select: function( item, event ) {
- var oldIndex = this.element[ 0 ].selectedIndex;
-
- // Change native select element
- this.element[ 0 ].selectedIndex = item.index;
- this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
- this._setAria( item );
- this._trigger( "select", event, { item: item } );
-
- if ( item.index !== oldIndex ) {
- this._trigger( "change", event, { item: item } );
- }
-
- this.close( event );
- },
-
- _setAria: function( item ) {
- var id = this.menuItems.eq( item.index ).attr( "id" );
-
- this.button.attr( {
- "aria-labelledby": id,
- "aria-activedescendant": id
- } );
- this.menu.attr( "aria-activedescendant", id );
- },
-
- _setOption: function( key, value ) {
- if ( key === "icons" ) {
- var icon = this.button.find( "span.ui-icon" );
- this._removeClass( icon, null, this.options.icons.button )
- ._addClass( icon, null, value.button );
- }
-
- this._super( key, value );
-
- if ( key === "appendTo" ) {
- this.menuWrap.appendTo( this._appendTo() );
- }
-
- if ( key === "width" ) {
- this._resizeButton();
- }
- },
-
- _setOptionDisabled: function( value ) {
- this._super( value );
-
- this.menuInstance.option( "disabled", value );
- this.button.attr( "aria-disabled", value );
- this._toggleClass( this.button, null, "ui-state-disabled", value );
-
- this.element.prop( "disabled", value );
- if ( value ) {
- this.button.attr( "tabindex", -1 );
- this.close();
- } else {
- this.button.attr( "tabindex", 0 );
- }
- },
-
- _appendTo: function() {
- var element = this.options.appendTo;
-
- if ( element ) {
- element = element.jquery || element.nodeType ?
- $( element ) :
- this.document.find( element ).eq( 0 );
- }
-
- if ( !element || !element[ 0 ] ) {
- element = this.element.closest( ".ui-front, dialog" );
- }
-
- if ( !element.length ) {
- element = this.document[ 0 ].body;
- }
-
- return element;
- },
-
- _toggleAttr: function() {
- this.button.attr( "aria-expanded", this.isOpen );
-
- // We can't use two _toggleClass() calls here, because we need to make sure
- // we always remove classes first and add them second, otherwise if both classes have the
- // same theme class, it will be removed after we add it.
- this._removeClass( this.button, "ui-selectmenu-button-" +
- ( this.isOpen ? "closed" : "open" ) )
- ._addClass( this.button, "ui-selectmenu-button-" +
- ( this.isOpen ? "open" : "closed" ) )
- ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );
-
- this.menu.attr( "aria-hidden", !this.isOpen );
- },
-
- _resizeButton: function() {
- var width = this.options.width;
-
- // For `width: false`, just remove inline style and stop
- if ( width === false ) {
- this.button.css( "width", "" );
- return;
- }
-
- // For `width: null`, match the width of the original element
- if ( width === null ) {
- width = this.element.show().outerWidth();
- this.element.hide();
- }
-
- this.button.outerWidth( width );
- },
-
- _resizeMenu: function() {
- this.menu.outerWidth( Math.max(
- this.button.outerWidth(),
-
- // Support: IE10
- // IE10 wraps long text (possibly a rounding bug)
- // so we add 1px to avoid the wrapping
- this.menu.width( "" ).outerWidth() + 1
- ) );
- },
-
- _getCreateOptions: function() {
- var options = this._super();
-
- options.disabled = this.element.prop( "disabled" );
-
- return options;
- },
-
- _parseOptions: function( options ) {
- var that = this,
- data = [];
- options.each( function( index, item ) {
- if ( item.hidden ) {
- return;
- }
-
- data.push( that._parseOption( $( item ), index ) );
- } );
- this.items = data;
- },
-
- _parseOption: function( option, index ) {
- var optgroup = option.parent( "optgroup" );
-
- return {
- element: option,
- index: index,
- value: option.val(),
- label: option.text(),
- optgroup: optgroup.attr( "label" ) || "",
- disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
- };
- },
-
- _destroy: function() {
- this._unbindFormResetHandler();
- this.menuWrap.remove();
- this.button.remove();
- this.element.show();
- this.element.removeUniqueId();
- this.labels.attr( "for", this.ids.element );
- }
-} ] );
-
-
-/*!
- * jQuery UI Slider 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Slider
-//>>group: Widgets
-//>>description: Displays a flexible slider with ranges and accessibility via keyboard.
-//>>docs: http://api.jqueryui.com/slider/
-//>>demos: http://jqueryui.com/slider/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/slider.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
- version: "1.13.1",
- widgetEventPrefix: "slide",
-
- options: {
- animate: false,
- classes: {
- "ui-slider": "ui-corner-all",
- "ui-slider-handle": "ui-corner-all",
-
- // Note: ui-widget-header isn't the most fittingly semantic framework class for this
- // element, but worked best visually with a variety of themes
- "ui-slider-range": "ui-corner-all ui-widget-header"
- },
- distance: 0,
- max: 100,
- min: 0,
- orientation: "horizontal",
- range: false,
- step: 1,
- value: 0,
- values: null,
-
- // Callbacks
- change: null,
- slide: null,
- start: null,
- stop: null
- },
-
- // Number of pages in a slider
- // (how many times can you page up/down to go through the whole range)
- numPages: 5,
-
- _create: function() {
- this._keySliding = false;
- this._mouseSliding = false;
- this._animateOff = true;
- this._handleIndex = null;
- this._detectOrientation();
- this._mouseInit();
- this._calculateNewMax();
-
- this._addClass( "ui-slider ui-slider-" + this.orientation,
- "ui-widget ui-widget-content" );
-
- this._refresh();
-
- this._animateOff = false;
- },
-
- _refresh: function() {
- this._createRange();
- this._createHandles();
- this._setupEvents();
- this._refreshValue();
- },
-
- _createHandles: function() {
- var i, handleCount,
- options = this.options,
- existingHandles = this.element.find( ".ui-slider-handle" ),
- handle = "<span tabindex='0'></span>",
- handles = [];
-
- handleCount = ( options.values && options.values.length ) || 1;
-
- if ( existingHandles.length > handleCount ) {
- existingHandles.slice( handleCount ).remove();
- existingHandles = existingHandles.slice( 0, handleCount );
- }
-
- for ( i = existingHandles.length; i < handleCount; i++ ) {
- handles.push( handle );
- }
-
- this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
-
- this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );
-
- this.handle = this.handles.eq( 0 );
-
- this.handles.each( function( i ) {
- $( this )
- .data( "ui-slider-handle-index", i )
- .attr( "tabIndex", 0 );
- } );
- },
-
- _createRange: function() {
- var options = this.options;
-
- if ( options.range ) {
- if ( options.range === true ) {
- if ( !options.values ) {
- options.values = [ this._valueMin(), this._valueMin() ];
- } else if ( options.values.length && options.values.length !== 2 ) {
- options.values = [ options.values[ 0 ], options.values[ 0 ] ];
- } else if ( Array.isArray( options.values ) ) {
- options.values = options.values.slice( 0 );
- }
- }
-
- if ( !this.range || !this.range.length ) {
- this.range = $( "<div>" )
- .appendTo( this.element );
-
- this._addClass( this.range, "ui-slider-range" );
- } else {
- this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );
-
- // Handle range switching from true to min/max
- this.range.css( {
- "left": "",
- "bottom": ""
- } );
- }
- if ( options.range === "min" || options.range === "max" ) {
- this._addClass( this.range, "ui-slider-range-" + options.range );
- }
- } else {
- if ( this.range ) {
- this.range.remove();
- }
- this.range = null;
- }
- },
-
- _setupEvents: function() {
- this._off( this.handles );
- this._on( this.handles, this._handleEvents );
- this._hoverable( this.handles );
- this._focusable( this.handles );
- },
-
- _destroy: function() {
- this.handles.remove();
- if ( this.range ) {
- this.range.remove();
- }
-
- this._mouseDestroy();
- },
-
- _mouseCapture: function( event ) {
- var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
- that = this,
- o = this.options;
-
- if ( o.disabled ) {
- return false;
- }
-
- this.elementSize = {
- width: this.element.outerWidth(),
- height: this.element.outerHeight()
- };
- this.elementOffset = this.element.offset();
-
- position = { x: event.pageX, y: event.pageY };
- normValue = this._normValueFromMouse( position );
- distance = this._valueMax() - this._valueMin() + 1;
- this.handles.each( function( i ) {
- var thisDistance = Math.abs( normValue - that.values( i ) );
- if ( ( distance > thisDistance ) ||
- ( distance === thisDistance &&
- ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
- distance = thisDistance;
- closestHandle = $( this );
- index = i;
- }
- } );
-
- allowed = this._start( event, index );
- if ( allowed === false ) {
- return false;
- }
- this._mouseSliding = true;
-
- this._handleIndex = index;
-
- this._addClass( closestHandle, null, "ui-state-active" );
- closestHandle.trigger( "focus" );
-
- offset = closestHandle.offset();
- mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
- this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
- left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
- top: event.pageY - offset.top -
- ( closestHandle.height() / 2 ) -
- ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
- ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
- ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
- };
-
- if ( !this.handles.hasClass( "ui-state-hover" ) ) {
- this._slide( event, index, normValue );
- }
- this._animateOff = true;
- return true;
- },
-
- _mouseStart: function() {
- return true;
- },
-
- _mouseDrag: function( event ) {
- var position = { x: event.pageX, y: event.pageY },
- normValue = this._normValueFromMouse( position );
-
- this._slide( event, this._handleIndex, normValue );
-
- return false;
- },
-
- _mouseStop: function( event ) {
- this._removeClass( this.handles, null, "ui-state-active" );
- this._mouseSliding = false;
-
- this._stop( event, this._handleIndex );
- this._change( event, this._handleIndex );
-
- this._handleIndex = null;
- this._clickOffset = null;
- this._animateOff = false;
-
- return false;
- },
-
- _detectOrientation: function() {
- this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
- },
-
- _normValueFromMouse: function( position ) {
- var pixelTotal,
- pixelMouse,
- percentMouse,
- valueTotal,
- valueMouse;
-
- if ( this.orientation === "horizontal" ) {
- pixelTotal = this.elementSize.width;
- pixelMouse = position.x - this.elementOffset.left -
- ( this._clickOffset ? this._clickOffset.left : 0 );
- } else {
- pixelTotal = this.elementSize.height;
- pixelMouse = position.y - this.elementOffset.top -
- ( this._clickOffset ? this._clickOffset.top : 0 );
- }
-
- percentMouse = ( pixelMouse / pixelTotal );
- if ( percentMouse > 1 ) {
- percentMouse = 1;
- }
- if ( percentMouse < 0 ) {
- percentMouse = 0;
- }
- if ( this.orientation === "vertical" ) {
- percentMouse = 1 - percentMouse;
- }
-
- valueTotal = this._valueMax() - this._valueMin();
- valueMouse = this._valueMin() + percentMouse * valueTotal;
-
- return this._trimAlignValue( valueMouse );
- },
-
- _uiHash: function( index, value, values ) {
- var uiHash = {
- handle: this.handles[ index ],
- handleIndex: index,
- value: value !== undefined ? value : this.value()
- };
-
- if ( this._hasMultipleValues() ) {
- uiHash.value = value !== undefined ? value : this.values( index );
- uiHash.values = values || this.values();
- }
-
- return uiHash;
- },
-
- _hasMultipleValues: function() {
- return this.options.values && this.options.values.length;
- },
-
- _start: function( event, index ) {
- return this._trigger( "start", event, this._uiHash( index ) );
- },
-
- _slide: function( event, index, newVal ) {
- var allowed, otherVal,
- currentValue = this.value(),
- newValues = this.values();
-
- if ( this._hasMultipleValues() ) {
- otherVal = this.values( index ? 0 : 1 );
- currentValue = this.values( index );
-
- if ( this.options.values.length === 2 && this.options.range === true ) {
- newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
- }
-
- newValues[ index ] = newVal;
- }
-
- if ( newVal === currentValue ) {
- return;
- }
-
- allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );
-
- // A slide can be canceled by returning false from the slide callback
- if ( allowed === false ) {
- return;
- }
-
- if ( this._hasMultipleValues() ) {
- this.values( index, newVal );
- } else {
- this.value( newVal );
- }
- },
-
- _stop: function( event, index ) {
- this._trigger( "stop", event, this._uiHash( index ) );
- },
-
- _change: function( event, index ) {
- if ( !this._keySliding && !this._mouseSliding ) {
-
- //store the last changed value index for reference when handles overlap
- this._lastChangedValue = index;
- this._trigger( "change", event, this._uiHash( index ) );
- }
- },
-
- value: function( newValue ) {
- if ( arguments.length ) {
- this.options.value = this._trimAlignValue( newValue );
- this._refreshValue();
- this._change( null, 0 );
- return;
- }
-
- return this._value();
- },
-
- values: function( index, newValue ) {
- var vals,
- newValues,
- i;
-
- if ( arguments.length > 1 ) {
- this.options.values[ index ] = this._trimAlignValue( newValue );
- this._refreshValue();
- this._change( null, index );
- return;
- }
-
- if ( arguments.length ) {
- if ( Array.isArray( arguments[ 0 ] ) ) {
- vals = this.options.values;
- newValues = arguments[ 0 ];
- for ( i = 0; i < vals.length; i += 1 ) {
- vals[ i ] = this._trimAlignValue( newValues[ i ] );
- this._change( null, i );
- }
- this._refreshValue();
- } else {
- if ( this._hasMultipleValues() ) {
- return this._values( index );
- } else {
- return this.value();
- }
- }
- } else {
- return this._values();
- }
- },
-
- _setOption: function( key, value ) {
- var i,
- valsLength = 0;
-
- if ( key === "range" && this.options.range === true ) {
- if ( value === "min" ) {
- this.options.value = this._values( 0 );
- this.options.values = null;
- } else if ( value === "max" ) {
- this.options.value = this._values( this.options.values.length - 1 );
- this.options.values = null;
- }
- }
-
- if ( Array.isArray( this.options.values ) ) {
- valsLength = this.options.values.length;
- }
-
- this._super( key, value );
-
- switch ( key ) {
- case "orientation":
- this._detectOrientation();
- this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
- ._addClass( "ui-slider-" + this.orientation );
- this._refreshValue();
- if ( this.options.range ) {
- this._refreshRange( value );
- }
-
- // Reset positioning from previous orientation
- this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
- break;
- case "value":
- this._animateOff = true;
- this._refreshValue();
- this._change( null, 0 );
- this._animateOff = false;
- break;
- case "values":
- this._animateOff = true;
- this._refreshValue();
-
- // Start from the last handle to prevent unreachable handles (#9046)
- for ( i = valsLength - 1; i >= 0; i-- ) {
- this._change( null, i );
- }
- this._animateOff = false;
- break;
- case "step":
- case "min":
- case "max":
- this._animateOff = true;
- this._calculateNewMax();
- this._refreshValue();
- this._animateOff = false;
- break;
- case "range":
- this._animateOff = true;
- this._refresh();
- this._animateOff = false;
- break;
- }
- },
-
- _setOptionDisabled: function( value ) {
- this._super( value );
-
- this._toggleClass( null, "ui-state-disabled", !!value );
- },
-
- //internal value getter
- // _value() returns value trimmed by min and max, aligned by step
- _value: function() {
- var val = this.options.value;
- val = this._trimAlignValue( val );
-
- return val;
- },
-
- //internal values getter
- // _values() returns array of values trimmed by min and max, aligned by step
- // _values( index ) returns single value trimmed by min and max, aligned by step
- _values: function( index ) {
- var val,
- vals,
- i;
-
- if ( arguments.length ) {
- val = this.options.values[ index ];
- val = this._trimAlignValue( val );
-
- return val;
- } else if ( this._hasMultipleValues() ) {
-
- // .slice() creates a copy of the array
- // this copy gets trimmed by min and max and then returned
- vals = this.options.values.slice();
- for ( i = 0; i < vals.length; i += 1 ) {
- vals[ i ] = this._trimAlignValue( vals[ i ] );
- }
-
- return vals;
- } else {
- return [];
- }
- },
-
- // Returns the step-aligned value that val is closest to, between (inclusive) min and max
- _trimAlignValue: function( val ) {
- if ( val <= this._valueMin() ) {
- return this._valueMin();
- }
- if ( val >= this._valueMax() ) {
- return this._valueMax();
- }
- var step = ( this.options.step > 0 ) ? this.options.step : 1,
- valModStep = ( val - this._valueMin() ) % step,
- alignValue = val - valModStep;
-
- if ( Math.abs( valModStep ) * 2 >= step ) {
- alignValue += ( valModStep > 0 ) ? step : ( -step );
- }
-
- // Since JavaScript has problems with large floats, round
- // the final value to 5 digits after the decimal point (see #4124)
- return parseFloat( alignValue.toFixed( 5 ) );
- },
-
- _calculateNewMax: function() {
- var max = this.options.max,
- min = this._valueMin(),
- step = this.options.step,
- aboveMin = Math.round( ( max - min ) / step ) * step;
- max = aboveMin + min;
- if ( max > this.options.max ) {
-
- //If max is not divisible by step, rounding off may increase its value
- max -= step;
- }
- this.max = parseFloat( max.toFixed( this._precision() ) );
- },
-
- _precision: function() {
- var precision = this._precisionOf( this.options.step );
- if ( this.options.min !== null ) {
- precision = Math.max( precision, this._precisionOf( this.options.min ) );
- }
- return precision;
- },
-
- _precisionOf: function( num ) {
- var str = num.toString(),
- decimal = str.indexOf( "." );
- return decimal === -1 ? 0 : str.length - decimal - 1;
- },
-
- _valueMin: function() {
- return this.options.min;
- },
-
- _valueMax: function() {
- return this.max;
- },
-
- _refreshRange: function( orientation ) {
- if ( orientation === "vertical" ) {
- this.range.css( { "width": "", "left": "" } );
- }
- if ( orientation === "horizontal" ) {
- this.range.css( { "height": "", "bottom": "" } );
- }
- },
-
- _refreshValue: function() {
- var lastValPercent, valPercent, value, valueMin, valueMax,
- oRange = this.options.range,
- o = this.options,
- that = this,
- animate = ( !this._animateOff ) ? o.animate : false,
- _set = {};
-
- if ( this._hasMultipleValues() ) {
- this.handles.each( function( i ) {
- valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
- that._valueMin() ) * 100;
- _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
- $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
- if ( that.options.range === true ) {
- if ( that.orientation === "horizontal" ) {
- if ( i === 0 ) {
- that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
- left: valPercent + "%"
- }, o.animate );
- }
- if ( i === 1 ) {
- that.range[ animate ? "animate" : "css" ]( {
- width: ( valPercent - lastValPercent ) + "%"
- }, {
- queue: false,
- duration: o.animate
- } );
- }
- } else {
- if ( i === 0 ) {
- that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
- bottom: ( valPercent ) + "%"
- }, o.animate );
- }
- if ( i === 1 ) {
- that.range[ animate ? "animate" : "css" ]( {
- height: ( valPercent - lastValPercent ) + "%"
- }, {
- queue: false,
- duration: o.animate
- } );
- }
- }
- }
- lastValPercent = valPercent;
- } );
- } else {
- value = this.value();
- valueMin = this._valueMin();
- valueMax = this._valueMax();
- valPercent = ( valueMax !== valueMin ) ?
- ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
- 0;
- _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
- this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
-
- if ( oRange === "min" && this.orientation === "horizontal" ) {
- this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
- width: valPercent + "%"
- }, o.animate );
- }
- if ( oRange === "max" && this.orientation === "horizontal" ) {
- this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
- width: ( 100 - valPercent ) + "%"
- }, o.animate );
- }
- if ( oRange === "min" && this.orientation === "vertical" ) {
- this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
- height: valPercent + "%"
- }, o.animate );
- }
- if ( oRange === "max" && this.orientation === "vertical" ) {
- this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
- height: ( 100 - valPercent ) + "%"
- }, o.animate );
- }
- }
- },
-
- _handleEvents: {
- keydown: function( event ) {
- var allowed, curVal, newVal, step,
- index = $( event.target ).data( "ui-slider-handle-index" );
-
- switch ( event.keyCode ) {
- case $.ui.keyCode.HOME:
- case $.ui.keyCode.END:
- case $.ui.keyCode.PAGE_UP:
- case $.ui.keyCode.PAGE_DOWN:
- case $.ui.keyCode.UP:
- case $.ui.keyCode.RIGHT:
- case $.ui.keyCode.DOWN:
- case $.ui.keyCode.LEFT:
- event.preventDefault();
- if ( !this._keySliding ) {
- this._keySliding = true;
- this._addClass( $( event.target ), null, "ui-state-active" );
- allowed = this._start( event, index );
- if ( allowed === false ) {
- return;
- }
- }
- break;
- }
-
- step = this.options.step;
- if ( this._hasMultipleValues() ) {
- curVal = newVal = this.values( index );
- } else {
- curVal = newVal = this.value();
- }
-
- switch ( event.keyCode ) {
- case $.ui.keyCode.HOME:
- newVal = this._valueMin();
- break;
- case $.ui.keyCode.END:
- newVal = this._valueMax();
- break;
- case $.ui.keyCode.PAGE_UP:
- newVal = this._trimAlignValue(
- curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
- );
- break;
- case $.ui.keyCode.PAGE_DOWN:
- newVal = this._trimAlignValue(
- curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
- break;
- case $.ui.keyCode.UP:
- case $.ui.keyCode.RIGHT:
- if ( curVal === this._valueMax() ) {
- return;
- }
- newVal = this._trimAlignValue( curVal + step );
- break;
- case $.ui.keyCode.DOWN:
- case $.ui.keyCode.LEFT:
- if ( curVal === this._valueMin() ) {
- return;
- }
- newVal = this._trimAlignValue( curVal - step );
- break;
- }
-
- this._slide( event, index, newVal );
- },
- keyup: function( event ) {
- var index = $( event.target ).data( "ui-slider-handle-index" );
-
- if ( this._keySliding ) {
- this._keySliding = false;
- this._stop( event, index );
- this._change( event, index );
- this._removeClass( $( event.target ), null, "ui-state-active" );
- }
- }
- }
-} );
-
-
-/*!
- * jQuery UI Sortable 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Sortable
-//>>group: Interactions
-//>>description: Enables items in a list to be sorted using the mouse.
-//>>docs: http://api.jqueryui.com/sortable/
-//>>demos: http://jqueryui.com/sortable/
-//>>css.structure: ../../themes/base/sortable.css
-
-
-var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
- version: "1.13.1",
- widgetEventPrefix: "sort",
- ready: false,
- options: {
- appendTo: "parent",
- axis: false,
- connectWith: false,
- containment: false,
- cursor: "auto",
- cursorAt: false,
- dropOnEmpty: true,
- forcePlaceholderSize: false,
- forceHelperSize: false,
- grid: false,
- handle: false,
- helper: "original",
- items: "> *",
- opacity: false,
- placeholder: false,
- revert: false,
- scroll: true,
- scrollSensitivity: 20,
- scrollSpeed: 20,
- scope: "default",
- tolerance: "intersect",
- zIndex: 1000,
-
- // Callbacks
- activate: null,
- beforeStop: null,
- change: null,
- deactivate: null,
- out: null,
- over: null,
- receive: null,
- remove: null,
- sort: null,
- start: null,
- stop: null,
- update: null
- },
-
- _isOverAxis: function( x, reference, size ) {
- return ( x >= reference ) && ( x < ( reference + size ) );
- },
-
- _isFloating: function( item ) {
- return ( /left|right/ ).test( item.css( "float" ) ) ||
- ( /inline|table-cell/ ).test( item.css( "display" ) );
- },
-
- _create: function() {
- this.containerCache = {};
- this._addClass( "ui-sortable" );
-
- //Get the items
- this.refresh();
-
- //Let's determine the parent's offset
- this.offset = this.element.offset();
-
- //Initialize mouse events for interaction
- this._mouseInit();
-
- this._setHandleClassName();
-
- //We're ready to go
- this.ready = true;
-
- },
-
- _setOption: function( key, value ) {
- this._super( key, value );
-
- if ( key === "handle" ) {
- this._setHandleClassName();
- }
- },
-
- _setHandleClassName: function() {
- var that = this;
- this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
- $.each( this.items, function() {
- that._addClass(
- this.instance.options.handle ?
- this.item.find( this.instance.options.handle ) :
- this.item,
- "ui-sortable-handle"
- );
- } );
- },
-
- _destroy: function() {
- this._mouseDestroy();
-
- for ( var i = this.items.length - 1; i >= 0; i-- ) {
- this.items[ i ].item.removeData( this.widgetName + "-item" );
- }
-
- return this;
- },
-
- _mouseCapture: function( event, overrideHandle ) {
- var currentItem = null,
- validHandle = false,
- that = this;
-
- if ( this.reverting ) {
- return false;
- }
-
- if ( this.options.disabled || this.options.type === "static" ) {
- return false;
- }
-
- //We have to refresh the items data once first
- this._refreshItems( event );
-
- //Find out if the clicked node (or one of its parents) is a actual item in this.items
- $( event.target ).parents().each( function() {
- if ( $.data( this, that.widgetName + "-item" ) === that ) {
- currentItem = $( this );
- return false;
- }
- } );
- if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
- currentItem = $( event.target );
- }
-
- if ( !currentItem ) {
- return false;
- }
- if ( this.options.handle && !overrideHandle ) {
- $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
- if ( this === event.target ) {
- validHandle = true;
- }
- } );
- if ( !validHandle ) {
- return false;
- }
- }
-
- this.currentItem = currentItem;
- this._removeCurrentsFromItems();
- return true;
-
- },
-
- _mouseStart: function( event, overrideHandle, noActivation ) {
-
- var i, body,
- o = this.options;
-
- this.currentContainer = this;
-
- //We only need to call refreshPositions, because the refreshItems call has been moved to
- // mouseCapture
- this.refreshPositions();
-
- //Prepare the dragged items parent
- this.appendTo = $( o.appendTo !== "parent" ?
- o.appendTo :
- this.currentItem.parent() );
-
- //Create and append the visible helper
- this.helper = this._createHelper( event );
-
- //Cache the helper size
- this._cacheHelperProportions();
-
- /*
- * - Position generation -
- * This block generates everything position related - it's the core of draggables.
- */
-
- //Cache the margins of the original element
- this._cacheMargins();
-
- //The element's absolute position on the page minus margins
- this.offset = this.currentItem.offset();
- this.offset = {
- top: this.offset.top - this.margins.top,
- left: this.offset.left - this.margins.left
- };
-
- $.extend( this.offset, {
- click: { //Where the click happened, relative to the element
- left: event.pageX - this.offset.left,
- top: event.pageY - this.offset.top
- },
-
- // This is a relative to absolute position minus the actual position calculation -
- // only used for relative positioned helper
- relative: this._getRelativeOffset()
- } );
-
- // After we get the helper offset, but before we get the parent offset we can
- // change the helper's position to absolute
- // TODO: Still need to figure out a way to make relative sorting possible
- this.helper.css( "position", "absolute" );
- this.cssPosition = this.helper.css( "position" );
-
- //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
- if ( o.cursorAt ) {
- this._adjustOffsetFromHelper( o.cursorAt );
- }
-
- //Cache the former DOM position
- this.domPosition = {
- prev: this.currentItem.prev()[ 0 ],
- parent: this.currentItem.parent()[ 0 ]
- };
-
- // If the helper is not the original, hide the original so it's not playing any role during
- // the drag, won't cause anything bad this way
- if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
- this.currentItem.hide();
- }
-
- //Create the placeholder
- this._createPlaceholder();
-
- //Get the next scrolling parent
- this.scrollParent = this.placeholder.scrollParent();
-
- $.extend( this.offset, {
- parent: this._getParentOffset()
- } );
-
- //Set a containment if given in the options
- if ( o.containment ) {
- this._setContainment();
- }
-
- if ( o.cursor && o.cursor !== "auto" ) { // cursor option
- body = this.document.find( "body" );
-
- // Support: IE
- this.storedCursor = body.css( "cursor" );
- body.css( "cursor", o.cursor );
-
- this.storedStylesheet =
- $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
- }
-
- // We need to make sure to grab the zIndex before setting the
- // opacity, because setting the opacity to anything lower than 1
- // causes the zIndex to change from "auto" to 0.
- if ( o.zIndex ) { // zIndex option
- if ( this.helper.css( "zIndex" ) ) {
- this._storedZIndex = this.helper.css( "zIndex" );
- }
- this.helper.css( "zIndex", o.zIndex );
- }
-
- if ( o.opacity ) { // opacity option
- if ( this.helper.css( "opacity" ) ) {
- this._storedOpacity = this.helper.css( "opacity" );
- }
- this.helper.css( "opacity", o.opacity );
- }
-
- //Prepare scrolling
- if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
- this.scrollParent[ 0 ].tagName !== "HTML" ) {
- this.overflowOffset = this.scrollParent.offset();
- }
-
- //Call callbacks
- this._trigger( "start", event, this._uiHash() );
-
- //Recache the helper size
- if ( !this._preserveHelperProportions ) {
- this._cacheHelperProportions();
- }
-
- //Post "activate" events to possible containers
- if ( !noActivation ) {
- for ( i = this.containers.length - 1; i >= 0; i-- ) {
- this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
- }
- }
-
- //Prepare possible droppables
- if ( $.ui.ddmanager ) {
- $.ui.ddmanager.current = this;
- }
-
- if ( $.ui.ddmanager && !o.dropBehaviour ) {
- $.ui.ddmanager.prepareOffsets( this, event );
- }
-
- this.dragging = true;
-
- this._addClass( this.helper, "ui-sortable-helper" );
-
- //Move the helper, if needed
- if ( !this.helper.parent().is( this.appendTo ) ) {
- this.helper.detach().appendTo( this.appendTo );
-
- //Update position
- this.offset.parent = this._getParentOffset();
- }
-
- //Generate the original position
- this.position = this.originalPosition = this._generatePosition( event );
- this.originalPageX = event.pageX;
- this.originalPageY = event.pageY;
- this.lastPositionAbs = this.positionAbs = this._convertPositionTo( "absolute" );
-
- this._mouseDrag( event );
-
- return true;
-
- },
-
- _scroll: function( event ) {
- var o = this.options,
- scrolled = false;
-
- if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
- this.scrollParent[ 0 ].tagName !== "HTML" ) {
-
- if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
- event.pageY < o.scrollSensitivity ) {
- this.scrollParent[ 0 ].scrollTop =
- scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
- } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
- this.scrollParent[ 0 ].scrollTop =
- scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
- }
-
- if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
- event.pageX < o.scrollSensitivity ) {
- this.scrollParent[ 0 ].scrollLeft = scrolled =
- this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
- } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
- this.scrollParent[ 0 ].scrollLeft = scrolled =
- this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
- }
-
- } else {
-
- if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
- scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
- } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
- o.scrollSensitivity ) {
- scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
- }
-
- if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
- scrolled = this.document.scrollLeft(
- this.document.scrollLeft() - o.scrollSpeed
- );
- } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
- o.scrollSensitivity ) {
- scrolled = this.document.scrollLeft(
- this.document.scrollLeft() + o.scrollSpeed
- );
- }
-
- }
-
- return scrolled;
- },
-
- _mouseDrag: function( event ) {
- var i, item, itemElement, intersection,
- o = this.options;
-
- //Compute the helpers position
- this.position = this._generatePosition( event );
- this.positionAbs = this._convertPositionTo( "absolute" );
-
- //Set the helper position
- if ( !this.options.axis || this.options.axis !== "y" ) {
- this.helper[ 0 ].style.left = this.position.left + "px";
- }
- if ( !this.options.axis || this.options.axis !== "x" ) {
- this.helper[ 0 ].style.top = this.position.top + "px";
- }
-
- //Do scrolling
- if ( o.scroll ) {
- if ( this._scroll( event ) !== false ) {
-
- //Update item positions used in position checks
- this._refreshItemPositions( true );
-
- if ( $.ui.ddmanager && !o.dropBehaviour ) {
- $.ui.ddmanager.prepareOffsets( this, event );
- }
- }
- }
-
- this.dragDirection = {
- vertical: this._getDragVerticalDirection(),
- horizontal: this._getDragHorizontalDirection()
- };
-
- //Rearrange
- for ( i = this.items.length - 1; i >= 0; i-- ) {
-
- //Cache variables and intersection, continue if no intersection
- item = this.items[ i ];
- itemElement = item.item[ 0 ];
- intersection = this._intersectsWithPointer( item );
- if ( !intersection ) {
- continue;
- }
-
- // Only put the placeholder inside the current Container, skip all
- // items from other containers. This works because when moving
- // an item from one container to another the
- // currentContainer is switched before the placeholder is moved.
- //
- // Without this, moving items in "sub-sortables" can cause
- // the placeholder to jitter between the outer and inner container.
- if ( item.instance !== this.currentContainer ) {
- continue;
- }
-
- // Cannot intersect with itself
- // no useless actions that have been done before
- // no action if the item moved is the parent of the item checked
- if ( itemElement !== this.currentItem[ 0 ] &&
- this.placeholder[ intersection === 1 ?
- "next" : "prev" ]()[ 0 ] !== itemElement &&
- !$.contains( this.placeholder[ 0 ], itemElement ) &&
- ( this.options.type === "semi-dynamic" ?
- !$.contains( this.element[ 0 ], itemElement ) :
- true
- )
- ) {
-
- this.direction = intersection === 1 ? "down" : "up";
-
- if ( this.options.tolerance === "pointer" ||
- this._intersectsWithSides( item ) ) {
- this._rearrange( event, item );
- } else {
- break;
- }
-
- this._trigger( "change", event, this._uiHash() );
- break;
- }
- }
-
- //Post events to containers
- this._contactContainers( event );
-
- //Interconnect with droppables
- if ( $.ui.ddmanager ) {
- $.ui.ddmanager.drag( this, event );
- }
-
- //Call callbacks
- this._trigger( "sort", event, this._uiHash() );
-
- this.lastPositionAbs = this.positionAbs;
- return false;
-
- },
-
- _mouseStop: function( event, noPropagation ) {
-
- if ( !event ) {
- return;
- }
-
- //If we are using droppables, inform the manager about the drop
- if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
- $.ui.ddmanager.drop( this, event );
- }
-
- if ( this.options.revert ) {
- var that = this,
- cur = this.placeholder.offset(),
- axis = this.options.axis,
- animation = {};
-
- if ( !axis || axis === "x" ) {
- animation.left = cur.left - this.offset.parent.left - this.margins.left +
- ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
- 0 :
- this.offsetParent[ 0 ].scrollLeft
- );
- }
- if ( !axis || axis === "y" ) {
- animation.top = cur.top - this.offset.parent.top - this.margins.top +
- ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
- 0 :
- this.offsetParent[ 0 ].scrollTop
- );
- }
- this.reverting = true;
- $( this.helper ).animate(
- animation,
- parseInt( this.options.revert, 10 ) || 500,
- function() {
- that._clear( event );
- }
- );
- } else {
- this._clear( event, noPropagation );
- }
-
- return false;
-
- },
-
- cancel: function() {
-
- if ( this.dragging ) {
-
- this._mouseUp( new $.Event( "mouseup", { target: null } ) );
-
- if ( this.options.helper === "original" ) {
- this.currentItem.css( this._storedCSS );
- this._removeClass( this.currentItem, "ui-sortable-helper" );
- } else {
- this.currentItem.show();
- }
-
- //Post deactivating events to containers
- for ( var i = this.containers.length - 1; i >= 0; i-- ) {
- this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
- if ( this.containers[ i ].containerCache.over ) {
- this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
- this.containers[ i ].containerCache.over = 0;
- }
- }
-
- }
-
- if ( this.placeholder ) {
-
- //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
- // it unbinds ALL events from the original node!
- if ( this.placeholder[ 0 ].parentNode ) {
- this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
- }
- if ( this.options.helper !== "original" && this.helper &&
- this.helper[ 0 ].parentNode ) {
- this.helper.remove();
- }
-
- $.extend( this, {
- helper: null,
- dragging: false,
- reverting: false,
- _noFinalSort: null
- } );
-
- if ( this.domPosition.prev ) {
- $( this.domPosition.prev ).after( this.currentItem );
- } else {
- $( this.domPosition.parent ).prepend( this.currentItem );
- }
- }
-
- return this;
-
- },
-
- serialize: function( o ) {
-
- var items = this._getItemsAsjQuery( o && o.connected ),
- str = [];
- o = o || {};
-
- $( items ).each( function() {
- var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
- .match( o.expression || ( /(.+)[\-=_](.+)/ ) );
- if ( res ) {
- str.push(
- ( o.key || res[ 1 ] + "[]" ) +
- "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
- }
- } );
-
- if ( !str.length && o.key ) {
- str.push( o.key + "=" );
- }
-
- return str.join( "&" );
-
- },
-
- toArray: function( o ) {
-
- var items = this._getItemsAsjQuery( o && o.connected ),
- ret = [];
-
- o = o || {};
-
- items.each( function() {
- ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
- } );
- return ret;
-
- },
-
- /* Be careful with the following core functions */
- _intersectsWith: function( item ) {
-
- var x1 = this.positionAbs.left,
- x2 = x1 + this.helperProportions.width,
- y1 = this.positionAbs.top,
- y2 = y1 + this.helperProportions.height,
- l = item.left,
- r = l + item.width,
- t = item.top,
- b = t + item.height,
- dyClick = this.offset.click.top,
- dxClick = this.offset.click.left,
- isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
- ( y1 + dyClick ) < b ),
- isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
- ( x1 + dxClick ) < r ),
- isOverElement = isOverElementHeight && isOverElementWidth;
-
- if ( this.options.tolerance === "pointer" ||
- this.options.forcePointerForContainers ||
- ( this.options.tolerance !== "pointer" &&
- this.helperProportions[ this.floating ? "width" : "height" ] >
- item[ this.floating ? "width" : "height" ] )
- ) {
- return isOverElement;
- } else {
-
- return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
- x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
- t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
- y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
-
- }
- },
-
- _intersectsWithPointer: function( item ) {
- var verticalDirection, horizontalDirection,
- isOverElementHeight = ( this.options.axis === "x" ) ||
- this._isOverAxis(
- this.positionAbs.top + this.offset.click.top, item.top, item.height ),
- isOverElementWidth = ( this.options.axis === "y" ) ||
- this._isOverAxis(
- this.positionAbs.left + this.offset.click.left, item.left, item.width ),
- isOverElement = isOverElementHeight && isOverElementWidth;
-
- if ( !isOverElement ) {
- return false;
- }
-
- verticalDirection = this.dragDirection.vertical;
- horizontalDirection = this.dragDirection.horizontal;
-
- return this.floating ?
- ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 ) :
- ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
-
- },
-
- _intersectsWithSides: function( item ) {
-
- var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
- this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
- isOverRightHalf = this._isOverAxis( this.positionAbs.left +
- this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
- verticalDirection = this.dragDirection.vertical,
- horizontalDirection = this.dragDirection.horizontal;
-
- if ( this.floating && horizontalDirection ) {
- return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
- ( horizontalDirection === "left" && !isOverRightHalf ) );
- } else {
- return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
- ( verticalDirection === "up" && !isOverBottomHalf ) );
- }
-
- },
-
- _getDragVerticalDirection: function() {
- var delta = this.positionAbs.top - this.lastPositionAbs.top;
- return delta !== 0 && ( delta > 0 ? "down" : "up" );
- },
-
- _getDragHorizontalDirection: function() {
- var delta = this.positionAbs.left - this.lastPositionAbs.left;
- return delta !== 0 && ( delta > 0 ? "right" : "left" );
- },
-
- refresh: function( event ) {
- this._refreshItems( event );
- this._setHandleClassName();
- this.refreshPositions();
- return this;
- },
-
- _connectWith: function() {
- var options = this.options;
- return options.connectWith.constructor === String ?
- [ options.connectWith ] :
- options.connectWith;
- },
-
- _getItemsAsjQuery: function( connected ) {
-
- var i, j, cur, inst,
- items = [],
- queries = [],
- connectWith = this._connectWith();
-
- if ( connectWith && connected ) {
- for ( i = connectWith.length - 1; i >= 0; i-- ) {
- cur = $( connectWith[ i ], this.document[ 0 ] );
- for ( j = cur.length - 1; j >= 0; j-- ) {
- inst = $.data( cur[ j ], this.widgetFullName );
- if ( inst && inst !== this && !inst.options.disabled ) {
- queries.push( [ typeof inst.options.items === "function" ?
- inst.options.items.call( inst.element ) :
- $( inst.options.items, inst.element )
- .not( ".ui-sortable-helper" )
- .not( ".ui-sortable-placeholder" ), inst ] );
- }
- }
- }
- }
-
- queries.push( [ typeof this.options.items === "function" ?
- this.options.items
- .call( this.element, null, { options: this.options, item: this.currentItem } ) :
- $( this.options.items, this.element )
- .not( ".ui-sortable-helper" )
- .not( ".ui-sortable-placeholder" ), this ] );
-
- function addItems() {
- items.push( this );
- }
- for ( i = queries.length - 1; i >= 0; i-- ) {
- queries[ i ][ 0 ].each( addItems );
- }
-
- return $( items );
-
- },
-
- _removeCurrentsFromItems: function() {
-
- var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
-
- this.items = $.grep( this.items, function( item ) {
- for ( var j = 0; j < list.length; j++ ) {
- if ( list[ j ] === item.item[ 0 ] ) {
- return false;
- }
- }
- return true;
- } );
-
- },
-
- _refreshItems: function( event ) {
-
- this.items = [];
- this.containers = [ this ];
-
- var i, j, cur, inst, targetData, _queries, item, queriesLength,
- items = this.items,
- queries = [ [ typeof this.options.items === "function" ?
- this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
- $( this.options.items, this.element ), this ] ],
- connectWith = this._connectWith();
-
- //Shouldn't be run the first time through due to massive slow-down
- if ( connectWith && this.ready ) {
- for ( i = connectWith.length - 1; i >= 0; i-- ) {
- cur = $( connectWith[ i ], this.document[ 0 ] );
- for ( j = cur.length - 1; j >= 0; j-- ) {
- inst = $.data( cur[ j ], this.widgetFullName );
- if ( inst && inst !== this && !inst.options.disabled ) {
- queries.push( [ typeof inst.options.items === "function" ?
- inst.options.items
- .call( inst.element[ 0 ], event, { item: this.currentItem } ) :
- $( inst.options.items, inst.element ), inst ] );
- this.containers.push( inst );
- }
- }
- }
- }
-
- for ( i = queries.length - 1; i >= 0; i-- ) {
- targetData = queries[ i ][ 1 ];
- _queries = queries[ i ][ 0 ];
-
- for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
- item = $( _queries[ j ] );
-
- // Data for target checking (mouse manager)
- item.data( this.widgetName + "-item", targetData );
-
- items.push( {
- item: item,
- instance: targetData,
- width: 0, height: 0,
- left: 0, top: 0
- } );
- }
- }
-
- },
-
- _refreshItemPositions: function( fast ) {
- var i, item, t, p;
-
- for ( i = this.items.length - 1; i >= 0; i-- ) {
- item = this.items[ i ];
-
- //We ignore calculating positions of all connected containers when we're not over them
- if ( this.currentContainer && item.instance !== this.currentContainer &&
- item.item[ 0 ] !== this.currentItem[ 0 ] ) {
- continue;
- }
-
- t = this.options.toleranceElement ?
- $( this.options.toleranceElement, item.item ) :
- item.item;
-
- if ( !fast ) {
- item.width = t.outerWidth();
- item.height = t.outerHeight();
- }
-
- p = t.offset();
- item.left = p.left;
- item.top = p.top;
- }
- },
-
- refreshPositions: function( fast ) {
-
- // Determine whether items are being displayed horizontally
- this.floating = this.items.length ?
- this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
- false;
-
- // This has to be redone because due to the item being moved out/into the offsetParent,
- // the offsetParent's position will change
- if ( this.offsetParent && this.helper ) {
- this.offset.parent = this._getParentOffset();
- }
-
- this._refreshItemPositions( fast );
-
- var i, p;
-
- if ( this.options.custom && this.options.custom.refreshContainers ) {
- this.options.custom.refreshContainers.call( this );
- } else {
- for ( i = this.containers.length - 1; i >= 0; i-- ) {
- p = this.containers[ i ].element.offset();
- this.containers[ i ].containerCache.left = p.left;
- this.containers[ i ].containerCache.top = p.top;
- this.containers[ i ].containerCache.width =
- this.containers[ i ].element.outerWidth();
- this.containers[ i ].containerCache.height =
- this.containers[ i ].element.outerHeight();
- }
- }
-
- return this;
- },
-
- _createPlaceholder: function( that ) {
- that = that || this;
- var className, nodeName,
- o = that.options;
-
- if ( !o.placeholder || o.placeholder.constructor === String ) {
- className = o.placeholder;
- nodeName = that.currentItem[ 0 ].nodeName.toLowerCase();
- o.placeholder = {
- element: function() {
-
- var element = $( "<" + nodeName + ">", that.document[ 0 ] );
-
- that._addClass( element, "ui-sortable-placeholder",
- className || that.currentItem[ 0 ].className )
- ._removeClass( element, "ui-sortable-helper" );
-
- if ( nodeName === "tbody" ) {
- that._createTrPlaceholder(
- that.currentItem.find( "tr" ).eq( 0 ),
- $( "<tr>", that.document[ 0 ] ).appendTo( element )
- );
- } else if ( nodeName === "tr" ) {
- that._createTrPlaceholder( that.currentItem, element );
- } else if ( nodeName === "img" ) {
- element.attr( "src", that.currentItem.attr( "src" ) );
- }
-
- if ( !className ) {
- element.css( "visibility", "hidden" );
- }
-
- return element;
- },
- update: function( container, p ) {
-
- // 1. If a className is set as 'placeholder option, we don't force sizes -
- // the class is responsible for that
- // 2. The option 'forcePlaceholderSize can be enabled to force it even if a
- // class name is specified
- if ( className && !o.forcePlaceholderSize ) {
- return;
- }
-
- // If the element doesn't have a actual height or width by itself (without
- // styles coming from a stylesheet), it receives the inline height and width
- // from the dragged item. Or, if it's a tbody or tr, it's going to have a height
- // anyway since we're populating them with <td>s above, but they're unlikely to
- // be the correct height on their own if the row heights are dynamic, so we'll
- // always assign the height of the dragged item given forcePlaceholderSize
- // is true.
- if ( !p.height() || ( o.forcePlaceholderSize &&
- ( nodeName === "tbody" || nodeName === "tr" ) ) ) {
- p.height(
- that.currentItem.innerHeight() -
- parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
- parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
- }
- if ( !p.width() ) {
- p.width(
- that.currentItem.innerWidth() -
- parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
- parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
- }
- }
- };
- }
-
- //Create the placeholder
- that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
-
- //Append it after the actual current item
- that.currentItem.after( that.placeholder );
-
- //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
- o.placeholder.update( that, that.placeholder );
-
- },
-
- _createTrPlaceholder: function( sourceTr, targetTr ) {
- var that = this;
-
- sourceTr.children().each( function() {
- $( "<td>&#160;</td>", that.document[ 0 ] )
- .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
- .appendTo( targetTr );
- } );
- },
-
- _contactContainers: function( event ) {
- var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
- floating, axis,
- innermostContainer = null,
- innermostIndex = null;
-
- // Get innermost container that intersects with item
- for ( i = this.containers.length - 1; i >= 0; i-- ) {
-
- // Never consider a container that's located within the item itself
- if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
- continue;
- }
-
- if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
-
- // If we've already found a container and it's more "inner" than this, then continue
- if ( innermostContainer &&
- $.contains(
- this.containers[ i ].element[ 0 ],
- innermostContainer.element[ 0 ] ) ) {
- continue;
- }
-
- innermostContainer = this.containers[ i ];
- innermostIndex = i;
-
- } else {
-
- // container doesn't intersect. trigger "out" event if necessary
- if ( this.containers[ i ].containerCache.over ) {
- this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
- this.containers[ i ].containerCache.over = 0;
- }
- }
-
- }
-
- // If no intersecting containers found, return
- if ( !innermostContainer ) {
- return;
- }
-
- // Move the item into the container if it's not there already
- if ( this.containers.length === 1 ) {
- if ( !this.containers[ innermostIndex ].containerCache.over ) {
- this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
- this.containers[ innermostIndex ].containerCache.over = 1;
- }
- } else {
-
- // When entering a new container, we will find the item with the least distance and
- // append our item near it
- dist = 10000;
- itemWithLeastDistance = null;
- floating = innermostContainer.floating || this._isFloating( this.currentItem );
- posProperty = floating ? "left" : "top";
- sizeProperty = floating ? "width" : "height";
- axis = floating ? "pageX" : "pageY";
-
- for ( j = this.items.length - 1; j >= 0; j-- ) {
- if ( !$.contains(
- this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
- ) {
- continue;
- }
- if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
- continue;
- }
-
- cur = this.items[ j ].item.offset()[ posProperty ];
- nearBottom = false;
- if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
- nearBottom = true;
- }
-
- if ( Math.abs( event[ axis ] - cur ) < dist ) {
- dist = Math.abs( event[ axis ] - cur );
- itemWithLeastDistance = this.items[ j ];
- this.direction = nearBottom ? "up" : "down";
- }
- }
-
- //Check if dropOnEmpty is enabled
- if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
- return;
- }
-
- if ( this.currentContainer === this.containers[ innermostIndex ] ) {
- if ( !this.currentContainer.containerCache.over ) {
- this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
- this.currentContainer.containerCache.over = 1;
- }
- return;
- }
-
- if ( itemWithLeastDistance ) {
- this._rearrange( event, itemWithLeastDistance, null, true );
- } else {
- this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
- }
- this._trigger( "change", event, this._uiHash() );
- this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
- this.currentContainer = this.containers[ innermostIndex ];
-
- //Update the placeholder
- this.options.placeholder.update( this.currentContainer, this.placeholder );
-
- //Update scrollParent
- this.scrollParent = this.placeholder.scrollParent();
-
- //Update overflowOffset
- if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
- this.scrollParent[ 0 ].tagName !== "HTML" ) {
- this.overflowOffset = this.scrollParent.offset();
- }
-
- this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
- this.containers[ innermostIndex ].containerCache.over = 1;
- }
-
- },
-
- _createHelper: function( event ) {
-
- var o = this.options,
- helper = typeof o.helper === "function" ?
- $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
- ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
-
- //Add the helper to the DOM if that didn't happen already
- if ( !helper.parents( "body" ).length ) {
- this.appendTo[ 0 ].appendChild( helper[ 0 ] );
- }
-
- if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
- this._storedCSS = {
- width: this.currentItem[ 0 ].style.width,
- height: this.currentItem[ 0 ].style.height,
- position: this.currentItem.css( "position" ),
- top: this.currentItem.css( "top" ),
- left: this.currentItem.css( "left" )
- };
- }
-
- if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
- helper.width( this.currentItem.width() );
- }
- if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
- helper.height( this.currentItem.height() );
- }
-
- return helper;
-
- },
-
- _adjustOffsetFromHelper: function( obj ) {
- if ( typeof obj === "string" ) {
- obj = obj.split( " " );
- }
- if ( Array.isArray( obj ) ) {
- obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
- }
- if ( "left" in obj ) {
- this.offset.click.left = obj.left + this.margins.left;
- }
- if ( "right" in obj ) {
- this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
- }
- if ( "top" in obj ) {
- this.offset.click.top = obj.top + this.margins.top;
- }
- if ( "bottom" in obj ) {
- this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
- }
- },
-
- _getParentOffset: function() {
-
- //Get the offsetParent and cache its position
- this.offsetParent = this.helper.offsetParent();
- var po = this.offsetParent.offset();
-
- // This is a special case where we need to modify a offset calculated on start, since the
- // following happened:
- // 1. The position of the helper is absolute, so it's position is calculated based on the
- // next positioned parent
- // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
- // the document, which means that the scroll is included in the initial calculation of the
- // offset of the parent, and never recalculated upon drag
- if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
- $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
- po.left += this.scrollParent.scrollLeft();
- po.top += this.scrollParent.scrollTop();
- }
-
- // This needs to be actually done for all browsers, since pageX/pageY includes this
- // information with an ugly IE fix
- if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
- ( this.offsetParent[ 0 ].tagName &&
- this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
- po = { top: 0, left: 0 };
- }
-
- return {
- top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
- left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
- };
-
- },
-
- _getRelativeOffset: function() {
-
- if ( this.cssPosition === "relative" ) {
- var p = this.currentItem.position();
- return {
- top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
- this.scrollParent.scrollTop(),
- left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
- this.scrollParent.scrollLeft()
- };
- } else {
- return { top: 0, left: 0 };
- }
-
- },
-
- _cacheMargins: function() {
- this.margins = {
- left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
- top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
- };
- },
-
- _cacheHelperProportions: function() {
- this.helperProportions = {
- width: this.helper.outerWidth(),
- height: this.helper.outerHeight()
- };
- },
-
- _setContainment: function() {
-
- var ce, co, over,
- o = this.options;
- if ( o.containment === "parent" ) {
- o.containment = this.helper[ 0 ].parentNode;
- }
- if ( o.containment === "document" || o.containment === "window" ) {
- this.containment = [
- 0 - this.offset.relative.left - this.offset.parent.left,
- 0 - this.offset.relative.top - this.offset.parent.top,
- o.containment === "document" ?
- this.document.width() :
- this.window.width() - this.helperProportions.width - this.margins.left,
- ( o.containment === "document" ?
- ( this.document.height() || document.body.parentNode.scrollHeight ) :
- this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
- ) - this.helperProportions.height - this.margins.top
- ];
- }
-
- if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
- ce = $( o.containment )[ 0 ];
- co = $( o.containment ).offset();
- over = ( $( ce ).css( "overflow" ) !== "hidden" );
-
- this.containment = [
- co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
- ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
- co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
- ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
- co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
- ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
- ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
- this.helperProportions.width - this.margins.left,
- co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
- ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
- ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
- this.helperProportions.height - this.margins.top
- ];
- }
-
- },
-
- _convertPositionTo: function( d, pos ) {
-
- if ( !pos ) {
- pos = this.position;
- }
- var mod = d === "absolute" ? 1 : -1,
- scroll = this.cssPosition === "absolute" &&
- !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
- $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
- this.offsetParent :
- this.scrollParent,
- scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
-
- return {
- top: (
-
- // The absolute mouse position
- pos.top +
-
- // Only for relative positioned nodes: Relative offset from element to offset parent
- this.offset.relative.top * mod +
-
- // The offsetParent's offset without borders (offset + border)
- this.offset.parent.top * mod -
- ( ( this.cssPosition === "fixed" ?
- -this.scrollParent.scrollTop() :
- ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
- ),
- left: (
-
- // The absolute mouse position
- pos.left +
-
- // Only for relative positioned nodes: Relative offset from element to offset parent
- this.offset.relative.left * mod +
-
- // The offsetParent's offset without borders (offset + border)
- this.offset.parent.left * mod -
- ( ( this.cssPosition === "fixed" ?
- -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
- scroll.scrollLeft() ) * mod )
- )
- };
-
- },
-
- _generatePosition: function( event ) {
-
- var top, left,
- o = this.options,
- pageX = event.pageX,
- pageY = event.pageY,
- scroll = this.cssPosition === "absolute" &&
- !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
- $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
- this.offsetParent :
- this.scrollParent,
- scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
-
- // This is another very weird special case that only happens for relative elements:
- // 1. If the css position is relative
- // 2. and the scroll parent is the document or similar to the offset parent
- // we have to refresh the relative offset during the scroll so there are no jumps
- if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
- this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
- this.offset.relative = this._getRelativeOffset();
- }
-
- /*
- * - Position constraining -
- * Constrain the position to a mix of grid, containment.
- */
-
- if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
-
- if ( this.containment ) {
- if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
- pageX = this.containment[ 0 ] + this.offset.click.left;
- }
- if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
- pageY = this.containment[ 1 ] + this.offset.click.top;
- }
- if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
- pageX = this.containment[ 2 ] + this.offset.click.left;
- }
- if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
- pageY = this.containment[ 3 ] + this.offset.click.top;
- }
- }
-
- if ( o.grid ) {
- top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
- o.grid[ 1 ] ) * o.grid[ 1 ];
- pageY = this.containment ?
- ( ( top - this.offset.click.top >= this.containment[ 1 ] &&
- top - this.offset.click.top <= this.containment[ 3 ] ) ?
- top :
- ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
- top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
- top;
-
- left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
- o.grid[ 0 ] ) * o.grid[ 0 ];
- pageX = this.containment ?
- ( ( left - this.offset.click.left >= this.containment[ 0 ] &&
- left - this.offset.click.left <= this.containment[ 2 ] ) ?
- left :
- ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
- left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
- left;
- }
-
- }
-
- return {
- top: (
-
- // The absolute mouse position
- pageY -
-
- // Click offset (relative to the element)
- this.offset.click.top -
-
- // Only for relative positioned nodes: Relative offset from element to offset parent
- this.offset.relative.top -
-
- // The offsetParent's offset without borders (offset + border)
- this.offset.parent.top +
- ( ( this.cssPosition === "fixed" ?
- -this.scrollParent.scrollTop() :
- ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
- ),
- left: (
-
- // The absolute mouse position
- pageX -
-
- // Click offset (relative to the element)
- this.offset.click.left -
-
- // Only for relative positioned nodes: Relative offset from element to offset parent
- this.offset.relative.left -
-
- // The offsetParent's offset without borders (offset + border)
- this.offset.parent.left +
- ( ( this.cssPosition === "fixed" ?
- -this.scrollParent.scrollLeft() :
- scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
- )
- };
-
- },
-
- _rearrange: function( event, i, a, hardRefresh ) {
-
- if ( a ) {
- a[ 0 ].appendChild( this.placeholder[ 0 ] );
- } else {
- i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
- ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
- }
-
- //Various things done here to improve the performance:
- // 1. we create a setTimeout, that calls refreshPositions
- // 2. on the instance, we have a counter variable, that get's higher after every append
- // 3. on the local scope, we copy the counter variable, and check in the timeout,
- // if it's still the same
- // 4. this lets only the last addition to the timeout stack through
- this.counter = this.counter ? ++this.counter : 1;
- var counter = this.counter;
-
- this._delay( function() {
- if ( counter === this.counter ) {
-
- //Precompute after each DOM insertion, NOT on mousemove
- this.refreshPositions( !hardRefresh );
- }
- } );
-
- },
-
- _clear: function( event, noPropagation ) {
-
- this.reverting = false;
-
- // We delay all events that have to be triggered to after the point where the placeholder
- // has been removed and everything else normalized again
- var i,
- delayedTriggers = [];
-
- // We first have to update the dom position of the actual currentItem
- // Note: don't do it if the current item is already removed (by a user), or it gets
- // reappended (see #4088)
- if ( !this._noFinalSort && this.currentItem.parent().length ) {
- this.placeholder.before( this.currentItem );
- }
- this._noFinalSort = null;
-
- if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
- for ( i in this._storedCSS ) {
- if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
- this._storedCSS[ i ] = "";
- }
- }
- this.currentItem.css( this._storedCSS );
- this._removeClass( this.currentItem, "ui-sortable-helper" );
- } else {
- this.currentItem.show();
- }
-
- if ( this.fromOutside && !noPropagation ) {
- delayedTriggers.push( function( event ) {
- this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
- } );
- }
- if ( ( this.fromOutside ||
- this.domPosition.prev !==
- this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
- this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
-
- // Trigger update callback if the DOM position has changed
- delayedTriggers.push( function( event ) {
- this._trigger( "update", event, this._uiHash() );
- } );
- }
-
- // Check if the items Container has Changed and trigger appropriate
- // events.
- if ( this !== this.currentContainer ) {
- if ( !noPropagation ) {
- delayedTriggers.push( function( event ) {
- this._trigger( "remove", event, this._uiHash() );
- } );
- delayedTriggers.push( ( function( c ) {
- return function( event ) {
- c._trigger( "receive", event, this._uiHash( this ) );
- };
- } ).call( this, this.currentContainer ) );
- delayedTriggers.push( ( function( c ) {
- return function( event ) {
- c._trigger( "update", event, this._uiHash( this ) );
- };
- } ).call( this, this.currentContainer ) );
- }
- }
-
- //Post events to containers
- function delayEvent( type, instance, container ) {
- return function( event ) {
- container._trigger( type, event, instance._uiHash( instance ) );
- };
- }
- for ( i = this.containers.length - 1; i >= 0; i-- ) {
- if ( !noPropagation ) {
- delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
- }
- if ( this.containers[ i ].containerCache.over ) {
- delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
- this.containers[ i ].containerCache.over = 0;
- }
- }
-
- //Do what was originally in plugins
- if ( this.storedCursor ) {
- this.document.find( "body" ).css( "cursor", this.storedCursor );
- this.storedStylesheet.remove();
- }
- if ( this._storedOpacity ) {
- this.helper.css( "opacity", this._storedOpacity );
- }
- if ( this._storedZIndex ) {
- this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
- }
-
- this.dragging = false;
-
- if ( !noPropagation ) {
- this._trigger( "beforeStop", event, this._uiHash() );
- }
-
- //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
- // it unbinds ALL events from the original node!
- this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
-
- if ( !this.cancelHelperRemoval ) {
- if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
- this.helper.remove();
- }
- this.helper = null;
- }
-
- if ( !noPropagation ) {
- for ( i = 0; i < delayedTriggers.length; i++ ) {
-
- // Trigger all delayed events
- delayedTriggers[ i ].call( this, event );
- }
- this._trigger( "stop", event, this._uiHash() );
- }
-
- this.fromOutside = false;
- return !this.cancelHelperRemoval;
-
- },
-
- _trigger: function() {
- if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
- this.cancel();
- }
- },
-
- _uiHash: function( _inst ) {
- var inst = _inst || this;
- return {
- helper: inst.helper,
- placeholder: inst.placeholder || $( [] ),
- position: inst.position,
- originalPosition: inst.originalPosition,
- offset: inst.positionAbs,
- item: inst.currentItem,
- sender: _inst ? _inst.element : null
- };
- }
-
-} );
-
-
-/*!
- * jQuery UI Spinner 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Spinner
-//>>group: Widgets
-//>>description: Displays buttons to easily input numbers via the keyboard or mouse.
-//>>docs: http://api.jqueryui.com/spinner/
-//>>demos: http://jqueryui.com/spinner/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/spinner.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-function spinnerModifier( fn ) {
- return function() {
- var previous = this.element.val();
- fn.apply( this, arguments );
- this._refresh();
- if ( previous !== this.element.val() ) {
- this._trigger( "change" );
- }
- };
-}
-
-$.widget( "ui.spinner", {
- version: "1.13.1",
- defaultElement: "<input>",
- widgetEventPrefix: "spin",
- options: {
- classes: {
- "ui-spinner": "ui-corner-all",
- "ui-spinner-down": "ui-corner-br",
- "ui-spinner-up": "ui-corner-tr"
- },
- culture: null,
- icons: {
- down: "ui-icon-triangle-1-s",
- up: "ui-icon-triangle-1-n"
- },
- incremental: true,
- max: null,
- min: null,
- numberFormat: null,
- page: 10,
- step: 1,
-
- change: null,
- spin: null,
- start: null,
- stop: null
- },
-
- _create: function() {
-
- // handle string values that need to be parsed
- this._setOption( "max", this.options.max );
- this._setOption( "min", this.options.min );
- this._setOption( "step", this.options.step );
-
- // Only format if there is a value, prevents the field from being marked
- // as invalid in Firefox, see #9573.
- if ( this.value() !== "" ) {
-
- // Format the value, but don't constrain.
- this._value( this.element.val(), true );
- }
-
- this._draw();
- this._on( this._events );
- this._refresh();
-
- // Turning off autocomplete prevents the browser from remembering the
- // value when navigating through history, so we re-enable autocomplete
- // if the page is unloaded before the widget is destroyed. #7790
- this._on( this.window, {
- beforeunload: function() {
- this.element.removeAttr( "autocomplete" );
- }
- } );
- },
-
- _getCreateOptions: function() {
- var options = this._super();
- var element = this.element;
-
- $.each( [ "min", "max", "step" ], function( i, option ) {
- var value = element.attr( option );
- if ( value != null && value.length ) {
- options[ option ] = value;
- }
- } );
-
- return options;
- },
-
- _events: {
- keydown: function( event ) {
- if ( this._start( event ) && this._keydown( event ) ) {
- event.preventDefault();
- }
- },
- keyup: "_stop",
- focus: function() {
- this.previous = this.element.val();
- },
- blur: function( event ) {
- if ( this.cancelBlur ) {
- delete this.cancelBlur;
- return;
- }
-
- this._stop();
- this._refresh();
- if ( this.previous !== this.element.val() ) {
- this._trigger( "change", event );
- }
- },
- mousewheel: function( event, delta ) {
- var activeElement = $.ui.safeActiveElement( this.document[ 0 ] );
- var isActive = this.element[ 0 ] === activeElement;
-
- if ( !isActive || !delta ) {
- return;
- }
-
- if ( !this.spinning && !this._start( event ) ) {
- return false;
- }
-
- this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
- clearTimeout( this.mousewheelTimer );
- this.mousewheelTimer = this._delay( function() {
- if ( this.spinning ) {
- this._stop( event );
- }
- }, 100 );
- event.preventDefault();
- },
- "mousedown .ui-spinner-button": function( event ) {
- var previous;
-
- // We never want the buttons to have focus; whenever the user is
- // interacting with the spinner, the focus should be on the input.
- // If the input is focused then this.previous is properly set from
- // when the input first received focus. If the input is not focused
- // then we need to set this.previous based on the value before spinning.
- previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ?
- this.previous : this.element.val();
- function checkFocus() {
- var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] );
- if ( !isActive ) {
- this.element.trigger( "focus" );
- this.previous = previous;
-
- // support: IE
- // IE sets focus asynchronously, so we need to check if focus
- // moved off of the input because the user clicked on the button.
- this._delay( function() {
- this.previous = previous;
- } );
- }
- }
-
- // Ensure focus is on (or stays on) the text field
- event.preventDefault();
- checkFocus.call( this );
-
- // Support: IE
- // IE doesn't prevent moving focus even with event.preventDefault()
- // so we set a flag to know when we should ignore the blur event
- // and check (again) if focus moved off of the input.
- this.cancelBlur = true;
- this._delay( function() {
- delete this.cancelBlur;
- checkFocus.call( this );
- } );
-
- if ( this._start( event ) === false ) {
- return;
- }
-
- this._repeat( null, $( event.currentTarget )
- .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
- },
- "mouseup .ui-spinner-button": "_stop",
- "mouseenter .ui-spinner-button": function( event ) {
-
- // button will add ui-state-active if mouse was down while mouseleave and kept down
- if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
- return;
- }
-
- if ( this._start( event ) === false ) {
- return false;
- }
- this._repeat( null, $( event.currentTarget )
- .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
- },
-
- // TODO: do we really want to consider this a stop?
- // shouldn't we just stop the repeater and wait until mouseup before
- // we trigger the stop event?
- "mouseleave .ui-spinner-button": "_stop"
- },
-
- // Support mobile enhanced option and make backcompat more sane
- _enhance: function() {
- this.uiSpinner = this.element
- .attr( "autocomplete", "off" )
- .wrap( "<span>" )
- .parent()
-
- // Add buttons
- .append(
- "<a></a><a></a>"
- );
- },
-
- _draw: function() {
- this._enhance();
-
- this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" );
- this._addClass( "ui-spinner-input" );
-
- this.element.attr( "role", "spinbutton" );
-
- // Button bindings
- this.buttons = this.uiSpinner.children( "a" )
- .attr( "tabIndex", -1 )
- .attr( "aria-hidden", true )
- .button( {
- classes: {
- "ui-button": ""
- }
- } );
-
- // TODO: Right now button does not support classes this is already updated in button PR
- this._removeClass( this.buttons, "ui-corner-all" );
-
- this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" );
- this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" );
- this.buttons.first().button( {
- "icon": this.options.icons.up,
- "showLabel": false
- } );
- this.buttons.last().button( {
- "icon": this.options.icons.down,
- "showLabel": false
- } );
-
- // IE 6 doesn't understand height: 50% for the buttons
- // unless the wrapper has an explicit height
- if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) &&
- this.uiSpinner.height() > 0 ) {
- this.uiSpinner.height( this.uiSpinner.height() );
- }
- },
-
- _keydown: function( event ) {
- var options = this.options,
- keyCode = $.ui.keyCode;
-
- switch ( event.keyCode ) {
- case keyCode.UP:
- this._repeat( null, 1, event );
- return true;
- case keyCode.DOWN:
- this._repeat( null, -1, event );
- return true;
- case keyCode.PAGE_UP:
- this._repeat( null, options.page, event );
- return true;
- case keyCode.PAGE_DOWN:
- this._repeat( null, -options.page, event );
- return true;
- }
-
- return false;
- },
-
- _start: function( event ) {
- if ( !this.spinning && this._trigger( "start", event ) === false ) {
- return false;
- }
-
- if ( !this.counter ) {
- this.counter = 1;
- }
- this.spinning = true;
- return true;
- },
-
- _repeat: function( i, steps, event ) {
- i = i || 500;
-
- clearTimeout( this.timer );
- this.timer = this._delay( function() {
- this._repeat( 40, steps, event );
- }, i );
-
- this._spin( steps * this.options.step, event );
- },
-
- _spin: function( step, event ) {
- var value = this.value() || 0;
-
- if ( !this.counter ) {
- this.counter = 1;
- }
-
- value = this._adjustValue( value + step * this._increment( this.counter ) );
-
- if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) {
- this._value( value );
- this.counter++;
- }
- },
-
- _increment: function( i ) {
- var incremental = this.options.incremental;
-
- if ( incremental ) {
- return typeof incremental === "function" ?
- incremental( i ) :
- Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
- }
-
- return 1;
- },
-
- _precision: function() {
- var precision = this._precisionOf( this.options.step );
- if ( this.options.min !== null ) {
- precision = Math.max( precision, this._precisionOf( this.options.min ) );
- }
- return precision;
- },
-
- _precisionOf: function( num ) {
- var str = num.toString(),
- decimal = str.indexOf( "." );
- return decimal === -1 ? 0 : str.length - decimal - 1;
- },
-
- _adjustValue: function( value ) {
- var base, aboveMin,
- options = this.options;
-
- // Make sure we're at a valid step
- // - find out where we are relative to the base (min or 0)
- base = options.min !== null ? options.min : 0;
- aboveMin = value - base;
-
- // - round to the nearest step
- aboveMin = Math.round( aboveMin / options.step ) * options.step;
-
- // - rounding is based on 0, so adjust back to our base
- value = base + aboveMin;
-
- // Fix precision from bad JS floating point math
- value = parseFloat( value.toFixed( this._precision() ) );
-
- // Clamp the value
- if ( options.max !== null && value > options.max ) {
- return options.max;
- }
- if ( options.min !== null && value < options.min ) {
- return options.min;
- }
-
- return value;
- },
-
- _stop: function( event ) {
- if ( !this.spinning ) {
- return;
- }
-
- clearTimeout( this.timer );
- clearTimeout( this.mousewheelTimer );
- this.counter = 0;
- this.spinning = false;
- this._trigger( "stop", event );
- },
-
- _setOption: function( key, value ) {
- var prevValue, first, last;
-
- if ( key === "culture" || key === "numberFormat" ) {
- prevValue = this._parse( this.element.val() );
- this.options[ key ] = value;
- this.element.val( this._format( prevValue ) );
- return;
- }
-
- if ( key === "max" || key === "min" || key === "step" ) {
- if ( typeof value === "string" ) {
- value = this._parse( value );
- }
- }
- if ( key === "icons" ) {
- first = this.buttons.first().find( ".ui-icon" );
- this._removeClass( first, null, this.options.icons.up );
- this._addClass( first, null, value.up );
- last = this.buttons.last().find( ".ui-icon" );
- this._removeClass( last, null, this.options.icons.down );
- this._addClass( last, null, value.down );
- }
-
- this._super( key, value );
- },
-
- _setOptionDisabled: function( value ) {
- this._super( value );
-
- this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value );
- this.element.prop( "disabled", !!value );
- this.buttons.button( value ? "disable" : "enable" );
- },
-
- _setOptions: spinnerModifier( function( options ) {
- this._super( options );
- } ),
-
- _parse: function( val ) {
- if ( typeof val === "string" && val !== "" ) {
- val = window.Globalize && this.options.numberFormat ?
- Globalize.parseFloat( val, 10, this.options.culture ) : +val;
- }
- return val === "" || isNaN( val ) ? null : val;
- },
-
- _format: function( value ) {
- if ( value === "" ) {
- return "";
- }
- return window.Globalize && this.options.numberFormat ?
- Globalize.format( value, this.options.numberFormat, this.options.culture ) :
- value;
- },
-
- _refresh: function() {
- this.element.attr( {
- "aria-valuemin": this.options.min,
- "aria-valuemax": this.options.max,
-
- // TODO: what should we do with values that can't be parsed?
- "aria-valuenow": this._parse( this.element.val() )
- } );
- },
-
- isValid: function() {
- var value = this.value();
-
- // Null is invalid
- if ( value === null ) {
- return false;
- }
-
- // If value gets adjusted, it's invalid
- return value === this._adjustValue( value );
- },
-
- // Update the value without triggering change
- _value: function( value, allowAny ) {
- var parsed;
- if ( value !== "" ) {
- parsed = this._parse( value );
- if ( parsed !== null ) {
- if ( !allowAny ) {
- parsed = this._adjustValue( parsed );
- }
- value = this._format( parsed );
- }
- }
- this.element.val( value );
- this._refresh();
- },
-
- _destroy: function() {
- this.element
- .prop( "disabled", false )
- .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" );
-
- this.uiSpinner.replaceWith( this.element );
- },
-
- stepUp: spinnerModifier( function( steps ) {
- this._stepUp( steps );
- } ),
- _stepUp: function( steps ) {
- if ( this._start() ) {
- this._spin( ( steps || 1 ) * this.options.step );
- this._stop();
- }
- },
-
- stepDown: spinnerModifier( function( steps ) {
- this._stepDown( steps );
- } ),
- _stepDown: function( steps ) {
- if ( this._start() ) {
- this._spin( ( steps || 1 ) * -this.options.step );
- this._stop();
- }
- },
-
- pageUp: spinnerModifier( function( pages ) {
- this._stepUp( ( pages || 1 ) * this.options.page );
- } ),
-
- pageDown: spinnerModifier( function( pages ) {
- this._stepDown( ( pages || 1 ) * this.options.page );
- } ),
-
- value: function( newVal ) {
- if ( !arguments.length ) {
- return this._parse( this.element.val() );
- }
- spinnerModifier( this._value ).call( this, newVal );
- },
-
- widget: function() {
- return this.uiSpinner;
- }
-} );
-
-// DEPRECATED
-// TODO: switch return back to widget declaration at top of file when this is removed
-if ( $.uiBackCompat !== false ) {
-
- // Backcompat for spinner html extension points
- $.widget( "ui.spinner", $.ui.spinner, {
- _enhance: function() {
- this.uiSpinner = this.element
- .attr( "autocomplete", "off" )
- .wrap( this._uiSpinnerHtml() )
- .parent()
-
- // Add buttons
- .append( this._buttonHtml() );
- },
- _uiSpinnerHtml: function() {
- return "<span>";
- },
-
- _buttonHtml: function() {
- return "<a></a><a></a>";
- }
- } );
-}
-
-var widgetsSpinner = $.ui.spinner;
-
-
-/*!
- * jQuery UI Tabs 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Tabs
-//>>group: Widgets
-//>>description: Transforms a set of container elements into a tab structure.
-//>>docs: http://api.jqueryui.com/tabs/
-//>>demos: http://jqueryui.com/tabs/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/tabs.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-$.widget( "ui.tabs", {
- version: "1.13.1",
- delay: 300,
- options: {
- active: null,
- classes: {
- "ui-tabs": "ui-corner-all",
- "ui-tabs-nav": "ui-corner-all",
- "ui-tabs-panel": "ui-corner-bottom",
- "ui-tabs-tab": "ui-corner-top"
- },
- collapsible: false,
- event: "click",
- heightStyle: "content",
- hide: null,
- show: null,
-
- // Callbacks
- activate: null,
- beforeActivate: null,
- beforeLoad: null,
- load: null
- },
-
- _isLocal: ( function() {
- var rhash = /#.*$/;
-
- return function( anchor ) {
- var anchorUrl, locationUrl;
-
- anchorUrl = anchor.href.replace( rhash, "" );
- locationUrl = location.href.replace( rhash, "" );
-
- // Decoding may throw an error if the URL isn't UTF-8 (#9518)
- try {
- anchorUrl = decodeURIComponent( anchorUrl );
- } catch ( error ) {}
- try {
- locationUrl = decodeURIComponent( locationUrl );
- } catch ( error ) {}
-
- return anchor.hash.length > 1 && anchorUrl === locationUrl;
- };
- } )(),
-
- _create: function() {
- var that = this,
- options = this.options;
-
- this.running = false;
-
- this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
- this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
-
- this._processTabs();
- options.active = this._initialActive();
-
- // Take disabling tabs via class attribute from HTML
- // into account and update option properly.
- if ( Array.isArray( options.disabled ) ) {
- options.disabled = $.uniqueSort( options.disabled.concat(
- $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
- return that.tabs.index( li );
- } )
- ) ).sort();
- }
-
- // Check for length avoids error when initializing empty list
- if ( this.options.active !== false && this.anchors.length ) {
- this.active = this._findActive( options.active );
- } else {
- this.active = $();
- }
-
- this._refresh();
-
- if ( this.active.length ) {
- this.load( options.active );
- }
- },
-
- _initialActive: function() {
- var active = this.options.active,
- collapsible = this.options.collapsible,
- locationHash = location.hash.substring( 1 );
-
- if ( active === null ) {
-
- // check the fragment identifier in the URL
- if ( locationHash ) {
- this.tabs.each( function( i, tab ) {
- if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
- active = i;
- return false;
- }
- } );
- }
-
- // Check for a tab marked active via a class
- if ( active === null ) {
- active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
- }
-
- // No active tab, set to false
- if ( active === null || active === -1 ) {
- active = this.tabs.length ? 0 : false;
- }
- }
-
- // Handle numbers: negative, out of range
- if ( active !== false ) {
- active = this.tabs.index( this.tabs.eq( active ) );
- if ( active === -1 ) {
- active = collapsible ? false : 0;
- }
- }
-
- // Don't allow collapsible: false and active: false
- if ( !collapsible && active === false && this.anchors.length ) {
- active = 0;
- }
-
- return active;
- },
-
- _getCreateEventData: function() {
- return {
- tab: this.active,
- panel: !this.active.length ? $() : this._getPanelForTab( this.active )
- };
- },
-
- _tabKeydown: function( event ) {
- var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
- selectedIndex = this.tabs.index( focusedTab ),
- goingForward = true;
-
- if ( this._handlePageNav( event ) ) {
- return;
- }
-
- switch ( event.keyCode ) {
- case $.ui.keyCode.RIGHT:
- case $.ui.keyCode.DOWN:
- selectedIndex++;
- break;
- case $.ui.keyCode.UP:
- case $.ui.keyCode.LEFT:
- goingForward = false;
- selectedIndex--;
- break;
- case $.ui.keyCode.END:
- selectedIndex = this.anchors.length - 1;
- break;
- case $.ui.keyCode.HOME:
- selectedIndex = 0;
- break;
- case $.ui.keyCode.SPACE:
-
- // Activate only, no collapsing
- event.preventDefault();
- clearTimeout( this.activating );
- this._activate( selectedIndex );
- return;
- case $.ui.keyCode.ENTER:
-
- // Toggle (cancel delayed activation, allow collapsing)
- event.preventDefault();
- clearTimeout( this.activating );
-
- // Determine if we should collapse or activate
- this._activate( selectedIndex === this.options.active ? false : selectedIndex );
- return;
- default:
- return;
- }
-
- // Focus the appropriate tab, based on which key was pressed
- event.preventDefault();
- clearTimeout( this.activating );
- selectedIndex = this._focusNextTab( selectedIndex, goingForward );
-
- // Navigating with control/command key will prevent automatic activation
- if ( !event.ctrlKey && !event.metaKey ) {
-
- // Update aria-selected immediately so that AT think the tab is already selected.
- // Otherwise AT may confuse the user by stating that they need to activate the tab,
- // but the tab will already be activated by the time the announcement finishes.
- focusedTab.attr( "aria-selected", "false" );
- this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
-
- this.activating = this._delay( function() {
- this.option( "active", selectedIndex );
- }, this.delay );
- }
- },
-
- _panelKeydown: function( event ) {
- if ( this._handlePageNav( event ) ) {
- return;
- }
-
- // Ctrl+up moves focus to the current tab
- if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
- event.preventDefault();
- this.active.trigger( "focus" );
- }
- },
-
- // Alt+page up/down moves focus to the previous/next tab (and activates)
- _handlePageNav: function( event ) {
- if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
- this._activate( this._focusNextTab( this.options.active - 1, false ) );
- return true;
- }
- if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
- this._activate( this._focusNextTab( this.options.active + 1, true ) );
- return true;
- }
- },
-
- _findNextTab: function( index, goingForward ) {
- var lastTabIndex = this.tabs.length - 1;
-
- function constrain() {
- if ( index > lastTabIndex ) {
- index = 0;
- }
- if ( index < 0 ) {
- index = lastTabIndex;
- }
- return index;
- }
-
- while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
- index = goingForward ? index + 1 : index - 1;
- }
-
- return index;
- },
-
- _focusNextTab: function( index, goingForward ) {
- index = this._findNextTab( index, goingForward );
- this.tabs.eq( index ).trigger( "focus" );
- return index;
- },
-
- _setOption: function( key, value ) {
- if ( key === "active" ) {
-
- // _activate() will handle invalid values and update this.options
- this._activate( value );
- return;
- }
-
- this._super( key, value );
-
- if ( key === "collapsible" ) {
- this._toggleClass( "ui-tabs-collapsible", null, value );
-
- // Setting collapsible: false while collapsed; open first panel
- if ( !value && this.options.active === false ) {
- this._activate( 0 );
- }
- }
-
- if ( key === "event" ) {
- this._setupEvents( value );
- }
-
- if ( key === "heightStyle" ) {
- this._setupHeightStyle( value );
- }
- },
-
- _sanitizeSelector: function( hash ) {
- return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
- },
-
- refresh: function() {
- var options = this.options,
- lis = this.tablist.children( ":has(a[href])" );
-
- // Get disabled tabs from class attribute from HTML
- // this will get converted to a boolean if needed in _refresh()
- options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
- return lis.index( tab );
- } );
-
- this._processTabs();
-
- // Was collapsed or no tabs
- if ( options.active === false || !this.anchors.length ) {
- options.active = false;
- this.active = $();
-
- // was active, but active tab is gone
- } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
-
- // all remaining tabs are disabled
- if ( this.tabs.length === options.disabled.length ) {
- options.active = false;
- this.active = $();
-
- // activate previous tab
- } else {
- this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
- }
-
- // was active, active tab still exists
- } else {
-
- // make sure active index is correct
- options.active = this.tabs.index( this.active );
- }
-
- this._refresh();
- },
-
- _refresh: function() {
- this._setOptionDisabled( this.options.disabled );
- this._setupEvents( this.options.event );
- this._setupHeightStyle( this.options.heightStyle );
-
- this.tabs.not( this.active ).attr( {
- "aria-selected": "false",
- "aria-expanded": "false",
- tabIndex: -1
- } );
- this.panels.not( this._getPanelForTab( this.active ) )
- .hide()
- .attr( {
- "aria-hidden": "true"
- } );
-
- // Make sure one tab is in the tab order
- if ( !this.active.length ) {
- this.tabs.eq( 0 ).attr( "tabIndex", 0 );
- } else {
- this.active
- .attr( {
- "aria-selected": "true",
- "aria-expanded": "true",
- tabIndex: 0
- } );
- this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
- this._getPanelForTab( this.active )
- .show()
- .attr( {
- "aria-hidden": "false"
- } );
- }
- },
-
- _processTabs: function() {
- var that = this,
- prevTabs = this.tabs,
- prevAnchors = this.anchors,
- prevPanels = this.panels;
-
- this.tablist = this._getList().attr( "role", "tablist" );
- this._addClass( this.tablist, "ui-tabs-nav",
- "ui-helper-reset ui-helper-clearfix ui-widget-header" );
-
- // Prevent users from focusing disabled tabs via click
- this.tablist
- .on( "mousedown" + this.eventNamespace, "> li", function( event ) {
- if ( $( this ).is( ".ui-state-disabled" ) ) {
- event.preventDefault();
- }
- } )
-
- // Support: IE <9
- // Preventing the default action in mousedown doesn't prevent IE
- // from focusing the element, so if the anchor gets focused, blur.
- // We don't have to worry about focusing the previously focused
- // element since clicking on a non-focusable element should focus
- // the body anyway.
- .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
- if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
- this.blur();
- }
- } );
-
- this.tabs = this.tablist.find( "> li:has(a[href])" )
- .attr( {
- role: "tab",
- tabIndex: -1
- } );
- this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
-
- this.anchors = this.tabs.map( function() {
- return $( "a", this )[ 0 ];
- } )
- .attr( {
- tabIndex: -1
- } );
- this._addClass( this.anchors, "ui-tabs-anchor" );
-
- this.panels = $();
-
- this.anchors.each( function( i, anchor ) {
- var selector, panel, panelId,
- anchorId = $( anchor ).uniqueId().attr( "id" ),
- tab = $( anchor ).closest( "li" ),
- originalAriaControls = tab.attr( "aria-controls" );
-
- // Inline tab
- if ( that._isLocal( anchor ) ) {
- selector = anchor.hash;
- panelId = selector.substring( 1 );
- panel = that.element.find( that._sanitizeSelector( selector ) );
-
- // remote tab
- } else {
-
- // If the tab doesn't already have aria-controls,
- // generate an id by using a throw-away element
- panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
- selector = "#" + panelId;
- panel = that.element.find( selector );
- if ( !panel.length ) {
- panel = that._createPanel( panelId );
- panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
- }
- panel.attr( "aria-live", "polite" );
- }
-
- if ( panel.length ) {
- that.panels = that.panels.add( panel );
- }
- if ( originalAriaControls ) {
- tab.data( "ui-tabs-aria-controls", originalAriaControls );
- }
- tab.attr( {
- "aria-controls": panelId,
- "aria-labelledby": anchorId
- } );
- panel.attr( "aria-labelledby", anchorId );
- } );
-
- this.panels.attr( "role", "tabpanel" );
- this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
-
- // Avoid memory leaks (#10056)
- if ( prevTabs ) {
- this._off( prevTabs.not( this.tabs ) );
- this._off( prevAnchors.not( this.anchors ) );
- this._off( prevPanels.not( this.panels ) );
- }
- },
-
- // Allow overriding how to find the list for rare usage scenarios (#7715)
- _getList: function() {
- return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
- },
-
- _createPanel: function( id ) {
- return $( "<div>" )
- .attr( "id", id )
- .data( "ui-tabs-destroy", true );
- },
-
- _setOptionDisabled: function( disabled ) {
- var currentItem, li, i;
-
- if ( Array.isArray( disabled ) ) {
- if ( !disabled.length ) {
- disabled = false;
- } else if ( disabled.length === this.anchors.length ) {
- disabled = true;
- }
- }
-
- // Disable tabs
- for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
- currentItem = $( li );
- if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
- currentItem.attr( "aria-disabled", "true" );
- this._addClass( currentItem, null, "ui-state-disabled" );
- } else {
- currentItem.removeAttr( "aria-disabled" );
- this._removeClass( currentItem, null, "ui-state-disabled" );
- }
- }
-
- this.options.disabled = disabled;
-
- this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
- disabled === true );
- },
-
- _setupEvents: function( event ) {
- var events = {};
- if ( event ) {
- $.each( event.split( " " ), function( index, eventName ) {
- events[ eventName ] = "_eventHandler";
- } );
- }
-
- this._off( this.anchors.add( this.tabs ).add( this.panels ) );
-
- // Always prevent the default action, even when disabled
- this._on( true, this.anchors, {
- click: function( event ) {
- event.preventDefault();
- }
- } );
- this._on( this.anchors, events );
- this._on( this.tabs, { keydown: "_tabKeydown" } );
- this._on( this.panels, { keydown: "_panelKeydown" } );
-
- this._focusable( this.tabs );
- this._hoverable( this.tabs );
- },
-
- _setupHeightStyle: function( heightStyle ) {
- var maxHeight,
- parent = this.element.parent();
-
- if ( heightStyle === "fill" ) {
- maxHeight = parent.height();
- maxHeight -= this.element.outerHeight() - this.element.height();
-
- this.element.siblings( ":visible" ).each( function() {
- var elem = $( this ),
- position = elem.css( "position" );
-
- if ( position === "absolute" || position === "fixed" ) {
- return;
- }
- maxHeight -= elem.outerHeight( true );
- } );
-
- this.element.children().not( this.panels ).each( function() {
- maxHeight -= $( this ).outerHeight( true );
- } );
-
- this.panels.each( function() {
- $( this ).height( Math.max( 0, maxHeight -
- $( this ).innerHeight() + $( this ).height() ) );
- } )
- .css( "overflow", "auto" );
- } else if ( heightStyle === "auto" ) {
- maxHeight = 0;
- this.panels.each( function() {
- maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
- } ).height( maxHeight );
- }
- },
-
- _eventHandler: function( event ) {
- var options = this.options,
- active = this.active,
- anchor = $( event.currentTarget ),
- tab = anchor.closest( "li" ),
- clickedIsActive = tab[ 0 ] === active[ 0 ],
- collapsing = clickedIsActive && options.collapsible,
- toShow = collapsing ? $() : this._getPanelForTab( tab ),
- toHide = !active.length ? $() : this._getPanelForTab( active ),
- eventData = {
- oldTab: active,
- oldPanel: toHide,
- newTab: collapsing ? $() : tab,
- newPanel: toShow
- };
-
- event.preventDefault();
-
- if ( tab.hasClass( "ui-state-disabled" ) ||
-
- // tab is already loading
- tab.hasClass( "ui-tabs-loading" ) ||
-
- // can't switch durning an animation
- this.running ||
-
- // click on active header, but not collapsible
- ( clickedIsActive && !options.collapsible ) ||
-
- // allow canceling activation
- ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
- return;
- }
-
- options.active = collapsing ? false : this.tabs.index( tab );
-
- this.active = clickedIsActive ? $() : tab;
- if ( this.xhr ) {
- this.xhr.abort();
- }
-
- if ( !toHide.length && !toShow.length ) {
- $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
- }
-
- if ( toShow.length ) {
- this.load( this.tabs.index( tab ), event );
- }
- this._toggle( event, eventData );
- },
-
- // Handles show/hide for selecting tabs
- _toggle: function( event, eventData ) {
- var that = this,
- toShow = eventData.newPanel,
- toHide = eventData.oldPanel;
-
- this.running = true;
-
- function complete() {
- that.running = false;
- that._trigger( "activate", event, eventData );
- }
-
- function show() {
- that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
-
- if ( toShow.length && that.options.show ) {
- that._show( toShow, that.options.show, complete );
- } else {
- toShow.show();
- complete();
- }
- }
-
- // Start out by hiding, then showing, then completing
- if ( toHide.length && this.options.hide ) {
- this._hide( toHide, this.options.hide, function() {
- that._removeClass( eventData.oldTab.closest( "li" ),
- "ui-tabs-active", "ui-state-active" );
- show();
- } );
- } else {
- this._removeClass( eventData.oldTab.closest( "li" ),
- "ui-tabs-active", "ui-state-active" );
- toHide.hide();
- show();
- }
-
- toHide.attr( "aria-hidden", "true" );
- eventData.oldTab.attr( {
- "aria-selected": "false",
- "aria-expanded": "false"
- } );
-
- // If we're switching tabs, remove the old tab from the tab order.
- // If we're opening from collapsed state, remove the previous tab from the tab order.
- // If we're collapsing, then keep the collapsing tab in the tab order.
- if ( toShow.length && toHide.length ) {
- eventData.oldTab.attr( "tabIndex", -1 );
- } else if ( toShow.length ) {
- this.tabs.filter( function() {
- return $( this ).attr( "tabIndex" ) === 0;
- } )
- .attr( "tabIndex", -1 );
- }
-
- toShow.attr( "aria-hidden", "false" );
- eventData.newTab.attr( {
- "aria-selected": "true",
- "aria-expanded": "true",
- tabIndex: 0
- } );
- },
-
- _activate: function( index ) {
- var anchor,
- active = this._findActive( index );
-
- // Trying to activate the already active panel
- if ( active[ 0 ] === this.active[ 0 ] ) {
- return;
- }
-
- // Trying to collapse, simulate a click on the current active header
- if ( !active.length ) {
- active = this.active;
- }
-
- anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
- this._eventHandler( {
- target: anchor,
- currentTarget: anchor,
- preventDefault: $.noop
- } );
- },
-
- _findActive: function( index ) {
- return index === false ? $() : this.tabs.eq( index );
- },
-
- _getIndex: function( index ) {
-
- // meta-function to give users option to provide a href string instead of a numerical index.
- if ( typeof index === "string" ) {
- index = this.anchors.index( this.anchors.filter( "[href$='" +
- $.escapeSelector( index ) + "']" ) );
- }
-
- return index;
- },
-
- _destroy: function() {
- if ( this.xhr ) {
- this.xhr.abort();
- }
-
- this.tablist
- .removeAttr( "role" )
- .off( this.eventNamespace );
-
- this.anchors
- .removeAttr( "role tabIndex" )
- .removeUniqueId();
-
- this.tabs.add( this.panels ).each( function() {
- if ( $.data( this, "ui-tabs-destroy" ) ) {
- $( this ).remove();
- } else {
- $( this ).removeAttr( "role tabIndex " +
- "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
- }
- } );
-
- this.tabs.each( function() {
- var li = $( this ),
- prev = li.data( "ui-tabs-aria-controls" );
- if ( prev ) {
- li
- .attr( "aria-controls", prev )
- .removeData( "ui-tabs-aria-controls" );
- } else {
- li.removeAttr( "aria-controls" );
- }
- } );
-
- this.panels.show();
-
- if ( this.options.heightStyle !== "content" ) {
- this.panels.css( "height", "" );
- }
- },
-
- enable: function( index ) {
- var disabled = this.options.disabled;
- if ( disabled === false ) {
- return;
- }
-
- if ( index === undefined ) {
- disabled = false;
- } else {
- index = this._getIndex( index );
- if ( Array.isArray( disabled ) ) {
- disabled = $.map( disabled, function( num ) {
- return num !== index ? num : null;
- } );
- } else {
- disabled = $.map( this.tabs, function( li, num ) {
- return num !== index ? num : null;
- } );
- }
- }
- this._setOptionDisabled( disabled );
- },
-
- disable: function( index ) {
- var disabled = this.options.disabled;
- if ( disabled === true ) {
- return;
- }
-
- if ( index === undefined ) {
- disabled = true;
- } else {
- index = this._getIndex( index );
- if ( $.inArray( index, disabled ) !== -1 ) {
- return;
- }
- if ( Array.isArray( disabled ) ) {
- disabled = $.merge( [ index ], disabled ).sort();
- } else {
- disabled = [ index ];
- }
- }
- this._setOptionDisabled( disabled );
- },
-
- load: function( index, event ) {
- index = this._getIndex( index );
- var that = this,
- tab = this.tabs.eq( index ),
- anchor = tab.find( ".ui-tabs-anchor" ),
- panel = this._getPanelForTab( tab ),
- eventData = {
- tab: tab,
- panel: panel
- },
- complete = function( jqXHR, status ) {
- if ( status === "abort" ) {
- that.panels.stop( false, true );
- }
-
- that._removeClass( tab, "ui-tabs-loading" );
- panel.removeAttr( "aria-busy" );
-
- if ( jqXHR === that.xhr ) {
- delete that.xhr;
- }
- };
-
- // Not remote
- if ( this._isLocal( anchor[ 0 ] ) ) {
- return;
- }
-
- this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
-
- // Support: jQuery <1.8
- // jQuery <1.8 returns false if the request is canceled in beforeSend,
- // but as of 1.8, $.ajax() always returns a jqXHR object.
- if ( this.xhr && this.xhr.statusText !== "canceled" ) {
- this._addClass( tab, "ui-tabs-loading" );
- panel.attr( "aria-busy", "true" );
-
- this.xhr
- .done( function( response, status, jqXHR ) {
-
- // support: jQuery <1.8
- // http://bugs.jquery.com/ticket/11778
- setTimeout( function() {
- panel.html( response );
- that._trigger( "load", event, eventData );
-
- complete( jqXHR, status );
- }, 1 );
- } )
- .fail( function( jqXHR, status ) {
-
- // support: jQuery <1.8
- // http://bugs.jquery.com/ticket/11778
- setTimeout( function() {
- complete( jqXHR, status );
- }, 1 );
- } );
- }
- },
-
- _ajaxSettings: function( anchor, event, eventData ) {
- var that = this;
- return {
-
- // Support: IE <11 only
- // Strip any hash that exists to prevent errors with the Ajax request
- url: anchor.attr( "href" ).replace( /#.*$/, "" ),
- beforeSend: function( jqXHR, settings ) {
- return that._trigger( "beforeLoad", event,
- $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
- }
- };
- },
-
- _getPanelForTab: function( tab ) {
- var id = $( tab ).attr( "aria-controls" );
- return this.element.find( this._sanitizeSelector( "#" + id ) );
- }
-} );
-
-// DEPRECATED
-// TODO: Switch return back to widget declaration at top of file when this is removed
-if ( $.uiBackCompat !== false ) {
-
- // Backcompat for ui-tab class (now ui-tabs-tab)
- $.widget( "ui.tabs", $.ui.tabs, {
- _processTabs: function() {
- this._superApply( arguments );
- this._addClass( this.tabs, "ui-tab" );
- }
- } );
-}
-
-var widgetsTabs = $.ui.tabs;
-
-
-/*!
- * jQuery UI Tooltip 1.13.1
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Tooltip
-//>>group: Widgets
-//>>description: Shows additional information for any element on hover or focus.
-//>>docs: http://api.jqueryui.com/tooltip/
-//>>demos: http://jqueryui.com/tooltip/
-//>>css.structure: ../../themes/base/core.css
-//>>css.structure: ../../themes/base/tooltip.css
-//>>css.theme: ../../themes/base/theme.css
-
-
-$.widget( "ui.tooltip", {
- version: "1.13.1",
- options: {
- classes: {
- "ui-tooltip": "ui-corner-all ui-widget-shadow"
- },
- content: function() {
- var title = $( this ).attr( "title" );
-
- // Escape title, since we're going from an attribute to raw HTML
- return $( "<a>" ).text( title ).html();
- },
- hide: true,
-
- // Disabled elements have inconsistent behavior across browsers (#8661)
- items: "[title]:not([disabled])",
- position: {
- my: "left top+15",
- at: "left bottom",
- collision: "flipfit flip"
- },
- show: true,
- track: false,
-
- // Callbacks
- close: null,
- open: null
- },
-
- _addDescribedBy: function( elem, id ) {
- var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
- describedby.push( id );
- elem
- .data( "ui-tooltip-id", id )
- .attr( "aria-describedby", String.prototype.trim.call( describedby.join( " " ) ) );
- },
-
- _removeDescribedBy: function( elem ) {
- var id = elem.data( "ui-tooltip-id" ),
- describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
- index = $.inArray( id, describedby );
-
- if ( index !== -1 ) {
- describedby.splice( index, 1 );
- }
-
- elem.removeData( "ui-tooltip-id" );
- describedby = String.prototype.trim.call( describedby.join( " " ) );
- if ( describedby ) {
- elem.attr( "aria-describedby", describedby );
- } else {
- elem.removeAttr( "aria-describedby" );
- }
- },
-
- _create: function() {
- this._on( {
- mouseover: "open",
- focusin: "open"
- } );
-
- // IDs of generated tooltips, needed for destroy
- this.tooltips = {};
-
- // IDs of parent tooltips where we removed the title attribute
- this.parents = {};
-
- // Append the aria-live region so tooltips announce correctly
- this.liveRegion = $( "<div>" )
- .attr( {
- role: "log",
- "aria-live": "assertive",
- "aria-relevant": "additions"
- } )
- .appendTo( this.document[ 0 ].body );
- this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
-
- this.disabledTitles = $( [] );
- },
-
- _setOption: function( key, value ) {
- var that = this;
-
- this._super( key, value );
-
- if ( key === "content" ) {
- $.each( this.tooltips, function( id, tooltipData ) {
- that._updateContent( tooltipData.element );
- } );
- }
- },
-
- _setOptionDisabled: function( value ) {
- this[ value ? "_disable" : "_enable" ]();
- },
-
- _disable: function() {
- var that = this;
-
- // Close open tooltips
- $.each( this.tooltips, function( id, tooltipData ) {
- var event = $.Event( "blur" );
- event.target = event.currentTarget = tooltipData.element[ 0 ];
- that.close( event, true );
- } );
-
- // Remove title attributes to prevent native tooltips
- this.disabledTitles = this.disabledTitles.add(
- this.element.find( this.options.items ).addBack()
- .filter( function() {
- var element = $( this );
- if ( element.is( "[title]" ) ) {
- return element
- .data( "ui-tooltip-title", element.attr( "title" ) )
- .removeAttr( "title" );
- }
- } )
- );
- },
-
- _enable: function() {
-
- // restore title attributes
- this.disabledTitles.each( function() {
- var element = $( this );
- if ( element.data( "ui-tooltip-title" ) ) {
- element.attr( "title", element.data( "ui-tooltip-title" ) );
- }
- } );
- this.disabledTitles = $( [] );
- },
-
- open: function( event ) {
- var that = this,
- target = $( event ? event.target : this.element )
-
- // we need closest here due to mouseover bubbling,
- // but always pointing at the same event target
- .closest( this.options.items );
-
- // No element to show a tooltip for or the tooltip is already open
- if ( !target.length || target.data( "ui-tooltip-id" ) ) {
- return;
- }
-
- if ( target.attr( "title" ) ) {
- target.data( "ui-tooltip-title", target.attr( "title" ) );
- }
-
- target.data( "ui-tooltip-open", true );
-
- // Kill parent tooltips, custom or native, for hover
- if ( event && event.type === "mouseover" ) {
- target.parents().each( function() {
- var parent = $( this ),
- blurEvent;
- if ( parent.data( "ui-tooltip-open" ) ) {
- blurEvent = $.Event( "blur" );
- blurEvent.target = blurEvent.currentTarget = this;
- that.close( blurEvent, true );
- }
- if ( parent.attr( "title" ) ) {
- parent.uniqueId();
- that.parents[ this.id ] = {
- element: this,
- title: parent.attr( "title" )
- };
- parent.attr( "title", "" );
- }
- } );
- }
-
- this._registerCloseHandlers( event, target );
- this._updateContent( target, event );
- },
-
- _updateContent: function( target, event ) {
- var content,
- contentOption = this.options.content,
- that = this,
- eventType = event ? event.type : null;
-
- if ( typeof contentOption === "string" || contentOption.nodeType ||
- contentOption.jquery ) {
- return this._open( event, target, contentOption );
- }
-
- content = contentOption.call( target[ 0 ], function( response ) {
-
- // IE may instantly serve a cached response for ajax requests
- // delay this call to _open so the other call to _open runs first
- that._delay( function() {
-
- // Ignore async response if tooltip was closed already
- if ( !target.data( "ui-tooltip-open" ) ) {
- return;
- }
-
- // JQuery creates a special event for focusin when it doesn't
- // exist natively. To improve performance, the native event
- // object is reused and the type is changed. Therefore, we can't
- // rely on the type being correct after the event finished
- // bubbling, so we set it back to the previous value. (#8740)
- if ( event ) {
- event.type = eventType;
- }
- this._open( event, target, response );
- } );
- } );
- if ( content ) {
- this._open( event, target, content );
- }
- },
-
- _open: function( event, target, content ) {
- var tooltipData, tooltip, delayedShow, a11yContent,
- positionOption = $.extend( {}, this.options.position );
-
- if ( !content ) {
- return;
- }
-
- // Content can be updated multiple times. If the tooltip already
- // exists, then just update the content and bail.
- tooltipData = this._find( target );
- if ( tooltipData ) {
- tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
- return;
- }
-
- // If we have a title, clear it to prevent the native tooltip
- // we have to check first to avoid defining a title if none exists
- // (we don't want to cause an element to start matching [title])
- //
- // We use removeAttr only for key events, to allow IE to export the correct
- // accessible attributes. For mouse events, set to empty string to avoid
- // native tooltip showing up (happens only when removing inside mouseover).
- if ( target.is( "[title]" ) ) {
- if ( event && event.type === "mouseover" ) {
- target.attr( "title", "" );
- } else {
- target.removeAttr( "title" );
- }
- }
-
- tooltipData = this._tooltip( target );
- tooltip = tooltipData.tooltip;
- this._addDescribedBy( target, tooltip.attr( "id" ) );
- tooltip.find( ".ui-tooltip-content" ).html( content );
-
- // Support: Voiceover on OS X, JAWS on IE <= 9
- // JAWS announces deletions even when aria-relevant="additions"
- // Voiceover will sometimes re-read the entire log region's contents from the beginning
- this.liveRegion.children().hide();
- a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
- a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
- a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
- a11yContent.appendTo( this.liveRegion );
-
- function position( event ) {
- positionOption.of = event;
- if ( tooltip.is( ":hidden" ) ) {
- return;
- }
- tooltip.position( positionOption );
- }
- if ( this.options.track && event && /^mouse/.test( event.type ) ) {
- this._on( this.document, {
- mousemove: position
- } );
-
- // trigger once to override element-relative positioning
- position( event );
- } else {
- tooltip.position( $.extend( {
- of: target
- }, this.options.position ) );
- }
-
- tooltip.hide();
-
- this._show( tooltip, this.options.show );
-
- // Handle tracking tooltips that are shown with a delay (#8644). As soon
- // as the tooltip is visible, position the tooltip using the most recent
- // event.
- // Adds the check to add the timers only when both delay and track options are set (#14682)
- if ( this.options.track && this.options.show && this.options.show.delay ) {
- delayedShow = this.delayedShow = setInterval( function() {
- if ( tooltip.is( ":visible" ) ) {
- position( positionOption.of );
- clearInterval( delayedShow );
- }
- }, 13 );
- }
-
- this._trigger( "open", event, { tooltip: tooltip } );
- },
-
- _registerCloseHandlers: function( event, target ) {
- var events = {
- keyup: function( event ) {
- if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
- var fakeEvent = $.Event( event );
- fakeEvent.currentTarget = target[ 0 ];
- this.close( fakeEvent, true );
- }
- }
- };
-
- // Only bind remove handler for delegated targets. Non-delegated
- // tooltips will handle this in destroy.
- if ( target[ 0 ] !== this.element[ 0 ] ) {
- events.remove = function() {
- var targetElement = this._find( target );
- if ( targetElement ) {
- this._removeTooltip( targetElement.tooltip );
- }
- };
- }
-
- if ( !event || event.type === "mouseover" ) {
- events.mouseleave = "close";
- }
- if ( !event || event.type === "focusin" ) {
- events.focusout = "close";
- }
- this._on( true, target, events );
- },
-
- close: function( event ) {
- var tooltip,
- that = this,
- target = $( event ? event.currentTarget : this.element ),
- tooltipData = this._find( target );
-
- // The tooltip may already be closed
- if ( !tooltipData ) {
-
- // We set ui-tooltip-open immediately upon open (in open()), but only set the
- // additional data once there's actually content to show (in _open()). So even if the
- // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
- // the period between open() and _open().
- target.removeData( "ui-tooltip-open" );
- return;
- }
-
- tooltip = tooltipData.tooltip;
-
- // Disabling closes the tooltip, so we need to track when we're closing
- // to avoid an infinite loop in case the tooltip becomes disabled on close
- if ( tooltipData.closing ) {
- return;
- }
-
- // Clear the interval for delayed tracking tooltips
- clearInterval( this.delayedShow );
-
- // Only set title if we had one before (see comment in _open())
- // If the title attribute has changed since open(), don't restore
- if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
- target.attr( "title", target.data( "ui-tooltip-title" ) );
- }
-
- this._removeDescribedBy( target );
-
- tooltipData.hiding = true;
- tooltip.stop( true );
- this._hide( tooltip, this.options.hide, function() {
- that._removeTooltip( $( this ) );
- } );
-
- target.removeData( "ui-tooltip-open" );
- this._off( target, "mouseleave focusout keyup" );
-
- // Remove 'remove' binding only on delegated targets
- if ( target[ 0 ] !== this.element[ 0 ] ) {
- this._off( target, "remove" );
- }
- this._off( this.document, "mousemove" );
-
- if ( event && event.type === "mouseleave" ) {
- $.each( this.parents, function( id, parent ) {
- $( parent.element ).attr( "title", parent.title );
- delete that.parents[ id ];
- } );
- }
-
- tooltipData.closing = true;
- this._trigger( "close", event, { tooltip: tooltip } );
- if ( !tooltipData.hiding ) {
- tooltipData.closing = false;
- }
- },
-
- _tooltip: function( element ) {
- var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
- content = $( "<div>" ).appendTo( tooltip ),
- id = tooltip.uniqueId().attr( "id" );
-
- this._addClass( content, "ui-tooltip-content" );
- this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
-
- tooltip.appendTo( this._appendTo( element ) );
-
- return this.tooltips[ id ] = {
- element: element,
- tooltip: tooltip
- };
- },
-
- _find: function( target ) {
- var id = target.data( "ui-tooltip-id" );
- return id ? this.tooltips[ id ] : null;
- },
-
- _removeTooltip: function( tooltip ) {
-
- // Clear the interval for delayed tracking tooltips
- clearInterval( this.delayedShow );
-
- tooltip.remove();
- delete this.tooltips[ tooltip.attr( "id" ) ];
- },
-
- _appendTo: function( target ) {
- var element = target.closest( ".ui-front, dialog" );
-
- if ( !element.length ) {
- element = this.document[ 0 ].body;
- }
-
- return element;
- },
-
- _destroy: function() {
- var that = this;
-
- // Close open tooltips
- $.each( this.tooltips, function( id, tooltipData ) {
-
- // Delegate to close method to handle common cleanup
- var event = $.Event( "blur" ),
- element = tooltipData.element;
- event.target = event.currentTarget = element[ 0 ];
- that.close( event, true );
-
- // Remove immediately; destroying an open tooltip doesn't use the
- // hide animation
- $( "#" + id ).remove();
-
- // Restore the title
- if ( element.data( "ui-tooltip-title" ) ) {
-
- // If the title attribute has changed since open(), don't restore
- if ( !element.attr( "title" ) ) {
- element.attr( "title", element.data( "ui-tooltip-title" ) );
- }
- element.removeData( "ui-tooltip-title" );
- }
- } );
- this.liveRegion.remove();
- }
-} );
-
-// DEPRECATED
-// TODO: Switch return back to widget declaration at top of file when this is removed
-if ( $.uiBackCompat !== false ) {
-
- // Backcompat for tooltipClass option
- $.widget( "ui.tooltip", $.ui.tooltip, {
- options: {
- tooltipClass: null
- },
- _tooltip: function() {
- var tooltipData = this._superApply( arguments );
- if ( this.options.tooltipClass ) {
- tooltipData.tooltip.addClass( this.options.tooltipClass );
- }
- return tooltipData;
- }
- } );
-}
-
-var widgetsTooltip = $.ui.tooltip;
-
-
-
-
-} ); \ No newline at end of file
diff --git a/static/js/jquery.min.js b/static/js/jquery.min.js
deleted file mode 100644
index c4c6022..0000000
--- a/static/js/jquery.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
-!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),j=function(e,t){return e===t&&(l=!0),0},D={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&D.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(j),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(j).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var D,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^([^.]*)(?:\.(.+)|)/;function we(){return!0}function Te(){return!1}function Ce(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ee(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ee(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Te;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Se(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n&&n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,we)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=be.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=be.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click",we),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?we:Te,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Te,isPropagationStopped:Te,isImmediatePropagationStopped:Te,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=we,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=we,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=we,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Se(this,e,Ce),!1},trigger:function(){return Se(this,e),!0},_default:function(){return!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return Ee(this,e,t,n,r)},one:function(e,t,n,r){return Ee(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Te),this.each(function(){S.event.remove(this,e,n,t)})}});var ke=/<script|<style|<link/i,Ae=/checked\s*(?:[^=]|=\s*.checked.)/i,Ne=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function He(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&Ae.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),He(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),De)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,qe),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(Ne,""),u,l))}return n}function Oe(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Le(o[r],a[r]);else Le(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Oe(this,e,!0)},remove:function(e){return Oe(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return He(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||je(this,e).appendChild(e)})},prepend:function(){return He(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=je(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!ke.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return He(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Pe=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Re=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Me=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Ie=new RegExp(ne.join("|"),"i");function We(e,t,n){var r,i,o,a,s=e.style;return(n=n||Re(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Pe.test(a)&&Ie.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function Fe(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px;border-collapse:separate",t.style.cssText="border:1px solid",t.style.height="1px",n.style.height="9px",n.style.display="block",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,re.removeChild(e)),a}}))}();var Be=["Webkit","Moz","ms"],$e=E.createElement("div").style,_e={};function ze(e){var t=S.cssProps[e]||_e[e];return t||(e in $e?e:_e[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Be.length;while(n--)if((e=Be[n]+t)in $e)return e}(e)||e)}var Ue=/^(none|table(?!-c[ea]).+)/,Xe=/^--/,Ve={position:"absolute",visibility:"hidden",display:"block"},Ge={letterSpacing:"0",fontWeight:"400"};function Ye(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Qe(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Je(e,t,n){var r=Re(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=We(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Pe.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Qe(e,t,n||(i?"border":"content"),o,r,a)+"px"}function Ke(e,t,n,r,i){return new Ke.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=We(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Xe.test(t),l=e.style;if(u||(t=ze(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Xe.test(t)||(t=ze(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=We(e,t,r)),"normal"===i&&t in Ge&&(i=Ge[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ue.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Je(e,u,n):Me(e,Ve,function(){return Je(e,u,n)})},set:function(e,t,n){var r,i=Re(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Qe(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Qe(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Ye(0,t,s)}}}),S.cssHooks.marginLeft=Fe(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(We(e,"marginLeft"))||e.getBoundingClientRect().left-Me(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Ye)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Re(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=Ke).prototype={constructor:Ke,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=Ke.propHooks[this.prop];return e&&e.get?e.get(this):Ke.propHooks._default.get(this)},run:function(e){var t,n=Ke.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ke.propHooks._default.set(this),this}}).init.prototype=Ke.prototype,(Ke.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[ze(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=Ke.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=Ke.prototype.init,S.fx.step={};var Ze,et,tt,nt,rt=/^(?:toggle|show|hide)$/,it=/queueHooks$/;function ot(){et&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(ot):C.setTimeout(ot,S.fx.interval),S.fx.tick())}function at(){return C.setTimeout(function(){Ze=void 0}),Ze=Date.now()}function st(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ut(e,t,n){for(var r,i=(lt.tweeners[t]||[]).concat(lt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function lt(o,e,t){var n,a,r=0,i=lt.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=Ze||at(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:Ze||at(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=lt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ut,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(lt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],lt.tweeners[n]=lt.tweeners[n]||[],lt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],rt.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ut(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?lt.prefilters.unshift(e):lt.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=lt(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&it.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(st(r,!0),e,t,n)}}),S.each({slideDown:st("show"),slideUp:st("hide"),slideToggle:st("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(Ze=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),Ze=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){et||(et=!0,ot())},S.fx.stop=function(){et=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},tt=E.createElement("input"),nt=E.createElement("select").appendChild(E.createElement("option")),tt.type="checkbox",y.checkOn=""!==tt.value,y.optSelected=nt.selected,(tt=E.createElement("input")).value="t",tt.type="radio",y.radioValue="t"===tt.value;var ct,ft=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?ct:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ct={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=ft[t]||S.find.attr;ft[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=ft[o],ft[o]=r,r=null!=a(e,t,n)?o:null,ft[o]=i),r}});var pt=/^(?:input|select|textarea|button)$/i,dt=/^(?:a|area)$/i;function ht(e){return(e.match(P)||[]).join(" ")}function gt(e){return e.getAttribute&&e.getAttribute("class")||""}function vt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):pt.test(e.nodeName)||dt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,gt(this)))});if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,gt(this)))});if(!arguments.length)return this.attr("class","");if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,gt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=vt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=gt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+ht(gt(n))+" ").indexOf(t))return!0;return!1}});var yt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(yt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:ht(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var mt=/^(?:focusinfocus|focusoutblur)$/,xt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!mt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,mt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,xt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,xt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var bt=C.location,wt={guid:Date.now()},Tt=/\?/;S.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||S.error("Invalid XML: "+(n?S.map(n.childNodes,function(e){return e.textContent}).join("\n"):e)),t};var Ct=/\[\]$/,Et=/\r?\n/g,St=/^(?:submit|button|image|reset|file)$/i,kt=/^(?:input|select|textarea|keygen)/i;function At(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||Ct.test(n)?i(n,t):At(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)At(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)At(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&kt.test(this.nodeName)&&!St.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(Et,"\r\n")}}):{name:t.name,value:n.replace(Et,"\r\n")}}).get()}});var Nt=/%20/g,jt=/#.*$/,Dt=/([?&])_=[^&]*/,qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Lt=/^(?:GET|HEAD)$/,Ht=/^\/\//,Ot={},Pt={},Rt="*/".concat("*"),Mt=E.createElement("a");function It(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Wt(t,i,o,a){var s={},u=t===Pt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function Ft(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Mt.href=bt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:bt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(bt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Rt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Ft(Ft(e,S.ajaxSettings),t):Ft(S.ajaxSettings,e)},ajaxPrefilter:It(Ot),ajaxTransport:It(Pt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=qt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||bt.href)+"").replace(Ht,bt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Mt.protocol+"//"+Mt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Wt(Ot,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Lt.test(v.type),f=v.url.replace(jt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Nt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Tt.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Dt,"$1"),o=(Tt.test(f)?"&":"?")+"_="+wt.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+Rt+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Wt(Pt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&S.inArray("json",v.dataTypes)<0&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Bt={0:200,1223:204},$t=S.ajaxSettings.xhr();y.cors=!!$t&&"withCredentials"in $t,y.ajax=$t=!!$t,S.ajaxTransport(function(i){var o,a;if(y.cors||$t&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Bt[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=ht(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Xt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Xt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return S});var Vt=C.jQuery,Gt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Gt),e&&C.jQuery===S&&(C.jQuery=Vt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S});
diff --git a/style.lisp b/style.lisp
deleted file mode 100644
index 6ee60a7..0000000
--- a/style.lisp
+++ /dev/null
@@ -1,8 +0,0 @@
-;;;; css.lisp
-
-(in-package :vampire)
-
-(defparameter *css-version* "4")
-
-(defun include-style (body)
- (load-css (html-document body) (format nil "/css/main-~a.css" *css-version*) :load-only-once nil))
diff --git a/vampire.asd b/vampire.asd
index 9014aa8..2751128 100644
--- a/vampire.asd
+++ b/vampire.asd
@@ -2,13 +2,14 @@
(asdf:defsystem #:vampire
:description "Live Collaborative Music Mixes"
- :author "Colin <colin@cicadas.surf>"
+ :author "Cicadas Devs <vampire@cicadas.surf>"
:license "AGPL-3.0"
- :version "0.1.0"
+ :version "0.2.0"
+ :pathname "src/"
:serial t
- :depends-on (#:clog
- #:hunchentoot
- #:clack-handler-hunchentoot
+ :depends-on (#:lazybones-hunchentoot
+ #:spinneret
+ #:parenscript
#:bknr.datastore
#:legion
#:defclass-std
@@ -17,21 +18,18 @@
#:jonathan
#:swank
#:zippy)
- :components ((:file "hunchentoot-handle-static-file")
- (:file "package")
- (:file "definition-macros")
+
+ :components ((:module "hunchentoot"
+ :serial t
+ :components ((:file "handle-static-file-monkeypatch")))
(:file "utilities")
+ (:file "config")
(:file "downloader")
(:file "model")
- (:file "session")
- (:file "style")
- (:file "navigation")
- (:file "about")
- (:file "new-account")
- (:file "explore")
- (:file "login")
- (:file "home")
- (:file "playlist")
- (:file "vampire")
- (:file "run")
- (:file "zipper")))
+ (:file "mailbox")
+ (:file "api")
+ (:file "site")
+ ; (:file "zipper")
+; (:file "vampire")
+ ;(:file "run")
+ ))
diff --git a/vampire.lisp b/vampire.lisp
deleted file mode 100644
index a45b853..0000000
--- a/vampire.lisp
+++ /dev/null
@@ -1,74 +0,0 @@
-;;;; vampire.lisp
-
-(in-package #:vampire)
-
-;;; SYSTEM CONFIG COMPONENT
-
-(defvar *config* nil)
-
-(defclass/std config ()
- ((datastore-directory :ir :std #P"/srv/vampire/store/")
- (static-directory :ir :std #P"/srv/vampire/static/")
- (swank-port :std nil :doc "If set, swank is started on this port.")
- (host :std "0.0.0.0")
- (port :ir :std 4919)
- (downloader-threads :ir :std 5)))
-
-(defun config-from-file (path)
- "PATH should be a path to a file containing a PLIST suitable for
- passing as the keyword arguments to (MAKE-INSTANCE 'CONFIG ...)"
- (apply #'make-instance 'config (read-from-file path)))
-
-;;; MAIN
-
-(defun main (body)
- (if (session-user body)
- (setf (url (location body)) "/home")
- (setf (url (location body)) "/login")))
-
-;;; STARTUP
-
-(defun initialize-database (config)
- (ensure-directories-exist (datastore-directory config))
- (make-instance
- 'bknr.datastore:mp-store
- :directory (datastore-directory config)
- :subsystems (list (make-instance 'bknr.datastore:store-object-subsystem))))
-
-(defun redirect-to-root (body)
- (setf (url (location body)) "/"))
-
-(defun when-logged-in? (fn)
- (<?> 'session-user fn 'redirect-to-root))
-
-
-
-(defun start-vampire (config)
- (setf *config* config)
- (initialize-database config )
- (start-downloader-service config)
- (clog:initialize 'main
- :port (port config)
- :host (host config)
- :extended-routing t
- :static-root (static-directory config))
- (set-on-new-window (when-logged-in? 'about-page) :path "/about")
- (set-on-new-window (when-logged-in? 'user-home-page) :path "/home")
- (set-on-new-window (when-logged-in? 'user-listing-page) :path "/user")
- (set-on-new-window 'login-page :path "/login")
- (set-on-new-window (when-logged-in? 'playlist-page) :path "/playlist")
- (set-on-new-window 'new-accout-page :path "/new-account")
- (set-on-new-window (when-logged-in? 'explore-page) :path "/explore")
-
- (when (swank-port config)
- (swank:create-server :port (swank-port config) :dont-close t)))
-
-(defun hacking-start ()
- (start-vampire (make-instance
- 'config
- :static-directory (merge-pathnames "vampire-static/" (user-homedir-pathname))
- :datastore-directory (merge-pathnames "vampire-store/" (user-homedir-pathname))))
- (clog:open-browser))
-
-
-