diff options
author | colin <colin@cicadas.surf> | 2023-11-12 12:07:41 -0800 |
---|---|---|
committer | colin <colin@cicadas.surf> | 2023-11-12 12:07:41 -0800 |
commit | a8fd8ff49a95e610c3cd38aba02ee28129d4d881 (patch) | |
tree | d1fd74ac58b6a351c2b90575510f5f7af28b441c | |
parent | 9ab26f07d209a387252a87dc10e986995bbc154a (diff) |
committing what I've got
-rw-r--r-- | INSTALL.md | 2 | ||||
-rw-r--r-- | README.md | 9 | ||||
-rw-r--r-- | README.org | 14 | ||||
-rw-r--r-- | about.lisp | 23 | ||||
-rw-r--r-- | build/build.lisp (renamed from build.lisp) | 5 | ||||
-rw-r--r-- | definition-macros.lisp | 19 | ||||
-rw-r--r-- | explore.lisp | 46 | ||||
-rw-r--r-- | home.lisp | 166 | ||||
-rw-r--r-- | login.lisp | 32 | ||||
-rw-r--r-- | model.lisp | 187 | ||||
-rw-r--r-- | navigation.lisp | 11 | ||||
-rw-r--r-- | new-account.lisp | 75 | ||||
-rw-r--r-- | playlist.lisp | 544 | ||||
-rw-r--r-- | session.lisp | 33 | ||||
-rw-r--r-- | src/api.lisp | 191 | ||||
-rw-r--r-- | src/config.lisp | 38 | ||||
-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.lisp | 10 | ||||
-rw-r--r-- | src/logger.lisp | 10 | ||||
-rw-r--r-- | src/mailbox.lisp | 17 | ||||
-rw-r--r-- | src/model.lisp | 260 | ||||
-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.lisp | 16 | ||||
-rw-r--r-- | src/site.lisp | 26 | ||||
-rw-r--r-- | src/utilities.lisp (renamed from utilities.lisp) | 54 | ||||
-rw-r--r-- | src/vampire.lisp | 46 | ||||
-rw-r--r-- | src/zipper.lisp (renamed from zipper.lisp) | 0 | ||||
-rw-r--r-- | static/boot.html | 17 | ||||
-rw-r--r-- | static/bootstrap.html | 19 | ||||
-rw-r--r-- | static/config.sexp (renamed from config.lisp) | 0 | ||||
-rw-r--r-- | static/css/main-2.css | 101 | ||||
-rw-r--r-- | static/css/main-3.css | 150 | ||||
-rw-r--r-- | static/css/main-4.css | 165 | ||||
-rw-r--r-- | static/css/main.css | 73 | ||||
-rw-r--r-- | static/css/reset.css | 2 | ||||
-rw-r--r-- | static/debug.html | 18 | ||||
-rw-r--r-- | static/favicon.ico | bin | 958 -> 0 bytes | |||
-rw-r--r-- | static/js/boot.js | 121 | ||||
-rw-r--r-- | static/js/jquery-ui.js | 19057 | ||||
-rw-r--r-- | static/js/jquery.min.js | 2 | ||||
-rw-r--r-- | style.lisp | 8 | ||||
-rw-r--r-- | vampire.asd | 38 | ||||
-rw-r--r-- | vampire.lisp | 74 |
45 files changed, 697 insertions, 21010 deletions
@@ -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/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 Binary files differdeleted file mode 100644 index 80a0bf9..0000000 --- a/static/favicon.ico +++ /dev/null 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, "'" ) + "'" : "" ) + // cell title - ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions - ( otherMonth && !showOtherMonths ? " " : // 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 ) ? " " : "" ); - } - - // 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 ) ? " " : "" ) + 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( " " ); - } - }, - - _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( " " ); - } - }, - - _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> </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)) - - - |