Merge branch '0.9.x' into merge
Conflicts: README actions/hostmeta.php classes/File_redirection.php lib/common.php lib/designsettings.php lib/router.php lib/util.php lib/xmppmanager.php plugins/OStatus/OStatusPlugin.php
This commit is contained in:
commit
9df856e667
285
EVENTS.txt
285
EVENTS.txt
|
@ -118,16 +118,16 @@ EndShowHTML: Showing after the html element
|
||||||
- $action: the current action
|
- $action: the current action
|
||||||
|
|
||||||
StartPublicGroupNav: Showing the public group nav menu
|
StartPublicGroupNav: Showing the public group nav menu
|
||||||
- $action: the current action
|
- $menu: the menu widget; use $menu->action for output
|
||||||
|
|
||||||
EndPublicGroupNav: At the end of the public group nav menu
|
EndPublicGroupNav: At the end of the public group nav menu
|
||||||
- $action: the current action
|
- $menu: the menu widget; use $menu->action for output
|
||||||
|
|
||||||
StartSubGroupNav: Showing the subscriptions group nav menu
|
StartSubGroupNav: Showing the subscriptions group nav menu
|
||||||
- $action: the current action
|
- $menu: the menu widget; use $menu->action for output
|
||||||
|
|
||||||
EndSubGroupNav: At the end of the subscriptions group nav menu
|
EndSubGroupNav: At the end of the subscriptions group nav menu
|
||||||
- $action: the current action
|
- $menu: the menu widget; use $menu->action for output
|
||||||
|
|
||||||
StartInitializeRouter: Before the router instance has been initialized; good place to add routes
|
StartInitializeRouter: Before the router instance has been initialized; good place to add routes
|
||||||
- $m: the Net_URL_Mapper that has just been set up
|
- $m: the Net_URL_Mapper that has just been set up
|
||||||
|
@ -302,6 +302,20 @@ StartProfileSaveForm: before starting to save a profile settings form
|
||||||
EndProfileSaveForm: after saving a profile settings form (after commit, no profile or user object!)
|
EndProfileSaveForm: after saving a profile settings form (after commit, no profile or user object!)
|
||||||
- $action: action object being shown
|
- $action: action object being shown
|
||||||
|
|
||||||
|
StartEmailFormData: just before showing text entry fields on email settings page
|
||||||
|
- $action: action object being shown
|
||||||
|
|
||||||
|
EndEmailFormData: just after showing text entry fields on email settings page
|
||||||
|
- $action: action object being shown
|
||||||
|
|
||||||
|
StartEmailSaveForm: before starting to save a email settings form
|
||||||
|
- $action: action object being shown
|
||||||
|
- &$user: user being saved
|
||||||
|
|
||||||
|
EndEmailSaveForm: after saving a email settings form (after commit)
|
||||||
|
- $action: action object being shown
|
||||||
|
- &$user: user being saved
|
||||||
|
|
||||||
StartRegistrationFormData: just before showing text entry fields on registration page
|
StartRegistrationFormData: just before showing text entry fields on registration page
|
||||||
- $action: action object being shown
|
- $action: action object being shown
|
||||||
|
|
||||||
|
@ -365,6 +379,14 @@ GetValidDaemons: Just before determining which daemons to run
|
||||||
HandleQueuedNotice: Handle a queued notice at queue time (or immediately if no queue)
|
HandleQueuedNotice: Handle a queued notice at queue time (or immediately if no queue)
|
||||||
- &$notice: notice to handle
|
- &$notice: notice to handle
|
||||||
|
|
||||||
|
StartHtmlElement: Reight before outputting the HTML element - allows plugins to add namespaces
|
||||||
|
- $action: the current action
|
||||||
|
- &$attrs: attributes for the HTML element
|
||||||
|
|
||||||
|
EndHtmlElement: Right after outputting the HTML element
|
||||||
|
- $action: the current action
|
||||||
|
- &$attrs: attributes for the HTML element
|
||||||
|
|
||||||
StartShowHeadElements: Right after the <head> tag
|
StartShowHeadElements: Right after the <head> tag
|
||||||
- $action: the current action
|
- $action: the current action
|
||||||
|
|
||||||
|
@ -876,233 +898,13 @@ EndDeleteUser: handling the post for deleting a user
|
||||||
- $action: action being shown
|
- $action: action being shown
|
||||||
- $user: user being deleted
|
- $user: user being deleted
|
||||||
|
|
||||||
StartActivityStart: starting the output for a notice activity <event>
|
StartNoticeAsActivity: before converting a notice to an activity
|
||||||
- &$notice: notice being output
|
- $notice: notice being converted
|
||||||
- &$xs: XMLStringer for output
|
- &$activity: initially empty activity
|
||||||
- &$attrs: <entry> attributes (mostly namespace declarations, if any)
|
|
||||||
|
|
||||||
EndActivityStart: end the opening tag for an activity <event>
|
EndNoticeAsActivity: after converting a notice to an activity (good time to customize!)
|
||||||
- &$notice: notice being output
|
- $notice: notice being converted
|
||||||
- &$xs: XMLStringer for output
|
- &$activity: activity, now more-or-less full
|
||||||
- $attrs: <entry> attributes (mostly namespace declarations, if any)
|
|
||||||
|
|
||||||
StartActivitySource: before outputting the <source> element for a notice activity
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
|
|
||||||
EndActivitySource: after outputting the <source> element for a notice activity
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
|
|
||||||
StartActivityTitle: before outputting notice activity title
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$title: title of the notice, mutable
|
|
||||||
|
|
||||||
EndActivityTitle: after outputting notice activity title
|
|
||||||
- $notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $title: title of the notice
|
|
||||||
|
|
||||||
StartActivityAuthor: before outputting atom author
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$atomAuthor: string for XML representing atom author
|
|
||||||
|
|
||||||
EndActivityAuthor: after outputting atom author
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$atomAuthor: string for XML representing atom author
|
|
||||||
|
|
||||||
StartActivityActor: before outputting activity actor element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$actor: string for XML representing activity actor
|
|
||||||
|
|
||||||
EndActivityActor: after outputting activity actor element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$actor: string for XML representing activity actor
|
|
||||||
|
|
||||||
StartActivityLink: before outputting activity HTML link element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$url: URL for activity HTML link element for a notice activity entry
|
|
||||||
|
|
||||||
EndActivityLink: before outputting activity HTML link element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $url: URL for activity HTML link element for a notice activity entry
|
|
||||||
|
|
||||||
StartActivityId: before outputting atom:id element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$id: atom:id (notice URI by default)
|
|
||||||
|
|
||||||
EndActivityId: after outputting atom:id element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $id: atom:id (notice URI by default)
|
|
||||||
|
|
||||||
StartActivityPublished: before outputting atom:published element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$published: atom:published value (notice created by default)
|
|
||||||
|
|
||||||
EndActivityPublished: before outputting atom:published element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $published: atom:published value (notice created by default)
|
|
||||||
|
|
||||||
StartActivityUpdated: before outputting atom:updated element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$updated: atom:updated value (same as atom:published by default)
|
|
||||||
|
|
||||||
EndActivityUpdated: after outputting atom:updated element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $updated: atom:updated value (same as atom:published by default)
|
|
||||||
|
|
||||||
StartActivityContent: before outputting atom:content element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$content: atom:content value (notice rendered HTML by default)
|
|
||||||
|
|
||||||
EndActivityContent: after outputting atom:content element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $content: atom:content value (notice rendered HTML by default)
|
|
||||||
|
|
||||||
StartActivityVerb: before outputting activity:verb element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$verb: activity:verb URI ('http://activitystrea.ms/schema/1.0/post' by default)
|
|
||||||
|
|
||||||
EndActivityVerb: after outputting activity:verb element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $verb: activity:verb URI ('http://activitystrea.ms/schema/1.0/post' by default)
|
|
||||||
|
|
||||||
StartActivityDefaultObjectType: before outputting activity:object-type element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$type: activity:object-type URI for default object ('http://activitystrea.ms/schema/1.0/note' by default)
|
|
||||||
|
|
||||||
EndActivityDefaultObjectType: after outputting activity:verb element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $type: activity:object-type URI for default object ('http://activitystrea.ms/schema/1.0/note' by default)
|
|
||||||
|
|
||||||
StartActivityObjects: before outputting activity:object elements for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$objects: array of ActivityObject objects to output (empty by default)
|
|
||||||
|
|
||||||
EndActivityObjects: after outputting activity:object elements for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $objects: array of ActivityObject objects to output (empty by default)
|
|
||||||
|
|
||||||
StartActivityNoticeInfo: before outputting statusnet:notice-info element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$noticeInfoAttr: array of attributes for notice info element
|
|
||||||
|
|
||||||
EndActivityNoticeInfo: after outputting statusnet:notice-info element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $noticeInfoAttr: array of attributes for notice info element
|
|
||||||
|
|
||||||
StartActivityInReplyTo: before outputting thr:in-reply-to element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$replyNotice: Notice object the main notice is in-reply-to
|
|
||||||
|
|
||||||
EndActivityInReplyTo: after outputting thr:in-reply-to element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $replyNotice: Notice object the main notice is in-reply-to
|
|
||||||
|
|
||||||
StartActivityConversation: before outputting ostatus:conversation link element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$conv: Conversation object
|
|
||||||
|
|
||||||
EndActivityConversation: after outputting ostatus:conversation link element for a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $conv: Conversation object
|
|
||||||
|
|
||||||
StartActivityAttentionProfiles: before outputting ostatus:attention link element for people in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$replyProfiles: array of profiles of people being replied to
|
|
||||||
|
|
||||||
EndActivityAttentionProfiles: after outputting ostatus:attention link element for people in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $replyProfiles: array of Profile object of people being replied to
|
|
||||||
|
|
||||||
StartActivityAttentionGroups: before outputting ostatus:attention link element for groups in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$groups: array of Group objects of groups being addressed
|
|
||||||
|
|
||||||
EndActivityAttentionGroups: after outputting ostatus:attention link element for groups in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $groups: array of Group objects of groups being addressed
|
|
||||||
|
|
||||||
StartActivityForward: before outputting ostatus:forward link element in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$repeat: Notice that was repeated
|
|
||||||
|
|
||||||
EndActivityForward: after outputting ostatus:forward link element in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $repeat: Notice that was repeated
|
|
||||||
|
|
||||||
StartActivityCategories: before outputting atom:category elements in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$tags: array of strings for tags on the notice (used for categories)
|
|
||||||
|
|
||||||
EndActivityCategories: after outputting atom:category elements in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $tags: array of strings for tags on the notice (used for categories)
|
|
||||||
|
|
||||||
StartActivityEnclosures: before outputting enclosure link elements in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$enclosures: array of enclosure objects (see File::getEnclosure() for details)
|
|
||||||
|
|
||||||
EndActivityEnclosures: after outputting enclosure link elements in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $enclosures: array of enclosure objects (see File::getEnclosure() for details)
|
|
||||||
|
|
||||||
StartActivityGeo: before outputting geo:rss element in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- &$lat: latitude
|
|
||||||
- &$lon: longitude
|
|
||||||
|
|
||||||
EndActivityGeo: after outputting geo:rss element in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
- $lat: latitude
|
|
||||||
- $lon: longitude
|
|
||||||
|
|
||||||
StartActivityEnd: before the closing </entry> in a notice activity entry (last chance for data!)
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
|
|
||||||
EndActivityEnd: after the closing </entry> in a notice activity entry
|
|
||||||
- &$notice: notice being output
|
|
||||||
- &$xs: XMLStringer for output
|
|
||||||
|
|
||||||
StartNoticeSaveWeb: before saving a notice through the Web interface
|
StartNoticeSaveWeb: before saving a notice through the Web interface
|
||||||
- $action: action being executed (instance of NewNoticeAction)
|
- $action: action being executed (instance of NewNoticeAction)
|
||||||
|
@ -1182,3 +984,26 @@ StartRevokeRole: when a role is being revoked
|
||||||
EndRevokeRole: when a role has been revoked
|
EndRevokeRole: when a role has been revoked
|
||||||
- $profile: profile that lost the role
|
- $profile: profile that lost the role
|
||||||
- $role: string name of the role
|
- $role: string name of the role
|
||||||
|
|
||||||
|
StartAtomPubNewActivity: When a new activity comes in through Atom Pub API
|
||||||
|
- &$activity: received activity
|
||||||
|
|
||||||
|
EndAtomPubNewActivity: When a new activity comes in through Atom Pub API
|
||||||
|
- $activity: received activity
|
||||||
|
- $notice: notice that was created
|
||||||
|
|
||||||
|
StartXrdActionAliases: About to set aliases for the XRD object for a user
|
||||||
|
- &$xrd: XRD object being shown
|
||||||
|
- $user: User being shown
|
||||||
|
|
||||||
|
EndXrdActionAliases: Done with aliases for the XRD object for a user
|
||||||
|
- &$xrd: XRD object being shown
|
||||||
|
- $user: User being shown
|
||||||
|
|
||||||
|
StartXrdActionLinks: About to set links for the XRD object for a user
|
||||||
|
- &$xrd: XRD object being shown
|
||||||
|
- $user: User being shown
|
||||||
|
|
||||||
|
EndXrdActionLinks: Done with links for the XRD object for a user
|
||||||
|
- &$xrd: XRD object being shown
|
||||||
|
- $user: User being shown
|
||||||
|
|
19
README
19
README
|
@ -220,14 +220,12 @@ and the URLs are listed here for your convenience.
|
||||||
version may render your StatusNet site unable to send or receive XMPP
|
version may render your StatusNet site unable to send or receive XMPP
|
||||||
messages.
|
messages.
|
||||||
- Facebook library. Used for the Facebook application.
|
- Facebook library. Used for the Facebook application.
|
||||||
- PEAR Services_oEmbed. Used for some multimedia integration.
|
- PEAR Validate is used for URL and email validation.
|
||||||
- PEAR HTTP_Request is an oEmbed dependency.
|
|
||||||
- PEAR Validate is an oEmbed dependency.
|
|
||||||
- PEAR Net_URL2 is an oEmbed dependency.
|
|
||||||
- Console_GetOpt for parsing command-line options.
|
- Console_GetOpt for parsing command-line options.
|
||||||
- libomb. a library for implementing OpenMicroBlogging 0.1, the
|
- libomb. a library for implementing OpenMicroBlogging 0.1, the
|
||||||
predecessor to OStatus.
|
predecessor to OStatus.
|
||||||
- HTTP_Request2, a library for making HTTP requests.
|
- HTTP_Request2, a library for making HTTP requests.
|
||||||
|
- PEAR Net_URL2 is an HTTP_Request2 dependency.
|
||||||
|
|
||||||
A design goal of StatusNet is that the basic Web functionality should
|
A design goal of StatusNet is that the basic Web functionality should
|
||||||
work on even the most restrictive commercial hosting services.
|
work on even the most restrictive commercial hosting services.
|
||||||
|
@ -1554,6 +1552,19 @@ maxnoticelength: If a notice is strictly longer than this limit, all
|
||||||
URLs in the notice will be shortened. Users can override.
|
URLs in the notice will be shortened. Users can override.
|
||||||
-1 means the text limit for notices.
|
-1 means the text limit for notices.
|
||||||
|
|
||||||
|
router
|
||||||
|
------
|
||||||
|
|
||||||
|
We use a router class for mapping URLs to code. This section controls
|
||||||
|
how that router works.
|
||||||
|
|
||||||
|
cache: whether to cache the router in memcache (or another caching
|
||||||
|
mechanism). Defaults to true, but may be set to false for
|
||||||
|
developers (who might be actively adding pages, so won't want the
|
||||||
|
router cached) or others who see strange behavior. You're unlikely
|
||||||
|
to need this unless you're a developer.
|
||||||
|
|
||||||
|
|
||||||
Plugins
|
Plugins
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@ class AllrssAction extends Rss10Action
|
||||||
* @param array $args Web and URL arguments
|
* @param array $args Web and URL arguments
|
||||||
*
|
*
|
||||||
* @return boolean false if user doesn't exist
|
* @return boolean false if user doesn't exist
|
||||||
|
*
|
||||||
|
*/
|
||||||
function prepare($args)
|
function prepare($args)
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
100
actions/apiatomservice.php
Normal file
100
actions/apiatomservice.php
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* An AtomPub service document for a user
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2010 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once INSTALLDIR.'/lib/apibareauth.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows an AtomPub service document for a user
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2010 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ApiAtomServiceAction extends ApiBareAuthAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Take arguments for running
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST args
|
||||||
|
*
|
||||||
|
* @return boolean success flag
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
$this->user = $this->getTargetUser($this->arg('id'));
|
||||||
|
|
||||||
|
if (empty($this->user)) {
|
||||||
|
$this->clientError(_('No such user.'), 404, $this->format);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the arguments. In our case, show a service document.
|
||||||
|
*
|
||||||
|
* @param Array $args unused.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
|
||||||
|
header('Content-Type: application/atomsvc+xml');
|
||||||
|
|
||||||
|
$this->startXML();
|
||||||
|
$this->elementStart('service', array('xmlns' => 'http://www.w3.org/2007/app',
|
||||||
|
'xmlns:atom' => 'http://www.w3.org/2005/Atom'));
|
||||||
|
$this->elementStart('workspace');
|
||||||
|
$this->element('atom:title', null, _('Main'));
|
||||||
|
$this->elementStart('collection',
|
||||||
|
array('href' => common_local_url('ApiTimelineUser',
|
||||||
|
array('id' => $this->user->id,
|
||||||
|
'format' => 'atom'))));
|
||||||
|
$this->element('atom:title',
|
||||||
|
null,
|
||||||
|
sprintf(_("%s timeline"),
|
||||||
|
$this->user->nickname));
|
||||||
|
$this->element('accept', null, 'application/atom+xml;type=entry');
|
||||||
|
$this->elementEnd('collection');
|
||||||
|
$this->elementEnd('workspace');
|
||||||
|
$this->elementEnd('service');
|
||||||
|
$this->endXML();
|
||||||
|
}
|
||||||
|
}
|
|
@ -119,7 +119,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction
|
||||||
$this->format
|
$this->format
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$content_shortened = common_shorten_links($this->content);
|
$content_shortened = $this->auth_user->shortenLinks($this->content);
|
||||||
if (Message::contentTooLong($content_shortened)) {
|
if (Message::contentTooLong($content_shortened)) {
|
||||||
$this->clientError(
|
$this->clientError(
|
||||||
// TRANS: Client error displayed when message content is too long.
|
// TRANS: Client error displayed when message content is too long.
|
||||||
|
|
|
@ -85,7 +85,7 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
|
||||||
if (empty($this->profile_a) || empty($this->profile_b)) {
|
if (empty($this->profile_a) || empty($this->profile_b)) {
|
||||||
$this->clientError(
|
$this->clientError(
|
||||||
// TRANS: Client error displayed when supplying invalid parameters to an API call checking if a friendship exists.
|
// TRANS: Client error displayed when supplying invalid parameters to an API call checking if a friendship exists.
|
||||||
_('Two valid IDs or screen_names must be supplied.'),
|
_('Two valid IDs or nick names must be supplied.'),
|
||||||
400,
|
400,
|
||||||
$this->format
|
$this->format
|
||||||
);
|
);
|
||||||
|
|
|
@ -73,7 +73,7 @@ class ApiGroupCreateAction extends ApiAuthAction
|
||||||
|
|
||||||
$this->user = $this->auth_user;
|
$this->user = $this->auth_user;
|
||||||
|
|
||||||
$this->nickname = $this->arg('nickname');
|
$this->nickname = Nickname::normalize($this->arg('nickname'));
|
||||||
$this->fullname = $this->arg('full_name');
|
$this->fullname = $this->arg('full_name');
|
||||||
$this->homepage = $this->arg('homepage');
|
$this->homepage = $this->arg('homepage');
|
||||||
$this->description = $this->arg('description');
|
$this->description = $this->arg('description');
|
||||||
|
@ -150,26 +150,7 @@ class ApiGroupCreateAction extends ApiAuthAction
|
||||||
*/
|
*/
|
||||||
function validateParams()
|
function validateParams()
|
||||||
{
|
{
|
||||||
$valid = Validate::string(
|
if ($this->groupNicknameExists($this->nickname)) {
|
||||||
$this->nickname, array(
|
|
||||||
'min_length' => 1,
|
|
||||||
'max_length' => 64,
|
|
||||||
'format' => NICKNAME_FMT
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$valid) {
|
|
||||||
$this->clientError(
|
|
||||||
// TRANS: Validation error in form for group creation.
|
|
||||||
_(
|
|
||||||
'Nickname must have only lowercase letters ' .
|
|
||||||
'and numbers and no spaces.'
|
|
||||||
),
|
|
||||||
403,
|
|
||||||
$this->format
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
} elseif ($this->groupNicknameExists($this->nickname)) {
|
|
||||||
$this->clientError(
|
$this->clientError(
|
||||||
// TRANS: Client error trying to create a group with a nickname this is already in use.
|
// TRANS: Client error trying to create a group with a nickname this is already in use.
|
||||||
_('Nickname already in use. Try another one.'),
|
_('Nickname already in use. Try another one.'),
|
||||||
|
@ -265,15 +246,7 @@ class ApiGroupCreateAction extends ApiAuthAction
|
||||||
|
|
||||||
foreach ($this->aliases as $alias) {
|
foreach ($this->aliases as $alias) {
|
||||||
|
|
||||||
$valid = Validate::string(
|
if (!Nickname::isValid($alias)) {
|
||||||
$alias, array(
|
|
||||||
'min_length' => 1,
|
|
||||||
'max_length' => 64,
|
|
||||||
'format' => NICKNAME_FMT
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$valid) {
|
|
||||||
$this->clientError(
|
$this->clientError(
|
||||||
// TRANS: Client error shown when providing an invalid alias during group creation.
|
// TRANS: Client error shown when providing an invalid alias during group creation.
|
||||||
// TRANS: %s is the invalid alias.
|
// TRANS: %s is the invalid alias.
|
||||||
|
|
|
@ -421,7 +421,7 @@ class ApiOauthAuthorizeAction extends Action
|
||||||
if ($this->app->name == 'anonymous') {
|
if ($this->app->name == 'anonymous') {
|
||||||
// Special message for the anonymous app and consumer.
|
// Special message for the anonymous app and consumer.
|
||||||
// TRANS: User notification of external application requesting account access.
|
// TRANS: User notification of external application requesting account access.
|
||||||
// TRANS: %3$s is the access type requested, %4$s is the StatusNet sitename.
|
// TRANS: %3$s is the access type requested (read-write or read-only), %4$s is the StatusNet sitename.
|
||||||
$msg = _('An application would like the ability ' .
|
$msg = _('An application would like the ability ' .
|
||||||
'to <strong>%3$s</strong> your %4$s account data. ' .
|
'to <strong>%3$s</strong> your %4$s account data. ' .
|
||||||
'You should only give access to your %4$s account ' .
|
'You should only give access to your %4$s account ' .
|
||||||
|
|
|
@ -114,7 +114,7 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
|
||||||
$this->page = 1;
|
$this->page = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Suppport since_id -- we need to tweak the backend
|
// TODO: Suppport max_id -- we need to tweak the backend
|
||||||
// Search classes to support it.
|
// Search classes to support it.
|
||||||
|
|
||||||
$this->since_id = $this->trimmed('since_id');
|
$this->since_id = $this->trimmed('since_id');
|
||||||
|
@ -177,6 +177,10 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
|
||||||
$this->max_id = $notice->id;
|
$this->max_id = $notice->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->since_id && $notice->id <= $this->since_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ($cnt > $this->rpp) {
|
if ($cnt > $this->rpp) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,9 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
|
||||||
$this->page = 1;
|
$this->page = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Suppport max_id -- we need to tweak the backend
|
||||||
|
// Search classes to support it.
|
||||||
|
|
||||||
$this->since_id = $this->trimmed('since_id');
|
$this->since_id = $this->trimmed('since_id');
|
||||||
$this->geocode = $this->trimmed('geocode');
|
$this->geocode = $this->trimmed('geocode');
|
||||||
|
|
||||||
|
@ -127,9 +130,9 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
|
||||||
$cnt = $notice->find();
|
$cnt = $notice->find();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: since_id, lang, geocode
|
// TODO: max_id, lang, geocode
|
||||||
|
|
||||||
$results = new JSONSearchResultsList($notice, $q, $this->rpp, $this->page);
|
$results = new JSONSearchResultsList($notice, $q, $this->rpp, $this->page, $this->since_id);
|
||||||
|
|
||||||
$this->initDocument('json');
|
$this->initDocument('json');
|
||||||
$results->show();
|
$results->show();
|
||||||
|
|
|
@ -100,13 +100,23 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
|
|
||||||
if (!in_array($this->format, array('xml', 'json'))) {
|
if (!in_array($this->format, array('xml', 'json', 'atom'))) {
|
||||||
// TRANS: Client error displayed when trying to handle an unknown API method.
|
// TRANS: Client error displayed when trying to handle an unknown API method.
|
||||||
$this->clientError(_('API method not found.'), $code = 404);
|
$this->clientError(_('API method not found.'), 404);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch ($_SERVER['REQUEST_METHOD']) {
|
||||||
|
case 'GET':
|
||||||
$this->showNotice();
|
$this->showNotice();
|
||||||
|
break;
|
||||||
|
case 'DELETE':
|
||||||
|
$this->deleteNotice();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$this->clientError(_('HTTP method not supported.'), 405);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,10 +127,18 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
||||||
function showNotice()
|
function showNotice()
|
||||||
{
|
{
|
||||||
if (!empty($this->notice)) {
|
if (!empty($this->notice)) {
|
||||||
if ($this->format == 'xml') {
|
switch ($this->format) {
|
||||||
|
case 'xml':
|
||||||
$this->showSingleXmlStatus($this->notice);
|
$this->showSingleXmlStatus($this->notice);
|
||||||
} elseif ($this->format == 'json') {
|
break;
|
||||||
|
case 'json':
|
||||||
$this->show_single_json_status($this->notice);
|
$this->show_single_json_status($this->notice);
|
||||||
|
break;
|
||||||
|
case 'atom':
|
||||||
|
$this->showSingleAtomStatus($this->notice);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception(sprintf(_("Unsupported format: %s"), $this->format));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// XXX: Twitter just sets a 404 header and doens't bother
|
// XXX: Twitter just sets a 404 header and doens't bother
|
||||||
|
@ -153,9 +171,14 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
||||||
*
|
*
|
||||||
* @return boolean true
|
* @return boolean true
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function isReadOnly($args)
|
function isReadOnly($args)
|
||||||
{
|
{
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -197,4 +220,31 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteNotice()
|
||||||
|
{
|
||||||
|
if ($this->format != 'atom') {
|
||||||
|
$this->clientError(_("Can only delete using the Atom format."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($this->auth_user) ||
|
||||||
|
($this->notice->profile_id != $this->auth_user->id &&
|
||||||
|
!$this->auth_user->hasRight(Right::DELETEOTHERSNOTICE))) {
|
||||||
|
$this->clientError(_('Can\'t delete this notice.'), 403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Event::handle('StartDeleteOwnNotice', array($this->auth_user, $this->notice))) {
|
||||||
|
$this->notice->delete();
|
||||||
|
Event::handle('EndDeleteOwnNotice', array($this->auth_user, $this->notice));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @fixme is there better output we could do here?
|
||||||
|
|
||||||
|
header('HTTP/1.1 200 OK');
|
||||||
|
header('Content-Type: text/plain');
|
||||||
|
print(sprintf(_('Deleted notice %d'), $this->notice->id));
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$status_shortened = common_shorten_links($this->status);
|
$status_shortened = $this->auth_user->shortenlinks($this->status);
|
||||||
|
|
||||||
if (Notice::contentTooLong($status_shortened)) {
|
if (Notice::contentTooLong($status_shortened)) {
|
||||||
// Note: Twitter truncates anything over 140, flags the status
|
// Note: Twitter truncates anything over 140, flags the status
|
||||||
|
|
|
@ -97,8 +97,13 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
|
|
||||||
|
if ($this->isPost()) {
|
||||||
|
$this->handlePost();
|
||||||
|
} else {
|
||||||
$this->showTimeline();
|
$this->showTimeline();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the timeline of notices
|
* Show the timeline of notices
|
||||||
|
@ -146,6 +151,49 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||||
|
|
||||||
$atom->setId($self);
|
$atom->setId($self);
|
||||||
$atom->setSelfLink($self);
|
$atom->setSelfLink($self);
|
||||||
|
|
||||||
|
// Add navigation links: next, prev, first
|
||||||
|
// Note: we use IDs rather than pages for navigation; page boundaries
|
||||||
|
// change too quickly!
|
||||||
|
|
||||||
|
if (!empty($this->next_id)) {
|
||||||
|
$nextUrl = common_local_url('ApiTimelineUser',
|
||||||
|
array('format' => 'atom',
|
||||||
|
'id' => $this->user->id),
|
||||||
|
array('max_id' => $this->next_id));
|
||||||
|
|
||||||
|
$atom->addLink($nextUrl,
|
||||||
|
array('rel' => 'next',
|
||||||
|
'type' => 'application/atom+xml'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($this->page > 1 || !empty($this->max_id)) && !empty($this->notices)) {
|
||||||
|
|
||||||
|
$lastNotice = $this->notices[0];
|
||||||
|
$lastId = $lastNotice->id;
|
||||||
|
|
||||||
|
$prevUrl = common_local_url('ApiTimelineUser',
|
||||||
|
array('format' => 'atom',
|
||||||
|
'id' => $this->user->id),
|
||||||
|
array('since_id' => $lastId));
|
||||||
|
|
||||||
|
$atom->addLink($prevUrl,
|
||||||
|
array('rel' => 'prev',
|
||||||
|
'type' => 'application/atom+xml'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->page > 1 || !empty($this->since_id) || !empty($this->max_id)) {
|
||||||
|
|
||||||
|
$firstUrl = common_local_url('ApiTimelineUser',
|
||||||
|
array('format' => 'atom',
|
||||||
|
'id' => $this->user->id));
|
||||||
|
|
||||||
|
$atom->addLink($firstUrl,
|
||||||
|
array('rel' => 'first',
|
||||||
|
'type' => 'application/atom+xml'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
$atom->addEntryFromNotices($this->notices);
|
$atom->addEntryFromNotices($this->notices);
|
||||||
$this->raw($atom->getString());
|
$this->raw($atom->getString());
|
||||||
|
|
||||||
|
@ -169,13 +217,18 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||||
{
|
{
|
||||||
$notices = array();
|
$notices = array();
|
||||||
|
|
||||||
$notice = $this->user->getNotices(
|
$notice = $this->user->getNotices(($this->page-1) * $this->count,
|
||||||
($this->page-1) * $this->count, $this->count,
|
$this->count + 1,
|
||||||
$this->since_id, $this->max_id
|
$this->since_id,
|
||||||
);
|
$this->max_id);
|
||||||
|
|
||||||
while ($notice->fetch()) {
|
while ($notice->fetch()) {
|
||||||
|
if (count($notices) < $this->count) {
|
||||||
$notices[] = clone($notice);
|
$notices[] = clone($notice);
|
||||||
|
} else {
|
||||||
|
$this->next_id = $notice->id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $notices;
|
return $notices;
|
||||||
|
@ -188,9 +241,14 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||||
*
|
*
|
||||||
* @return boolean true
|
* @return boolean true
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function isReadOnly($args)
|
function isReadOnly($args)
|
||||||
{
|
{
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -234,4 +292,202 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handlePost()
|
||||||
|
{
|
||||||
|
if (empty($this->auth_user) ||
|
||||||
|
$this->auth_user->id != $this->user->id) {
|
||||||
|
// TRANS: Client error displayed trying to add a notice to another user's timeline.
|
||||||
|
$this->clientError(_('Only the user can add to their own timeline.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only handle posts for Atom
|
||||||
|
if ($this->format != 'atom') {
|
||||||
|
// TRANS: Client error displayed when using another format than AtomPub.
|
||||||
|
$this->clientError(_('Only accept AtomPub for Atom feeds.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$xml = file_get_contents('php://input');
|
||||||
|
|
||||||
|
$dom = DOMDocument::loadXML($xml);
|
||||||
|
|
||||||
|
if ($dom->documentElement->namespaceURI != Activity::ATOM ||
|
||||||
|
$dom->documentElement->localName != 'entry') {
|
||||||
|
// TRANS: Client error displayed when not using an Atom entry.
|
||||||
|
$this->clientError(_('Atom post must be an Atom entry.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$activity = new Activity($dom->documentElement);
|
||||||
|
|
||||||
|
if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {
|
||||||
|
|
||||||
|
if ($activity->verb != ActivityVerb::POST) {
|
||||||
|
// TRANS: Client error displayed when not using the POST verb.
|
||||||
|
// TRANS: Do not translate POST.
|
||||||
|
$this->clientError(_('Can only handle POST activities.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$note = $activity->objects[0];
|
||||||
|
|
||||||
|
if (!in_array($note->type, array(ActivityObject::NOTE,
|
||||||
|
ActivityObject::BLOGENTRY,
|
||||||
|
ActivityObject::STATUS))) {
|
||||||
|
// TRANS: Client error displayed when using an unsupported activity object type.
|
||||||
|
// TRANS: %s is the unsupported activity object type.
|
||||||
|
$this->clientError(sprintf(_('Cannot handle activity object type "%s".'),
|
||||||
|
$note->type));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$saved = $this->postNote($activity);
|
||||||
|
|
||||||
|
Event::handle('EndAtomPubNewActivity', array($activity, $saved));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($saved)) {
|
||||||
|
header("Location: " . common_local_url('ApiStatusesShow', array('notice_id' => $saved->id,
|
||||||
|
'format' => 'atom')));
|
||||||
|
$this->showSingleAtomStatus($saved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function postNote($activity)
|
||||||
|
{
|
||||||
|
$note = $activity->objects[0];
|
||||||
|
|
||||||
|
// Use summary as fallback for content
|
||||||
|
|
||||||
|
if (!empty($note->content)) {
|
||||||
|
$sourceContent = $note->content;
|
||||||
|
} else if (!empty($note->summary)) {
|
||||||
|
$sourceContent = $note->summary;
|
||||||
|
} else if (!empty($note->title)) {
|
||||||
|
$sourceContent = $note->title;
|
||||||
|
} else {
|
||||||
|
// @fixme fetch from $sourceUrl?
|
||||||
|
// TRANS: Client error displayed when posting a notice without content through the API.
|
||||||
|
$this->clientError(sprintf(_('No content for notice %d.'),
|
||||||
|
$note->id));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get (safe!) HTML and text versions of the content
|
||||||
|
|
||||||
|
$rendered = $this->purify($sourceContent);
|
||||||
|
$content = html_entity_decode(strip_tags($rendered), ENT_QUOTES, 'UTF-8');
|
||||||
|
|
||||||
|
$shortened = $this->auth_user->shortenLinks($content);
|
||||||
|
|
||||||
|
$options = array('is_local' => Notice::LOCAL_PUBLIC,
|
||||||
|
'rendered' => $rendered,
|
||||||
|
'replies' => array(),
|
||||||
|
'groups' => array(),
|
||||||
|
'tags' => array(),
|
||||||
|
'urls' => array());
|
||||||
|
|
||||||
|
// accept remote URI (not necessarily a good idea)
|
||||||
|
|
||||||
|
common_debug("Note ID is {$note->id}");
|
||||||
|
|
||||||
|
if (!empty($note->id)) {
|
||||||
|
$notice = Notice::staticGet('uri', trim($note->id));
|
||||||
|
|
||||||
|
if (!empty($notice)) {
|
||||||
|
// TRANS: Client error displayed when using another format than AtomPub.
|
||||||
|
$this->clientError(sprintf(_('Notice with URI "%s" already exists.'),
|
||||||
|
$note->id));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
common_log(LOG_NOTICE, "Saving client-supplied notice URI '$note->id'");
|
||||||
|
$options['uri'] = $note->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// accept remote create time (also maybe not such a good idea)
|
||||||
|
|
||||||
|
if (!empty($activity->time)) {
|
||||||
|
common_log(LOG_NOTICE, "Saving client-supplied create time {$activity->time}");
|
||||||
|
$options['created'] = common_sql_date($activity->time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for optional attributes...
|
||||||
|
|
||||||
|
if (!empty($activity->context)) {
|
||||||
|
|
||||||
|
foreach ($activity->context->attention as $uri) {
|
||||||
|
|
||||||
|
$profile = Profile::fromURI($uri);
|
||||||
|
|
||||||
|
if (!empty($profile)) {
|
||||||
|
$options['replies'] = $uri;
|
||||||
|
} else {
|
||||||
|
$group = User_group::staticGet('uri', $uri);
|
||||||
|
if (!empty($group)) {
|
||||||
|
$options['groups'] = $uri;
|
||||||
|
} else {
|
||||||
|
// @fixme: hook for discovery here
|
||||||
|
common_log(LOG_WARNING, sprintf(_('AtomPub post with unknown attention URI %s'), $uri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maintain direct reply associations
|
||||||
|
// @fixme what about conversation ID?
|
||||||
|
|
||||||
|
if (!empty($activity->context->replyToID)) {
|
||||||
|
$orig = Notice::staticGet('uri',
|
||||||
|
$activity->context->replyToID);
|
||||||
|
if (!empty($orig)) {
|
||||||
|
$options['reply_to'] = $orig->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$location = $activity->context->location;
|
||||||
|
|
||||||
|
if ($location) {
|
||||||
|
$options['lat'] = $location->lat;
|
||||||
|
$options['lon'] = $location->lon;
|
||||||
|
if ($location->location_id) {
|
||||||
|
$options['location_ns'] = $location->location_ns;
|
||||||
|
$options['location_id'] = $location->location_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Atom categories <-> hashtags
|
||||||
|
|
||||||
|
foreach ($activity->categories as $cat) {
|
||||||
|
if ($cat->term) {
|
||||||
|
$term = common_canonical_tag($cat->term);
|
||||||
|
if ($term) {
|
||||||
|
$options['tags'][] = $term;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Atom enclosures -> attachment URLs
|
||||||
|
foreach ($activity->enclosures as $href) {
|
||||||
|
// @fixme save these locally or....?
|
||||||
|
$options['urls'][] = $href;
|
||||||
|
}
|
||||||
|
|
||||||
|
$saved = Notice::saveNew($this->user->id,
|
||||||
|
$content,
|
||||||
|
'atompub', // TODO: deal with this
|
||||||
|
$options);
|
||||||
|
|
||||||
|
return $saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
function purify($content)
|
||||||
|
{
|
||||||
|
require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
|
||||||
|
|
||||||
|
$config = array('safe' => 1,
|
||||||
|
'deny_attribute' => 'id,style,on*');
|
||||||
|
return htmLawed($content, $config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,21 +177,14 @@ class EditgroupAction extends GroupDesignAction
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$nickname = common_canonical_nickname($this->trimmed('nickname'));
|
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||||
$fullname = $this->trimmed('fullname');
|
$fullname = $this->trimmed('fullname');
|
||||||
$homepage = $this->trimmed('homepage');
|
$homepage = $this->trimmed('homepage');
|
||||||
$description = $this->trimmed('description');
|
$description = $this->trimmed('description');
|
||||||
$location = $this->trimmed('location');
|
$location = $this->trimmed('location');
|
||||||
$aliasstring = $this->trimmed('aliases');
|
$aliasstring = $this->trimmed('aliases');
|
||||||
|
|
||||||
if (!Validate::string($nickname, array('min_length' => 1,
|
if ($this->nicknameExists($nickname)) {
|
||||||
'max_length' => 64,
|
|
||||||
'format' => NICKNAME_FMT))) {
|
|
||||||
// TRANS: Group edit form validation error.
|
|
||||||
$this->showForm(_('Nickname must have only lowercase letters '.
|
|
||||||
'and numbers and no spaces.'));
|
|
||||||
return;
|
|
||||||
} else if ($this->nicknameExists($nickname)) {
|
|
||||||
// TRANS: Group edit form validation error.
|
// TRANS: Group edit form validation error.
|
||||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||||
return;
|
return;
|
||||||
|
@ -241,9 +234,7 @@ class EditgroupAction extends GroupDesignAction
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($aliases as $alias) {
|
foreach ($aliases as $alias) {
|
||||||
if (!Validate::string($alias, array('min_length' => 1,
|
if (!Nickname::isValid($alias)) {
|
||||||
'max_length' => 64,
|
|
||||||
'format' => NICKNAME_FMT))) {
|
|
||||||
// TRANS: Group edit form validation error.
|
// TRANS: Group edit form validation error.
|
||||||
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
|
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -79,6 +79,7 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||||
function showScripts()
|
function showScripts()
|
||||||
{
|
{
|
||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
|
$this->script('emailsettings.js');
|
||||||
$this->autofocus('email');
|
$this->autofocus('email');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +150,26 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||||
$this->elementStart('fieldset', array('id' => 'settings_email_incoming'));
|
$this->elementStart('fieldset', array('id' => 'settings_email_incoming'));
|
||||||
// TRANS: Form legend for incoming e-mail settings form.
|
// TRANS: Form legend for incoming e-mail settings form.
|
||||||
$this->element('legend', null, _('Incoming email'));
|
$this->element('legend', null, _('Incoming email'));
|
||||||
|
|
||||||
|
$this->elementStart('ul', 'form_data');
|
||||||
|
$this->elementStart('li');
|
||||||
|
$this->checkbox('emailpost',
|
||||||
|
// TRANS: Checkbox label in e-mail preferences form.
|
||||||
|
_('I want to post notices by email.'),
|
||||||
|
$user->emailpost);
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
|
// Our stylesheets make the form_data list items all floats, which
|
||||||
|
// creates lots of problems with trying to wrap divs around things.
|
||||||
|
// This should force a break before the next section, which needs
|
||||||
|
// to be separate so we can disable the things in it when the
|
||||||
|
// checkbox is off.
|
||||||
|
$this->elementStart('div', array('style' => 'clear: both'));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
|
||||||
|
$this->elementStart('div', array('id' => 'emailincoming'));
|
||||||
|
|
||||||
if ($user->incomingemail) {
|
if ($user->incomingemail) {
|
||||||
$this->elementStart('p');
|
$this->elementStart('p');
|
||||||
$this->element('span', 'address', $user->incomingemail);
|
$this->element('span', 'address', $user->incomingemail);
|
||||||
|
@ -163,13 +184,22 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->elementStart('p');
|
$this->elementStart('p');
|
||||||
$this->element('span', 'input_instructions',
|
if ($user->incomingemail) {
|
||||||
|
// TRANS: Instructions for incoming e-mail address input form, when an address has already been assigned.
|
||||||
|
$msg = _('Make a new email address for posting to; '.
|
||||||
|
'cancels the old one.');
|
||||||
|
} else {
|
||||||
// TRANS: Instructions for incoming e-mail address input form.
|
// TRANS: Instructions for incoming e-mail address input form.
|
||||||
_('Make a new email address for posting to; '.
|
$msg = _('To send notices via email, we need to create a unique email address for you on this server:');
|
||||||
'cancels the old one.'));
|
}
|
||||||
|
$this->element('span', 'input_instructions', $msg);
|
||||||
$this->elementEnd('p');
|
$this->elementEnd('p');
|
||||||
|
|
||||||
// TRANS: Button label for adding an e-mail address to send notices from.
|
// TRANS: Button label for adding an e-mail address to send notices from.
|
||||||
$this->submit('newincoming', _m('BUTTON','New'));
|
$this->submit('newincoming', _m('BUTTON','New'));
|
||||||
|
|
||||||
|
$this->elementEnd('div'); // div#emailincoming
|
||||||
|
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +208,8 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||||
$this->element('legend', null, _('Email preferences'));
|
$this->element('legend', null, _('Email preferences'));
|
||||||
|
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
|
|
||||||
|
if (Event::handle('StartEmailFormData', array($this))) {
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->checkbox('emailnotifysub',
|
$this->checkbox('emailnotifysub',
|
||||||
// TRANS: Checkbox label in e-mail preferences form.
|
// TRANS: Checkbox label in e-mail preferences form.
|
||||||
|
@ -209,20 +241,14 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||||
_('Allow friends to nudge me and send me an email.'),
|
_('Allow friends to nudge me and send me an email.'),
|
||||||
$user->emailnotifynudge);
|
$user->emailnotifynudge);
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
if (common_config('emailpost', 'enabled')) {
|
|
||||||
$this->elementStart('li');
|
|
||||||
$this->checkbox('emailpost',
|
|
||||||
// TRANS: Checkbox label in e-mail preferences form.
|
|
||||||
_('I want to post notices by email.'),
|
|
||||||
$user->emailpost);
|
|
||||||
$this->elementEnd('li');
|
|
||||||
}
|
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->checkbox('emailmicroid',
|
$this->checkbox('emailmicroid',
|
||||||
// TRANS: Checkbox label in e-mail preferences form.
|
// TRANS: Checkbox label in e-mail preferences form.
|
||||||
_('Publish a MicroID for my email address.'),
|
_('Publish a MicroID for my email address.'),
|
||||||
$user->emailmicroid);
|
$user->emailmicroid);
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
|
Event::handle('EndEmailFormData', array($this));
|
||||||
|
}
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
// TRANS: Button label to save e-mail preferences.
|
// TRANS: Button label to save e-mail preferences.
|
||||||
$this->submit('save', _m('BUTTON','Save'));
|
$this->submit('save', _m('BUTTON','Save'));
|
||||||
|
@ -299,6 +325,10 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||||
|
|
||||||
function savePreferences()
|
function savePreferences()
|
||||||
{
|
{
|
||||||
|
$user = common_current_user();
|
||||||
|
|
||||||
|
if (Event::handle('StartEmailSaveForm', array($this, &$user))) {
|
||||||
|
|
||||||
$emailnotifysub = $this->boolean('emailnotifysub');
|
$emailnotifysub = $this->boolean('emailnotifysub');
|
||||||
$emailnotifyfav = $this->boolean('emailnotifyfav');
|
$emailnotifyfav = $this->boolean('emailnotifyfav');
|
||||||
$emailnotifymsg = $this->boolean('emailnotifymsg');
|
$emailnotifymsg = $this->boolean('emailnotifymsg');
|
||||||
|
@ -307,8 +337,6 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||||
$emailmicroid = $this->boolean('emailmicroid');
|
$emailmicroid = $this->boolean('emailmicroid');
|
||||||
$emailpost = $this->boolean('emailpost');
|
$emailpost = $this->boolean('emailpost');
|
||||||
|
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
assert(!is_null($user)); // should already be checked
|
assert(!is_null($user)); // should already be checked
|
||||||
|
|
||||||
$user->query('BEGIN');
|
$user->query('BEGIN');
|
||||||
|
@ -334,9 +362,12 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||||
|
|
||||||
$user->query('COMMIT');
|
$user->query('COMMIT');
|
||||||
|
|
||||||
|
Event::handle('EndEmailSaveForm', array($this));
|
||||||
|
|
||||||
// TRANS: Confirmation message for successful e-mail preferences save.
|
// TRANS: Confirmation message for successful e-mail preferences save.
|
||||||
$this->showForm(_('Email preferences saved.'), true);
|
$this->showForm(_('Email preferences saved.'), true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the address passed in by the user
|
* Add the address passed in by the user
|
||||||
|
@ -501,6 +532,7 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||||
$orig = clone($user);
|
$orig = clone($user);
|
||||||
|
|
||||||
$user->incomingemail = null;
|
$user->incomingemail = null;
|
||||||
|
$user->emailpost = 0;
|
||||||
|
|
||||||
if (!$user->updateKeys($orig)) {
|
if (!$user->updateKeys($orig)) {
|
||||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||||
|
@ -525,6 +557,7 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||||
$orig = clone($user);
|
$orig = clone($user);
|
||||||
|
|
||||||
$user->incomingemail = mail_new_incoming_address();
|
$user->incomingemail = mail_new_incoming_address();
|
||||||
|
$user->emailpost = 1;
|
||||||
|
|
||||||
if (!$user->updateKeys($orig)) {
|
if (!$user->updateKeys($orig)) {
|
||||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||||
|
|
|
@ -185,29 +185,11 @@ class FavoritedAction extends Action
|
||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
|
$pop = new Popularity();
|
||||||
$cutoff = sprintf("fave.modified > '%s'",
|
$pop->offset = ($this->page - 1) * NOTICES_PER_PAGE;
|
||||||
common_sql_date(time() - common_config('popular', 'cutoff')));
|
$pop->limit = NOTICES_PER_PAGE;
|
||||||
|
$pop->expiry = 600;
|
||||||
$qry = 'SELECT notice.*, '.
|
$notice = $pop->getNotices();
|
||||||
$weightexpr . ' as weight ' .
|
|
||||||
'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
|
|
||||||
"WHERE $cutoff " .
|
|
||||||
'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' .
|
|
||||||
'ORDER BY weight DESC';
|
|
||||||
|
|
||||||
$offset = ($this->page - 1) * NOTICES_PER_PAGE;
|
|
||||||
$limit = NOTICES_PER_PAGE + 1;
|
|
||||||
|
|
||||||
if (common_config('db', 'type') == 'pgsql') {
|
|
||||||
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
|
||||||
} else {
|
|
||||||
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$notice = Memcached_DataObject::cachedQuery('Notice',
|
|
||||||
$qry,
|
|
||||||
600);
|
|
||||||
|
|
||||||
$nl = new NoticeList($notice, $this);
|
$nl = new NoticeList($notice, $this);
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,11 @@ class HostMetaAction extends Action
|
||||||
$xrd->host = $domain;
|
$xrd->host = $domain;
|
||||||
|
|
||||||
if(Event::handle('StartHostMetaLinks', array(&$xrd->links))) {
|
if(Event::handle('StartHostMetaLinks', array(&$xrd->links))) {
|
||||||
|
$url = common_local_url('userxrd');
|
||||||
|
$url.= '?uri={uri}';
|
||||||
|
$xrd->links[] = array('rel' => Discovery::LRDD_REL,
|
||||||
|
'template' => $url,
|
||||||
|
'title' => array('Resource Descriptor'));
|
||||||
Event::handle('EndHostMetaLinks', array(&$xrd->links));
|
Event::handle('EndHostMetaLinks', array(&$xrd->links));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,21 +113,18 @@ class NewgroupAction extends Action
|
||||||
|
|
||||||
function trySave()
|
function trySave()
|
||||||
{
|
{
|
||||||
$nickname = $this->trimmed('nickname');
|
try {
|
||||||
|
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||||
|
} catch (NicknameException $e) {
|
||||||
|
$this->showForm($e->getMessage());
|
||||||
|
}
|
||||||
$fullname = $this->trimmed('fullname');
|
$fullname = $this->trimmed('fullname');
|
||||||
$homepage = $this->trimmed('homepage');
|
$homepage = $this->trimmed('homepage');
|
||||||
$description = $this->trimmed('description');
|
$description = $this->trimmed('description');
|
||||||
$location = $this->trimmed('location');
|
$location = $this->trimmed('location');
|
||||||
$aliasstring = $this->trimmed('aliases');
|
$aliasstring = $this->trimmed('aliases');
|
||||||
|
|
||||||
if (!Validate::string($nickname, array('min_length' => 1,
|
if ($this->nicknameExists($nickname)) {
|
||||||
'max_length' => 64,
|
|
||||||
'format' => NICKNAME_FMT))) {
|
|
||||||
// TRANS: Group create form validation error.
|
|
||||||
$this->showForm(_('Nickname must have only lowercase letters '.
|
|
||||||
'and numbers and no spaces.'));
|
|
||||||
return;
|
|
||||||
} else if ($this->nicknameExists($nickname)) {
|
|
||||||
// TRANS: Group create form validation error.
|
// TRANS: Group create form validation error.
|
||||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||||
return;
|
return;
|
||||||
|
@ -177,9 +174,7 @@ class NewgroupAction extends Action
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($aliases as $alias) {
|
foreach ($aliases as $alias) {
|
||||||
if (!Validate::string($alias, array('min_length' => 1,
|
if (!Nickname::isValid($alias)) {
|
||||||
'max_length' => 64,
|
|
||||||
'format' => NICKNAME_FMT))) {
|
|
||||||
// TRANS: Group create form validation error.
|
// TRANS: Group create form validation error.
|
||||||
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
|
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -144,7 +144,7 @@ class NewmessageAction extends Action
|
||||||
$this->showForm(_('No content!'));
|
$this->showForm(_('No content!'));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
$content_shortened = common_shorten_links($this->content);
|
$content_shortened = $user->shortenLinks($this->content);
|
||||||
|
|
||||||
if (Message::contentTooLong($content_shortened)) {
|
if (Message::contentTooLong($content_shortened)) {
|
||||||
// TRANS: Form validation error displayed when message content is too long.
|
// TRANS: Form validation error displayed when message content is too long.
|
||||||
|
|
|
@ -154,7 +154,7 @@ class NewnoticeAction extends Action
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$content_shortened = common_shorten_links($content);
|
$content_shortened = $user->shortenLinks($content);
|
||||||
if (Notice::contentTooLong($content_shortened)) {
|
if (Notice::contentTooLong($content_shortened)) {
|
||||||
// TRANS: Client error displayed when the parameter "status" is missing.
|
// TRANS: Client error displayed when the parameter "status" is missing.
|
||||||
// TRANS: %d is the maximum number of character for a notice.
|
// TRANS: %d is the maximum number of character for a notice.
|
||||||
|
|
|
@ -108,10 +108,23 @@ class OembedAction extends Action
|
||||||
$oembed['url']=$file_oembed->url;
|
$oembed['url']=$file_oembed->url;
|
||||||
}else if(substr($attachment->mimetype,0,strlen('image/'))=='image/'){
|
}else if(substr($attachment->mimetype,0,strlen('image/'))=='image/'){
|
||||||
$oembed['type']='photo';
|
$oembed['type']='photo';
|
||||||
//TODO set width and height
|
if ($attachment->filename) {
|
||||||
//$oembed['width']=
|
$filepath = File::path($attachment->filename);
|
||||||
//$oembed['height']=
|
$gis = @getimagesize($filepath);
|
||||||
|
if ($gis) {
|
||||||
|
$oembed['width'] = $gis[0];
|
||||||
|
$oembed['height'] = $gis[1];
|
||||||
|
} else {
|
||||||
|
// TODO Either throw an error or find a fallback?
|
||||||
|
}
|
||||||
|
}
|
||||||
$oembed['url']=$attachment->url;
|
$oembed['url']=$attachment->url;
|
||||||
|
$thumb = $attachment->getThumbnail();
|
||||||
|
if ($thumb) {
|
||||||
|
$oembed['thumbnail_url'] = $thumb->url;
|
||||||
|
$oembed['thumbnail_width'] = $thumb->width;
|
||||||
|
$oembed['thumbnail_height'] = $thumb->height;
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
$oembed['type']='link';
|
$oembed['type']='link';
|
||||||
$oembed['url']=common_local_url('attachment',
|
$oembed['url']=common_local_url('attachment',
|
||||||
|
|
|
@ -225,7 +225,13 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||||
|
|
||||||
if (Event::handle('StartProfileSaveForm', array($this))) {
|
if (Event::handle('StartProfileSaveForm', array($this))) {
|
||||||
|
|
||||||
$nickname = $this->trimmed('nickname');
|
try {
|
||||||
|
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||||
|
} catch (NicknameException $e) {
|
||||||
|
$this->showForm($e->getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$fullname = $this->trimmed('fullname');
|
$fullname = $this->trimmed('fullname');
|
||||||
$homepage = $this->trimmed('homepage');
|
$homepage = $this->trimmed('homepage');
|
||||||
$bio = $this->trimmed('bio');
|
$bio = $this->trimmed('bio');
|
||||||
|
@ -236,13 +242,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||||
$tagstring = $this->trimmed('tags');
|
$tagstring = $this->trimmed('tags');
|
||||||
|
|
||||||
// Some validation
|
// Some validation
|
||||||
if (!Validate::string($nickname, array('min_length' => 1,
|
if (!User::allowed_nickname($nickname)) {
|
||||||
'max_length' => 64,
|
|
||||||
'format' => NICKNAME_FMT))) {
|
|
||||||
// TRANS: Validation error in form for profile settings.
|
|
||||||
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
|
||||||
return;
|
|
||||||
} else if (!User::allowed_nickname($nickname)) {
|
|
||||||
// TRANS: Validation error in form for profile settings.
|
// TRANS: Validation error in form for profile settings.
|
||||||
$this->showForm(_('Not a valid nickname.'));
|
$this->showForm(_('Not a valid nickname.'));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -191,7 +191,11 @@ class RegisterAction extends Action
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input scrubbing
|
// Input scrubbing
|
||||||
$nickname = common_canonical_nickname($nickname);
|
try {
|
||||||
|
$nickname = Nickname::normalize($nickname);
|
||||||
|
} catch (NicknameException $e) {
|
||||||
|
$this->showForm($e->getMessage());
|
||||||
|
}
|
||||||
$email = common_canonical_email($email);
|
$email = common_canonical_email($email);
|
||||||
|
|
||||||
if (!$this->boolean('license')) {
|
if (!$this->boolean('license')) {
|
||||||
|
@ -199,11 +203,6 @@ class RegisterAction extends Action
|
||||||
'agree to the license.'));
|
'agree to the license.'));
|
||||||
} else if ($email && !Validate::email($email, common_config('email', 'check_domain'))) {
|
} else if ($email && !Validate::email($email, common_config('email', 'check_domain'))) {
|
||||||
$this->showForm(_('Not a valid email address.'));
|
$this->showForm(_('Not a valid email address.'));
|
||||||
} else if (!Validate::string($nickname, array('min_length' => 1,
|
|
||||||
'max_length' => 64,
|
|
||||||
'format' => NICKNAME_FMT))) {
|
|
||||||
$this->showForm(_('Nickname must have only lowercase letters '.
|
|
||||||
'and numbers and no spaces.'));
|
|
||||||
} else if ($this->nicknameExists($nickname)) {
|
} else if ($this->nicknameExists($nickname)) {
|
||||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||||
} else if (!User::allowed_nickname($nickname)) {
|
} else if (!User::allowed_nickname($nickname)) {
|
||||||
|
|
|
@ -162,6 +162,20 @@ class RsdAction extends Action
|
||||||
'true');
|
'true');
|
||||||
$this->elementEnd('settings');
|
$this->elementEnd('settings');
|
||||||
$this->elementEnd('api');
|
$this->elementEnd('api');
|
||||||
|
|
||||||
|
// Atom API
|
||||||
|
|
||||||
|
if (empty($this->user)) {
|
||||||
|
$service = common_local_url('ApiAtomService');
|
||||||
|
} else {
|
||||||
|
$service = common_local_url('ApiAtomService', array('id' => $this->user->nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->element('api', array('name' => 'Atom',
|
||||||
|
'preferred' => 'false',
|
||||||
|
'apiLink' => $service,
|
||||||
|
'blogID' => $blogID));
|
||||||
|
|
||||||
Event::handle('EndRsdListApis', array($this, $this->user));
|
Event::handle('EndRsdListApis', array($this, $this->user));
|
||||||
}
|
}
|
||||||
$this->elementEnd('apis');
|
$this->elementEnd('apis');
|
||||||
|
|
|
@ -325,8 +325,38 @@ class SingleNoticeItem extends DoFollowListItem
|
||||||
$this->showEnd();
|
$this->showEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For our zoomed-in special case we'll use a fuller list
|
||||||
|
* for the attachment info.
|
||||||
|
*/
|
||||||
function showNoticeAttachments() {
|
function showNoticeAttachments() {
|
||||||
$al = new AttachmentList($this->notice, $this->out);
|
$al = new AttachmentList($this->notice, $this->out);
|
||||||
$al->show();
|
$al->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show the avatar of the notice's author
|
||||||
|
*
|
||||||
|
* We use the larger size for single notice page.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showAvatar()
|
||||||
|
{
|
||||||
|
$avatar_size = AVATAR_PROFILE_SIZE;
|
||||||
|
|
||||||
|
$avatar = $this->profile->getAvatar($avatar_size);
|
||||||
|
|
||||||
|
$this->out->element('img', array('src' => ($avatar) ?
|
||||||
|
$avatar->displayUrl() :
|
||||||
|
Avatar::defaultImage($avatar_size),
|
||||||
|
'class' => 'avatar photo',
|
||||||
|
'width' => $avatar_size,
|
||||||
|
'height' => $avatar_size,
|
||||||
|
'alt' =>
|
||||||
|
($this->profile->fullname) ?
|
||||||
|
$this->profile->fullname :
|
||||||
|
$this->profile->nickname));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,9 +32,9 @@ class UserxrdAction extends XrdAction
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
$this->uri = $this->trimmed('uri');
|
$this->uri = $this->trimmed('uri');
|
||||||
$this->uri = Discovery::normalize($this->uri);
|
$this->uri = self::normalize($this->uri);
|
||||||
|
|
||||||
if (Discovery::isWebfinger($this->uri)) {
|
if (self::isWebfinger($this->uri)) {
|
||||||
$parts = explode('@', substr(urldecode($this->uri), 5));
|
$parts = explode('@', substr(urldecode($this->uri), 5));
|
||||||
if (count($parts) == 2) {
|
if (count($parts) == 2) {
|
||||||
list($nick, $domain) = $parts;
|
list($nick, $domain) = $parts;
|
|
@ -116,10 +116,24 @@ class File extends Memcached_DataObject
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Go look at a URL and possibly save data about it if it's new:
|
||||||
|
* - follow redirect chains and store them in file_redirection
|
||||||
|
* - look up oEmbed data and save it in file_oembed
|
||||||
|
* - if a thumbnail is available, save it in file_thumbnail
|
||||||
|
* - save file record with basic info
|
||||||
|
* - optionally save a file_to_post record
|
||||||
|
* - return the File object with the full reference
|
||||||
|
*
|
||||||
* @fixme refactor this mess, it's gotten pretty scary.
|
* @fixme refactor this mess, it's gotten pretty scary.
|
||||||
* @param bool $followRedirects
|
* @param string $given_url the URL we're looking at
|
||||||
|
* @param int $notice_id (optional)
|
||||||
|
* @param bool $followRedirects defaults to true
|
||||||
|
*
|
||||||
|
* @return mixed File on success, -1 on some errors
|
||||||
|
*
|
||||||
|
* @throws ServerException on some errors
|
||||||
*/
|
*/
|
||||||
function processNew($given_url, $notice_id=null, $followRedirects=true) {
|
public function processNew($given_url, $notice_id=null, $followRedirects=true) {
|
||||||
if (empty($given_url)) return -1; // error, no url to process
|
if (empty($given_url)) return -1; // error, no url to process
|
||||||
$given_url = File_redirection::_canonUrl($given_url);
|
$given_url = File_redirection::_canonUrl($given_url);
|
||||||
if (empty($given_url)) return -1; // error, no url to process
|
if (empty($given_url)) return -1; // error, no url to process
|
||||||
|
@ -169,9 +183,9 @@ class File extends Memcached_DataObject
|
||||||
if (empty($x)) {
|
if (empty($x)) {
|
||||||
$x = File::staticGet($file_id);
|
$x = File::staticGet($file_id);
|
||||||
if (empty($x)) {
|
if (empty($x)) {
|
||||||
// FIXME: This could possibly be a clearer message :)
|
// @todo FIXME: This could possibly be a clearer message :)
|
||||||
// TRANS: Server exception thrown when... Robin thinks something is impossible!
|
// TRANS: Server exception thrown when... Robin thinks something is impossible!
|
||||||
throw new ServerException(_("Robin thinks something is impossible."));
|
throw new ServerException(_('Robin thinks something is impossible.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,8 +200,10 @@ class File extends Memcached_DataObject
|
||||||
if ($fileSize > common_config('attachments', 'file_quota')) {
|
if ($fileSize > common_config('attachments', 'file_quota')) {
|
||||||
// TRANS: Message given if an upload is larger than the configured maximum.
|
// TRANS: Message given if an upload is larger than the configured maximum.
|
||||||
// TRANS: %1$d is the byte limit for uploads, %2$d is the byte count for the uploaded file.
|
// TRANS: %1$d is the byte limit for uploads, %2$d is the byte count for the uploaded file.
|
||||||
return sprintf(_('No file may be larger than %1$d bytes ' .
|
// TRANS: %1$s is used for plural.
|
||||||
'and the file you sent was %2$d bytes. Try to upload a smaller version.'),
|
return sprintf(_m('No file may be larger than %1$d byte and the file you sent was %2$d bytes. Try to upload a smaller version.',
|
||||||
|
'No file may be larger than %1$d bytes and the file you sent was %2$d bytes. Try to upload a smaller version.',
|
||||||
|
common_config('attachments', 'file_quota')),
|
||||||
common_config('attachments', 'file_quota'), $fileSize);
|
common_config('attachments', 'file_quota'), $fileSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,8 +213,11 @@ class File extends Memcached_DataObject
|
||||||
$total = $this->total + $fileSize;
|
$total = $this->total + $fileSize;
|
||||||
if ($total > common_config('attachments', 'user_quota')) {
|
if ($total > common_config('attachments', 'user_quota')) {
|
||||||
// TRANS: Message given if an upload would exceed user quota.
|
// TRANS: Message given if an upload would exceed user quota.
|
||||||
// TRANS: %d (number) is the user quota in bytes.
|
// TRANS: %d (number) is the user quota in bytes and is used for plural.
|
||||||
return sprintf(_('A file this large would exceed your user quota of %d bytes.'), common_config('attachments', 'user_quota'));
|
return sprintf(_m('A file this large would exceed your user quota of %d byte.',
|
||||||
|
'A file this large would exceed your user quota of %d bytes.',
|
||||||
|
common_config('attachments', 'user_quota')),
|
||||||
|
common_config('attachments', 'user_quota'));
|
||||||
}
|
}
|
||||||
$query .= ' AND EXTRACT(month FROM file.modified) = EXTRACT(month FROM now()) and EXTRACT(year FROM file.modified) = EXTRACT(year FROM now())';
|
$query .= ' AND EXTRACT(month FROM file.modified) = EXTRACT(month FROM now()) and EXTRACT(year FROM file.modified) = EXTRACT(year FROM now())';
|
||||||
$this->query($query);
|
$this->query($query);
|
||||||
|
@ -206,8 +225,11 @@ class File extends Memcached_DataObject
|
||||||
$total = $this->total + $fileSize;
|
$total = $this->total + $fileSize;
|
||||||
if ($total > common_config('attachments', 'monthly_quota')) {
|
if ($total > common_config('attachments', 'monthly_quota')) {
|
||||||
// TRANS: Message given id an upload would exceed a user's monthly quota.
|
// TRANS: Message given id an upload would exceed a user's monthly quota.
|
||||||
// TRANS: $d (number) is the monthly user quota in bytes.
|
// TRANS: $d (number) is the monthly user quota in bytes and is used for plural.
|
||||||
return sprintf(_('A file this large would exceed your monthly quota of %d bytes.'), common_config('attachments', 'monthly_quota'));
|
return sprintf(_m('A file this large would exceed your monthly quota of %d byte.',
|
||||||
|
'A file this large would exceed your monthly quota of %d bytes.',
|
||||||
|
common_config('attachments', 'monthly_quota')),
|
||||||
|
common_config('attachments', 'monthly_quota'));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -217,12 +239,19 @@ class File extends Memcached_DataObject
|
||||||
static function filename($profile, $basename, $mimetype)
|
static function filename($profile, $basename, $mimetype)
|
||||||
{
|
{
|
||||||
require_once 'MIME/Type/Extension.php';
|
require_once 'MIME/Type/Extension.php';
|
||||||
|
|
||||||
|
// We have to temporarily disable auto handling of PEAR errors...
|
||||||
|
PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
|
||||||
|
|
||||||
$mte = new MIME_Type_Extension();
|
$mte = new MIME_Type_Extension();
|
||||||
try {
|
|
||||||
$ext = $mte->getExtension($mimetype);
|
$ext = $mte->getExtension($mimetype);
|
||||||
} catch ( Exception $e) {
|
if (PEAR::isError($ext)) {
|
||||||
$ext = strtolower(preg_replace('/\W/', '', $mimetype));
|
$ext = strtolower(preg_replace('/\W/', '', $mimetype));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore error handling.
|
||||||
|
PEAR::staticPopErrorHandling();
|
||||||
|
|
||||||
$nickname = $profile->nickname;
|
$nickname = $profile->nickname;
|
||||||
$datestamp = strftime('%Y%m%dT%H%M%S', time());
|
$datestamp = strftime('%Y%m%dT%H%M%S', time());
|
||||||
$random = strtolower(common_confirmation_code(32));
|
$random = strtolower(common_confirmation_code(32));
|
||||||
|
@ -292,9 +321,7 @@ class File extends Memcached_DataObject
|
||||||
}
|
}
|
||||||
|
|
||||||
$protocol = 'https';
|
$protocol = 'https';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$path = common_config('attachments', 'path');
|
$path = common_config('attachments', 'path');
|
||||||
$server = common_config('attachments', 'server');
|
$server = common_config('attachments', 'server');
|
||||||
|
|
||||||
|
@ -339,22 +366,28 @@ class File extends Memcached_DataObject
|
||||||
$mimetype = substr($mimetype,0,$semicolon);
|
$mimetype = substr($mimetype,0,$semicolon);
|
||||||
}
|
}
|
||||||
if(in_array($mimetype,$notEnclosureMimeTypes)){
|
if(in_array($mimetype,$notEnclosureMimeTypes)){
|
||||||
|
// Never treat generic HTML links as an enclosure type!
|
||||||
|
// But if we have oEmbed info, we'll consider it golden.
|
||||||
$oembed = File_oembed::staticGet('file_id',$this->id);
|
$oembed = File_oembed::staticGet('file_id',$this->id);
|
||||||
if($oembed){
|
if($oembed && in_array($oembed->type, array('photo', 'video'))){
|
||||||
$mimetype = strtolower($oembed->mimetype);
|
$mimetype = strtolower($oembed->mimetype);
|
||||||
$semicolon = strpos($mimetype,';');
|
$semicolon = strpos($mimetype,';');
|
||||||
if($semicolon){
|
if($semicolon){
|
||||||
$mimetype = substr($mimetype,0,$semicolon);
|
$mimetype = substr($mimetype,0,$semicolon);
|
||||||
}
|
}
|
||||||
if(in_array($mimetype,$notEnclosureMimeTypes)){
|
// @fixme uncertain if this is right.
|
||||||
return false;
|
// we want to expose things like YouTube videos as
|
||||||
}else{
|
// viewable attachments, but don't expose them as
|
||||||
|
// downloadable enclosures.....?
|
||||||
|
//if (in_array($mimetype, $notEnclosureMimeTypes)) {
|
||||||
|
// return false;
|
||||||
|
//} else {
|
||||||
if($oembed->mimetype) $enclosure->mimetype=$oembed->mimetype;
|
if($oembed->mimetype) $enclosure->mimetype=$oembed->mimetype;
|
||||||
if($oembed->url) $enclosure->url=$oembed->url;
|
if($oembed->url) $enclosure->url=$oembed->url;
|
||||||
if($oembed->title) $enclosure->title=$oembed->title;
|
if($oembed->title) $enclosure->title=$oembed->title;
|
||||||
if($oembed->modified) $enclosure->modified=$oembed->modified;
|
if($oembed->modified) $enclosure->modified=$oembed->modified;
|
||||||
unset($oembed->size);
|
unset($oembed->size);
|
||||||
}
|
//}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -369,4 +402,14 @@ class File extends Memcached_DataObject
|
||||||
$enclosure = $this->getEnclosure();
|
$enclosure = $this->getEnclosure();
|
||||||
return !empty($enclosure);
|
return !empty($enclosure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attachment's thumbnail record, if any.
|
||||||
|
*
|
||||||
|
* @return File_thumbnail
|
||||||
|
*/
|
||||||
|
function getThumbnail()
|
||||||
|
{
|
||||||
|
return File_thumbnail::staticGet('file_id', $this->id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,28 +58,18 @@ class File_oembed extends Memcached_DataObject
|
||||||
return array(false, false, false);
|
return array(false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getOembed($url, $maxwidth = 500, $maxheight = 400) {
|
function _getOembed($url) {
|
||||||
require_once INSTALLDIR.'/extlib/Services/oEmbed.php';
|
|
||||||
$parameters = array(
|
$parameters = array(
|
||||||
'maxwidth'=>$maxwidth,
|
'maxwidth' => common_config('attachments', 'thumb_width'),
|
||||||
'maxheight'=>$maxheight,
|
'maxheight' => common_config('attachments', 'thumb_height'),
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
$oEmbed = new Services_oEmbed($url);
|
return oEmbedHelper::getObject($url, $parameters);
|
||||||
$object = $oEmbed->getObject($parameters);
|
|
||||||
return $object;
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
try{
|
common_log(LOG_ERR, "Error during oembed lookup for $url - " . $e->getMessage());
|
||||||
$oEmbed = new Services_oEmbed($url, array(
|
|
||||||
Services_oEmbed::OPTION_API => common_config('oohembed', 'endpoint')
|
|
||||||
));
|
|
||||||
$object = $oEmbed->getObject($parameters);
|
|
||||||
return $object;
|
|
||||||
}catch(Exception $ex){
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save embedding info for a new file.
|
* Save embedding info for a new file.
|
||||||
|
@ -120,7 +110,7 @@ class File_oembed extends Memcached_DataObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$file_oembed->insert();
|
$file_oembed->insert();
|
||||||
if (!empty($data->thumbnail_url)) {
|
if (!empty($data->thumbnail_url) || ($data->type == 'photo')) {
|
||||||
$ft = File_thumbnail::staticGet('file_id', $file_id);
|
$ft = File_thumbnail::staticGet('file_id', $file_id);
|
||||||
if (!empty($ft)) {
|
if (!empty($ft)) {
|
||||||
common_log(LOG_WARNING, "Strangely, a File_thumbnail object exists for new file $file_id",
|
common_log(LOG_WARNING, "Strangely, a File_thumbnail object exists for new file $file_id",
|
||||||
|
|
|
@ -91,9 +91,16 @@ class File_redirection extends Memcached_DataObject
|
||||||
$request->setMethod(HTTP_Request2::METHOD_HEAD);
|
$request->setMethod(HTTP_Request2::METHOD_HEAD);
|
||||||
$response = $request->send();
|
$response = $request->send();
|
||||||
|
|
||||||
if (405 == $response->getStatus()) {
|
if (405 == $response->getStatus() || 204 == $response->getStatus()) {
|
||||||
|
// HTTP 405 Unsupported Method
|
||||||
// Server doesn't support HEAD method? Can this really happen?
|
// Server doesn't support HEAD method? Can this really happen?
|
||||||
// We'll try again as a GET and ignore the response data.
|
// We'll try again as a GET and ignore the response data.
|
||||||
|
//
|
||||||
|
// HTTP 204 No Content
|
||||||
|
// YFrog sends 204 responses back for our HEAD checks, which
|
||||||
|
// seems like it may be a logic error in their servers. If
|
||||||
|
// we get a 204 back, re-run it as a GET... if there's really
|
||||||
|
// no content it'll be cheap. :)
|
||||||
$request = self::_commonHttp($short_url, $redirs);
|
$request = self::_commonHttp($short_url, $redirs);
|
||||||
$response = $request->send();
|
$response = $request->send();
|
||||||
}
|
}
|
||||||
|
@ -132,6 +139,7 @@ class File_redirection extends Memcached_DataObject
|
||||||
* reached.
|
* reached.
|
||||||
*
|
*
|
||||||
* @param string $in_url
|
* @param string $in_url
|
||||||
|
* @param boolean $discover true to attempt dereferencing the redirect if we don't know it already
|
||||||
* @return mixed one of:
|
* @return mixed one of:
|
||||||
* string - target URL, if this is a direct link or a known redirect
|
* string - target URL, if this is a direct link or a known redirect
|
||||||
* array - redirect info if this is an *unknown* redirect:
|
* array - redirect info if this is an *unknown* redirect:
|
||||||
|
@ -143,7 +151,7 @@ class File_redirection extends Memcached_DataObject
|
||||||
* size (optional): byte size from Content-Length header
|
* size (optional): byte size from Content-Length header
|
||||||
* time (optional): timestamp from Last-Modified header
|
* time (optional): timestamp from Last-Modified header
|
||||||
*/
|
*/
|
||||||
public function where($in_url) {
|
public function where($in_url, $discover=true) {
|
||||||
// let's see if we know this...
|
// let's see if we know this...
|
||||||
$a = File::staticGet('url', $in_url);
|
$a = File::staticGet('url', $in_url);
|
||||||
|
|
||||||
|
@ -159,8 +167,13 @@ class File_redirection extends Memcached_DataObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($discover) {
|
||||||
$ret = File_redirection::lookupWhere($in_url);
|
$ret = File_redirection::lookupWhere($in_url);
|
||||||
return $ret;
|
return $ret;
|
||||||
|
} else {
|
||||||
|
// No manual dereferencing; leave the unknown URL as is.
|
||||||
|
return $in_url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -174,14 +187,14 @@ class File_redirection extends Memcached_DataObject
|
||||||
* may be saved.
|
* may be saved.
|
||||||
*
|
*
|
||||||
* @param string $long_url
|
* @param string $long_url
|
||||||
|
* @param User $user whose shortening options to use; defaults to the current web session user
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
function makeShort($long_url, $user=null)
|
||||||
function makeShort($long_url)
|
|
||||||
{
|
{
|
||||||
$canon = File_redirection::_canonUrl($long_url);
|
$canon = File_redirection::_canonUrl($long_url);
|
||||||
|
|
||||||
$short_url = File_redirection::_userMakeShort($canon);
|
$short_url = File_redirection::_userMakeShort($canon, $user);
|
||||||
|
|
||||||
// Did we get one? Is it shorter?
|
// Did we get one? Is it shorter?
|
||||||
|
|
||||||
|
@ -206,11 +219,11 @@ class File_redirection extends Memcached_DataObject
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function forceShort($long_url)
|
function forceShort($long_url, $user)
|
||||||
{
|
{
|
||||||
$canon = File_redirection::_canonUrl($long_url);
|
$canon = File_redirection::_canonUrl($long_url);
|
||||||
|
|
||||||
$short_url = File_redirection::_userMakeShort($canon, true);
|
$short_url = File_redirection::_userMakeShort($canon, $user, true);
|
||||||
|
|
||||||
// Did we get one? Is it shorter?
|
// Did we get one? Is it shorter?
|
||||||
if (!empty($short_url)) {
|
if (!empty($short_url)) {
|
||||||
|
@ -220,8 +233,8 @@ class File_redirection extends Memcached_DataObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _userMakeShort($long_url, $force = false) {
|
function _userMakeShort($long_url, User $user=null, $force = false) {
|
||||||
$short_url = common_shorten_url($long_url, $force);
|
$short_url = common_shorten_url($long_url, $user, $force);
|
||||||
if (!empty($short_url) && $short_url != $long_url) {
|
if (!empty($short_url) && $short_url != $long_url) {
|
||||||
$short_url = (string)$short_url;
|
$short_url = (string)$short_url;
|
||||||
// store it
|
// store it
|
||||||
|
@ -265,6 +278,18 @@ class File_redirection extends Memcached_DataObject
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic attempt to canonicalize a URL, cleaning up some standard variants
|
||||||
|
* such as funny syntax or a missing path. Used internally when cleaning
|
||||||
|
* up URLs for storage and following redirect chains.
|
||||||
|
*
|
||||||
|
* Note that despite being on File_redirect, this function DOES NOT perform
|
||||||
|
* any dereferencing of redirects.
|
||||||
|
*
|
||||||
|
* @param string $in_url input URL
|
||||||
|
* @param string $default_scheme if given a bare link; defaults to 'http://'
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
function _canonUrl($in_url, $default_scheme = 'http://') {
|
function _canonUrl($in_url, $default_scheme = 'http://') {
|
||||||
if (empty($in_url)) return false;
|
if (empty($in_url)) return false;
|
||||||
$out_url = $in_url;
|
$out_url = $in_url;
|
||||||
|
|
|
@ -48,12 +48,45 @@ class File_thumbnail extends Memcached_DataObject
|
||||||
return array(false, false, false);
|
return array(false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveNew($data, $file_id) {
|
/**
|
||||||
|
* Save oEmbed-provided thumbnail data
|
||||||
|
*
|
||||||
|
* @param object $data
|
||||||
|
* @param int $file_id
|
||||||
|
*/
|
||||||
|
public static function saveNew($data, $file_id) {
|
||||||
|
if (!empty($data->thumbnail_url)) {
|
||||||
|
// Non-photo types such as video will usually
|
||||||
|
// show us a thumbnail, though it's not required.
|
||||||
|
self::saveThumbnail($file_id,
|
||||||
|
$data->thumbnail_url,
|
||||||
|
$data->thumbnail_width,
|
||||||
|
$data->thumbnail_height);
|
||||||
|
} else if ($data->type == 'photo') {
|
||||||
|
// The inline photo URL given should also fit within
|
||||||
|
// our requested thumbnail size, per oEmbed spec.
|
||||||
|
self::saveThumbnail($file_id,
|
||||||
|
$data->url,
|
||||||
|
$data->width,
|
||||||
|
$data->height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save a thumbnail record for the referenced file record.
|
||||||
|
*
|
||||||
|
* @param int $file_id
|
||||||
|
* @param string $url
|
||||||
|
* @param int $width
|
||||||
|
* @param int $height
|
||||||
|
*/
|
||||||
|
static function saveThumbnail($file_id, $url, $width, $height)
|
||||||
|
{
|
||||||
$tn = new File_thumbnail;
|
$tn = new File_thumbnail;
|
||||||
$tn->file_id = $file_id;
|
$tn->file_id = $file_id;
|
||||||
$tn->url = $data->thumbnail_url;
|
$tn->url = $url;
|
||||||
$tn->width = intval($data->thumbnail_width);
|
$tn->width = intval($width);
|
||||||
$tn->height = intval($data->thumbnail_height);
|
$tn->height = intval($height);
|
||||||
$tn->insert();
|
$tn->insert();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,12 +45,19 @@ class Message extends Memcached_DataObject
|
||||||
throw new ClientException(_('You are banned from sending direct messages.'));
|
throw new ClientException(_('You are banned from sending direct messages.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$user = User::staticGet('id', $sender->id);
|
||||||
|
|
||||||
$msg = new Message();
|
$msg = new Message();
|
||||||
|
|
||||||
$msg->from_profile = $from;
|
$msg->from_profile = $from;
|
||||||
$msg->to_profile = $to;
|
$msg->to_profile = $to;
|
||||||
|
if ($user) {
|
||||||
|
// Use the sender's URL shortening options.
|
||||||
|
$msg->content = $user->shortenLinks($content);
|
||||||
|
} else {
|
||||||
$msg->content = common_shorten_links($content);
|
$msg->content = common_shorten_links($content);
|
||||||
$msg->rendered = common_render_text($content);
|
}
|
||||||
|
$msg->rendered = common_render_text($msg->content);
|
||||||
$msg->created = common_sql_now();
|
$msg->created = common_sql_now();
|
||||||
$msg->source = $source;
|
$msg->source = $source;
|
||||||
|
|
||||||
|
|
|
@ -256,9 +256,14 @@ class Notice extends Memcached_DataObject
|
||||||
$is_local = Notice::LOCAL_PUBLIC;
|
$is_local = Notice::LOCAL_PUBLIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
$profile = Profile::staticGet($profile_id);
|
$profile = Profile::staticGet('id', $profile_id);
|
||||||
|
$user = User::staticGet('id', $profile_id);
|
||||||
|
if ($user) {
|
||||||
|
// Use the local user's shortening preferences, if applicable.
|
||||||
|
$final = $user->shortenLinks($content);
|
||||||
|
} else {
|
||||||
$final = common_shorten_links($content);
|
$final = common_shorten_links($content);
|
||||||
|
}
|
||||||
|
|
||||||
if (Notice::contentTooLong($final)) {
|
if (Notice::contentTooLong($final)) {
|
||||||
// TRANS: Client exception thrown if a notice contains too many characters.
|
// TRANS: Client exception thrown if a notice contains too many characters.
|
||||||
|
@ -476,8 +481,10 @@ class Notice extends Memcached_DataObject
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function saveUrls() {
|
function saveUrls() {
|
||||||
|
if (common_config('attachments', 'process_links')) {
|
||||||
common_replace_urls_callback($this->content, array($this, 'saveUrl'), $this->id);
|
common_replace_urls_callback($this->content, array($this, 'saveUrl'), $this->id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the given URLs as related links/attachments to the db
|
* Save the given URLs as related links/attachments to the db
|
||||||
|
@ -489,17 +496,18 @@ class Notice extends Memcached_DataObject
|
||||||
*/
|
*/
|
||||||
function saveKnownUrls($urls)
|
function saveKnownUrls($urls)
|
||||||
{
|
{
|
||||||
|
if (common_config('attachments', 'process_links')) {
|
||||||
// @fixme validation?
|
// @fixme validation?
|
||||||
foreach (array_unique($urls) as $url) {
|
foreach (array_unique($urls) as $url) {
|
||||||
File::processNew($url, $this->id);
|
File::processNew($url, $this->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private callback
|
* @private callback
|
||||||
*/
|
*/
|
||||||
function saveUrl($data) {
|
function saveUrl($url, $notice_id) {
|
||||||
list($url, $notice_id) = $data;
|
|
||||||
File::processNew($url, $notice_id);
|
File::processNew($url, $notice_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,10 +532,8 @@ class Notice extends Memcached_DataObject
|
||||||
$notice = new Notice();
|
$notice = new Notice();
|
||||||
$notice->profile_id = $profile_id;
|
$notice->profile_id = $profile_id;
|
||||||
$notice->content = $content;
|
$notice->content = $content;
|
||||||
if (common_config('db','type') == 'pgsql')
|
$threshold = common_sql_date(time() - common_config('site', 'dupelimit'));
|
||||||
$notice->whereAdd('extract(epoch from now() - created) < ' . common_config('site', 'dupelimit'));
|
$notice->whereAdd(sprintf("created > '%s'", $notice->escape($threshold)));
|
||||||
else
|
|
||||||
$notice->whereAdd('now() - created < ' . common_config('site', 'dupelimit'));
|
|
||||||
|
|
||||||
$cnt = $notice->count();
|
$cnt = $notice->count();
|
||||||
return ($cnt == 0);
|
return ($cnt == 0);
|
||||||
|
@ -904,7 +910,7 @@ class Notice extends Memcached_DataObject
|
||||||
{
|
{
|
||||||
if (!is_array($group_ids)) {
|
if (!is_array($group_ids)) {
|
||||||
// TRANS: Server exception thrown when no array is provided to the method saveKnownGroups().
|
// TRANS: Server exception thrown when no array is provided to the method saveKnownGroups().
|
||||||
throw new ServerException(_("Bad type provided to saveKnownGroups"));
|
throw new ServerException(_('Bad type provided to saveKnownGroups.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$groups = array();
|
$groups = array();
|
||||||
|
@ -1220,16 +1226,34 @@ class Notice extends Memcached_DataObject
|
||||||
return $groups;
|
return $groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
function asActivity()
|
/**
|
||||||
|
* Convert a notice into an activity for export.
|
||||||
|
*
|
||||||
|
* @param User $cur Current user
|
||||||
|
*
|
||||||
|
* @return Activity activity object representing this Notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function asActivity($cur = null, $source = false)
|
||||||
{
|
{
|
||||||
$profile = $this->getProfile();
|
$act = self::cacheGet(Cache::codeKey('notice:as-activity:'.$this->id));
|
||||||
|
|
||||||
|
if (!empty($act)) {
|
||||||
|
return $act;
|
||||||
|
}
|
||||||
|
|
||||||
$act = new Activity();
|
$act = new Activity();
|
||||||
|
|
||||||
|
if (Event::handle('StartNoticeAsActivity', array($this, &$act))) {
|
||||||
|
|
||||||
|
$profile = $this->getProfile();
|
||||||
|
|
||||||
$act->actor = ActivityObject::fromProfile($profile);
|
$act->actor = ActivityObject::fromProfile($profile);
|
||||||
$act->verb = ActivityVerb::POST;
|
$act->verb = ActivityVerb::POST;
|
||||||
$act->objects[] = ActivityObject::fromNotice($this);
|
$act->objects[] = ActivityObject::fromNotice($this);
|
||||||
|
|
||||||
|
// XXX: should this be handled by default processing for object entry?
|
||||||
|
|
||||||
$act->time = strtotime($this->created);
|
$act->time = strtotime($this->created);
|
||||||
$act->link = $this->bestUrl();
|
$act->link = $this->bestUrl();
|
||||||
|
|
||||||
|
@ -1237,6 +1261,29 @@ class Notice extends Memcached_DataObject
|
||||||
$act->id = $this->uri;
|
$act->id = $this->uri;
|
||||||
$act->title = common_xml_safe_str($this->content);
|
$act->title = common_xml_safe_str($this->content);
|
||||||
|
|
||||||
|
// Categories
|
||||||
|
|
||||||
|
$tags = $this->getTags();
|
||||||
|
|
||||||
|
foreach ($tags as $tag) {
|
||||||
|
$cat = new AtomCategory();
|
||||||
|
$cat->term = $tag;
|
||||||
|
|
||||||
|
$act->categories[] = $cat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enclosures
|
||||||
|
// XXX: use Atom Media and/or File activity objects instead
|
||||||
|
|
||||||
|
$attachments = $this->attachments();
|
||||||
|
|
||||||
|
foreach ($attachments as $attachment) {
|
||||||
|
$enclosure = $attachment->getEnclosure();
|
||||||
|
if ($enclosure) {
|
||||||
|
$act->enclosures[] = $enclosure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$ctx = new ActivityContext();
|
$ctx = new ActivityContext();
|
||||||
|
|
||||||
if (!empty($this->reply_to)) {
|
if (!empty($this->reply_to)) {
|
||||||
|
@ -1273,185 +1320,18 @@ class Notice extends Memcached_DataObject
|
||||||
$ctx->attention[] = $group->uri;
|
$ctx->attention[] = $group->uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX: deprecated; use ActivityVerb::SHARE instead
|
||||||
|
|
||||||
|
$repeat = null;
|
||||||
|
|
||||||
|
if (!empty($this->repeat_of)) {
|
||||||
|
$repeat = Notice::staticGet('id', $this->repeat_of);
|
||||||
|
$ctx->forwardID = $repeat->uri;
|
||||||
|
$ctx->forwardUrl = $repeat->bestUrl();
|
||||||
|
}
|
||||||
|
|
||||||
$act->context = $ctx;
|
$act->context = $ctx;
|
||||||
|
|
||||||
return $act;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This has gotten way too long. Needs to be sliced up into functional bits
|
|
||||||
// or ideally exported to a utility class.
|
|
||||||
|
|
||||||
function asAtomEntry($namespace=false, $source=false, $author=true, $cur=null)
|
|
||||||
{
|
|
||||||
$profile = $this->getProfile();
|
|
||||||
|
|
||||||
$xs = new XMLStringer(true);
|
|
||||||
|
|
||||||
if ($namespace) {
|
|
||||||
$attrs = array('xmlns' => 'http://www.w3.org/2005/Atom',
|
|
||||||
'xmlns:thr' => 'http://purl.org/syndication/thread/1.0',
|
|
||||||
'xmlns:georss' => 'http://www.georss.org/georss',
|
|
||||||
'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/',
|
|
||||||
'xmlns:media' => 'http://purl.org/syndication/atommedia',
|
|
||||||
'xmlns:poco' => 'http://portablecontacts.net/spec/1.0',
|
|
||||||
'xmlns:ostatus' => 'http://ostatus.org/schema/1.0',
|
|
||||||
'xmlns:statusnet' => 'http://status.net/schema/api/1/');
|
|
||||||
} else {
|
|
||||||
$attrs = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityStart', array(&$this, &$xs, &$attrs))) {
|
|
||||||
$xs->elementStart('entry', $attrs);
|
|
||||||
Event::handle('EndActivityStart', array(&$this, &$xs, &$attrs));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Event::handle('StartActivitySource', array(&$this, &$xs))) {
|
|
||||||
if ($source) {
|
|
||||||
$atom_feed = $profile->getAtomFeed();
|
|
||||||
|
|
||||||
if (!empty($atom_feed)) {
|
|
||||||
$xs->elementStart('source');
|
|
||||||
|
|
||||||
// XXX: we should store the actual feed ID
|
|
||||||
|
|
||||||
$xs->element('id', null, $atom_feed);
|
|
||||||
|
|
||||||
// XXX: we should store the actual feed title
|
|
||||||
|
|
||||||
$xs->element('title', null, $profile->getBestName());
|
|
||||||
|
|
||||||
$xs->element('link', array('rel' => 'alternate',
|
|
||||||
'type' => 'text/html',
|
|
||||||
'href' => $profile->profileurl));
|
|
||||||
|
|
||||||
$xs->element('link', array('rel' => 'self',
|
|
||||||
'type' => 'application/atom+xml',
|
|
||||||
'href' => $atom_feed));
|
|
||||||
|
|
||||||
$xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE));
|
|
||||||
|
|
||||||
$notice = $profile->getCurrentNotice();
|
|
||||||
|
|
||||||
if (!empty($notice)) {
|
|
||||||
$xs->element('updated', null, self::utcDate($notice->created));
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = User::staticGet('id', $profile->id);
|
|
||||||
|
|
||||||
if (!empty($user)) {
|
|
||||||
$xs->element('link', array('rel' => 'license',
|
|
||||||
'href' => common_config('license', 'url')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$xs->elementEnd('source');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::handle('EndActivitySource', array(&$this, &$xs));
|
|
||||||
}
|
|
||||||
|
|
||||||
$title = common_xml_safe_str($this->content);
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityTitle', array(&$this, &$xs, &$title))) {
|
|
||||||
$xs->element('title', null, $title);
|
|
||||||
Event::handle('EndActivityTitle', array($this, &$xs, $title));
|
|
||||||
}
|
|
||||||
|
|
||||||
$atomAuthor = '';
|
|
||||||
|
|
||||||
if ($author) {
|
|
||||||
$atomAuthor = $profile->asAtomAuthor($cur);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityAuthor', array(&$this, &$xs, &$atomAuthor))) {
|
|
||||||
if (!empty($atomAuthor)) {
|
|
||||||
$xs->raw($atomAuthor);
|
|
||||||
Event::handle('EndActivityAuthor', array(&$this, &$xs, &$atomAuthor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$actor = '';
|
|
||||||
|
|
||||||
if ($author) {
|
|
||||||
$actor = $profile->asActivityActor();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityActor', array(&$this, &$xs, &$actor))) {
|
|
||||||
if (!empty($actor)) {
|
|
||||||
$xs->raw($actor);
|
|
||||||
Event::handle('EndActivityActor', array(&$this, &$xs, &$actor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = $this->bestUrl();
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityLink', array(&$this, &$xs, &$url))) {
|
|
||||||
$xs->element('link', array('rel' => 'alternate',
|
|
||||||
'type' => 'text/html',
|
|
||||||
'href' => $url));
|
|
||||||
Event::handle('EndActivityLink', array(&$this, &$xs, $url));
|
|
||||||
}
|
|
||||||
|
|
||||||
$id = $this->uri;
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityId', array(&$this, &$xs, &$id))) {
|
|
||||||
$xs->element('id', null, $id);
|
|
||||||
Event::handle('EndActivityId', array(&$this, &$xs, $id));
|
|
||||||
}
|
|
||||||
|
|
||||||
$published = self::utcDate($this->created);
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityPublished', array(&$this, &$xs, &$published))) {
|
|
||||||
$xs->element('published', null, $published);
|
|
||||||
Event::handle('EndActivityPublished', array(&$this, &$xs, $published));
|
|
||||||
}
|
|
||||||
|
|
||||||
$updated = $published; // XXX: notices are usually immutable
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityUpdated', array(&$this, &$xs, &$updated))) {
|
|
||||||
$xs->element('updated', null, $updated);
|
|
||||||
Event::handle('EndActivityUpdated', array(&$this, &$xs, $updated));
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = common_xml_safe_str($this->rendered);
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityContent', array(&$this, &$xs, &$content))) {
|
|
||||||
$xs->element('content', array('type' => 'html'), $content);
|
|
||||||
Event::handle('EndActivityContent', array(&$this, &$xs, $content));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Most of our notices represent POSTing a NOTE. This is the default verb
|
|
||||||
// for activity streams, so we normally just leave it out.
|
|
||||||
|
|
||||||
$verb = ActivityVerb::POST;
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityVerb', array(&$this, &$xs, &$verb))) {
|
|
||||||
$xs->element('activity:verb', null, $verb);
|
|
||||||
Event::handle('EndActivityVerb', array(&$this, &$xs, $verb));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use the default behavior for activity streams: if there's no activity:object,
|
|
||||||
// then treat the entry itself as the object. Here, you can set the type of that object,
|
|
||||||
// which is normally a NOTE.
|
|
||||||
|
|
||||||
$type = ActivityObject::NOTE;
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityDefaultObjectType', array(&$this, &$xs, &$type))) {
|
|
||||||
$xs->element('activity:object-type', null, $type);
|
|
||||||
Event::handle('EndActivityDefaultObjectType', array(&$this, &$xs, $type));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since we usually use the entry itself as an object, we don't have an explicit
|
|
||||||
// object. Some extensions may want to add them (for photo, event, music, etc.).
|
|
||||||
|
|
||||||
$objects = array();
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityObjects', array(&$this, &$xs, &$objects))) {
|
|
||||||
foreach ($objects as $object) {
|
|
||||||
$xs->raw($object->asString());
|
|
||||||
}
|
|
||||||
Event::handle('EndActivityObjects', array(&$this, &$xs, $objects));
|
|
||||||
}
|
|
||||||
|
|
||||||
$noticeInfoAttr = array('local_id' => $this->id); // local notice ID (useful to clients for ordering)
|
$noticeInfoAttr = array('local_id' => $this->id); // local notice ID (useful to clients for ordering)
|
||||||
|
|
||||||
$ns = $this->getSource();
|
$ns = $this->getSource();
|
||||||
|
@ -1472,154 +1352,74 @@ class Notice extends Memcached_DataObject
|
||||||
|
|
||||||
if (!empty($cur)) {
|
if (!empty($cur)) {
|
||||||
$noticeInfoAttr['favorite'] = ($cur->hasFave($this)) ? "true" : "false";
|
$noticeInfoAttr['favorite'] = ($cur->hasFave($this)) ? "true" : "false";
|
||||||
$profile = $cur->getProfile();
|
$cp = $cur->getProfile();
|
||||||
$noticeInfoAttr['repeated'] = ($profile->hasRepeated($this->id)) ? "true" : "false";
|
$noticeInfoAttr['repeated'] = ($cp->hasRepeated($this->id)) ? "true" : "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($this->repeat_of)) {
|
if (!empty($this->repeat_of)) {
|
||||||
$noticeInfoAttr['repeat_of'] = $this->repeat_of;
|
$noticeInfoAttr['repeat_of'] = $this->repeat_of;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Event::handle('StartActivityNoticeInfo', array(&$this, &$xs, &$noticeInfoAttr))) {
|
$act->extra[] = array('statusnet:notice_info', $noticeInfoAttr, null);
|
||||||
$xs->element('statusnet:notice_info', $noticeInfoAttr, null);
|
|
||||||
Event::handle('EndActivityNoticeInfo', array(&$this, &$xs, $noticeInfoAttr));
|
if ($source) {
|
||||||
|
|
||||||
|
$atom_feed = $profile->getAtomFeed();
|
||||||
|
|
||||||
|
if (!empty($atom_feed)) {
|
||||||
|
|
||||||
|
$act->source = new ActivitySource();
|
||||||
|
|
||||||
|
// XXX: we should store the actual feed ID
|
||||||
|
|
||||||
|
$act->source->id = $atom_feed;
|
||||||
|
|
||||||
|
// XXX: we should store the actual feed title
|
||||||
|
|
||||||
|
$act->source->title = $profile->getBestName();
|
||||||
|
|
||||||
|
$act->source->links['alternate'] = $profile->profileurl;
|
||||||
|
$act->source->links['self'] = $atom_feed;
|
||||||
|
|
||||||
|
$act->source->icon = $profile->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||||
|
|
||||||
|
$notice = $profile->getCurrentNotice();
|
||||||
|
|
||||||
|
if (!empty($notice)) {
|
||||||
|
$act->source->updated = self::utcDate($notice->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
$replyNotice = null;
|
$user = User::staticGet('id', $profile->id);
|
||||||
|
|
||||||
if ($this->reply_to) {
|
if (!empty($user)) {
|
||||||
$replyNotice = Notice::staticGet('id', $this->reply_to);
|
$act->source->links['license'] = common_config('license', 'url');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Event::handle('StartActivityInReplyTo', array(&$this, &$xs, &$replyNotice))) {
|
|
||||||
if (!empty($replyNotice)) {
|
|
||||||
$xs->element('link', array('rel' => 'related',
|
|
||||||
'href' => $replyNotice->bestUrl()));
|
|
||||||
$xs->element('thr:in-reply-to',
|
|
||||||
array('ref' => $replyNotice->uri,
|
|
||||||
'href' => $replyNotice->bestUrl()));
|
|
||||||
Event::handle('EndActivityInReplyTo', array(&$this, &$xs, $replyNotice));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$conv = null;
|
if ($this->isLocal()) {
|
||||||
|
$act->selfLink = common_local_url('ApiStatusesShow', array('id' => $this->id,
|
||||||
if (!empty($this->conversation)) {
|
'format' => 'atom'));
|
||||||
$conv = Conversation::staticGet('id', $this->conversation);
|
$act->editLink = $act->selfLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Event::handle('StartActivityConversation', array(&$this, &$xs, &$conv))) {
|
Event::handle('EndNoticeAsActivity', array($this, &$act));
|
||||||
if (!empty($conv)) {
|
|
||||||
$xs->element('link', array('rel' => 'ostatus:conversation',
|
|
||||||
'href' => $conv->uri));
|
|
||||||
}
|
|
||||||
Event::handle('EndActivityConversation', array(&$this, &$xs, $conv));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$replyProfiles = array();
|
self::cacheSet(Cache::codeKey('notice:as-activity:'.$this->id), $act);
|
||||||
|
|
||||||
$reply_ids = $this->getReplies();
|
return $act;
|
||||||
|
|
||||||
foreach ($reply_ids as $id) {
|
|
||||||
$profile = Profile::staticGet('id', $id);
|
|
||||||
if (!empty($profile)) {
|
|
||||||
$replyProfiles[] = $profile;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Event::handle('StartActivityAttentionProfiles', array(&$this, &$xs, &$replyProfiles))) {
|
// This has gotten way too long. Needs to be sliced up into functional bits
|
||||||
foreach ($replyProfiles as $profile) {
|
// or ideally exported to a utility class.
|
||||||
$xs->element('link', array('rel' => 'ostatus:attention',
|
|
||||||
'href' => $profile->getUri()));
|
function asAtomEntry($namespace=false, $source=false, $author=true, $cur=null)
|
||||||
$xs->element('link', array('rel' => 'mentioned',
|
{
|
||||||
'href' => $profile->getUri()));
|
$act = $this->asActivity($cur, $source);
|
||||||
}
|
return $act->asString($namespace, $author);
|
||||||
Event::handle('EndActivityAttentionProfiles', array(&$this, &$xs, $replyProfiles));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$groups = $this->getGroups();
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityAttentionGroups', array(&$this, &$xs, &$groups))) {
|
|
||||||
foreach ($groups as $group) {
|
|
||||||
$xs->element('link', array('rel' => 'ostatus:attention',
|
|
||||||
'href' => $group->permalink()));
|
|
||||||
$xs->element('link', array('rel' => 'mentioned',
|
|
||||||
'href' => $group->permalink()));
|
|
||||||
}
|
|
||||||
Event::handle('EndActivityAttentionGroups', array(&$this, &$xs, $groups));
|
|
||||||
}
|
|
||||||
|
|
||||||
$repeat = null;
|
|
||||||
|
|
||||||
if (!empty($this->repeat_of)) {
|
|
||||||
$repeat = Notice::staticGet('id', $this->repeat_of);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityForward', array(&$this, &$xs, &$repeat))) {
|
|
||||||
if (!empty($repeat)) {
|
|
||||||
$xs->element('ostatus:forward',
|
|
||||||
array('ref' => $repeat->uri,
|
|
||||||
'href' => $repeat->bestUrl()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::handle('EndActivityForward', array(&$this, &$xs, $repeat));
|
|
||||||
}
|
|
||||||
|
|
||||||
$tags = $this->getTags();
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityCategories', array(&$this, &$xs, &$tags))) {
|
|
||||||
foreach ($tags as $tag) {
|
|
||||||
$xs->element('category', array('term' => $tag));
|
|
||||||
}
|
|
||||||
Event::handle('EndActivityCategories', array(&$this, &$xs, $tags));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enclosures
|
|
||||||
|
|
||||||
$enclosures = array();
|
|
||||||
|
|
||||||
$attachments = $this->attachments();
|
|
||||||
|
|
||||||
foreach ($attachments as $attachment) {
|
|
||||||
$enclosure = $attachment->getEnclosure();
|
|
||||||
if ($enclosure) {
|
|
||||||
$enclosures[] = $enclosure;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityEnclosures', array(&$this, &$xs, &$enclosures))) {
|
|
||||||
foreach ($enclosures as $enclosure) {
|
|
||||||
$attributes = array('rel' => 'enclosure',
|
|
||||||
'href' => $enclosure->url,
|
|
||||||
'type' => $enclosure->mimetype,
|
|
||||||
'length' => $enclosure->size);
|
|
||||||
|
|
||||||
if ($enclosure->title) {
|
|
||||||
$attributes['title'] = $enclosure->title;
|
|
||||||
}
|
|
||||||
|
|
||||||
$xs->element('link', $attributes, null);
|
|
||||||
}
|
|
||||||
Event::handle('EndActivityEnclosures', array(&$this, &$xs, $enclosures));
|
|
||||||
}
|
|
||||||
|
|
||||||
$lat = $this->lat;
|
|
||||||
$lon = $this->lon;
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityGeo', array(&$this, &$xs, &$lat, &$lon))) {
|
|
||||||
if (!empty($lat) && !empty($lon)) {
|
|
||||||
$xs->element('georss:point', null, $lat . ' ' . $lon);
|
|
||||||
}
|
|
||||||
Event::handle('EndActivityGeo', array(&$this, &$xs, $lat, $lon));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Event::handle('StartActivityEnd', array(&$this, &$xs))) {
|
|
||||||
$xs->elementEnd('entry');
|
|
||||||
Event::handle('EndActivityEnd', array(&$this, &$xs));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $xs->getString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an XML string fragment with a reference to a notice as an
|
* Returns an XML string fragment with a reference to a notice as an
|
||||||
|
@ -1630,6 +1430,7 @@ class Notice extends Memcached_DataObject
|
||||||
* @param string $element one of 'subject', 'object', 'target'
|
* @param string $element one of 'subject', 'object', 'target'
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function asActivityNoun($element)
|
function asActivityNoun($element)
|
||||||
{
|
{
|
||||||
$noun = ActivityObject::fromNotice($this);
|
$noun = ActivityObject::fromNotice($this);
|
||||||
|
|
|
@ -125,6 +125,14 @@ class Profile extends Memcached_DataObject
|
||||||
return $avatar;
|
return $avatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete attached avatars for this user from the database and filesystem.
|
||||||
|
* This should be used instead of a batch delete() to ensure that files
|
||||||
|
* get removed correctly.
|
||||||
|
*
|
||||||
|
* @param boolean $original true to delete only the original-size file
|
||||||
|
* @return <type>
|
||||||
|
*/
|
||||||
function delete_avatars($original=true)
|
function delete_avatars($original=true)
|
||||||
{
|
{
|
||||||
$avatar = new Avatar();
|
$avatar = new Avatar();
|
||||||
|
@ -494,6 +502,29 @@ class Profile extends Memcached_DataObject
|
||||||
return $cnt;
|
return $cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this profile subscribed to another profile?
|
||||||
|
*
|
||||||
|
* @param Profile $other
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
function isSubscribed($other)
|
||||||
|
{
|
||||||
|
return Subscription::exists($this, $other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are these two profiles subscribed to each other?
|
||||||
|
*
|
||||||
|
* @param Profile $other
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
function mutuallySubscribed($other)
|
||||||
|
{
|
||||||
|
return $this->isSubscribed($other) &&
|
||||||
|
$other->isSubscribed($this);
|
||||||
|
}
|
||||||
|
|
||||||
function hasFave($notice)
|
function hasFave($notice)
|
||||||
{
|
{
|
||||||
$cache = Cache::instance();
|
$cache = Cache::instance();
|
||||||
|
@ -641,9 +672,11 @@ class Profile extends Memcached_DataObject
|
||||||
$this->_deleteMessages();
|
$this->_deleteMessages();
|
||||||
$this->_deleteTags();
|
$this->_deleteTags();
|
||||||
$this->_deleteBlocks();
|
$this->_deleteBlocks();
|
||||||
|
$this->delete_avatars();
|
||||||
|
|
||||||
$related = array('Avatar',
|
// Warning: delete() will run on the batch objects,
|
||||||
'Reply',
|
// not on individual objects.
|
||||||
|
$related = array('Reply',
|
||||||
'Group_member',
|
'Group_member',
|
||||||
);
|
);
|
||||||
Event::handle('ProfileDeleteRelated', array($this, &$related));
|
Event::handle('ProfileDeleteRelated', array($this, &$related));
|
||||||
|
|
|
@ -32,7 +32,7 @@ class Queue_item extends Memcached_DataObject
|
||||||
if ($transports) {
|
if ($transports) {
|
||||||
if (is_array($transports)) {
|
if (is_array($transports)) {
|
||||||
// @fixme use safer escaping
|
// @fixme use safer escaping
|
||||||
$list = implode("','", array_map('addslashes', $transports));
|
$list = implode("','", array_map(array($qi, 'escape'), $transports));
|
||||||
$qi->whereAdd("transport in ('$list')");
|
$qi->whereAdd("transport in ('$list')");
|
||||||
} else {
|
} else {
|
||||||
$qi->transport = $transports;
|
$qi->transport = $transports;
|
||||||
|
|
|
@ -79,7 +79,8 @@ class User extends Memcached_DataObject
|
||||||
|
|
||||||
function isSubscribed($other)
|
function isSubscribed($other)
|
||||||
{
|
{
|
||||||
return Subscription::exists($this->getProfile(), $other);
|
$profile = $this->getProfile();
|
||||||
|
return $profile->isSubscribed($other);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'update' won't write key columns, so we have to do it ourselves.
|
// 'update' won't write key columns, so we have to do it ourselves.
|
||||||
|
@ -110,6 +111,16 @@ class User extends Memcached_DataObject
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given nickname is potentially usable, or if it's
|
||||||
|
* excluded by any blacklists on this system.
|
||||||
|
*
|
||||||
|
* WARNING: INPUT IS NOT VALIDATED OR NORMALIZED. NON-NORMALIZED INPUT
|
||||||
|
* OR INVALID INPUT MAY LEAD TO FALSE RESULTS.
|
||||||
|
*
|
||||||
|
* @param string $nickname
|
||||||
|
* @return boolean true if clear, false if blacklisted
|
||||||
|
*/
|
||||||
static function allowed_nickname($nickname)
|
static function allowed_nickname($nickname)
|
||||||
{
|
{
|
||||||
// XXX: should already be validated for size, content, etc.
|
// XXX: should already be validated for size, content, etc.
|
||||||
|
@ -413,8 +424,8 @@ class User extends Memcached_DataObject
|
||||||
|
|
||||||
function mutuallySubscribed($other)
|
function mutuallySubscribed($other)
|
||||||
{
|
{
|
||||||
return $this->isSubscribed($other) &&
|
$profile = $this->getProfile();
|
||||||
$other->isSubscribed($this);
|
return $profile->mutuallySubscribed($other);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mutuallySubscribedUsers()
|
function mutuallySubscribedUsers()
|
||||||
|
@ -911,4 +922,55 @@ class User extends Memcached_DataObject
|
||||||
throw new ServerException(_('Single-user mode code called when not enabled.'));
|
throw new ServerException(_('Single-user mode code called when not enabled.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is kind of a hack for using external setup code that's trying to
|
||||||
|
* build single-user sites.
|
||||||
|
*
|
||||||
|
* Will still return a username if the config singleuser/nickname is set
|
||||||
|
* even if the account doesn't exist, which normally indicates that the
|
||||||
|
* site is horribly misconfigured.
|
||||||
|
*
|
||||||
|
* At the moment, we need to let it through so that router setup can
|
||||||
|
* complete, otherwise we won't be able to create the account.
|
||||||
|
*
|
||||||
|
* This will be easier when we can more easily create the account and
|
||||||
|
* *then* switch the site to 1user mode without jumping through hoops.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws ServerException if no valid single user account is present
|
||||||
|
* @throws ServerException if called when not in single-user mode
|
||||||
|
*/
|
||||||
|
static function singleUserNickname()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$user = User::singleUser();
|
||||||
|
return $user->nickname;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if (common_config('singleuser', 'enabled') && common_config('singleuser', 'nickname')) {
|
||||||
|
common_log(LOG_WARN, "Warning: code attempting to pull single-user nickname when the account does not exist. If this is not setup time, this is probably a bug.");
|
||||||
|
return common_config('singleuser', 'nickname');
|
||||||
|
}
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find and shorten links in the given text using this user's URL shortening
|
||||||
|
* settings.
|
||||||
|
*
|
||||||
|
* By default, links will be left untouched if the text is shorter than the
|
||||||
|
* configured maximum notice length. Pass true for the $always parameter
|
||||||
|
* to force all links to be shortened regardless.
|
||||||
|
*
|
||||||
|
* Side effects: may save file and file_redirection records for referenced URLs.
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @param boolean $always
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function shortenLinks($text, $always=false)
|
||||||
|
{
|
||||||
|
return common_shorten_links($text, $always, $this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,3 +107,15 @@ create table group_alias (
|
||||||
index group_alias_group_id_idx (group_id)
|
index group_alias_group_id_idx (group_id)
|
||||||
|
|
||||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
|
create table session (
|
||||||
|
|
||||||
|
id varchar(32) primary key comment 'session ID',
|
||||||
|
session_data text comment 'session data',
|
||||||
|
created datetime not null comment 'date this record was created',
|
||||||
|
modified timestamp comment 'date this record was modified',
|
||||||
|
|
||||||
|
index session_modified_idx (modified)
|
||||||
|
|
||||||
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,106 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Listener for HTTP_Request and HTTP_Response objects
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE:
|
|
||||||
*
|
|
||||||
* Copyright (c) 2002-2007, Richard Heyes
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* o Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* o Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* o The names of the authors may not be used to endorse or promote
|
|
||||||
* products derived from this software without specific prior written
|
|
||||||
* permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @category HTTP
|
|
||||||
* @package HTTP_Request
|
|
||||||
* @author Alexey Borzov <avb@php.net>
|
|
||||||
* @copyright 2002-2007 Richard Heyes
|
|
||||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
|
||||||
* @version CVS: $Id: Listener.php,v 1.3 2007/05/18 10:33:31 avb Exp $
|
|
||||||
* @link http://pear.php.net/package/HTTP_Request/
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener for HTTP_Request and HTTP_Response objects
|
|
||||||
*
|
|
||||||
* This class implements the Observer part of a Subject-Observer
|
|
||||||
* design pattern.
|
|
||||||
*
|
|
||||||
* @category HTTP
|
|
||||||
* @package HTTP_Request
|
|
||||||
* @author Alexey Borzov <avb@php.net>
|
|
||||||
* @version Release: 1.4.4
|
|
||||||
*/
|
|
||||||
class HTTP_Request_Listener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A listener's identifier
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
var $_id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor, sets the object's identifier
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
function HTTP_Request_Listener()
|
|
||||||
{
|
|
||||||
$this->_id = md5(uniqid('http_request_', 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the listener's identifier
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function getId()
|
|
||||||
{
|
|
||||||
return $this->_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called when Listener is notified of an event
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param object an object the listener is attached to
|
|
||||||
* @param string Event name
|
|
||||||
* @param mixed Additional data
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
function update(&$subject, $event, $data = null)
|
|
||||||
{
|
|
||||||
echo "Notified of event: '$event'\n";
|
|
||||||
if (null !== $data) {
|
|
||||||
echo "Additional data: ";
|
|
||||||
var_dump($data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
|
@ -37,7 +37,7 @@
|
||||||
* @package Net_URL_Mapper
|
* @package Net_URL_Mapper
|
||||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||||
* @version CVS: $Id: Mapper.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
* @version CVS: $Id: Mapper.php 232857 2007-03-28 10:23:04Z mansion $
|
||||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* @package Net_URL_Mapper
|
* @package Net_URL_Mapper
|
||||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||||
* @version CVS: $Id: Exception.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
* @version CVS: $Id: Exception.php 232857 2007-03-28 10:23:04Z mansion $
|
||||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* @package Net_URL_Mapper
|
* @package Net_URL_Mapper
|
||||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||||
* @version CVS: $Id: Part.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
* @version CVS: $Id: Part.php 232857 2007-03-28 10:23:04Z mansion $
|
||||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* @package Net_URL_Mapper
|
* @package Net_URL_Mapper
|
||||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||||
* @version CVS: $Id: Dynamic.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
* @version CVS: $Id: Dynamic.php 232857 2007-03-28 10:23:04Z mansion $
|
||||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* @package Net_URL_Mapper
|
* @package Net_URL_Mapper
|
||||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||||
* @version CVS: $Id: Fixed.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
* @version CVS: $Id: Fixed.php 232857 2007-03-28 10:23:04Z mansion $
|
||||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* @package Net_URL_Mapper
|
* @package Net_URL_Mapper
|
||||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||||
* @version CVS: $Id: Wildcard.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
* @version CVS: $Id: Wildcard.php 232857 2007-03-28 10:23:04Z mansion $
|
||||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* @package Net_URL_Mapper
|
* @package Net_URL_Mapper
|
||||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||||
* @version CVS: $Id: Path.php,v 1.1 2007/03/28 10:23:04 mansion Exp $
|
* @version CVS: $Id: Path.php 296456 2010-03-20 00:41:08Z kguest $
|
||||||
* @link http://pear.php.net/package/Net_URL_Mapper
|
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -84,6 +84,22 @@ class Net_URL_Mapper_Path
|
||||||
$this->getRequired();
|
$this->getRequired();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the object is serialized
|
||||||
|
* Make sure we do not store too much info when the object is serialized
|
||||||
|
* and call the regular expressions generator functions so that they will
|
||||||
|
* not need to be generated again on wakeup.
|
||||||
|
*
|
||||||
|
* @return array Name of properties to store when serialized
|
||||||
|
*/
|
||||||
|
public function __sleep()
|
||||||
|
{
|
||||||
|
$this->getFormat();
|
||||||
|
$this->getRule();
|
||||||
|
return array('alias', 'path', 'defaults', 'rule', 'format',
|
||||||
|
'parts', 'minKeys', 'maxKeys', 'fixed', 'required');
|
||||||
|
}
|
||||||
|
|
||||||
public function getPath()
|
public function getPath()
|
||||||
{
|
{
|
||||||
return $this->path;
|
return $this->path;
|
||||||
|
@ -241,7 +257,12 @@ class Net_URL_Mapper_Path
|
||||||
}
|
}
|
||||||
$path = '/'.trim(Net_URL::resolvePath($path), '/');
|
$path = '/'.trim(Net_URL::resolvePath($path), '/');
|
||||||
if (!empty($qstring)) {
|
if (!empty($qstring)) {
|
||||||
$path .= '?'.http_build_query($qstring);
|
if(strpos($path, '?') === false) {
|
||||||
|
$path .= '?';
|
||||||
|
} else {
|
||||||
|
$path .= '&';
|
||||||
|
}
|
||||||
|
$path .= http_build_query($qstring);
|
||||||
}
|
}
|
||||||
if (!empty($anchor)) {
|
if (!empty($anchor)) {
|
||||||
$path .= '#'.ltrim($anchor, '#');
|
$path .= '#'.ltrim($anchor, '#');
|
||||||
|
|
334
extlib/Net/URL/Mapper/Path.plex
Normal file
334
extlib/Net/URL/Mapper/Path.plex
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* URL parser and mapper
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENSE:
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006, Bertrand Mansion <golgote@mamasam.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * The names of the authors may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @category Net
|
||||||
|
* @package Net_URL_Mapper
|
||||||
|
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||||
|
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||||
|
* @version CVS: $Id: Path.plex 283937 2009-07-12 11:37:21Z mansion $
|
||||||
|
* @link http://pear.php.net/package/Net_URL_Mapper
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'Net/URL/Mapper/Part/Dynamic.php';
|
||||||
|
require_once 'Net/URL/Mapper/Part/Wildcard.php';
|
||||||
|
require_once 'Net/URL/Mapper/Part/Fixed.php';
|
||||||
|
|
||||||
|
class Net_URL_Mapper_Path
|
||||||
|
{
|
||||||
|
private $path = '';
|
||||||
|
private $N = 0;
|
||||||
|
public $token;
|
||||||
|
public $value;
|
||||||
|
private $line = 1;
|
||||||
|
private $state = 1;
|
||||||
|
|
||||||
|
|
||||||
|
protected $alias;
|
||||||
|
protected $rules = array();
|
||||||
|
protected $defaults = array();
|
||||||
|
protected $parts = array();
|
||||||
|
protected $rule;
|
||||||
|
protected $format;
|
||||||
|
protected $minKeys;
|
||||||
|
protected $maxKeys;
|
||||||
|
protected $fixed = true;
|
||||||
|
protected $required;
|
||||||
|
|
||||||
|
public function __construct($path = '', $defaults = array(), $rules = array())
|
||||||
|
{
|
||||||
|
$this->path = '/'.trim(Net_URL::resolvePath($path), '/');
|
||||||
|
$this->setDefaults($defaults);
|
||||||
|
$this->setRules($rules);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->parsePath();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// The path could not be parsed correctly, treat it as fixed
|
||||||
|
$this->fixed = true;
|
||||||
|
$part = self::createPart(Net_URL_Mapper_Part::FIXED, $this->path, $this->path);
|
||||||
|
$this->parts = array($part);
|
||||||
|
}
|
||||||
|
$this->getRequired();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the object is serialized
|
||||||
|
* Make sure we do not store too much info when the object is serialized
|
||||||
|
* and call the regular expressions generator functions so that they will
|
||||||
|
* not need to be generated again on wakeup.
|
||||||
|
*
|
||||||
|
* @return array Name of properties to store when serialized
|
||||||
|
*/
|
||||||
|
public function __sleep()
|
||||||
|
{
|
||||||
|
$this->getFormat();
|
||||||
|
$this->getRule();
|
||||||
|
return array('alias', 'path', 'defaults', 'rule', 'format',
|
||||||
|
'parts', 'minKeys', 'maxKeys', 'fixed', 'required');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPath()
|
||||||
|
{
|
||||||
|
return $this->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function parsePath()
|
||||||
|
{
|
||||||
|
while ($this->yylex()) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path alias
|
||||||
|
* Path aliases can be used instead of full path
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public function getAlias()
|
||||||
|
{
|
||||||
|
return $this->alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the path name
|
||||||
|
* @param string Set the path name
|
||||||
|
* @see getAlias()
|
||||||
|
*/
|
||||||
|
public function setAlias($alias)
|
||||||
|
{
|
||||||
|
$this->alias = $alias;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path parts default values
|
||||||
|
* @return null|array
|
||||||
|
*/
|
||||||
|
public function getDefaults()
|
||||||
|
{
|
||||||
|
return $this->defaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the path parts default values
|
||||||
|
* @param array Associative array with format partname => value
|
||||||
|
*/
|
||||||
|
public function setDefaults($defaults)
|
||||||
|
{
|
||||||
|
if (is_array($defaults)) {
|
||||||
|
$this->defaults = $defaults;
|
||||||
|
} else {
|
||||||
|
$this->defaults = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the path parts default values
|
||||||
|
* @param array Associative array with format partname => value
|
||||||
|
*/
|
||||||
|
public function setRules($rules)
|
||||||
|
{
|
||||||
|
if (is_array($rules)) {
|
||||||
|
$this->rules = $rules;
|
||||||
|
} else {
|
||||||
|
$this->rules = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the regular expression used to match this path
|
||||||
|
* @return string PERL Regular expression
|
||||||
|
*/
|
||||||
|
public function getRule()
|
||||||
|
{
|
||||||
|
if (is_null($this->rule)) {
|
||||||
|
$this->rule = '/^';
|
||||||
|
foreach ($this->parts as $path => $part) {
|
||||||
|
$this->rule .= $part->getRule();
|
||||||
|
}
|
||||||
|
$this->rule .= '$/';
|
||||||
|
}
|
||||||
|
return $this->rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormat()
|
||||||
|
{
|
||||||
|
if (is_null($this->format)) {
|
||||||
|
$this->format = '/^';
|
||||||
|
foreach ($this->parts as $path => $part) {
|
||||||
|
$this->format .= $part->getFormat();
|
||||||
|
}
|
||||||
|
$this->format .= '$/';
|
||||||
|
}
|
||||||
|
return $this->format;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addPart($part)
|
||||||
|
{
|
||||||
|
if (array_key_exists($part->content, $this->defaults)) {
|
||||||
|
$part->setRequired(false);
|
||||||
|
$part->setDefaults($this->defaults[$part->content]);
|
||||||
|
}
|
||||||
|
if (isset($this->rules[$part->content])) {
|
||||||
|
$part->setRule($this->rules[$part->content]);
|
||||||
|
}
|
||||||
|
$this->rule = null;
|
||||||
|
if ($part->getType() != Net_URL_Mapper_Part::FIXED) {
|
||||||
|
$this->fixed = false;
|
||||||
|
$this->parts[$part->content] = $part;
|
||||||
|
} else {
|
||||||
|
$this->parts[] = $part;
|
||||||
|
}
|
||||||
|
return $part;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createPart($type, $content, $path)
|
||||||
|
{
|
||||||
|
switch ($type) {
|
||||||
|
case Net_URL_Mapper_Part::DYNAMIC:
|
||||||
|
return new Net_URL_Mapper_Part_Dynamic($content, $path);
|
||||||
|
break;
|
||||||
|
case Net_URL_Mapper_Part::WILDCARD:
|
||||||
|
return new Net_URL_Mapper_Part_Wildcard($content, $path);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new Net_URL_Mapper_Part_Fixed($content, $path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the path contains the given part by name
|
||||||
|
* If value parameter is given, the part also checks if the
|
||||||
|
* given value conforms to the part rule.
|
||||||
|
* @param string Part name
|
||||||
|
* @param mixed The value to check against
|
||||||
|
*/
|
||||||
|
public function hasKey($partName, $value = null)
|
||||||
|
{
|
||||||
|
if (array_key_exists($partName, $this->parts)) {
|
||||||
|
if (!is_null($value) && $value !== false) {
|
||||||
|
return $this->parts[$partName]->match($value);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} elseif (array_key_exists($partName, $this->defaults) &&
|
||||||
|
$value == $this->defaults[$partName]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generate($values = array(), $qstring = array(), $anchor = '')
|
||||||
|
{
|
||||||
|
$path = '';
|
||||||
|
foreach ($this->parts as $part) {
|
||||||
|
$path .= $part->generate($values);
|
||||||
|
}
|
||||||
|
$path = '/'.trim(Net_URL::resolvePath($path), '/');
|
||||||
|
if (!empty($qstring)) {
|
||||||
|
$path .= '?'.http_build_query($qstring);
|
||||||
|
}
|
||||||
|
if (!empty($anchor)) {
|
||||||
|
$path .= '#'.ltrim($anchor, '#');
|
||||||
|
}
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequired()
|
||||||
|
{
|
||||||
|
if (!isset($this->required)) {
|
||||||
|
$req = array();
|
||||||
|
foreach ($this->parts as $part) {
|
||||||
|
if ($part->isRequired()) {
|
||||||
|
$req[] = $part->content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->required = $req;
|
||||||
|
}
|
||||||
|
return $this->required;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMaxKeys()
|
||||||
|
{
|
||||||
|
if (is_null($this->maxKeys)) {
|
||||||
|
$this->maxKeys = count($this->required);
|
||||||
|
$this->maxKeys += count($this->defaults);
|
||||||
|
}
|
||||||
|
return $this->maxKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!lex2php
|
||||||
|
%input $this->path
|
||||||
|
%counter $this->N
|
||||||
|
%token $this->token
|
||||||
|
%value $this->value
|
||||||
|
%line $this->line
|
||||||
|
static = /\/?([^\/:\*]+)/
|
||||||
|
variable = /([a-zA-Z0-9_]+)/
|
||||||
|
dynamic = /\/?:/
|
||||||
|
wildcard = @/?\*@
|
||||||
|
grouping = /\/?\(([a-zA-Z0-9_]+)\)/
|
||||||
|
*/
|
||||||
|
/*!lex2php
|
||||||
|
%statename START
|
||||||
|
dynamic grouping {
|
||||||
|
$c = $yy_subpatterns[0];
|
||||||
|
$part = self::createPart(Net_URL_Mapper_Part::DYNAMIC, $c, $this->value);
|
||||||
|
$this->addPart($part);
|
||||||
|
}
|
||||||
|
wildcard grouping {
|
||||||
|
$c = $yy_subpatterns[0];
|
||||||
|
$part = self::createPart(Net_URL_Mapper_Part::WILDCARD, $c, $this->value);
|
||||||
|
$this->addPart($part);
|
||||||
|
}
|
||||||
|
dynamic variable {
|
||||||
|
$c = $yy_subpatterns[0];
|
||||||
|
$part = self::createPart(Net_URL_Mapper_Part::DYNAMIC, $c, $this->value);
|
||||||
|
$this->addPart($part);
|
||||||
|
}
|
||||||
|
wildcard variable {
|
||||||
|
$c = $yy_subpatterns[0];
|
||||||
|
$part = self::createPart(Net_URL_Mapper_Part::WILDCARD, $c, $this->value);
|
||||||
|
$this->addPart($part);
|
||||||
|
}
|
||||||
|
static {
|
||||||
|
$c = $yy_subpatterns[0];
|
||||||
|
$part = self::createPart(Net_URL_Mapper_Part::FIXED, $c, $this->value);
|
||||||
|
$this->addPart($part);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -1,357 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for oEmbed consumption
|
|
||||||
*
|
|
||||||
* PHP version 5.1.0+
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008, Digg.com, Inc.
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* - Neither the name of Digg.com, Inc. nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version SVN: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'Validate.php';
|
|
||||||
require_once 'Net/URL2.php';
|
|
||||||
require_once 'HTTP/Request.php';
|
|
||||||
require_once 'Services/oEmbed/Exception.php';
|
|
||||||
require_once 'Services/oEmbed/Exception/NoSupport.php';
|
|
||||||
require_once 'Services/oEmbed/Object.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for consuming oEmbed objects
|
|
||||||
*
|
|
||||||
* <code>
|
|
||||||
* <?php
|
|
||||||
*
|
|
||||||
* require_once 'Services/oEmbed.php';
|
|
||||||
*
|
|
||||||
* // The URL that we'd like to find out more information about.
|
|
||||||
* $url = 'http://flickr.com/photos/joestump/2848795611/';
|
|
||||||
*
|
|
||||||
* // The oEmbed API URI. Not all providers support discovery yet so we're
|
|
||||||
* // explicitly providing one here. If one is not provided Services_oEmbed
|
|
||||||
* // attempts to discover it. If none is found an exception is thrown.
|
|
||||||
* $oEmbed = new Services_oEmbed($url, array(
|
|
||||||
* Services_oEmbed::OPTION_API => 'http://www.flickr.com/services/oembed/'
|
|
||||||
* ));
|
|
||||||
* $object = $oEmbed->getObject();
|
|
||||||
*
|
|
||||||
* // All of the objects have somewhat sane __toString() methods that allow
|
|
||||||
* // you to output them directly.
|
|
||||||
* echo (string)$object;
|
|
||||||
*
|
|
||||||
* ?>
|
|
||||||
* </code>
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version Release: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
class Services_oEmbed
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* HTTP timeout in seconds
|
|
||||||
*
|
|
||||||
* All HTTP requests made by Services_oEmbed will respect this timeout.
|
|
||||||
* This can be passed to {@link Services_oEmbed::setOption()} or to the
|
|
||||||
* options parameter in {@link Services_oEmbed::__construct()}.
|
|
||||||
*
|
|
||||||
* @var string OPTION_TIMEOUT Timeout in seconds
|
|
||||||
*/
|
|
||||||
const OPTION_TIMEOUT = 'http_timeout';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP User-Agent
|
|
||||||
*
|
|
||||||
* All HTTP requests made by Services_oEmbed will be sent with the
|
|
||||||
* string set by this option.
|
|
||||||
*
|
|
||||||
* @var string OPTION_USER_AGENT The HTTP User-Agent string
|
|
||||||
*/
|
|
||||||
const OPTION_USER_AGENT = 'http_user_agent';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The API's URI
|
|
||||||
*
|
|
||||||
* If the API is known ahead of time this option can be used to explicitly
|
|
||||||
* set it. If not present then the API is attempted to be discovered
|
|
||||||
* through the auto-discovery mechanism.
|
|
||||||
*
|
|
||||||
* @var string OPTION_API
|
|
||||||
*/
|
|
||||||
const OPTION_API = 'oembed_api';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for oEmbed requests
|
|
||||||
*
|
|
||||||
* @var array $options The options for making requests
|
|
||||||
*/
|
|
||||||
protected $options = array(
|
|
||||||
self::OPTION_TIMEOUT => 3,
|
|
||||||
self::OPTION_API => null,
|
|
||||||
self::OPTION_USER_AGENT => 'Services_oEmbed 0.1.0'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL of object to get embed information for
|
|
||||||
*
|
|
||||||
* @var object $url {@link Net_URL2} instance of URL of object
|
|
||||||
*/
|
|
||||||
protected $url = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param string $url The URL to fetch an oEmbed for
|
|
||||||
* @param array $options A list of options for the oEmbed lookup
|
|
||||||
*
|
|
||||||
* @throws {@link Services_oEmbed_Exception} if the $url is invalid
|
|
||||||
* @throws {@link Services_oEmbed_Exception} when no valid API is found
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct($url, array $options = array())
|
|
||||||
{
|
|
||||||
if (Validate::uri($url)) {
|
|
||||||
$this->url = new Net_URL2($url);
|
|
||||||
} else {
|
|
||||||
throw new Services_oEmbed_Exception('URL is invalid');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($options)) {
|
|
||||||
foreach ($options as $key => $val) {
|
|
||||||
$this->setOption($key, $val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->options[self::OPTION_API] === null) {
|
|
||||||
$this->options[self::OPTION_API] = $this->discover($url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set an option for the oEmbed request
|
|
||||||
*
|
|
||||||
* @param mixed $option The option name
|
|
||||||
* @param mixed $value The option value
|
|
||||||
*
|
|
||||||
* @see Services_oEmbed::OPTION_API, Services_oEmbed::OPTION_TIMEOUT
|
|
||||||
* @throws {@link Services_oEmbed_Exception} on invalid option
|
|
||||||
* @access public
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function setOption($option, $value)
|
|
||||||
{
|
|
||||||
switch ($option) {
|
|
||||||
case self::OPTION_API:
|
|
||||||
case self::OPTION_TIMEOUT:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Services_oEmbed_Exception(
|
|
||||||
'Invalid option "' . $option . '"'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$func = '_set_' . $option;
|
|
||||||
if (method_exists($this, $func)) {
|
|
||||||
$this->options[$option] = $this->$func($value);
|
|
||||||
} else {
|
|
||||||
$this->options[$option] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the API option
|
|
||||||
*
|
|
||||||
* @param string $value The API's URI
|
|
||||||
*
|
|
||||||
* @throws {@link Services_oEmbed_Exception} on invalid API URI
|
|
||||||
* @see Validate::uri()
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function _set_oembed_api($value)
|
|
||||||
{
|
|
||||||
if (!Validate::uri($value)) {
|
|
||||||
throw new Services_oEmbed_Exception(
|
|
||||||
'API URI provided is invalid'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the oEmbed response
|
|
||||||
*
|
|
||||||
* @param array $params Optional parameters for
|
|
||||||
*
|
|
||||||
* @throws {@link Services_oEmbed_Exception} on cURL errors
|
|
||||||
* @throws {@link Services_oEmbed_Exception} on HTTP errors
|
|
||||||
* @throws {@link Services_oEmbed_Exception} when result is not parsable
|
|
||||||
* @return object The oEmbed response as an object
|
|
||||||
*/
|
|
||||||
public function getObject(array $params = array())
|
|
||||||
{
|
|
||||||
$params['url'] = $this->url->getURL();
|
|
||||||
if (!isset($params['format'])) {
|
|
||||||
$params['format'] = 'json';
|
|
||||||
}
|
|
||||||
|
|
||||||
$sets = array();
|
|
||||||
foreach ($params as $var => $val) {
|
|
||||||
$sets[] = $var . '=' . urlencode($val);
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = $this->options[self::OPTION_API] . '?' . implode('&', $sets);
|
|
||||||
|
|
||||||
$ch = curl_init();
|
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
|
||||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->options[self::OPTION_TIMEOUT]);
|
|
||||||
$result = curl_exec($ch);
|
|
||||||
|
|
||||||
if (curl_errno($ch)) {
|
|
||||||
throw new Services_oEmbed_Exception(
|
|
||||||
curl_error($ch), curl_errno($ch)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
||||||
if (substr($code, 0, 1) != '2') {
|
|
||||||
throw new Services_oEmbed_Exception('Non-200 code returned. Got code ' . $code);
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_close($ch);
|
|
||||||
|
|
||||||
switch ($params['format']) {
|
|
||||||
case 'json':
|
|
||||||
$res = json_decode($result);
|
|
||||||
if (!is_object($res)) {
|
|
||||||
throw new Services_oEmbed_Exception(
|
|
||||||
'Could not parse JSON response'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'xml':
|
|
||||||
libxml_use_internal_errors(true);
|
|
||||||
$res = simplexml_load_string($result);
|
|
||||||
if (!$res instanceof SimpleXMLElement) {
|
|
||||||
$errors = libxml_get_errors();
|
|
||||||
$err = array_shift($errors);
|
|
||||||
libxml_clear_errors();
|
|
||||||
libxml_use_internal_errors(false);
|
|
||||||
throw new Services_oEmbed_Exception(
|
|
||||||
$err->message, $error->code
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Services_oEmbed_Object::factory($res);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discover an oEmbed API
|
|
||||||
*
|
|
||||||
* @param string $url The URL to attempt to discover oEmbed for
|
|
||||||
*
|
|
||||||
* @throws {@link Services_oEmbed_Exception} if the $url is invalid
|
|
||||||
* @return string The oEmbed API endpoint discovered
|
|
||||||
*/
|
|
||||||
protected function discover($url)
|
|
||||||
{
|
|
||||||
$body = $this->sendRequest($url);
|
|
||||||
|
|
||||||
// Find all <link /> tags that have a valid oembed type set. We then
|
|
||||||
// extract the href attribute for each type.
|
|
||||||
$regexp = '#<link([^>]*)type[\s\n]*=[\s\n]*"' .
|
|
||||||
'(application/json|text/xml)\+oembed"([^>]*)>#im';
|
|
||||||
|
|
||||||
$m = $ret = array();
|
|
||||||
if (!preg_match_all($regexp, $body, $m)) {
|
|
||||||
throw new Services_oEmbed_Exception_NoSupport(
|
|
||||||
'No valid oEmbed links found on page'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($m[0] as $i => $link) {
|
|
||||||
$h = array();
|
|
||||||
if (preg_match('/[\s\n]+href[\s\n]*=[\s\n]*"([^"]+)"/im', $link, $h)) {
|
|
||||||
$ret[$m[2][$i]] = $h[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (isset($ret['application/json']) ? $ret['application/json'] : array_pop($ret));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a GET request to the provider
|
|
||||||
*
|
|
||||||
* @param mixed $url The URL to send the request to
|
|
||||||
*
|
|
||||||
* @throws {@link Services_oEmbed_Exception} on HTTP errors
|
|
||||||
* @return string The contents of the response
|
|
||||||
*/
|
|
||||||
private function sendRequest($url)
|
|
||||||
{
|
|
||||||
$ch = curl_init();
|
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
|
||||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->options[self::OPTION_TIMEOUT]);
|
|
||||||
curl_setopt($ch, CURLOPT_USERAGENT, $this->options[self::OPTION_USER_AGENT]);
|
|
||||||
$result = curl_exec($ch);
|
|
||||||
if (curl_errno($ch)) {
|
|
||||||
throw new Services_oEmbed_Exception(
|
|
||||||
curl_error($ch), curl_errno($ch)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
||||||
if (substr($code, 0, 1) != '2') {
|
|
||||||
throw new Services_oEmbed_Exception('Non-200 code returned. Got code ' . $code);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,65 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base exception class for {@link Services_oEmbed}
|
|
||||||
*
|
|
||||||
* PHP version 5.1.0+
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008, Digg.com, Inc.
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* - Neither the name of Digg.com, Inc. nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version SVN: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'PEAR/Exception.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base exception class for {@link Services_oEmbed}
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version Release: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
class Services_oEmbed_Exception extends PEAR_Exception
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,63 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception class when no oEmbed support is discovered
|
|
||||||
*
|
|
||||||
* PHP version 5.2.0+
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008, Digg.com, Inc.
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* - Neither the name of Digg.com, Inc. nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version SVN: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception class when no oEmbed support is discovered
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version Release: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
class Services_oEmbed_Exception_NoSupport extends Services_oEmbed_Exception
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,126 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for oEmbed consumption
|
|
||||||
*
|
|
||||||
* PHP version 5.1.0+
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008, Digg.com, Inc.
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* - Neither the name of Digg.com, Inc. nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version SVN: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'Services/oEmbed/Object/Exception.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for consuming oEmbed objects
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version Release: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
abstract class Services_oEmbed_Object
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Valid oEmbed object types
|
|
||||||
*
|
|
||||||
* @var array $types Array of valid object types
|
|
||||||
* @see Services_oEmbed_Object::factory()
|
|
||||||
*/
|
|
||||||
static protected $types = array(
|
|
||||||
'photo' => 'Photo',
|
|
||||||
'video' => 'Video',
|
|
||||||
'link' => 'Link',
|
|
||||||
'rich' => 'Rich'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an oEmbed object from result
|
|
||||||
*
|
|
||||||
* @param object $object Raw object returned from API
|
|
||||||
*
|
|
||||||
* @throws {@link Services_oEmbed_Object_Exception} on object error
|
|
||||||
* @return object Instance of object driver
|
|
||||||
* @see Services_oEmbed_Object_Link, Services_oEmbed_Object_Photo
|
|
||||||
* @see Services_oEmbed_Object_Rich, Services_oEmbed_Object_Video
|
|
||||||
*/
|
|
||||||
static public function factory($object)
|
|
||||||
{
|
|
||||||
if (!isset($object->type)) {
|
|
||||||
throw new Services_oEmbed_Object_Exception(
|
|
||||||
'Object has no type'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$type = (string)$object->type;
|
|
||||||
if (!isset(self::$types[$type])) {
|
|
||||||
throw new Services_oEmbed_Object_Exception(
|
|
||||||
'Object type is unknown or invalid: ' . $type
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$file = 'Services/oEmbed/Object/' . self::$types[$type] . '.php';
|
|
||||||
include_once $file;
|
|
||||||
|
|
||||||
$class = 'Services_oEmbed_Object_' . self::$types[$type];
|
|
||||||
if (!class_exists($class)) {
|
|
||||||
throw new Services_oEmbed_Object_Exception(
|
|
||||||
'Object class is invalid or not present'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$instance = new $class($object);
|
|
||||||
return $instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiation is not allowed
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function __construct()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,139 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for oEmbed objects
|
|
||||||
*
|
|
||||||
* PHP version 5.1.0+
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008, Digg.com, Inc.
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* - Neither the name of Digg.com, Inc. nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version SVN: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for oEmbed objects
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version Release: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
abstract class Services_oEmbed_Object_Common
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Raw object returned from API
|
|
||||||
*
|
|
||||||
* @var object $object The raw object from the API
|
|
||||||
*/
|
|
||||||
protected $object = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required fields per the specification
|
|
||||||
*
|
|
||||||
* @var array $required Array of required fields
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
protected $required = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param object $object Raw object returned from the API
|
|
||||||
*
|
|
||||||
* @throws {@link Services_oEmbed_Object_Exception} on missing fields
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct($object)
|
|
||||||
{
|
|
||||||
$this->object = $object;
|
|
||||||
|
|
||||||
$this->required[] = 'version';
|
|
||||||
foreach ($this->required as $field) {
|
|
||||||
if (!isset($this->$field)) {
|
|
||||||
throw new Services_oEmbed_Object_Exception(
|
|
||||||
'Object is missing required ' . $field . ' attribute'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get object variable
|
|
||||||
*
|
|
||||||
* @param string $var Variable to get
|
|
||||||
*
|
|
||||||
* @see Services_oEmbed_Object_Common::$object
|
|
||||||
* @return mixed Attribute's value or null if it's not set/exists
|
|
||||||
*/
|
|
||||||
public function __get($var)
|
|
||||||
{
|
|
||||||
if (property_exists($this->object, $var)) {
|
|
||||||
return $this->object->$var;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is variable set?
|
|
||||||
*
|
|
||||||
* @param string $var Variable name to check
|
|
||||||
*
|
|
||||||
* @return boolean True if set, false if not
|
|
||||||
* @see Services_oEmbed_Object_Common::$object
|
|
||||||
*/
|
|
||||||
public function __isset($var)
|
|
||||||
{
|
|
||||||
if (property_exists($this->object, $var)) {
|
|
||||||
return (isset($this->object->$var));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Require a sane __toString for all objects
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
abstract public function __toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,65 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception for {@link Services_oEmbed_Object}
|
|
||||||
*
|
|
||||||
* PHP version 5.1.0+
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008, Digg.com, Inc.
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* - Neither the name of Digg.com, Inc. nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version SVN: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'Services/oEmbed/Exception.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception for {@link Services_oEmbed_Object}
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version Release: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
class Services_oEmbed_Object_Exception extends Services_oEmbed_Exception
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,73 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Link object for {@link Services_oEmbed}
|
|
||||||
*
|
|
||||||
* PHP version 5.2.0+
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008, Digg.com, Inc.
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* - Neither the name of Digg.com, Inc. nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version SVN: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'Services/oEmbed/Object/Common.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Link object for {@link Services_oEmbed}
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version Release: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
class Services_oEmbed_Object_Link extends Services_oEmbed_Object_Common
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Output a sane link
|
|
||||||
*
|
|
||||||
* @return string An HTML link of the object
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return '<a href="' . $this->url . '">' . $this->title . '</a>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,89 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Photo object for {@link Services_oEmbed}
|
|
||||||
*
|
|
||||||
* PHP version 5.2.0+
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008, Digg.com, Inc.
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* - Neither the name of Digg.com, Inc. nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version SVN: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'Services/oEmbed/Object/Common.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Photo object for {@link Services_oEmbed}
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version Release: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
class Services_oEmbed_Object_Photo extends Services_oEmbed_Object_Common
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Required fields for photo objects
|
|
||||||
*
|
|
||||||
* @var array $required Required fields
|
|
||||||
*/
|
|
||||||
protected $required = array(
|
|
||||||
'url', 'width', 'height'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output a valid HTML tag for image
|
|
||||||
*
|
|
||||||
* @return string HTML <img /> tag for Photo
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
$img = '<img src="' . $this->url . '" width="' . $this->width . '" ' .
|
|
||||||
'height="' . $this->height . '"';
|
|
||||||
|
|
||||||
if (isset($this->title)) {
|
|
||||||
$img .= ' alt="' . $this->title . '"';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $img . ' />';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,82 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Photo object for {@link Services_oEmbed}
|
|
||||||
*
|
|
||||||
* PHP version 5.2.0+
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008, Digg.com, Inc.
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* - Neither the name of Digg.com, Inc. nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version SVN: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'Services/oEmbed/Object/Common.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Photo object for {@link Services_oEmbed}
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version Release: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
class Services_oEmbed_Object_Rich extends Services_oEmbed_Object_Common
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Required fields for rich objects
|
|
||||||
*
|
|
||||||
* @var array $required Required fields
|
|
||||||
*/
|
|
||||||
protected $required = array(
|
|
||||||
'html', 'width', 'height'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output a the HTML tag for rich object
|
|
||||||
*
|
|
||||||
* @return string HTML for rich object
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return $this->html;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,82 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Photo object for {@link Services_oEmbed}
|
|
||||||
*
|
|
||||||
* PHP version 5.2.0+
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008, Digg.com, Inc.
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* - Neither the name of Digg.com, Inc. nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version SVN: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'Services/oEmbed/Object/Common.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Photo object for {@link Services_oEmbed}
|
|
||||||
*
|
|
||||||
* @category Services
|
|
||||||
* @package Services_oEmbed
|
|
||||||
* @author Joe Stump <joe@joestump.net>
|
|
||||||
* @copyright 2008 Digg.com, Inc.
|
|
||||||
* @license http://tinyurl.com/42zef New BSD License
|
|
||||||
* @version Release: @version@
|
|
||||||
* @link http://code.google.com/p/digg
|
|
||||||
* @link http://oembed.com
|
|
||||||
*/
|
|
||||||
class Services_oEmbed_Object_Video extends Services_oEmbed_Object_Common
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Required fields for video objects
|
|
||||||
*
|
|
||||||
* @var array $required Required fields
|
|
||||||
*/
|
|
||||||
protected $required = array(
|
|
||||||
'html', 'width', 'height'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output a valid embed tag for video
|
|
||||||
*
|
|
||||||
* @return string HTML for video
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return $this->html;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
23
js/emailsettings.js
Normal file
23
js/emailsettings.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
function toggleIncomingOptions() {
|
||||||
|
var enabled = $('#emailpost').attr('checked');
|
||||||
|
if (enabled) {
|
||||||
|
// Note: button style currently does not respond to disabled in our main themes.
|
||||||
|
// Graying out the whole section with a 50% transparency will do for now. :)
|
||||||
|
// @todo: add a general 'disabled' class style to the base themes.
|
||||||
|
$('#emailincoming').removeAttr('style')
|
||||||
|
.find('input').removeAttr('disabled');
|
||||||
|
} else {
|
||||||
|
$('#emailincoming').attr('style', 'opacity: 0.5')
|
||||||
|
.find('input').attr('disabled', 'disabled');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleIncomingOptions();
|
||||||
|
|
||||||
|
$('#emailpost').click(function() {
|
||||||
|
toggleIncomingOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
1
js/jquery.cookie.min.js
vendored
Normal file
1
js/jquery.cookie.min.js
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
jQuery.cookie=function(b,j,m){if(typeof j!="undefined"){m=m||{};if(j===null){j="";m.expires=-1}var e="";if(m.expires&&(typeof m.expires=="number"||m.expires.toUTCString)){var f;if(typeof m.expires=="number"){f=new Date();f.setTime(f.getTime()+(m.expires*24*60*60*1000))}else{f=m.expires}e="; expires="+f.toUTCString()}var l=m.path?"; path="+(m.path):"";var g=m.domain?"; domain="+(m.domain):"";var a=m.secure?"; secure":"";document.cookie=[b,"=",encodeURIComponent(j),e,l,g,a].join("")}else{var d=null;if(document.cookie&&document.cookie!=""){var k=document.cookie.split(";");for(var h=0;h<k.length;h++){var c=jQuery.trim(k[h]);if(c.substring(0,b.length+1)==(b+"=")){d=decodeURIComponent(c.substring(b.length+1));break}}}return d}};
|
|
@ -1,14 +1,12 @@
|
||||||
/*
|
/*!
|
||||||
* jQuery Form Plugin
|
* jQuery Form Plugin
|
||||||
* version: 2.17 (06-NOV-2008)
|
* version: 2.49 (18-OCT-2010)
|
||||||
* @requires jQuery v1.2.2 or later
|
* @requires jQuery v1.3.2 or later
|
||||||
*
|
*
|
||||||
* Examples and documentation at: http://malsup.com/jquery/form/
|
* Examples and documentation at: http://malsup.com/jquery/form/
|
||||||
* Dual licensed under the MIT and GPL licenses:
|
* Dual licensed under the MIT and GPL licenses:
|
||||||
* http://www.opensource.org/licenses/mit-license.php
|
* http://www.opensource.org/licenses/mit-license.php
|
||||||
* http://www.gnu.org/licenses/gpl.html
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
*
|
|
||||||
* Revision: $Id$
|
|
||||||
*/
|
*/
|
||||||
;(function($) {
|
;(function($) {
|
||||||
|
|
||||||
|
@ -20,11 +18,11 @@
|
||||||
to bind your own submit handler to the form. For example,
|
to bind your own submit handler to the form. For example,
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('#myForm').bind('submit', function() {
|
$('#myForm').bind('submit', function(e) {
|
||||||
|
e.preventDefault(); // <-- important
|
||||||
$(this).ajaxSubmit({
|
$(this).ajaxSubmit({
|
||||||
target: '#output'
|
target: '#output'
|
||||||
});
|
});
|
||||||
return false; // <-- important!
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -52,13 +50,22 @@ $.fn.ajaxSubmit = function(options) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof options == 'function')
|
if (typeof options == 'function') {
|
||||||
options = { success: options };
|
options = { success: options };
|
||||||
|
}
|
||||||
|
|
||||||
options = $.extend({
|
var url = $.trim(this.attr('action'));
|
||||||
url: this.attr('action') || window.location.toString(),
|
if (url) {
|
||||||
type: this.attr('method') || 'GET'
|
// clean url (don't include hash vaue)
|
||||||
}, options || {});
|
url = (url.match(/^([^#]+)/)||[])[1];
|
||||||
|
}
|
||||||
|
url = url || window.location.href || '';
|
||||||
|
|
||||||
|
options = $.extend(true, {
|
||||||
|
url: url,
|
||||||
|
type: this.attr('method') || 'GET',
|
||||||
|
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
|
||||||
|
}, options);
|
||||||
|
|
||||||
// hook for manipulating the form data before it is extracted;
|
// hook for manipulating the form data before it is extracted;
|
||||||
// convenient for use with rich editors like tinyMCE or FCKEditor
|
// convenient for use with rich editors like tinyMCE or FCKEditor
|
||||||
|
@ -75,16 +82,20 @@ $.fn.ajaxSubmit = function(options) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
var a = this.formToArray(options.semantic);
|
var n,v,a = this.formToArray(options.semantic);
|
||||||
if (options.data) {
|
if (options.data) {
|
||||||
options.extraData = options.data;
|
options.extraData = options.data;
|
||||||
for (var n in options.data) {
|
for (n in options.data) {
|
||||||
if(options.data[n] instanceof Array) {
|
if(options.data[n] instanceof Array) {
|
||||||
for (var k in options.data[n])
|
for (var k in options.data[n]) {
|
||||||
a.push( { name: n, value: options.data[n][k] } )
|
a.push( { name: n, value: options.data[n][k] } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = options.data[n];
|
||||||
|
v = $.isFunction(v) ? v() : v; // if value is fn, invoke it
|
||||||
|
a.push( { name: n, value: v } );
|
||||||
}
|
}
|
||||||
else
|
|
||||||
a.push( { name: n, value: options.data[n] } );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,46 +118,57 @@ $.fn.ajaxSubmit = function(options) {
|
||||||
options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
|
options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
|
||||||
options.data = null; // data is null for 'get'
|
options.data = null; // data is null for 'get'
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
options.data = q; // data is the query string for 'post'
|
options.data = q; // data is the query string for 'post'
|
||||||
|
}
|
||||||
|
|
||||||
var $form = this, callbacks = [];
|
var $form = this, callbacks = [];
|
||||||
if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
|
if (options.resetForm) {
|
||||||
if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
|
callbacks.push(function() { $form.resetForm(); });
|
||||||
|
}
|
||||||
|
if (options.clearForm) {
|
||||||
|
callbacks.push(function() { $form.clearForm(); });
|
||||||
|
}
|
||||||
|
|
||||||
// perform a load on the target only if dataType is not provided
|
// perform a load on the target only if dataType is not provided
|
||||||
if (!options.dataType && options.target) {
|
if (!options.dataType && options.target) {
|
||||||
var oldSuccess = options.success || function(){};
|
var oldSuccess = options.success || function(){};
|
||||||
callbacks.push(function(data) {
|
callbacks.push(function(data) {
|
||||||
$(options.target).html(data).each(oldSuccess, arguments);
|
var fn = options.replaceTarget ? 'replaceWith' : 'html';
|
||||||
|
$(options.target)[fn](data).each(oldSuccess, arguments);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (options.success)
|
else if (options.success) {
|
||||||
callbacks.push(options.success);
|
callbacks.push(options.success);
|
||||||
|
}
|
||||||
|
|
||||||
options.success = function(data, status) {
|
options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
|
||||||
for (var i=0, max=callbacks.length; i < max; i++)
|
var context = options.context || options; // jQuery 1.4+ supports scope context
|
||||||
callbacks[i].apply(options, [data, status, $form]);
|
for (var i=0, max=callbacks.length; i < max; i++) {
|
||||||
|
callbacks[i].apply(context, [data, status, xhr || $form, $form]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// are there files to upload?
|
// are there files to upload?
|
||||||
var files = $('input:file', this).fieldValue();
|
var fileInputs = $('input:file', this).length > 0;
|
||||||
var found = false;
|
var mp = 'multipart/form-data';
|
||||||
for (var j=0; j < files.length; j++)
|
var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
|
||||||
if (files[j])
|
|
||||||
found = true;
|
|
||||||
|
|
||||||
// options.iframe allows user to force iframe mode
|
// options.iframe allows user to force iframe mode
|
||||||
if (options.iframe || found) {
|
// 06-NOV-09: now defaulting to iframe mode if file input is detected
|
||||||
|
if (options.iframe !== false && (fileInputs || options.iframe || multipart)) {
|
||||||
// hack to fix Safari hang (thanks to Tim Molendijk for this)
|
// hack to fix Safari hang (thanks to Tim Molendijk for this)
|
||||||
// see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
|
// see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
|
||||||
if ($.browser.safari && options.closeKeepAlive)
|
if (options.closeKeepAlive) {
|
||||||
$.get(options.closeKeepAlive, fileUpload);
|
$.get(options.closeKeepAlive, fileUpload);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
fileUpload();
|
fileUpload();
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
$.ajax(options);
|
$.ajax(options);
|
||||||
|
}
|
||||||
|
|
||||||
// fire 'notify' event
|
// fire 'notify' event
|
||||||
this.trigger('form-submit-notify', [this, options]);
|
this.trigger('form-submit-notify', [this, options]);
|
||||||
|
@ -157,20 +179,27 @@ $.fn.ajaxSubmit = function(options) {
|
||||||
function fileUpload() {
|
function fileUpload() {
|
||||||
var form = $form[0];
|
var form = $form[0];
|
||||||
|
|
||||||
if ($(':input[name=submit]', form).length) {
|
if ($(':input[name=submit],:input[id=submit]', form).length) {
|
||||||
alert('Error: Form elements must not be named "submit".');
|
// if there is an input with a name or id of 'submit' then we won't be
|
||||||
|
// able to invoke the submit fn on the form (at least not x-browser)
|
||||||
|
alert('Error: Form elements must not have name or id of "submit".');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var opts = $.extend({}, $.ajaxSettings, options);
|
var s = $.extend(true, {}, $.ajaxSettings, options);
|
||||||
var s = jQuery.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
|
s.context = s.context || s;
|
||||||
|
var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id;
|
||||||
var id = 'jqFormIO' + (new Date().getTime());
|
window[fn] = function() {
|
||||||
var $io = $('<iframe id="' + id + '" name="' + id + '" />');
|
var f = $io.data('form-plugin-onload');
|
||||||
|
if (f) {
|
||||||
|
f();
|
||||||
|
window[fn] = undefined;
|
||||||
|
try { delete window[fn]; } catch(e){}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" onload="window[\'_\'+this.id]()" />');
|
||||||
var io = $io[0];
|
var io = $io[0];
|
||||||
|
|
||||||
if ($.browser.msie || $.browser.opera)
|
|
||||||
io.src = 'javascript:false;document.write("");';
|
|
||||||
$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
|
$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
|
||||||
|
|
||||||
var xhr = { // mock object
|
var xhr = { // mock object
|
||||||
|
@ -184,23 +213,30 @@ $.fn.ajaxSubmit = function(options) {
|
||||||
setRequestHeader: function() {},
|
setRequestHeader: function() {},
|
||||||
abort: function() {
|
abort: function() {
|
||||||
this.aborted = 1;
|
this.aborted = 1;
|
||||||
$io.attr('src','about:blank'); // abort op in progress
|
$io.attr('src', s.iframeSrc); // abort op in progress
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var g = opts.global;
|
var g = s.global;
|
||||||
// trigger ajax global events so that activity/block indicators work like normal
|
// trigger ajax global events so that activity/block indicators work like normal
|
||||||
if (g && ! $.active++) $.event.trigger("ajaxStart");
|
if (g && ! $.active++) {
|
||||||
if (g) $.event.trigger("ajaxSend", [xhr, opts]);
|
$.event.trigger("ajaxStart");
|
||||||
|
}
|
||||||
|
if (g) {
|
||||||
|
$.event.trigger("ajaxSend", [xhr, s]);
|
||||||
|
}
|
||||||
|
|
||||||
if (s.beforeSend && s.beforeSend(xhr, s) === false) {
|
if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
|
||||||
s.global && jQuery.active--;
|
if (s.global) {
|
||||||
|
$.active--;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (xhr.aborted)
|
if (xhr.aborted) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var cbInvoked = 0;
|
var cbInvoked = false;
|
||||||
var timedOut = 0;
|
var timedOut = 0;
|
||||||
|
|
||||||
// add submitting element to data if we know it
|
// add submitting element to data if we know it
|
||||||
|
@ -208,27 +244,31 @@ $.fn.ajaxSubmit = function(options) {
|
||||||
if (sub) {
|
if (sub) {
|
||||||
var n = sub.name;
|
var n = sub.name;
|
||||||
if (n && !sub.disabled) {
|
if (n && !sub.disabled) {
|
||||||
options.extraData = options.extraData || {};
|
s.extraData = s.extraData || {};
|
||||||
options.extraData[n] = sub.value;
|
s.extraData[n] = sub.value;
|
||||||
if (sub.type == "image") {
|
if (sub.type == "image") {
|
||||||
options.extraData[name+'.x'] = form.clk_x;
|
s.extraData[n+'.x'] = form.clk_x;
|
||||||
options.extraData[name+'.y'] = form.clk_y;
|
s.extraData[n+'.y'] = form.clk_y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// take a breath so that pending repaints get some cpu time before the upload starts
|
// take a breath so that pending repaints get some cpu time before the upload starts
|
||||||
setTimeout(function() {
|
function doSubmit() {
|
||||||
// make sure form attrs are set
|
// make sure form attrs are set
|
||||||
var t = $form.attr('target'), a = $form.attr('action');
|
var t = $form.attr('target'), a = $form.attr('action');
|
||||||
$form.attr({
|
|
||||||
target: id,
|
// update form attrs in IE friendly way
|
||||||
method: 'POST',
|
form.setAttribute('target',id);
|
||||||
action: opts.url
|
if (form.getAttribute('method') != 'POST') {
|
||||||
});
|
form.setAttribute('method', 'POST');
|
||||||
|
}
|
||||||
|
if (form.getAttribute('action') != s.url) {
|
||||||
|
form.setAttribute('action', s.url);
|
||||||
|
}
|
||||||
|
|
||||||
// ie borks in some cases when setting encoding
|
// ie borks in some cases when setting encoding
|
||||||
if (! options.skipEncodingOverride) {
|
if (! s.skipEncodingOverride) {
|
||||||
$form.attr({
|
$form.attr({
|
||||||
encoding: 'multipart/form-data',
|
encoding: 'multipart/form-data',
|
||||||
enctype: 'multipart/form-data'
|
enctype: 'multipart/form-data'
|
||||||
|
@ -236,90 +276,141 @@ $.fn.ajaxSubmit = function(options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// support timout
|
// support timout
|
||||||
if (opts.timeout)
|
if (s.timeout) {
|
||||||
setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
|
setTimeout(function() { timedOut = true; cb(); }, s.timeout);
|
||||||
|
}
|
||||||
|
|
||||||
// add "extra" data to form if provided in options
|
// add "extra" data to form if provided in options
|
||||||
var extraInputs = [];
|
var extraInputs = [];
|
||||||
try {
|
try {
|
||||||
if (options.extraData)
|
if (s.extraData) {
|
||||||
for (var n in options.extraData)
|
for (var n in s.extraData) {
|
||||||
extraInputs.push(
|
extraInputs.push(
|
||||||
$('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
|
$('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />')
|
||||||
.appendTo(form)[0]);
|
.appendTo(form)[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// add iframe to doc and submit the form
|
// add iframe to doc and submit the form
|
||||||
$io.appendTo('body');
|
$io.appendTo('body');
|
||||||
io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
|
$io.data('form-plugin-onload', cb);
|
||||||
form.submit();
|
form.submit();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// reset attrs and remove "extra" input elements
|
// reset attrs and remove "extra" input elements
|
||||||
$form.attr('action', a);
|
form.setAttribute('action',a);
|
||||||
t ? $form.attr('target', t) : $form.removeAttr('target');
|
if(t) {
|
||||||
|
form.setAttribute('target', t);
|
||||||
|
} else {
|
||||||
|
$form.removeAttr('target');
|
||||||
|
}
|
||||||
$(extraInputs).remove();
|
$(extraInputs).remove();
|
||||||
}
|
}
|
||||||
}, 10);
|
}
|
||||||
|
|
||||||
|
if (s.forceSync) {
|
||||||
|
doSubmit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setTimeout(doSubmit, 10); // this lets dom updates render
|
||||||
|
}
|
||||||
|
|
||||||
|
var data, doc, domCheckCount = 50;
|
||||||
|
|
||||||
function cb() {
|
function cb() {
|
||||||
if (cbInvoked++) return;
|
if (cbInvoked) {
|
||||||
|
|
||||||
io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
|
|
||||||
|
|
||||||
var operaHack = 0;
|
|
||||||
var ok = true;
|
|
||||||
try {
|
|
||||||
if (timedOut) throw 'timeout';
|
|
||||||
// extract the server response from the iframe
|
|
||||||
var data, doc;
|
|
||||||
|
|
||||||
doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
|
|
||||||
|
|
||||||
if (doc.body == null && !operaHack && $.browser.opera) {
|
|
||||||
// In Opera 9.2.x the iframe DOM is not always traversable when
|
|
||||||
// the onload callback fires so we give Opera 100ms to right itself
|
|
||||||
operaHack = 1;
|
|
||||||
cbInvoked--;
|
|
||||||
setTimeout(cb, 100);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
xhr.responseText = doc.body ? doc.body.innerHTML : null;
|
$io.removeData('form-plugin-onload');
|
||||||
|
|
||||||
|
var ok = true;
|
||||||
|
try {
|
||||||
|
if (timedOut) {
|
||||||
|
throw 'timeout';
|
||||||
|
}
|
||||||
|
// extract the server response from the iframe
|
||||||
|
doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
|
||||||
|
|
||||||
|
var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
|
||||||
|
log('isXml='+isXml);
|
||||||
|
if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
|
||||||
|
if (--domCheckCount) {
|
||||||
|
// in some browsers (Opera) the iframe DOM is not always traversable when
|
||||||
|
// the onload callback fires, so we loop a bit to accommodate
|
||||||
|
log('requeing onLoad callback, DOM not available');
|
||||||
|
setTimeout(cb, 250);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// let this fall through because server response could be an empty document
|
||||||
|
//log('Could not access iframe DOM after mutiple tries.');
|
||||||
|
//throw 'DOMException: not available';
|
||||||
|
}
|
||||||
|
|
||||||
|
//log('response detected');
|
||||||
|
cbInvoked = true;
|
||||||
|
xhr.responseText = doc.documentElement ? doc.documentElement.innerHTML : null;
|
||||||
xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
|
xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
|
||||||
xhr.getResponseHeader = function(header){
|
xhr.getResponseHeader = function(header){
|
||||||
var headers = {'content-type': opts.dataType};
|
var headers = {'content-type': s.dataType};
|
||||||
return headers[header];
|
return headers[header];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (opts.dataType == 'json' || opts.dataType == 'script') {
|
var scr = /(json|script)/.test(s.dataType);
|
||||||
|
if (scr || s.textarea) {
|
||||||
|
// see if user embedded response in textarea
|
||||||
var ta = doc.getElementsByTagName('textarea')[0];
|
var ta = doc.getElementsByTagName('textarea')[0];
|
||||||
xhr.responseText = ta ? ta.value : xhr.responseText;
|
if (ta) {
|
||||||
|
xhr.responseText = ta.value;
|
||||||
}
|
}
|
||||||
else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
|
else if (scr) {
|
||||||
|
// account for browsers injecting pre around json response
|
||||||
|
var pre = doc.getElementsByTagName('pre')[0];
|
||||||
|
var b = doc.getElementsByTagName('body')[0];
|
||||||
|
if (pre) {
|
||||||
|
xhr.responseText = pre.innerHTML;
|
||||||
|
}
|
||||||
|
else if (b) {
|
||||||
|
xhr.responseText = b.innerHTML;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
|
||||||
xhr.responseXML = toXml(xhr.responseText);
|
xhr.responseXML = toXml(xhr.responseText);
|
||||||
}
|
}
|
||||||
data = $.httpData(xhr, opts.dataType);
|
data = $.httpData(xhr, s.dataType);
|
||||||
}
|
}
|
||||||
catch(e){
|
catch(e){
|
||||||
|
log('error caught:',e);
|
||||||
ok = false;
|
ok = false;
|
||||||
$.handleError(opts, xhr, 'error', e);
|
xhr.error = e;
|
||||||
|
$.handleError(s, xhr, 'error', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
|
// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
|
||||||
if (ok) {
|
if (ok) {
|
||||||
opts.success(data, 'success');
|
s.success.call(s.context, data, 'success', xhr);
|
||||||
if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
|
if (g) {
|
||||||
|
$.event.trigger("ajaxSuccess", [xhr, s]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (g) {
|
||||||
|
$.event.trigger("ajaxComplete", [xhr, s]);
|
||||||
|
}
|
||||||
|
if (g && ! --$.active) {
|
||||||
|
$.event.trigger("ajaxStop");
|
||||||
|
}
|
||||||
|
if (s.complete) {
|
||||||
|
s.complete.call(s.context, xhr, ok ? 'success' : 'error');
|
||||||
}
|
}
|
||||||
if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
|
|
||||||
if (g && ! --$.active) $.event.trigger("ajaxStop");
|
|
||||||
if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
|
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
|
$io.removeData('form-plugin-onload');
|
||||||
$io.remove();
|
$io.remove();
|
||||||
xhr.responseXML = null;
|
xhr.responseXML = null;
|
||||||
}, 100);
|
}, 100);
|
||||||
};
|
}
|
||||||
|
|
||||||
function toXml(s, doc) {
|
function toXml(s, doc) {
|
||||||
if (window.ActiveXObject) {
|
if (window.ActiveXObject) {
|
||||||
|
@ -327,11 +418,12 @@ $.fn.ajaxSubmit = function(options) {
|
||||||
doc.async = 'false';
|
doc.async = 'false';
|
||||||
doc.loadXML(s);
|
doc.loadXML(s);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
doc = (new DOMParser()).parseFromString(s, 'text/xml');
|
doc = (new DOMParser()).parseFromString(s, 'text/xml');
|
||||||
|
}
|
||||||
return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
|
return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -350,40 +442,60 @@ $.fn.ajaxSubmit = function(options) {
|
||||||
* the form itself.
|
* the form itself.
|
||||||
*/
|
*/
|
||||||
$.fn.ajaxForm = function(options) {
|
$.fn.ajaxForm = function(options) {
|
||||||
return this.ajaxFormUnbind().bind('submit.form-plugin',function() {
|
// in jQuery 1.3+ we can fix mistakes with the ready state
|
||||||
|
if (this.length === 0) {
|
||||||
|
var o = { s: this.selector, c: this.context };
|
||||||
|
if (!$.isReady && o.s) {
|
||||||
|
log('DOM not ready, queuing ajaxForm');
|
||||||
|
$(function() {
|
||||||
|
$(o.s,o.c).ajaxForm(options);
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
// is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
|
||||||
|
log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
|
||||||
|
if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
|
||||||
|
e.preventDefault();
|
||||||
$(this).ajaxSubmit(options);
|
$(this).ajaxSubmit(options);
|
||||||
return false;
|
}
|
||||||
}).each(function() {
|
}).bind('click.form-plugin', function(e) {
|
||||||
// store options in hash
|
var target = e.target;
|
||||||
$(":submit,input:image", this).bind('click.form-plugin',function(e) {
|
var $el = $(target);
|
||||||
var form = this.form;
|
if (!($el.is(":submit,input:image"))) {
|
||||||
form.clk = this;
|
// is this a child element of the submit el? (ex: a span within a button)
|
||||||
if (this.type == 'image') {
|
var t = $el.closest(':submit');
|
||||||
|
if (t.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
target = t[0];
|
||||||
|
}
|
||||||
|
var form = this;
|
||||||
|
form.clk = target;
|
||||||
|
if (target.type == 'image') {
|
||||||
if (e.offsetX != undefined) {
|
if (e.offsetX != undefined) {
|
||||||
form.clk_x = e.offsetX;
|
form.clk_x = e.offsetX;
|
||||||
form.clk_y = e.offsetY;
|
form.clk_y = e.offsetY;
|
||||||
} else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
|
} else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
|
||||||
var offset = $(this).offset();
|
var offset = $el.offset();
|
||||||
form.clk_x = e.pageX - offset.left;
|
form.clk_x = e.pageX - offset.left;
|
||||||
form.clk_y = e.pageY - offset.top;
|
form.clk_y = e.pageY - offset.top;
|
||||||
} else {
|
} else {
|
||||||
form.clk_x = e.pageX - this.offsetLeft;
|
form.clk_x = e.pageX - target.offsetLeft;
|
||||||
form.clk_y = e.pageY - this.offsetTop;
|
form.clk_y = e.pageY - target.offsetTop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// clear form vars
|
// clear form vars
|
||||||
setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 10);
|
setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
|
// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
|
||||||
$.fn.ajaxFormUnbind = function() {
|
$.fn.ajaxFormUnbind = function() {
|
||||||
this.unbind('submit.form-plugin');
|
return this.unbind('submit.form-plugin click.form-plugin');
|
||||||
return this.each(function() {
|
|
||||||
$(":submit,input:image", this).unbind('click.form-plugin');
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -399,39 +511,50 @@ $.fn.ajaxFormUnbind = function() {
|
||||||
*/
|
*/
|
||||||
$.fn.formToArray = function(semantic) {
|
$.fn.formToArray = function(semantic) {
|
||||||
var a = [];
|
var a = [];
|
||||||
if (this.length == 0) return a;
|
if (this.length === 0) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
var form = this[0];
|
var form = this[0];
|
||||||
var els = semantic ? form.getElementsByTagName('*') : form.elements;
|
var els = semantic ? form.getElementsByTagName('*') : form.elements;
|
||||||
if (!els) return a;
|
if (!els) {
|
||||||
for(var i=0, max=els.length; i < max; i++) {
|
return a;
|
||||||
var el = els[i];
|
}
|
||||||
var n = el.name;
|
|
||||||
if (!n) continue;
|
|
||||||
|
|
||||||
if (semantic && form.clk && el.type == "image") {
|
var i,j,n,v,el,max,jmax;
|
||||||
// handle image inputs on the fly when semantic == true
|
for(i=0, max=els.length; i < max; i++) {
|
||||||
if(!el.disabled && form.clk == el)
|
el = els[i];
|
||||||
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
n = el.name;
|
||||||
|
if (!n) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var v = $.fieldValue(el, true);
|
if (semantic && form.clk && el.type == "image") {
|
||||||
|
// handle image inputs on the fly when semantic == true
|
||||||
|
if(!el.disabled && form.clk == el) {
|
||||||
|
a.push({name: n, value: $(el).val()});
|
||||||
|
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = $.fieldValue(el, true);
|
||||||
if (v && v.constructor == Array) {
|
if (v && v.constructor == Array) {
|
||||||
for(var j=0, jmax=v.length; j < jmax; j++)
|
for(j=0, jmax=v.length; j < jmax; j++) {
|
||||||
a.push({name: n, value: v[j]});
|
a.push({name: n, value: v[j]});
|
||||||
}
|
}
|
||||||
else if (v !== null && typeof v != 'undefined')
|
}
|
||||||
|
else if (v !== null && typeof v != 'undefined') {
|
||||||
a.push({name: n, value: v});
|
a.push({name: n, value: v});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!semantic && form.clk) {
|
if (!semantic && form.clk) {
|
||||||
// input type=='image' are not found in elements array! handle them here
|
// input type=='image' are not found in elements array! handle it here
|
||||||
var inputs = form.getElementsByTagName("input");
|
var $input = $(form.clk), input = $input[0];
|
||||||
for(var i=0, max=inputs.length; i < max; i++) {
|
n = input.name;
|
||||||
var input = inputs[i];
|
if (n && !input.disabled && input.type == 'image') {
|
||||||
var n = input.name;
|
a.push({name: n, value: $input.val()});
|
||||||
if(n && !input.disabled && input.type == "image" && form.clk == input)
|
|
||||||
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,14 +578,18 @@ $.fn.fieldSerialize = function(successful) {
|
||||||
var a = [];
|
var a = [];
|
||||||
this.each(function() {
|
this.each(function() {
|
||||||
var n = this.name;
|
var n = this.name;
|
||||||
if (!n) return;
|
if (!n) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var v = $.fieldValue(this, successful);
|
var v = $.fieldValue(this, successful);
|
||||||
if (v && v.constructor == Array) {
|
if (v && v.constructor == Array) {
|
||||||
for (var i=0,max=v.length; i < max; i++)
|
for (var i=0,max=v.length; i < max; i++) {
|
||||||
a.push({name: n, value: v[i]});
|
a.push({name: n, value: v[i]});
|
||||||
}
|
}
|
||||||
else if (v !== null && typeof v != 'undefined')
|
}
|
||||||
|
else if (v !== null && typeof v != 'undefined') {
|
||||||
a.push({name: this.name, value: v});
|
a.push({name: this.name, value: v});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
//hand off to jQuery.param for proper encoding
|
//hand off to jQuery.param for proper encoding
|
||||||
return $.param(a);
|
return $.param(a);
|
||||||
|
@ -510,8 +637,9 @@ $.fn.fieldValue = function(successful) {
|
||||||
for (var val=[], i=0, max=this.length; i < max; i++) {
|
for (var val=[], i=0, max=this.length; i < max; i++) {
|
||||||
var el = this[i];
|
var el = this[i];
|
||||||
var v = $.fieldValue(el, successful);
|
var v = $.fieldValue(el, successful);
|
||||||
if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
|
if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
v.constructor == Array ? $.merge(val, v) : val.push(v);
|
v.constructor == Array ? $.merge(val, v) : val.push(v);
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
|
@ -522,32 +650,41 @@ $.fn.fieldValue = function(successful) {
|
||||||
*/
|
*/
|
||||||
$.fieldValue = function(el, successful) {
|
$.fieldValue = function(el, successful) {
|
||||||
var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
|
var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
|
||||||
if (typeof successful == 'undefined') successful = true;
|
if (successful === undefined) {
|
||||||
|
successful = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
|
if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
|
||||||
(t == 'checkbox' || t == 'radio') && !el.checked ||
|
(t == 'checkbox' || t == 'radio') && !el.checked ||
|
||||||
(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
|
(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
|
||||||
tag == 'select' && el.selectedIndex == -1))
|
tag == 'select' && el.selectedIndex == -1)) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (tag == 'select') {
|
if (tag == 'select') {
|
||||||
var index = el.selectedIndex;
|
var index = el.selectedIndex;
|
||||||
if (index < 0) return null;
|
if (index < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
var a = [], ops = el.options;
|
var a = [], ops = el.options;
|
||||||
var one = (t == 'select-one');
|
var one = (t == 'select-one');
|
||||||
var max = (one ? index+1 : ops.length);
|
var max = (one ? index+1 : ops.length);
|
||||||
for(var i=(one ? index : 0); i < max; i++) {
|
for(var i=(one ? index : 0); i < max; i++) {
|
||||||
var op = ops[i];
|
var op = ops[i];
|
||||||
if (op.selected) {
|
if (op.selected) {
|
||||||
// extra pain for IE...
|
var v = op.value;
|
||||||
var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
|
if (!v) { // extra pain for IE...
|
||||||
if (one) return v;
|
v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
|
||||||
|
}
|
||||||
|
if (one) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
a.push(v);
|
a.push(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
return el.value;
|
return $(el).val();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -570,12 +707,15 @@ $.fn.clearForm = function() {
|
||||||
$.fn.clearFields = $.fn.clearInputs = function() {
|
$.fn.clearFields = $.fn.clearInputs = function() {
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
var t = this.type, tag = this.tagName.toLowerCase();
|
var t = this.type, tag = this.tagName.toLowerCase();
|
||||||
if (t == 'file' || t == 'text' || t == 'password' || tag == 'textarea')
|
if (t == 'text' || t == 'password' || tag == 'textarea') {
|
||||||
this.value = '';
|
this.value = '';
|
||||||
else if (t == 'checkbox' || t == 'radio')
|
}
|
||||||
|
else if (t == 'checkbox' || t == 'radio') {
|
||||||
this.checked = false;
|
this.checked = false;
|
||||||
else if (tag == 'select')
|
}
|
||||||
|
else if (tag == 'select') {
|
||||||
this.selectedIndex = -1;
|
this.selectedIndex = -1;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -586,8 +726,9 @@ $.fn.resetForm = function() {
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
// guard against an input with the name of 'reset'
|
// guard against an input with the name of 'reset'
|
||||||
// note that IE reports the reset function as an 'object'
|
// note that IE reports the reset function as an 'object'
|
||||||
if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
|
if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
|
||||||
this.reset();
|
this.reset();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -595,9 +736,11 @@ $.fn.resetForm = function() {
|
||||||
* Enables or disables any matching elements.
|
* Enables or disables any matching elements.
|
||||||
*/
|
*/
|
||||||
$.fn.enable = function(b) {
|
$.fn.enable = function(b) {
|
||||||
if (b == undefined) b = true;
|
if (b === undefined) {
|
||||||
|
b = true;
|
||||||
|
}
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
this.disabled = !b
|
this.disabled = !b;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -606,11 +749,14 @@ $.fn.enable = function(b) {
|
||||||
* selects/deselects and matching option elements.
|
* selects/deselects and matching option elements.
|
||||||
*/
|
*/
|
||||||
$.fn.selected = function(select) {
|
$.fn.selected = function(select) {
|
||||||
if (select == undefined) select = true;
|
if (select === undefined) {
|
||||||
|
select = true;
|
||||||
|
}
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
var t = this.type;
|
var t = this.type;
|
||||||
if (t == 'checkbox' || t == 'radio')
|
if (t == 'checkbox' || t == 'radio') {
|
||||||
this.checked = select;
|
this.checked = select;
|
||||||
|
}
|
||||||
else if (this.tagName.toLowerCase() == 'option') {
|
else if (this.tagName.toLowerCase() == 'option') {
|
||||||
var $sel = $(this).parent('select');
|
var $sel = $(this).parent('select');
|
||||||
if (select && $sel[0] && $sel[0].type == 'select-one') {
|
if (select && $sel[0] && $sel[0].type == 'select-one') {
|
||||||
|
@ -625,8 +771,15 @@ $.fn.selected = function(select) {
|
||||||
// helper fn for console logging
|
// helper fn for console logging
|
||||||
// set $.fn.ajaxSubmit.debug to true to enable debug logging
|
// set $.fn.ajaxSubmit.debug to true to enable debug logging
|
||||||
function log() {
|
function log() {
|
||||||
if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
|
if ($.fn.ajaxSubmit.debug) {
|
||||||
window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
|
var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
|
||||||
|
if (window.console && window.console.log) {
|
||||||
|
window.console.log(msg);
|
||||||
|
}
|
||||||
|
else if (window.opera && window.opera.postError) {
|
||||||
|
window.opera.postError(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
|
|
11
js/jquery.form.min.js
vendored
Normal file
11
js/jquery.form.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2750
js/jquery.js
vendored
2750
js/jquery.js
vendored
File diff suppressed because it is too large
Load Diff
292
js/jquery.min.js
vendored
292
js/jquery.min.js
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*!
|
/*!
|
||||||
* jQuery JavaScript Library v1.4.2
|
* jQuery JavaScript Library v1.4.4
|
||||||
* http://jquery.com/
|
* http://jquery.com/
|
||||||
*
|
*
|
||||||
* Copyright 2010, John Resig
|
* Copyright 2010, John Resig
|
||||||
|
@ -11,145 +11,157 @@
|
||||||
* Copyright 2010, The Dojo Foundation
|
* Copyright 2010, The Dojo Foundation
|
||||||
* Released under the MIT, BSD, and GPL Licenses.
|
* Released under the MIT, BSD, and GPL Licenses.
|
||||||
*
|
*
|
||||||
* Date: Sat Feb 13 22:33:48 2010 -0500
|
* Date: Thu Nov 11 19:04:53 2010 -0500
|
||||||
*/
|
*/
|
||||||
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
|
(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h=
|
||||||
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
|
h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,"")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType==="mouseenter"||
|
||||||
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
|
h.preType==="mouseleave"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La,
|
||||||
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
|
"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,
|
||||||
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
|
e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,
|
||||||
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
|
"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+
|
||||||
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
|
a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,
|
||||||
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
|
C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j,
|
||||||
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
|
s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,
|
||||||
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
|
j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length},
|
||||||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
|
toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j===
|
||||||
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
|
-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false;
|
||||||
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
|
if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--;
|
||||||
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
|
if(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload",
|
||||||
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
|
b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&&
|
||||||
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
|
!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&&
|
||||||
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
|
l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z],
|
||||||
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
|
z,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?"":O.call(j)}:function(j){return j==null?"":j.toString().replace(k,"").replace(o,"")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z==="string"||z==="function"||z==="regexp"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j,
|
||||||
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
|
s){var v=j.length,z=0;if(typeof s.length==="number")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s==="string"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v=
|
||||||
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
|
s;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s==="object"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf("compatible")<0&&n.exec(j)||
|
||||||
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
|
[];return{browser:j[1]||"",version:j[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(j,s){R["[object "+s+"]"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\s/.test("\u00a0")){k=/^[\s\xA0]+/;o=/[\s\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener("DOMContentLoaded",u,
|
||||||
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
|
false);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState==="complete"){t.detachEvent("onreadystatechange",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement("script"),d=t.createElement("div"),e="script"+c.now();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"),
|
||||||
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
|
k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false,
|
||||||
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
|
scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent=
|
||||||
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
|
false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom=
|
||||||
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
|
1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display=
|
||||||
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
|
"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h=
|
||||||
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
|
c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);
|
||||||
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
|
else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf("data-")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a==="object")return this.each(function(){c.data(this,
|
||||||
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
|
a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(b===B){d=this.triggerHandler("getData"+k[1]+"!",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler("setData"+k[1]+"!",x);c.data(this,a,b);o.triggerHandler("changeData"+k[1]+"!",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var e=
|
||||||
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
|
c.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,
|
||||||
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
|
a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var sa=/[\n\t]/g,ha=/\s+/,Sa=/\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",
|
||||||
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
|
colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===
|
||||||
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
|
1)if(f.className){for(var h=" "+f.className+" ",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(" "+b[k]+" ")<0)l+=" "+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr("class")))});if(a&&typeof a==="string"||a===B)for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(sa," "),
|
||||||
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
|
l=0,k=b.length;l<k;l++)h=h.replace(" "+b[l]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?"addClass":"removeClass"](f)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,
|
||||||
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
|
"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(sa," ").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";
|
||||||
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
|
if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute("disabled")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,"optgroup"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Sa,"")}return B}var k=c.isFunction(a);return this.each(function(o){var x=c(this),r=a;if(this.nodeType===1){if(k)r=
|
||||||
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
|
a.call(this,o,x.val());if(r==null)r="";else if(typeof r==="number")r+="";else if(c.isArray(r))r=c.map(r,function(C){return C==null?"":C+""});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},
|
||||||
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
|
attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&
|
||||||
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
|
b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0};
|
||||||
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
|
c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,
|
||||||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
|
arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid=
|
||||||
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
|
d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+
|
||||||
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
|
c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b=
|
||||||
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
|
w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===
|
||||||
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
|
8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k===
|
||||||
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
|
"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+
|
||||||
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
|
d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
|
||||||
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
|
fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
|
||||||
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
|
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,
|
||||||
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
|
Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=
|
||||||
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
|
c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};
|
||||||
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
|
var va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!==
|
||||||
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
|
"form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length){a.liveFired=B;return la("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=B;return la("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V,
|
||||||
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
|
xa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired=
|
||||||
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
|
B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type===
|
||||||
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
|
"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]===
|
||||||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
|
0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d,
|
||||||
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
|
a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=
|
||||||
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
|
1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d===
|
||||||
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
|
"object"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=e;e=B}for(d=(d||"").split(" ");(l=d[k++])!=null;){o=X.exec(l);x="";if(o){x=o[0];l=l.replace(X,"")}if(l==="hover")d.push("mouseenter"+x,"mouseleave"+x);else{o=l;if(l==="focus"||l==="blur"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b==="live"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],"live."+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind("live."+Y(l,r),f)}}return this}});
|
||||||
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
|
c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
|
||||||
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
|
(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!=="string"){if(y===i){F=true;break}}else if(k.filter(i,
|
||||||
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
|
[y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3];
|
||||||
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
|
break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr,
|
||||||
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
|
q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h=
|
||||||
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
|
l;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!=="\\"){u[1]=(u[1]||"").replace(/\\/g,"");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],"");break}}}}m||(m=i.getElementsByTagName("*"));
|
||||||
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
|
return{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!==
|
||||||
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
|
B){n||(F=y);g=g.replace(o.match[N],"");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var o=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
|
||||||
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
|
POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,i){var n=typeof i==="string",m=n&&!/\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()===
|
||||||
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
|
i?q||false:q===i}n&&k.filter(i,g,true)},">":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},"":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=i=i.toLowerCase();q=a}q("parentNode",i,p,g,m,n)},"~":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=
|
||||||
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
|
i=i.toLowerCase();q=a}q("previousSibling",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!=="undefined"&&!n)return(g=i.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!=="undefined"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=" "+g[1].replace(/\\/g,
|
||||||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
|
"")+" ";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n,
|
||||||
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
|
m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===
|
||||||
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
|
true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===
|
||||||
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
|
g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]-
|
||||||
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
|
0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n===
|
||||||
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
|
"first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===
|
||||||
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
|
i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]];
|
||||||
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
|
if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m,
|
||||||
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
|
g);else if(typeof g.length==="number")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1;
|
||||||
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
|
for(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i="",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement("div"),
|
||||||
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
|
i="script"+(new Date).getTime(),n=t.documentElement;g.innerHTML="<a name='"+i+"'/>";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g);
|
||||||
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
|
n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&&
|
||||||
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
|
function(){var g=k,i=t.createElement("div");i.innerHTML="<p class='TEST'></p>";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F||
|
||||||
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
|
p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g=
|
||||||
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
|
t.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition?
|
||||||
|
function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML;
|
||||||
|
c.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\[\.,]*$/,bb=Array.prototype.slice,cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},
|
||||||
|
not:function(a){return this.pushStack(ma(this,a,false),"not",a)},filter:function(a){return this.pushStack(ma(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h=
|
||||||
|
h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context):
|
||||||
|
c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,
|
||||||
|
2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,
|
||||||
|
b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&
|
||||||
|
e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/<tbody/i,eb=/<|&#?\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/\=([^="'>\s]+\/)>/g,P={option:[1,
|
||||||
|
"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
|
||||||
|
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
|
||||||
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
|
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
|
||||||
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
|
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
|
||||||
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
|
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
|
||||||
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
|
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null;
|
||||||
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
|
else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=
|
||||||
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
|
c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l==="string"&&Da.test(l))return this.each(function(){c(this).domManip(a,
|
||||||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
|
b,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")):
|
||||||
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
|
this[f]:this[f],f>0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",
|
||||||
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
|
prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument||
|
||||||
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
|
b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1></$2>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]==="<table>"&&!x?r.childNodes:[];for(o=k.length-
|
||||||
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
|
1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));
|
||||||
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
|
d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i,
|
||||||
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
|
jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,
|
||||||
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
|
zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),
|
||||||
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
|
h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b);
|
||||||
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
|
if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=
|
||||||
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
|
d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left;
|
||||||
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
|
e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
||||||
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
|
ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b===
|
||||||
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
|
"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("<div>").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&
|
||||||
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
|
!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})},
|
||||||
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
|
getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html",
|
||||||
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
|
script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data||
|
||||||
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
|
!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache=
|
||||||
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
|
false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset;
|
||||||
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
|
A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type",
|
||||||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
|
b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&&
|
||||||
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
|
c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d||
|
||||||
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
|
c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]=
|
||||||
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
|
encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",
|
||||||
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
|
[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),
|
||||||
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
|
e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});
|
||||||
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
|
if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",
|
||||||
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
|
3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,"olddisplay")&&b==="none")b=a.style.display="";b===""&&c.css(a,"display")==="none"&&c.data(a,"olddisplay",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===""||b==="none")a.style.display=c.data(a,"olddisplay")||""}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay",
|
||||||
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
|
d)}for(a=0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,
|
||||||
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
|
d,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(":hidden"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]==="hide"&&o||a[l]==="show"&&!o)return h.complete.call(this);if(k&&(l==="height"||l==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)===
|
||||||
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
|
"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C==="toggle"?o?"show":"hide":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(x,A,(L||1)+g);I=(L||
|
||||||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
|
1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]==="-="?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,
|
||||||
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
|
d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*
|
||||||
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
|
Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)}
|
||||||
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
|
var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;
|
||||||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
|
this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||
|
||||||
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
|
this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=
|
||||||
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
|
c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===
|
||||||
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
|
b.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&
|
||||||
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
|
h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle;
|
||||||
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
|
for(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position==="fixed")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"){k+=
|
||||||
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
|
parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position==="relative"||d.position==="static"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position==="fixed"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",
|
||||||
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
|
height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=
|
||||||
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
|
f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,
|
||||||
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
|
"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),l=c.css(a,"top"),k=c.css(a,"left"),o=e==="absolute"&&c.inArray("auto",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a,
|
||||||
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
|
e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&&
|
||||||
|
c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();
|
||||||
|
c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+
|
||||||
|
b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window);
|
||||||
|
|
483
js/json2.js
483
js/json2.js
|
@ -1,4 +1,483 @@
|
||||||
|
alert('IMPORTANT: Remove this line from json2.js before deployment.');
|
||||||
/*
|
/*
|
||||||
http://www.JSON.org/json2.js minified
|
http://www.JSON.org/json2.js
|
||||||
|
2010-08-25
|
||||||
|
|
||||||
|
Public Domain.
|
||||||
|
|
||||||
|
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||||
|
|
||||||
|
See http://www.JSON.org/js.html
|
||||||
|
|
||||||
|
|
||||||
|
This code should be minified before deployment.
|
||||||
|
See http://javascript.crockford.com/jsmin.html
|
||||||
|
|
||||||
|
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||||
|
NOT CONTROL.
|
||||||
|
|
||||||
|
|
||||||
|
This file creates a global JSON object containing two methods: stringify
|
||||||
|
and parse.
|
||||||
|
|
||||||
|
JSON.stringify(value, replacer, space)
|
||||||
|
value any JavaScript value, usually an object or array.
|
||||||
|
|
||||||
|
replacer an optional parameter that determines how object
|
||||||
|
values are stringified for objects. It can be a
|
||||||
|
function or an array of strings.
|
||||||
|
|
||||||
|
space an optional parameter that specifies the indentation
|
||||||
|
of nested structures. If it is omitted, the text will
|
||||||
|
be packed without extra whitespace. If it is a number,
|
||||||
|
it will specify the number of spaces to indent at each
|
||||||
|
level. If it is a string (such as '\t' or ' '),
|
||||||
|
it contains the characters used to indent at each level.
|
||||||
|
|
||||||
|
This method produces a JSON text from a JavaScript value.
|
||||||
|
|
||||||
|
When an object value is found, if the object contains a toJSON
|
||||||
|
method, its toJSON method will be called and the result will be
|
||||||
|
stringified. A toJSON method does not serialize: it returns the
|
||||||
|
value represented by the name/value pair that should be serialized,
|
||||||
|
or undefined if nothing should be serialized. The toJSON method
|
||||||
|
will be passed the key associated with the value, and this will be
|
||||||
|
bound to the value
|
||||||
|
|
||||||
|
For example, this would serialize Dates as ISO strings.
|
||||||
|
|
||||||
|
Date.prototype.toJSON = function (key) {
|
||||||
|
function f(n) {
|
||||||
|
// Format integers to have at least two digits.
|
||||||
|
return n < 10 ? '0' + n : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getUTCFullYear() + '-' +
|
||||||
|
f(this.getUTCMonth() + 1) + '-' +
|
||||||
|
f(this.getUTCDate()) + 'T' +
|
||||||
|
f(this.getUTCHours()) + ':' +
|
||||||
|
f(this.getUTCMinutes()) + ':' +
|
||||||
|
f(this.getUTCSeconds()) + 'Z';
|
||||||
|
};
|
||||||
|
|
||||||
|
You can provide an optional replacer method. It will be passed the
|
||||||
|
key and value of each member, with this bound to the containing
|
||||||
|
object. The value that is returned from your method will be
|
||||||
|
serialized. If your method returns undefined, then the member will
|
||||||
|
be excluded from the serialization.
|
||||||
|
|
||||||
|
If the replacer parameter is an array of strings, then it will be
|
||||||
|
used to select the members to be serialized. It filters the results
|
||||||
|
such that only members with keys listed in the replacer array are
|
||||||
|
stringified.
|
||||||
|
|
||||||
|
Values that do not have JSON representations, such as undefined or
|
||||||
|
functions, will not be serialized. Such values in objects will be
|
||||||
|
dropped; in arrays they will be replaced with null. You can use
|
||||||
|
a replacer function to replace those with JSON values.
|
||||||
|
JSON.stringify(undefined) returns undefined.
|
||||||
|
|
||||||
|
The optional space parameter produces a stringification of the
|
||||||
|
value that is filled with line breaks and indentation to make it
|
||||||
|
easier to read.
|
||||||
|
|
||||||
|
If the space parameter is a non-empty string, then that string will
|
||||||
|
be used for indentation. If the space parameter is a number, then
|
||||||
|
the indentation will be that many spaces.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||||
|
// text is '["e",{"pluribus":"unum"}]'
|
||||||
|
|
||||||
|
|
||||||
|
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
|
||||||
|
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
|
||||||
|
|
||||||
|
text = JSON.stringify([new Date()], function (key, value) {
|
||||||
|
return this[key] instanceof Date ?
|
||||||
|
'Date(' + this[key] + ')' : value;
|
||||||
|
});
|
||||||
|
// text is '["Date(---current time---)"]'
|
||||||
|
|
||||||
|
|
||||||
|
JSON.parse(text, reviver)
|
||||||
|
This method parses a JSON text to produce an object or array.
|
||||||
|
It can throw a SyntaxError exception.
|
||||||
|
|
||||||
|
The optional reviver parameter is a function that can filter and
|
||||||
|
transform the results. It receives each of the keys and values,
|
||||||
|
and its return value is used instead of the original value.
|
||||||
|
If it returns what it received, then the structure is not modified.
|
||||||
|
If it returns undefined then the member is deleted.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
// Parse the text. Values that look like ISO date strings will
|
||||||
|
// be converted to Date objects.
|
||||||
|
|
||||||
|
myData = JSON.parse(text, function (key, value) {
|
||||||
|
var a;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
a =
|
||||||
|
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||||
|
if (a) {
|
||||||
|
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||||
|
+a[5], +a[6]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
|
||||||
|
var d;
|
||||||
|
if (typeof value === 'string' &&
|
||||||
|
value.slice(0, 5) === 'Date(' &&
|
||||||
|
value.slice(-1) === ')') {
|
||||||
|
d = new Date(value.slice(5, -1));
|
||||||
|
if (d) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
This is a reference implementation. You are free to copy, modify, or
|
||||||
|
redistribute.
|
||||||
*/
|
*/
|
||||||
if(!this.JSON){JSON={};}(function(){function f(n){return n<10?'0'+n:n;}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z';};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}if(typeof rep==='function'){value=rep.call(holder,key,value);}switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}v=partial.length===0?'[]':gap?'[\n'+gap+partial.join(',\n'+gap)+'\n'+mind+']':'['+partial.join(',')+']';gap=mind;return v;}if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}return str('',{'':value});};}if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}return reviver.call(holder,key,value);}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}throw new SyntaxError('JSON.parse');};}}());
|
|
||||||
|
/*jslint evil: true, strict: false */
|
||||||
|
|
||||||
|
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
|
||||||
|
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
||||||
|
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
||||||
|
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
||||||
|
test, toJSON, toString, valueOf
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Create a JSON object only if one does not already exist. We create the
|
||||||
|
// methods in a closure to avoid creating global variables.
|
||||||
|
|
||||||
|
if (!this.JSON) {
|
||||||
|
this.JSON = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
function f(n) {
|
||||||
|
// Format integers to have at least two digits.
|
||||||
|
return n < 10 ? '0' + n : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof Date.prototype.toJSON !== 'function') {
|
||||||
|
|
||||||
|
Date.prototype.toJSON = function (key) {
|
||||||
|
|
||||||
|
return isFinite(this.valueOf()) ?
|
||||||
|
this.getUTCFullYear() + '-' +
|
||||||
|
f(this.getUTCMonth() + 1) + '-' +
|
||||||
|
f(this.getUTCDate()) + 'T' +
|
||||||
|
f(this.getUTCHours()) + ':' +
|
||||||
|
f(this.getUTCMinutes()) + ':' +
|
||||||
|
f(this.getUTCSeconds()) + 'Z' : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
String.prototype.toJSON =
|
||||||
|
Number.prototype.toJSON =
|
||||||
|
Boolean.prototype.toJSON = function (key) {
|
||||||
|
return this.valueOf();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||||
|
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||||
|
gap,
|
||||||
|
indent,
|
||||||
|
meta = { // table of character substitutions
|
||||||
|
'\b': '\\b',
|
||||||
|
'\t': '\\t',
|
||||||
|
'\n': '\\n',
|
||||||
|
'\f': '\\f',
|
||||||
|
'\r': '\\r',
|
||||||
|
'"' : '\\"',
|
||||||
|
'\\': '\\\\'
|
||||||
|
},
|
||||||
|
rep;
|
||||||
|
|
||||||
|
|
||||||
|
function quote(string) {
|
||||||
|
|
||||||
|
// If the string contains no control characters, no quote characters, and no
|
||||||
|
// backslash characters, then we can safely slap some quotes around it.
|
||||||
|
// Otherwise we must also replace the offending characters with safe escape
|
||||||
|
// sequences.
|
||||||
|
|
||||||
|
escapable.lastIndex = 0;
|
||||||
|
return escapable.test(string) ?
|
||||||
|
'"' + string.replace(escapable, function (a) {
|
||||||
|
var c = meta[a];
|
||||||
|
return typeof c === 'string' ? c :
|
||||||
|
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||||
|
}) + '"' :
|
||||||
|
'"' + string + '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function str(key, holder) {
|
||||||
|
|
||||||
|
// Produce a string from holder[key].
|
||||||
|
|
||||||
|
var i, // The loop counter.
|
||||||
|
k, // The member key.
|
||||||
|
v, // The member value.
|
||||||
|
length,
|
||||||
|
mind = gap,
|
||||||
|
partial,
|
||||||
|
value = holder[key];
|
||||||
|
|
||||||
|
// If the value has a toJSON method, call it to obtain a replacement value.
|
||||||
|
|
||||||
|
if (value && typeof value === 'object' &&
|
||||||
|
typeof value.toJSON === 'function') {
|
||||||
|
value = value.toJSON(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we were called with a replacer function, then call the replacer to
|
||||||
|
// obtain a replacement value.
|
||||||
|
|
||||||
|
if (typeof rep === 'function') {
|
||||||
|
value = rep.call(holder, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// What happens next depends on the value's type.
|
||||||
|
|
||||||
|
switch (typeof value) {
|
||||||
|
case 'string':
|
||||||
|
return quote(value);
|
||||||
|
|
||||||
|
case 'number':
|
||||||
|
|
||||||
|
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||||
|
|
||||||
|
return isFinite(value) ? String(value) : 'null';
|
||||||
|
|
||||||
|
case 'boolean':
|
||||||
|
case 'null':
|
||||||
|
|
||||||
|
// If the value is a boolean or null, convert it to a string. Note:
|
||||||
|
// typeof null does not produce 'null'. The case is included here in
|
||||||
|
// the remote chance that this gets fixed someday.
|
||||||
|
|
||||||
|
return String(value);
|
||||||
|
|
||||||
|
// If the type is 'object', we might be dealing with an object or an array or
|
||||||
|
// null.
|
||||||
|
|
||||||
|
case 'object':
|
||||||
|
|
||||||
|
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||||
|
// so watch out for that case.
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make an array to hold the partial results of stringifying this object value.
|
||||||
|
|
||||||
|
gap += indent;
|
||||||
|
partial = [];
|
||||||
|
|
||||||
|
// Is the value an array?
|
||||||
|
|
||||||
|
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||||
|
|
||||||
|
// The value is an array. Stringify every element. Use null as a placeholder
|
||||||
|
// for non-JSON values.
|
||||||
|
|
||||||
|
length = value.length;
|
||||||
|
for (i = 0; i < length; i += 1) {
|
||||||
|
partial[i] = str(i, value) || 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all of the elements together, separated with commas, and wrap them in
|
||||||
|
// brackets.
|
||||||
|
|
||||||
|
v = partial.length === 0 ? '[]' :
|
||||||
|
gap ? '[\n' + gap +
|
||||||
|
partial.join(',\n' + gap) + '\n' +
|
||||||
|
mind + ']' :
|
||||||
|
'[' + partial.join(',') + ']';
|
||||||
|
gap = mind;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the replacer is an array, use it to select the members to be stringified.
|
||||||
|
|
||||||
|
if (rep && typeof rep === 'object') {
|
||||||
|
length = rep.length;
|
||||||
|
for (i = 0; i < length; i += 1) {
|
||||||
|
k = rep[i];
|
||||||
|
if (typeof k === 'string') {
|
||||||
|
v = str(k, value);
|
||||||
|
if (v) {
|
||||||
|
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Otherwise, iterate through all of the keys in the object.
|
||||||
|
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.hasOwnProperty.call(value, k)) {
|
||||||
|
v = str(k, value);
|
||||||
|
if (v) {
|
||||||
|
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all of the member texts together, separated with commas,
|
||||||
|
// and wrap them in braces.
|
||||||
|
|
||||||
|
v = partial.length === 0 ? '{}' :
|
||||||
|
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
|
||||||
|
mind + '}' : '{' + partial.join(',') + '}';
|
||||||
|
gap = mind;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the JSON object does not yet have a stringify method, give it one.
|
||||||
|
|
||||||
|
if (typeof JSON.stringify !== 'function') {
|
||||||
|
JSON.stringify = function (value, replacer, space) {
|
||||||
|
|
||||||
|
// The stringify method takes a value and an optional replacer, and an optional
|
||||||
|
// space parameter, and returns a JSON text. The replacer can be a function
|
||||||
|
// that can replace values, or an array of strings that will select the keys.
|
||||||
|
// A default replacer method can be provided. Use of the space parameter can
|
||||||
|
// produce text that is more easily readable.
|
||||||
|
|
||||||
|
var i;
|
||||||
|
gap = '';
|
||||||
|
indent = '';
|
||||||
|
|
||||||
|
// If the space parameter is a number, make an indent string containing that
|
||||||
|
// many spaces.
|
||||||
|
|
||||||
|
if (typeof space === 'number') {
|
||||||
|
for (i = 0; i < space; i += 1) {
|
||||||
|
indent += ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the space parameter is a string, it will be used as the indent string.
|
||||||
|
|
||||||
|
} else if (typeof space === 'string') {
|
||||||
|
indent = space;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a replacer, it must be a function or an array.
|
||||||
|
// Otherwise, throw an error.
|
||||||
|
|
||||||
|
rep = replacer;
|
||||||
|
if (replacer && typeof replacer !== 'function' &&
|
||||||
|
(typeof replacer !== 'object' ||
|
||||||
|
typeof replacer.length !== 'number')) {
|
||||||
|
throw new Error('JSON.stringify');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a fake root object containing our value under the key of ''.
|
||||||
|
// Return the result of stringifying the value.
|
||||||
|
|
||||||
|
return str('', {'': value});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If the JSON object does not yet have a parse method, give it one.
|
||||||
|
|
||||||
|
if (typeof JSON.parse !== 'function') {
|
||||||
|
JSON.parse = function (text, reviver) {
|
||||||
|
|
||||||
|
// The parse method takes a text and an optional reviver function, and returns
|
||||||
|
// a JavaScript value if the text is a valid JSON text.
|
||||||
|
|
||||||
|
var j;
|
||||||
|
|
||||||
|
function walk(holder, key) {
|
||||||
|
|
||||||
|
// The walk method is used to recursively walk the resulting structure so
|
||||||
|
// that modifications can be made.
|
||||||
|
|
||||||
|
var k, v, value = holder[key];
|
||||||
|
if (value && typeof value === 'object') {
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.hasOwnProperty.call(value, k)) {
|
||||||
|
v = walk(value, k);
|
||||||
|
if (v !== undefined) {
|
||||||
|
value[k] = v;
|
||||||
|
} else {
|
||||||
|
delete value[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reviver.call(holder, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Parsing happens in four stages. In the first stage, we replace certain
|
||||||
|
// Unicode characters with escape sequences. JavaScript handles many characters
|
||||||
|
// incorrectly, either silently deleting them, or treating them as line endings.
|
||||||
|
|
||||||
|
text = String(text);
|
||||||
|
cx.lastIndex = 0;
|
||||||
|
if (cx.test(text)) {
|
||||||
|
text = text.replace(cx, function (a) {
|
||||||
|
return '\\u' +
|
||||||
|
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the second stage, we run the text against regular expressions that look
|
||||||
|
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
||||||
|
// because they can cause invocation, and '=' because it can cause mutation.
|
||||||
|
// But just to be safe, we want to reject all unexpected forms.
|
||||||
|
|
||||||
|
// We split the second stage into 4 regexp operations in order to work around
|
||||||
|
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||||
|
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
||||||
|
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||||
|
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||||
|
// we look to see that the remaining characters are only whitespace or ']' or
|
||||||
|
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||||
|
|
||||||
|
if (/^[\],:{}\s]*$/
|
||||||
|
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
|
||||||
|
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
|
||||||
|
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||||
|
|
||||||
|
// In the third stage we use the eval function to compile the text into a
|
||||||
|
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||||
|
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||||
|
// in parens to eliminate the ambiguity.
|
||||||
|
|
||||||
|
j = eval('(' + text + ')');
|
||||||
|
|
||||||
|
// In the optional fourth stage, we recursively walk the new structure, passing
|
||||||
|
// each name/value pair to a reviver function for possible transformation.
|
||||||
|
|
||||||
|
return typeof reviver === 'function' ?
|
||||||
|
walk({'': j}, '') : j;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||||
|
|
||||||
|
throw new SyntaxError('JSON.parse');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
|
1
js/json2.min.js
vendored
Normal file
1
js/json2.min.js
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
alert("IMPORTANT: Remove this line from json2.js before deployment.");if(!this.JSON){this.JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}());
|
166
js/util.js
166
js/util.js
|
@ -56,7 +56,7 @@ var SN = { // StatusNet
|
||||||
NoticeDataGeoCookie: 'NoticeDataGeo',
|
NoticeDataGeoCookie: 'NoticeDataGeo',
|
||||||
NoticeDataGeoSelected: 'notice_data-geo_selected',
|
NoticeDataGeoSelected: 'notice_data-geo_selected',
|
||||||
StatusNetInstance:'StatusNetInstance'
|
StatusNetInstance:'StatusNetInstance'
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
messages: {},
|
messages: {},
|
||||||
|
@ -236,8 +236,9 @@ var SN = { // StatusNet
|
||||||
form.append('<p class="form_response error">Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists.</p>');
|
form.append('<p class="form_response error">Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists.</p>');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ($('.'+SN.C.S.Error, xhr.responseXML).length > 0) {
|
var response = SN.U.GetResponseXML(xhr);
|
||||||
form.append(document._importNode($('.'+SN.C.S.Error, xhr.responseXML)[0], true));
|
if ($('.'+SN.C.S.Error, response).length > 0) {
|
||||||
|
form.append(document._importNode($('.'+SN.C.S.Error, response)[0], true));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (parseInt(xhr.status) === 0 || jQuery.inArray(parseInt(xhr.status), SN.C.I.HTTP20x30x) >= 0) {
|
if (parseInt(xhr.status) === 0 || jQuery.inArray(parseInt(xhr.status), SN.C.I.HTTP20x30x) >= 0) {
|
||||||
|
@ -326,6 +327,16 @@ var SN = { // StatusNet
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
GetResponseXML: function(xhr) {
|
||||||
|
// Work around unavailable responseXML when document.domain
|
||||||
|
// has been modified by Meteor or other tools.
|
||||||
|
try {
|
||||||
|
return xhr.responseXML;
|
||||||
|
} catch (e) {
|
||||||
|
return (new DOMParser()).parseFromString(xhr.responseText, "text/xml");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
NoticeReply: function() {
|
NoticeReply: function() {
|
||||||
if ($('#'+SN.C.S.NoticeDataText).length > 0 && $('#content .notice_reply').length > 0) {
|
if ($('#'+SN.C.S.NoticeDataText).length > 0 && $('#content .notice_reply').length > 0) {
|
||||||
$('#content .notice').each(function() { SN.U.NoticeReplyTo($(this)); });
|
$('#content .notice').each(function() { SN.U.NoticeReplyTo($(this)); });
|
||||||
|
@ -427,61 +438,6 @@ var SN = { // StatusNet
|
||||||
return false;
|
return false;
|
||||||
}).attr('title', SN.msg('showmore_tooltip'));
|
}).attr('title', SN.msg('showmore_tooltip'));
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
$.fn.jOverlay.options = {
|
|
||||||
method : 'GET',
|
|
||||||
data : '',
|
|
||||||
url : '',
|
|
||||||
color : '#000',
|
|
||||||
opacity : '0.6',
|
|
||||||
zIndex : 9999,
|
|
||||||
center : false,
|
|
||||||
imgLoading : $('address .url')[0].href+'theme/base/images/illustrations/illu_progress_loading-01.gif',
|
|
||||||
bgClickToClose : true,
|
|
||||||
success : function() {
|
|
||||||
$('#jOverlayContent').append('<button class="close">×</button>');
|
|
||||||
$('#jOverlayContent button').click($.closeOverlay);
|
|
||||||
},
|
|
||||||
timeout : 0,
|
|
||||||
autoHide : true,
|
|
||||||
css : {'max-width':'542px', 'top':'5%', 'left':'32.5%'}
|
|
||||||
};
|
|
||||||
|
|
||||||
notice.find('a.attachment').click(function() {
|
|
||||||
var attachId = ($(this).attr('id').substring('attachment'.length + 1));
|
|
||||||
if (attachId) {
|
|
||||||
$().jOverlay({url: $('address .url')[0].href+'attachment/' + attachId + '/ajax'});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if ($('#shownotice').length == 0) {
|
|
||||||
var t;
|
|
||||||
notice.find('a.thumbnail').hover(
|
|
||||||
function() {
|
|
||||||
var anchor = $(this);
|
|
||||||
$('a.thumbnail').children('img').hide();
|
|
||||||
anchor.closest(".entry-title").addClass('ov');
|
|
||||||
|
|
||||||
if (anchor.children('img').length === 0) {
|
|
||||||
t = setTimeout(function() {
|
|
||||||
$.get($('address .url')[0].href+'attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) {
|
|
||||||
anchor.append(data);
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
anchor.children('img').show();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
clearTimeout(t);
|
|
||||||
$('a.thumbnail').children('img').hide();
|
|
||||||
$(this).closest('.entry-title').removeClass('ov');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
NoticeDataAttach: function() {
|
NoticeDataAttach: function() {
|
||||||
|
@ -501,9 +457,103 @@ var SN = { // StatusNet
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
if (typeof this.files == "object") {
|
||||||
|
// Some newer browsers will let us fetch the files for preview.
|
||||||
|
for (var i = 0; i < this.files.length; i++) {
|
||||||
|
SN.U.PreviewAttach(this.files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For browsers with FileAPI support: make a thumbnail if possible,
|
||||||
|
* and append it into the attachment display widget.
|
||||||
|
*
|
||||||
|
* Known good:
|
||||||
|
* - Firefox 3.6.6, 4.0b7
|
||||||
|
* - Chrome 8.0.552.210
|
||||||
|
*
|
||||||
|
* Known ok metadata, can't get contents:
|
||||||
|
* - Safari 5.0.2
|
||||||
|
*
|
||||||
|
* Known fail:
|
||||||
|
* - Opera 10.63, 11 beta (no input.files interface)
|
||||||
|
*
|
||||||
|
* @param {File} file
|
||||||
|
*
|
||||||
|
* @todo use configured thumbnail size
|
||||||
|
* @todo detect pixel size?
|
||||||
|
* @todo should we render a thumbnail to a canvas and then use the smaller image?
|
||||||
|
*/
|
||||||
|
PreviewAttach: function(file) {
|
||||||
|
var tooltip = file.type + ' ' + Math.round(file.size / 1024) + 'KB';
|
||||||
|
var preview = true;
|
||||||
|
|
||||||
|
var blobAsDataURL;
|
||||||
|
if (typeof window.createObjectURL != "undefined") {
|
||||||
|
/**
|
||||||
|
* createObjectURL lets us reference the file directly from an <img>
|
||||||
|
* This produces a compact URL with an opaque reference to the file,
|
||||||
|
* which we can reference immediately.
|
||||||
|
*
|
||||||
|
* - Firefox 3.6.6: no
|
||||||
|
* - Firefox 4.0b7: no
|
||||||
|
* - Safari 5.0.2: no
|
||||||
|
* - Chrome 8.0.552.210: works!
|
||||||
|
*/
|
||||||
|
blobAsDataURL = function(blob, callback) {
|
||||||
|
callback(window.createObjectURL(blob));
|
||||||
|
}
|
||||||
|
} else if (typeof window.FileReader != "undefined") {
|
||||||
|
/**
|
||||||
|
* FileAPI's FileReader can build a data URL from a blob's contents,
|
||||||
|
* but it must read the file and build it asynchronously. This means
|
||||||
|
* we'll be passing a giant data URL around, which may be inefficient.
|
||||||
|
*
|
||||||
|
* - Firefox 3.6.6: works!
|
||||||
|
* - Firefox 4.0b7: works!
|
||||||
|
* - Safari 5.0.2: no
|
||||||
|
* - Chrome 8.0.552.210: works!
|
||||||
|
*/
|
||||||
|
blobAsDataURL = function(blob, callback) {
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function(event) {
|
||||||
|
callback(reader.result);
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
preview = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/svg+xml'];
|
||||||
|
if ($.inArray(file.type, imageTypes) == -1) {
|
||||||
|
// We probably don't know how to show the file.
|
||||||
|
preview = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxSize = 8 * 1024 * 1024;
|
||||||
|
if (file.size > maxSize) {
|
||||||
|
// Don't kill the browser trying to load some giant image.
|
||||||
|
preview = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preview) {
|
||||||
|
blobAsDataURL(file, function(url) {
|
||||||
|
var img = $('<img>')
|
||||||
|
.attr('title', tooltip)
|
||||||
|
.attr('alt', tooltip)
|
||||||
|
.attr('src', url)
|
||||||
|
.attr('style', 'height: 120px');
|
||||||
|
$('#'+SN.C.S.NoticeDataAttachSelected).append(img);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var img = $('<div></div>').text(tooltip);
|
||||||
|
$('#'+SN.C.S.NoticeDataAttachSelected).append(img);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
NoticeLocationAttach: function() {
|
NoticeLocationAttach: function() {
|
||||||
var NLat = $('#'+SN.C.S.NoticeLat).val();
|
var NLat = $('#'+SN.C.S.NoticeLat).val();
|
||||||
var NLon = $('#'+SN.C.S.NoticeLon).val();
|
var NLon = $('#'+SN.C.S.NoticeLon).val();
|
||||||
|
|
1
js/util.min.js
vendored
Normal file
1
js/util.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -274,15 +274,15 @@ class Action extends HTMLOutputter // lawsuit
|
||||||
if (Event::handle('StartShowScripts', array($this))) {
|
if (Event::handle('StartShowScripts', array($this))) {
|
||||||
if (Event::handle('StartShowJQueryScripts', array($this))) {
|
if (Event::handle('StartShowJQueryScripts', array($this))) {
|
||||||
$this->script('jquery.min.js');
|
$this->script('jquery.min.js');
|
||||||
$this->script('jquery.form.js');
|
$this->script('jquery.form.min.js');
|
||||||
$this->script('jquery.cookie.js');
|
$this->script('jquery.cookie.min.js');
|
||||||
$this->inlineScript('if (typeof window.JSON !== "object") { $.getScript("'.common_path('js/json2.js').'"); }');
|
$this->inlineScript('if (typeof window.JSON !== "object") { $.getScript("'.common_path('js/json2.min.js').'"); }');
|
||||||
$this->script('jquery.joverlay.min.js');
|
$this->script('jquery.joverlay.min.js');
|
||||||
Event::handle('EndShowJQueryScripts', array($this));
|
Event::handle('EndShowJQueryScripts', array($this));
|
||||||
}
|
}
|
||||||
if (Event::handle('StartShowStatusNetScripts', array($this)) &&
|
if (Event::handle('StartShowStatusNetScripts', array($this)) &&
|
||||||
Event::handle('StartShowLaconicaScripts', array($this))) {
|
Event::handle('StartShowLaconicaScripts', array($this))) {
|
||||||
$this->script('util.js');
|
$this->script('util.min.js');
|
||||||
$this->showScriptMessages();
|
$this->showScriptMessages();
|
||||||
// Frame-busting code to avoid clickjacking attacks.
|
// Frame-busting code to avoid clickjacking attacks.
|
||||||
$this->inlineScript('if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
|
$this->inlineScript('if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
|
||||||
|
@ -300,9 +300,11 @@ class Action extends HTMLOutputter // lawsuit
|
||||||
* events and appending to the array. Try to avoid adding strings that won't be used, as
|
* events and appending to the array. Try to avoid adding strings that won't be used, as
|
||||||
* they'll be added to HTML output.
|
* they'll be added to HTML output.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function showScriptMessages()
|
function showScriptMessages()
|
||||||
{
|
{
|
||||||
$messages = array();
|
$messages = array();
|
||||||
|
|
||||||
if (Event::handle('StartScriptMessages', array($this, &$messages))) {
|
if (Event::handle('StartScriptMessages', array($this, &$messages))) {
|
||||||
// Common messages needed for timeline views etc...
|
// Common messages needed for timeline views etc...
|
||||||
|
|
||||||
|
@ -310,11 +312,14 @@ class Action extends HTMLOutputter // lawsuit
|
||||||
$messages['showmore_tooltip'] = _m('TOOLTIP', 'Show more');
|
$messages['showmore_tooltip'] = _m('TOOLTIP', 'Show more');
|
||||||
|
|
||||||
$messages = array_merge($messages, $this->getScriptMessages());
|
$messages = array_merge($messages, $this->getScriptMessages());
|
||||||
}
|
|
||||||
Event::handle('EndScriptMessages', array($this, &$messages));
|
Event::handle('EndScriptMessages', array($this, &$messages));
|
||||||
if ($messages) {
|
}
|
||||||
|
|
||||||
|
if (!empty($messages)) {
|
||||||
$this->inlineScript('SN.messages=' . json_encode($messages));
|
$this->inlineScript('SN.messages=' . json_encode($messages));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $messages;
|
return $messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1404,4 +1409,15 @@ class Action extends HTMLOutputter // lawsuit
|
||||||
$this->clientError(_('There was a problem with your session token.'));
|
$this->clientError(_('There was a problem with your session token.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the current request is a POST
|
||||||
|
*
|
||||||
|
* @return boolean true if POST; otherwise false.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isPost()
|
||||||
|
{
|
||||||
|
return ($_SERVER['REQUEST_METHOD'] == 'POST');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
196
lib/activity.php
196
lib/activity.php
|
@ -101,6 +101,11 @@ class Activity
|
||||||
public $categories = array(); // list of AtomCategory objects
|
public $categories = array(); // list of AtomCategory objects
|
||||||
public $enclosures = array(); // list of enclosure URL references
|
public $enclosures = array(); // list of enclosure URL references
|
||||||
|
|
||||||
|
public $extra = array(); // extra elements as array(tag, attrs, content)
|
||||||
|
public $source; // ActivitySource object representing 'home feed'
|
||||||
|
public $selfLink; // <link rel='self' type='application/atom+xml'>
|
||||||
|
public $editLink; // <link rel='edit' type='application/atom+xml'>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns a regular old Atom <entry> into a magical activity
|
* Turns a regular old Atom <entry> into a magical activity
|
||||||
*
|
*
|
||||||
|
@ -235,6 +240,11 @@ class Activity
|
||||||
foreach (ActivityUtils::getLinks($entry, 'enclosure') as $link) {
|
foreach (ActivityUtils::getLinks($entry, 'enclosure') as $link) {
|
||||||
$this->enclosures[] = $link->getAttribute('href');
|
$this->enclosures[] = $link->getAttribute('href');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From APP. Might be useful.
|
||||||
|
|
||||||
|
$this->selfLink = ActivityUtils::getLink($entry, 'self', 'application/atom+xml');
|
||||||
|
$this->editLink = ActivityUtils::getLink($entry, 'edit', 'application/atom+xml');
|
||||||
}
|
}
|
||||||
|
|
||||||
function _fromRssItem($item, $channel)
|
function _fromRssItem($item, $channel)
|
||||||
|
@ -319,24 +329,65 @@ class Activity
|
||||||
|
|
||||||
function asString($namespace=false, $author=true)
|
function asString($namespace=false, $author=true)
|
||||||
{
|
{
|
||||||
|
$c = Cache::instance();
|
||||||
|
|
||||||
|
$str = $c->get(Cache::codeKey('activity:as-string:'.$this->id));
|
||||||
|
|
||||||
|
if (!empty($str)) {
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
$xs = new XMLStringer(true);
|
$xs = new XMLStringer(true);
|
||||||
|
|
||||||
if ($namespace) {
|
if ($namespace) {
|
||||||
$attrs = array('xmlns' => 'http://www.w3.org/2005/Atom',
|
$attrs = array('xmlns' => 'http://www.w3.org/2005/Atom',
|
||||||
|
'xmlns:thr' => 'http://purl.org/syndication/thread/1.0',
|
||||||
'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/',
|
'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/',
|
||||||
'xmlns:georss' => 'http://www.georss.org/georss',
|
'xmlns:georss' => 'http://www.georss.org/georss',
|
||||||
'xmlns:ostatus' => 'http://ostatus.org/schema/1.0',
|
'xmlns:ostatus' => 'http://ostatus.org/schema/1.0',
|
||||||
'xmlns:poco' => 'http://portablecontacts.net/spec/1.0',
|
'xmlns:poco' => 'http://portablecontacts.net/spec/1.0',
|
||||||
'xmlns:media' => 'http://purl.org/syndication/atommedia');
|
'xmlns:media' => 'http://purl.org/syndication/atommedia',
|
||||||
|
'xmlns:statusnet' => 'http://status.net/schema/api/1/');
|
||||||
} else {
|
} else {
|
||||||
$attrs = array();
|
$attrs = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
$xs->elementStart('entry', $attrs);
|
$xs->elementStart('entry', $attrs);
|
||||||
|
|
||||||
|
if ($this->verb == ActivityVerb::POST && count($this->objects) == 1) {
|
||||||
|
|
||||||
|
$obj = $this->objects[0];
|
||||||
|
|
||||||
|
$xs->element('id', null, $obj->id);
|
||||||
|
$xs->element('activity:object-type', null, $obj->type);
|
||||||
|
|
||||||
|
if (!empty($obj->title)) {
|
||||||
|
$xs->element('title', null, $obj->title);
|
||||||
|
} else {
|
||||||
|
// XXX need a better default title
|
||||||
|
$xs->element('title', null, _('Post'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($obj->content)) {
|
||||||
|
$xs->element('content', array('type' => 'html'), $obj->content);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($obj->summary)) {
|
||||||
|
$xs->element('summary', null, $obj->summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($obj->link)) {
|
||||||
|
$xs->element('link', array('rel' => 'alternate',
|
||||||
|
'type' => 'text/html'),
|
||||||
|
$obj->link);
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: some object types might have other values here.
|
||||||
|
|
||||||
|
} else {
|
||||||
$xs->element('id', null, $this->id);
|
$xs->element('id', null, $this->id);
|
||||||
$xs->element('title', null, $this->title);
|
$xs->element('title', null, $this->title);
|
||||||
$xs->element('published', null, self::iso8601Date($this->time));
|
|
||||||
$xs->element('content', array('type' => 'html'), $this->content);
|
$xs->element('content', array('type' => 'html'), $this->content);
|
||||||
|
|
||||||
if (!empty($this->summary)) {
|
if (!empty($this->summary)) {
|
||||||
|
@ -349,7 +400,14 @@ class Activity
|
||||||
$this->link);
|
$this->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: add context
|
}
|
||||||
|
|
||||||
|
$xs->element('activity:verb', null, $this->verb);
|
||||||
|
|
||||||
|
$published = self::iso8601Date($this->time);
|
||||||
|
|
||||||
|
$xs->element('published', null, $published);
|
||||||
|
$xs->element('updated', null, $published);
|
||||||
|
|
||||||
if ($author) {
|
if ($author) {
|
||||||
$xs->elementStart('author');
|
$xs->elementStart('author');
|
||||||
|
@ -361,14 +419,61 @@ class Activity
|
||||||
$xs->raw($this->actor->asString('activity:actor'));
|
$xs->raw($this->actor->asString('activity:actor'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$xs->element('activity:verb', null, $this->verb);
|
if ($this->verb != ActivityVerb::POST || count($this->objects) != 1) {
|
||||||
|
|
||||||
if (!empty($this->objects)) {
|
|
||||||
foreach($this->objects as $object) {
|
foreach($this->objects as $object) {
|
||||||
$xs->raw($object->asString());
|
$xs->raw($object->asString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($this->context)) {
|
||||||
|
|
||||||
|
if (!empty($this->context->replyToID)) {
|
||||||
|
if (!empty($this->context->replyToUrl)) {
|
||||||
|
$xs->element('thr:in-reply-to',
|
||||||
|
array('ref' => $this->context->replyToID,
|
||||||
|
'href' => $this->context->replyToUrl));
|
||||||
|
} else {
|
||||||
|
$xs->element('thr:in-reply-to',
|
||||||
|
array('ref' => $this->context->replyToID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->context->replyToUrl)) {
|
||||||
|
$xs->element('link', array('rel' => 'related',
|
||||||
|
'href' => $this->context->replyToUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->context->conversation)) {
|
||||||
|
$xs->element('link', array('rel' => 'ostatus:conversation',
|
||||||
|
'href' => $this->context->conversation));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->context->attention as $attnURI) {
|
||||||
|
$xs->element('link', array('rel' => 'ostatus:attention',
|
||||||
|
'href' => $attnURI));
|
||||||
|
$xs->element('link', array('rel' => 'mentioned',
|
||||||
|
'href' => $attnURI));
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: shoulda used ActivityVerb::SHARE
|
||||||
|
|
||||||
|
if (!empty($this->context->forwardID)) {
|
||||||
|
if (!empty($this->context->forwardUrl)) {
|
||||||
|
$xs->element('ostatus:forward',
|
||||||
|
array('ref' => $this->context->forwardID,
|
||||||
|
'href' => $this->context->forwardUrl));
|
||||||
|
} else {
|
||||||
|
$xs->element('ostatus:forward',
|
||||||
|
array('ref' => $this->context->forwardID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->context->location)) {
|
||||||
|
$loc = $this->context->location;
|
||||||
|
$xs->element('georss:point', null, $loc->lat . ' ' . $loc->lon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->target) {
|
if ($this->target) {
|
||||||
$xs->raw($this->target->asString('activity:target'));
|
$xs->raw($this->target->asString('activity:target'));
|
||||||
}
|
}
|
||||||
|
@ -377,9 +482,86 @@ class Activity
|
||||||
$xs->raw($cat->asString());
|
$xs->raw($cat->asString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// can be either URLs or enclosure objects
|
||||||
|
|
||||||
|
foreach ($this->enclosures as $enclosure) {
|
||||||
|
if (is_string($enclosure)) {
|
||||||
|
$xs->element('link', array('rel' => 'enclosure',
|
||||||
|
'href' => $enclosure));
|
||||||
|
} else {
|
||||||
|
$attributes = array('rel' => 'enclosure',
|
||||||
|
'href' => $enclosure->url,
|
||||||
|
'type' => $enclosure->mimetype,
|
||||||
|
'length' => $enclosure->size);
|
||||||
|
if ($enclosure->title) {
|
||||||
|
$attributes['title'] = $enclosure->title;
|
||||||
|
}
|
||||||
|
$xs->element('link', $attributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info on the source feed
|
||||||
|
|
||||||
|
if (!empty($this->source)) {
|
||||||
|
$xs->elementStart('source');
|
||||||
|
|
||||||
|
$xs->element('id', null, $this->source->id);
|
||||||
|
$xs->element('title', null, $this->source->title);
|
||||||
|
|
||||||
|
if (array_key_exists('alternate', $this->source->links)) {
|
||||||
|
$xs->element('link', array('rel' => 'alternate',
|
||||||
|
'type' => 'text/html',
|
||||||
|
'href' => $this->source->links['alternate']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('self', $this->source->links)) {
|
||||||
|
$xs->element('link', array('rel' => 'self',
|
||||||
|
'type' => 'application/atom+xml',
|
||||||
|
'href' => $this->source->links['self']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('license', $this->source->links)) {
|
||||||
|
$xs->element('link', array('rel' => 'license',
|
||||||
|
'href' => $this->source->links['license']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->source->icon)) {
|
||||||
|
$xs->element('icon', null, $this->source->icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->source->updated)) {
|
||||||
|
$xs->element('updated', null, $this->source->updated);
|
||||||
|
}
|
||||||
|
|
||||||
|
$xs->elementEnd('source');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->selfLink)) {
|
||||||
|
$xs->element('link', array('rel' => 'self',
|
||||||
|
'type' => 'application/atom+xml',
|
||||||
|
'href' => $this->selfLink));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->editLink)) {
|
||||||
|
$xs->element('link', array('rel' => 'edit',
|
||||||
|
'type' => 'application/atom+xml',
|
||||||
|
'href' => $this->editLink));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For throwing in extra elements; used for statusnet:notice_info
|
||||||
|
|
||||||
|
foreach ($this->extra as $el) {
|
||||||
|
list($tag, $attrs, $content) = $el;
|
||||||
|
$xs->element($tag, $attrs, $content);
|
||||||
|
}
|
||||||
|
|
||||||
$xs->elementEnd('entry');
|
$xs->elementEnd('entry');
|
||||||
|
|
||||||
return $xs->getString();
|
$str = $xs->getString();
|
||||||
|
|
||||||
|
$c->set(Cache::codeKey('activity:as-string:'.$this->id), $str);
|
||||||
|
|
||||||
|
return $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function _child($element, $tag, $namespace=self::SPEC)
|
private function _child($element, $tag, $namespace=self::SPEC)
|
||||||
|
|
|
@ -39,6 +39,8 @@ class ActivityContext
|
||||||
public $location;
|
public $location;
|
||||||
public $attention = array();
|
public $attention = array();
|
||||||
public $conversation;
|
public $conversation;
|
||||||
|
public $forwardID; // deprecated, use ActivityVerb::SHARE instead
|
||||||
|
public $forwardUrl; // deprecated, use ActivityVerb::SHARE instead
|
||||||
|
|
||||||
const THR = 'http://purl.org/syndication/thread/1.0';
|
const THR = 'http://purl.org/syndication/thread/1.0';
|
||||||
const GEORSS = 'http://www.georss.org/georss';
|
const GEORSS = 'http://www.georss.org/georss';
|
||||||
|
|
56
lib/activitysource.php
Normal file
56
lib/activitysource.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Activity source, to save in <atom:source>
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Feed
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @copyright 2010 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feed data to store in the <atom:source> element
|
||||||
|
*
|
||||||
|
* I wanted to use Atom10Feed but it seems more heavyweight than what's
|
||||||
|
* needed here.
|
||||||
|
*
|
||||||
|
* @category OStatus
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2010 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ActivitySource
|
||||||
|
{
|
||||||
|
public $id;
|
||||||
|
public $title;
|
||||||
|
public $icon;
|
||||||
|
public $updated;
|
||||||
|
public $links;
|
||||||
|
}
|
|
@ -728,6 +728,12 @@ class ApiAction extends Action
|
||||||
$this->endDocument('xml');
|
$this->endDocument('xml');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showSingleAtomStatus($notice)
|
||||||
|
{
|
||||||
|
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||||
|
print $notice->asAtomEntry(true, true, true, $this->auth_user);
|
||||||
|
}
|
||||||
|
|
||||||
function show_single_json_status($notice)
|
function show_single_json_status($notice)
|
||||||
{
|
{
|
||||||
$this->initDocument('json');
|
$this->initDocument('json');
|
||||||
|
@ -1361,11 +1367,16 @@ class ApiAction extends Action
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function is_decimal($str)
|
||||||
|
{
|
||||||
|
return preg_match('/^[0-9]+$/', $str);
|
||||||
|
}
|
||||||
|
|
||||||
function getTargetUser($id)
|
function getTargetUser($id)
|
||||||
{
|
{
|
||||||
if (empty($id)) {
|
if (empty($id)) {
|
||||||
// Twitter supports these other ways of passing the user ID
|
// Twitter supports these other ways of passing the user ID
|
||||||
if (is_numeric($this->arg('id'))) {
|
if (self::is_decimal($this->arg('id'))) {
|
||||||
return User::staticGet($this->arg('id'));
|
return User::staticGet($this->arg('id'));
|
||||||
} else if ($this->arg('id')) {
|
} else if ($this->arg('id')) {
|
||||||
$nickname = common_canonical_nickname($this->arg('id'));
|
$nickname = common_canonical_nickname($this->arg('id'));
|
||||||
|
@ -1373,7 +1384,7 @@ class ApiAction extends Action
|
||||||
} else if ($this->arg('user_id')) {
|
} else if ($this->arg('user_id')) {
|
||||||
// This is to ensure that a non-numeric user_id still
|
// This is to ensure that a non-numeric user_id still
|
||||||
// overrides screen_name even if it doesn't get used
|
// overrides screen_name even if it doesn't get used
|
||||||
if (is_numeric($this->arg('user_id'))) {
|
if (self::is_decimal($this->arg('user_id'))) {
|
||||||
return User::staticGet('id', $this->arg('user_id'));
|
return User::staticGet('id', $this->arg('user_id'));
|
||||||
}
|
}
|
||||||
} else if ($this->arg('screen_name')) {
|
} else if ($this->arg('screen_name')) {
|
||||||
|
@ -1384,7 +1395,7 @@ class ApiAction extends Action
|
||||||
return $this->auth_user;
|
return $this->auth_user;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (is_numeric($id)) {
|
} else if (self::is_decimal($id)) {
|
||||||
return User::staticGet($id);
|
return User::staticGet($id);
|
||||||
} else {
|
} else {
|
||||||
$nickname = common_canonical_nickname($id);
|
$nickname = common_canonical_nickname($id);
|
||||||
|
@ -1397,7 +1408,7 @@ class ApiAction extends Action
|
||||||
if (empty($id)) {
|
if (empty($id)) {
|
||||||
|
|
||||||
// Twitter supports these other ways of passing the user ID
|
// Twitter supports these other ways of passing the user ID
|
||||||
if (is_numeric($this->arg('id'))) {
|
if (self::is_decimal($this->arg('id'))) {
|
||||||
return Profile::staticGet($this->arg('id'));
|
return Profile::staticGet($this->arg('id'));
|
||||||
} else if ($this->arg('id')) {
|
} else if ($this->arg('id')) {
|
||||||
// Screen names currently can only uniquely identify a local user.
|
// Screen names currently can only uniquely identify a local user.
|
||||||
|
@ -1407,7 +1418,7 @@ class ApiAction extends Action
|
||||||
} else if ($this->arg('user_id')) {
|
} else if ($this->arg('user_id')) {
|
||||||
// This is to ensure that a non-numeric user_id still
|
// This is to ensure that a non-numeric user_id still
|
||||||
// overrides screen_name even if it doesn't get used
|
// overrides screen_name even if it doesn't get used
|
||||||
if (is_numeric($this->arg('user_id'))) {
|
if (self::is_decimal($this->arg('user_id'))) {
|
||||||
return Profile::staticGet('id', $this->arg('user_id'));
|
return Profile::staticGet('id', $this->arg('user_id'));
|
||||||
}
|
}
|
||||||
} else if ($this->arg('screen_name')) {
|
} else if ($this->arg('screen_name')) {
|
||||||
|
@ -1415,7 +1426,7 @@ class ApiAction extends Action
|
||||||
$user = User::staticGet('nickname', $nickname);
|
$user = User::staticGet('nickname', $nickname);
|
||||||
return $user ? $user->getProfile() : null;
|
return $user ? $user->getProfile() : null;
|
||||||
}
|
}
|
||||||
} else if (is_numeric($id)) {
|
} else if (self::is_decimal($id)) {
|
||||||
return Profile::staticGet($id);
|
return Profile::staticGet($id);
|
||||||
} else {
|
} else {
|
||||||
$nickname = common_canonical_nickname($id);
|
$nickname = common_canonical_nickname($id);
|
||||||
|
@ -1427,7 +1438,7 @@ class ApiAction extends Action
|
||||||
function getTargetGroup($id)
|
function getTargetGroup($id)
|
||||||
{
|
{
|
||||||
if (empty($id)) {
|
if (empty($id)) {
|
||||||
if (is_numeric($this->arg('id'))) {
|
if (self::is_decimal($this->arg('id'))) {
|
||||||
return User_group::staticGet($this->arg('id'));
|
return User_group::staticGet($this->arg('id'));
|
||||||
} else if ($this->arg('id')) {
|
} else if ($this->arg('id')) {
|
||||||
$nickname = common_canonical_nickname($this->arg('id'));
|
$nickname = common_canonical_nickname($this->arg('id'));
|
||||||
|
@ -1440,7 +1451,7 @@ class ApiAction extends Action
|
||||||
} else if ($this->arg('group_id')) {
|
} else if ($this->arg('group_id')) {
|
||||||
// This is to ensure that a non-numeric user_id still
|
// This is to ensure that a non-numeric user_id still
|
||||||
// overrides screen_name even if it doesn't get used
|
// overrides screen_name even if it doesn't get used
|
||||||
if (is_numeric($this->arg('group_id'))) {
|
if (self::is_decimal($this->arg('group_id'))) {
|
||||||
return User_group::staticGet('id', $this->arg('group_id'));
|
return User_group::staticGet('id', $this->arg('group_id'));
|
||||||
}
|
}
|
||||||
} else if ($this->arg('group_name')) {
|
} else if ($this->arg('group_name')) {
|
||||||
|
@ -1453,7 +1464,7 @@ class ApiAction extends Action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (is_numeric($id)) {
|
} else if (self::is_decimal($id)) {
|
||||||
return User_group::staticGet($id);
|
return User_group::staticGet($id);
|
||||||
} else {
|
} else {
|
||||||
$nickname = common_canonical_nickname($id);
|
$nickname = common_canonical_nickname($id);
|
||||||
|
|
|
@ -72,6 +72,6 @@ class AtomCategory
|
||||||
}
|
}
|
||||||
$xs = new XMLStringer();
|
$xs = new XMLStringer();
|
||||||
$xs->element('category', $attribs);
|
$xs->element('category', $attribs);
|
||||||
return $xs->asString();
|
return $xs->getString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,23 +79,33 @@ class AttachmentList extends Widget
|
||||||
$atts = new File;
|
$atts = new File;
|
||||||
$att = $atts->getAttachments($this->notice->id);
|
$att = $atts->getAttachments($this->notice->id);
|
||||||
if (empty($att)) return 0;
|
if (empty($att)) return 0;
|
||||||
$this->out->elementStart('dl', array('id' =>'attachments',
|
$this->showListStart();
|
||||||
'class' => 'entry-content'));
|
|
||||||
// TRANS: DT element label in attachment list.
|
|
||||||
$this->out->element('dt', null, _('Attachments'));
|
|
||||||
$this->out->elementStart('dd');
|
|
||||||
$this->out->elementStart('ol', array('class' => 'attachments'));
|
|
||||||
|
|
||||||
foreach ($att as $n=>$attachment) {
|
foreach ($att as $n=>$attachment) {
|
||||||
$item = $this->newListItem($attachment);
|
$item = $this->newListItem($attachment);
|
||||||
$item->show();
|
$item->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->showListEnd();
|
||||||
|
|
||||||
|
return count($att);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showListStart()
|
||||||
|
{
|
||||||
|
$this->out->elementStart('dl', array('id' =>'attachments',
|
||||||
|
'class' => 'entry-content'));
|
||||||
|
// TRANS: DT element label in attachment list.
|
||||||
|
$this->out->element('dt', null, _('Attachments'));
|
||||||
|
$this->out->elementStart('dd');
|
||||||
|
$this->out->elementStart('ol', array('class' => 'attachments'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function showListEnd()
|
||||||
|
{
|
||||||
$this->out->elementEnd('dd');
|
$this->out->elementEnd('dd');
|
||||||
$this->out->elementEnd('ol');
|
$this->out->elementEnd('ol');
|
||||||
$this->out->elementEnd('dl');
|
$this->out->elementEnd('dl');
|
||||||
|
|
||||||
return count($att);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,7 +197,10 @@ class AttachmentListItem extends Widget
|
||||||
}
|
}
|
||||||
|
|
||||||
function linkAttr() {
|
function linkAttr() {
|
||||||
return array('class' => 'attachment', 'href' => $this->attachment->url, 'id' => 'attachment-' . $this->attachment->id);
|
return array('class' => 'attachment',
|
||||||
|
'href' => $this->attachment->url,
|
||||||
|
'id' => 'attachment-' . $this->attachment->id,
|
||||||
|
'title' => $this->title());
|
||||||
}
|
}
|
||||||
|
|
||||||
function showLink() {
|
function showLink() {
|
||||||
|
@ -203,12 +216,34 @@ class AttachmentListItem extends Widget
|
||||||
}
|
}
|
||||||
|
|
||||||
function showRepresentation() {
|
function showRepresentation() {
|
||||||
$thumbnail = File_thumbnail::staticGet('file_id', $this->attachment->id);
|
$thumb = $this->getThumbInfo();
|
||||||
if (!empty($thumbnail)) {
|
if ($thumb) {
|
||||||
$this->out->element('img', array('alt' => '', 'src' => $thumbnail->url, 'width' => $thumbnail->width, 'height' => $thumbnail->height));
|
$this->out->element('img', array('alt' => '', 'src' => $thumb->url, 'width' => $thumb->width, 'height' => $thumb->height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pull a thumbnail image reference for the given file, and if necessary
|
||||||
|
* resize it to match currently thumbnail size settings.
|
||||||
|
*
|
||||||
|
* @return File_Thumbnail or false/null
|
||||||
|
*/
|
||||||
|
function getThumbInfo()
|
||||||
|
{
|
||||||
|
$thumbnail = File_thumbnail::staticGet('file_id', $this->attachment->id);
|
||||||
|
if ($thumbnail) {
|
||||||
|
$maxWidth = common_config('attachments', 'thumb_width');
|
||||||
|
$maxHeight = common_config('attachments', 'thumb_height');
|
||||||
|
if ($thumbnail->width > $maxWidth) {
|
||||||
|
$thumb = clone($thumbnail);
|
||||||
|
$thumb->width = $maxWidth;
|
||||||
|
$thumb->height = intval($thumbnail->height * $maxWidth / $thumbnail->width);
|
||||||
|
return $thumb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* start a single notice.
|
* start a single notice.
|
||||||
*
|
*
|
||||||
|
@ -234,6 +269,9 @@ class AttachmentListItem extends Widget
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used for one-off attachment action
|
||||||
|
*/
|
||||||
class Attachment extends AttachmentListItem
|
class Attachment extends AttachmentListItem
|
||||||
{
|
{
|
||||||
function showLink() {
|
function showLink() {
|
||||||
|
@ -417,15 +455,6 @@ class Attachment extends AttachmentListItem
|
||||||
|
|
||||||
function showFallback()
|
function showFallback()
|
||||||
{
|
{
|
||||||
// If we don't know how to display an attachment inline, we probably
|
// still needed: should show a link?
|
||||||
// shouldn't have gotten to this point.
|
|
||||||
//
|
|
||||||
// But, here we are... displaying details on a file or remote URL
|
|
||||||
// either on the main view or in an ajax-loaded lightbox. As a lesser
|
|
||||||
// of several evils, we'll try redirecting to the actual target via
|
|
||||||
// client-side JS.
|
|
||||||
|
|
||||||
common_log(LOG_ERR, "Empty or unknown type for file id {$this->attachment->id}; falling back to client-side redirect.");
|
|
||||||
$this->out->raw('<script>window.location = ' . json_encode($this->attachment->url) . ';</script>');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,55 @@ class Cache
|
||||||
return 'statusnet:' . $base_key . ':' . $extra;
|
return 'statusnet:' . $base_key . ':' . $extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a cache key for data dependent on code
|
||||||
|
*
|
||||||
|
* For cache elements that are dependent on changes in code, this creates
|
||||||
|
* a more-or-less fingerprint of the current running code and adds it to
|
||||||
|
* the cache key. In the case of an upgrade of core, or addition or
|
||||||
|
* removal of plugins, a new unique fingerprint is generated and used.
|
||||||
|
*
|
||||||
|
* There can still be problems with a) differences in versions of the
|
||||||
|
* plugins and b) people running code between official versions. This is
|
||||||
|
* usually a problem only for experienced users like developers, who know
|
||||||
|
* how to clear their cache.
|
||||||
|
*
|
||||||
|
* For sites that run code between versions (like the status.net cloud),
|
||||||
|
* there's an additional build number configuration setting.
|
||||||
|
*
|
||||||
|
* @param string $extra the real part of the key
|
||||||
|
*
|
||||||
|
* @return string full key
|
||||||
|
*/
|
||||||
|
|
||||||
|
static function codeKey($extra)
|
||||||
|
{
|
||||||
|
static $prefix = null;
|
||||||
|
|
||||||
|
if (empty($prefix)) {
|
||||||
|
|
||||||
|
$plugins = StatusNet::getActivePlugins();
|
||||||
|
$names = array();
|
||||||
|
|
||||||
|
foreach ($plugins as $plugin) {
|
||||||
|
$names[] = $plugin[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$names = array_unique($names);
|
||||||
|
asort($names);
|
||||||
|
|
||||||
|
// Unique enough.
|
||||||
|
|
||||||
|
$uniq = crc32(implode(',', $names));
|
||||||
|
|
||||||
|
$build = common_config('site', 'build');
|
||||||
|
|
||||||
|
$prefix = STATUSNET_VERSION.':'.$build.':'.$uniq;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Cache::key($prefix.':'.$extra);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a string suitable for use as a key
|
* Make a string suitable for use as a key
|
||||||
*
|
*
|
||||||
|
|
|
@ -139,7 +139,7 @@ class Command
|
||||||
{
|
{
|
||||||
$user = null;
|
$user = null;
|
||||||
if (Event::handle('StartCommandGetUser', array($this, $arg, &$user))) {
|
if (Event::handle('StartCommandGetUser', array($this, $arg, &$user))) {
|
||||||
$user = User::staticGet('nickname', $arg);
|
$user = User::staticGet('nickname', Nickname::normalize($arg));
|
||||||
}
|
}
|
||||||
Event::handle('EndCommandGetUser', array($this, $arg, &$user));
|
Event::handle('EndCommandGetUser', array($this, $arg, &$user));
|
||||||
if (!$user){
|
if (!$user){
|
||||||
|
@ -479,7 +479,7 @@ class MessageCommand extends Command
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->text = common_shorten_links($this->text);
|
$this->text = $this->user->shortenLinks($this->text);
|
||||||
|
|
||||||
if (Message::contentTooLong($this->text)) {
|
if (Message::contentTooLong($this->text)) {
|
||||||
// XXX: i18n. Needs plural support.
|
// XXX: i18n. Needs plural support.
|
||||||
|
@ -582,7 +582,7 @@ class ReplyCommand extends Command
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->text = common_shorten_links($this->text);
|
$this->text = $this->user->shortenLinks($this->text);
|
||||||
|
|
||||||
if (Notice::contentTooLong($this->text)) {
|
if (Notice::contentTooLong($this->text)) {
|
||||||
// XXX: i18n. Needs plural support.
|
// XXX: i18n. Needs plural support.
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
* @category Action
|
* @category Action
|
||||||
* @package StatusNet
|
* @package StatusNet
|
||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
* @copyright 2009 StatusNet, Inc.
|
* @copyright 2009-2010 StatusNet, Inc.
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
@ -40,12 +40,33 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||||
* @category Action
|
* @category Action
|
||||||
* @package StatusNet
|
* @package StatusNet
|
||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class CurrentUserDesignAction extends Action
|
class CurrentUserDesignAction extends Action
|
||||||
{
|
{
|
||||||
|
|
||||||
|
protected $cur = null; // The current user
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For initializing members of the class. Set a the
|
||||||
|
* current user here.
|
||||||
|
*
|
||||||
|
* @param array $argarray misc. arguments
|
||||||
|
*
|
||||||
|
* @return boolean true
|
||||||
|
*/
|
||||||
|
function prepare($argarray)
|
||||||
|
{
|
||||||
|
parent::prepare($argarray);
|
||||||
|
|
||||||
|
$this->cur = common_current_user();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A design for this action
|
* A design for this action
|
||||||
*
|
*
|
||||||
|
@ -55,11 +76,9 @@ class CurrentUserDesignAction extends Action
|
||||||
*/
|
*/
|
||||||
function getDesign()
|
function getDesign()
|
||||||
{
|
{
|
||||||
$cur = common_current_user();
|
if (!empty($this->cur)) {
|
||||||
|
|
||||||
if (!empty($cur)) {
|
$design = $this->cur->getDesign();
|
||||||
|
|
||||||
$design = $cur->getDesign();
|
|
||||||
|
|
||||||
if (!empty($design)) {
|
if (!empty($design)) {
|
||||||
return $design;
|
return $design;
|
||||||
|
@ -68,4 +87,10 @@ class CurrentUserDesignAction extends Action
|
||||||
|
|
||||||
return parent::getDesign();
|
return parent::getDesign();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCurrentUser()
|
||||||
|
{
|
||||||
|
return $this->cur;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,8 @@ $default =
|
||||||
'textlimit' => 140,
|
'textlimit' => 140,
|
||||||
'indent' => true,
|
'indent' => true,
|
||||||
'use_x_sendfile' => false,
|
'use_x_sendfile' => false,
|
||||||
'notice' => null // site wide notice text
|
'notice' => null, // site wide notice text
|
||||||
|
'build' => 1, // build number, for code-dependent cache
|
||||||
),
|
),
|
||||||
'db' =>
|
'db' =>
|
||||||
array('database' => 'YOU HAVE TO SET THIS IN config.php',
|
array('database' => 'YOU HAVE TO SET THIS IN config.php',
|
||||||
|
@ -251,6 +252,10 @@ $default =
|
||||||
'monthly_quota' => 15000000,
|
'monthly_quota' => 15000000,
|
||||||
'uploads' => true,
|
'uploads' => true,
|
||||||
'filecommand' => '/usr/bin/file',
|
'filecommand' => '/usr/bin/file',
|
||||||
|
'show_thumbs' => true, // show thumbnails in notice lists for uploaded images, and photos and videos linked remotely that provide oEmbed info
|
||||||
|
'thumb_width' => 100,
|
||||||
|
'thumb_height' => 75,
|
||||||
|
'process_links' => true, // check linked resources for embeddable photos and videos; this will hit referenced external web sites when processing new messages.
|
||||||
),
|
),
|
||||||
'application' =>
|
'application' =>
|
||||||
array('desclimit' => null),
|
array('desclimit' => null),
|
||||||
|
@ -331,4 +336,6 @@ $default =
|
||||||
array('ssl_cafile' => false, // To enable SSL cert validation, point to a CA bundle (eg '/usr/lib/ssl/certs/ca-certificates.crt')
|
array('ssl_cafile' => false, // To enable SSL cert validation, point to a CA bundle (eg '/usr/lib/ssl/certs/ca-certificates.crt')
|
||||||
'curl' => false, // Use CURL backend for HTTP fetches if available. (If not, PHP's socket streams will be used.)
|
'curl' => false, // Use CURL backend for HTTP fetches if available. (If not, PHP's socket streams will be used.)
|
||||||
),
|
),
|
||||||
|
'router' =>
|
||||||
|
array('cache' => true), // whether to cache the router object. Defaults to true, turn off for devel
|
||||||
);
|
);
|
||||||
|
|
|
@ -127,19 +127,24 @@ class DesignForm extends Form
|
||||||
$this->out->elementEnd('fieldset');
|
$this->out->elementEnd('fieldset');
|
||||||
|
|
||||||
$this->out->elementStart('fieldset', array('id' => 'settings_design_color'));
|
$this->out->elementStart('fieldset', array('id' => 'settings_design_color'));
|
||||||
|
// TRANS: Fieldset legend on profile design page to change profile page colours.
|
||||||
$this->out->element('legend', null, _('Change colours'));
|
$this->out->element('legend', null, _('Change colours'));
|
||||||
$this->colourData();
|
$this->colourData();
|
||||||
$this->out->elementEnd('fieldset');
|
$this->out->elementEnd('fieldset');
|
||||||
|
|
||||||
$this->out->elementStart('fieldset');
|
$this->out->elementStart('fieldset');
|
||||||
|
|
||||||
|
// TRANS: Button text on profile design page to immediately reset all colour settings to default.
|
||||||
$this->out->submit('defaults', _('Use defaults'), 'submit form_action-default',
|
$this->out->submit('defaults', _('Use defaults'), 'submit form_action-default',
|
||||||
|
// TRANS: Title for button on profile design page to reset all colour settings to default.
|
||||||
'defaults', _('Restore default designs'));
|
'defaults', _('Restore default designs'));
|
||||||
|
|
||||||
$this->out->element('input', array('id' => 'settings_design_reset',
|
$this->out->element('input', array('id' => 'settings_design_reset',
|
||||||
'type' => 'reset',
|
'type' => 'reset',
|
||||||
'value' => 'Reset',
|
// TRANS: Button text on profile design page to reset all colour settings to default without saving.
|
||||||
|
'value' => _m('BUTTON', 'Reset'),
|
||||||
'class' => 'submit form_action-primary',
|
'class' => 'submit form_action-primary',
|
||||||
|
// TRANS: Title for button on profile design page to reset all colour settings to default without saving.
|
||||||
'title' => _('Reset back to default')));
|
'title' => _('Reset back to default')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,10 +153,13 @@ class DesignForm extends Form
|
||||||
$this->out->elementStart('ul', 'form_data');
|
$this->out->elementStart('ul', 'form_data');
|
||||||
$this->out->elementStart('li');
|
$this->out->elementStart('li');
|
||||||
$this->out->element('label', array('for' => 'design_background-image_file'),
|
$this->out->element('label', array('for' => 'design_background-image_file'),
|
||||||
|
// TRANS: Label in form on profile design page.
|
||||||
|
// TRANS: Field contains file name on user's computer that could be that user's custom profile background image.
|
||||||
_('Upload file'));
|
_('Upload file'));
|
||||||
$this->out->element('input', array('name' => 'design_background-image_file',
|
$this->out->element('input', array('name' => 'design_background-image_file',
|
||||||
'type' => 'file',
|
'type' => 'file',
|
||||||
'id' => 'design_background-image_file'));
|
'id' => 'design_background-image_file'));
|
||||||
|
// TRANS: Instructions for form on profile design page.
|
||||||
$this->out->element('p', 'form_guide', _('You can upload your personal ' .
|
$this->out->element('p', 'form_guide', _('You can upload your personal ' .
|
||||||
'background image. The maximum file size is 2Mb.'));
|
'background image. The maximum file size is 2Mb.'));
|
||||||
$this->out->element('input', array('name' => 'MAX_FILE_SIZE',
|
$this->out->element('input', array('name' => 'MAX_FILE_SIZE',
|
||||||
|
@ -182,7 +190,8 @@ class DesignForm extends Form
|
||||||
|
|
||||||
$this->out->element('label', array('for' => 'design_background-image_on',
|
$this->out->element('label', array('for' => 'design_background-image_on',
|
||||||
'class' => 'radio'),
|
'class' => 'radio'),
|
||||||
_('On'));
|
// TRANS: Radio button on profile design page that will enable use of the uploaded profile image.
|
||||||
|
_m('RADIO', 'On'));
|
||||||
|
|
||||||
$attrs = array('name' => 'design_background-image_onoff',
|
$attrs = array('name' => 'design_background-image_onoff',
|
||||||
'type' => 'radio',
|
'type' => 'radio',
|
||||||
|
@ -198,12 +207,16 @@ class DesignForm extends Form
|
||||||
|
|
||||||
$this->out->element('label', array('for' => 'design_background-image_off',
|
$this->out->element('label', array('for' => 'design_background-image_off',
|
||||||
'class' => 'radio'),
|
'class' => 'radio'),
|
||||||
_('Off'));
|
// TRANS: Radio button on profile design page that will disable use of the uploaded profile image.
|
||||||
|
_m('RADIO', 'Off'));
|
||||||
|
// TRANS: Form guide for a set of radio buttons on the profile design page that will enable or disable
|
||||||
|
// TRANS: use of the uploaded profile image.
|
||||||
$this->out->element('p', 'form_guide', _('Turn background image on or off.'));
|
$this->out->element('p', 'form_guide', _('Turn background image on or off.'));
|
||||||
$this->out->elementEnd('li');
|
$this->out->elementEnd('li');
|
||||||
|
|
||||||
$this->out->elementStart('li');
|
$this->out->elementStart('li');
|
||||||
$this->out->checkbox('design_background-image_repeat',
|
$this->out->checkbox('design_background-image_repeat',
|
||||||
|
// TRANS: Checkbox label on profile design page that will cause the profile image to be tiled.
|
||||||
_('Tile background image'),
|
_('Tile background image'),
|
||||||
($this->design->disposition & BACKGROUND_TILE) ? true : false);
|
($this->design->disposition & BACKGROUND_TILE) ? true : false);
|
||||||
$this->out->elementEnd('li');
|
$this->out->elementEnd('li');
|
||||||
|
@ -221,6 +234,7 @@ class DesignForm extends Form
|
||||||
$bgcolor = new WebColor($this->design->backgroundcolor);
|
$bgcolor = new WebColor($this->design->backgroundcolor);
|
||||||
|
|
||||||
$this->out->elementStart('li');
|
$this->out->elementStart('li');
|
||||||
|
// TRANS: Label on profile design page for setting a profile page background colour.
|
||||||
$this->out->element('label', array('for' => 'swatch-1'), _('Background'));
|
$this->out->element('label', array('for' => 'swatch-1'), _('Background'));
|
||||||
$this->out->element('input', array('name' => 'design_background',
|
$this->out->element('input', array('name' => 'design_background',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
@ -234,6 +248,7 @@ class DesignForm extends Form
|
||||||
$ccolor = new WebColor($this->design->contentcolor);
|
$ccolor = new WebColor($this->design->contentcolor);
|
||||||
|
|
||||||
$this->out->elementStart('li');
|
$this->out->elementStart('li');
|
||||||
|
// TRANS: Label on profile design page for setting a profile page content colour.
|
||||||
$this->out->element('label', array('for' => 'swatch-2'), _('Content'));
|
$this->out->element('label', array('for' => 'swatch-2'), _('Content'));
|
||||||
$this->out->element('input', array('name' => 'design_content',
|
$this->out->element('input', array('name' => 'design_content',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
@ -247,6 +262,7 @@ class DesignForm extends Form
|
||||||
$sbcolor = new WebColor($this->design->sidebarcolor);
|
$sbcolor = new WebColor($this->design->sidebarcolor);
|
||||||
|
|
||||||
$this->out->elementStart('li');
|
$this->out->elementStart('li');
|
||||||
|
// TRANS: Label on profile design page for setting a profile page sidebar colour.
|
||||||
$this->out->element('label', array('for' => 'swatch-3'), _('Sidebar'));
|
$this->out->element('label', array('for' => 'swatch-3'), _('Sidebar'));
|
||||||
$this->out->element('input', array('name' => 'design_sidebar',
|
$this->out->element('input', array('name' => 'design_sidebar',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
@ -260,6 +276,7 @@ class DesignForm extends Form
|
||||||
$tcolor = new WebColor($this->design->textcolor);
|
$tcolor = new WebColor($this->design->textcolor);
|
||||||
|
|
||||||
$this->out->elementStart('li');
|
$this->out->elementStart('li');
|
||||||
|
// TRANS: Label on profile design page for setting a profile page text colour.
|
||||||
$this->out->element('label', array('for' => 'swatch-4'), _('Text'));
|
$this->out->element('label', array('for' => 'swatch-4'), _('Text'));
|
||||||
$this->out->element('input', array('name' => 'design_text',
|
$this->out->element('input', array('name' => 'design_text',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
@ -273,6 +290,7 @@ class DesignForm extends Form
|
||||||
$lcolor = new WebColor($this->design->linkcolor);
|
$lcolor = new WebColor($this->design->linkcolor);
|
||||||
|
|
||||||
$this->out->elementStart('li');
|
$this->out->elementStart('li');
|
||||||
|
// TRANS: Label on profile design page for setting a profile page links colour.
|
||||||
$this->out->element('label', array('for' => 'swatch-5'), _('Links'));
|
$this->out->element('label', array('for' => 'swatch-5'), _('Links'));
|
||||||
$this->out->element('input', array('name' => 'design_links',
|
$this->out->element('input', array('name' => 'design_links',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
@ -298,7 +316,9 @@ class DesignForm extends Form
|
||||||
|
|
||||||
function formActions()
|
function formActions()
|
||||||
{
|
{
|
||||||
$this->out->submit('save', _('Save'), 'submit form_action-secondary',
|
// TRANS: Button text on profile design page to save settings.
|
||||||
|
$this->out->submit('save', _m('BUTTON','Save'), 'submit form_action-secondary',
|
||||||
|
// TRANS: Title for button on profile design page to save settings.
|
||||||
'save', _('Save design'));
|
'save', _('Save design'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,8 @@ require_once INSTALLDIR . '/lib/webcolor.php';
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class DesignSettingsAction extends AccountSettingsAction
|
class DesignSettingsAction extends AccountSettingsAction
|
||||||
{
|
{
|
||||||
|
|
||||||
var $submitaction = null;
|
var $submitaction = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,9 +57,9 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
*
|
*
|
||||||
* @return string Title of the page
|
* @return string Title of the page
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
|
// TRANS: Page title for profile design page.
|
||||||
return _('Profile design');
|
return _('Profile design');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,9 +68,9 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
*
|
*
|
||||||
* @return instructions for use
|
* @return instructions for use
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function getInstructions()
|
function getInstructions()
|
||||||
{
|
{
|
||||||
|
// TRANS: Instructions for profile design page.
|
||||||
return _('Customize the way your profile looks ' .
|
return _('Customize the way your profile looks ' .
|
||||||
'with a background image and a colour palette of your choice.');
|
'with a background image and a colour palette of your choice.');
|
||||||
}
|
}
|
||||||
|
@ -84,11 +82,11 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
*
|
*
|
||||||
* @return nothing
|
* @return nothing
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function showDesignForm($design)
|
function showDesignForm($design)
|
||||||
{
|
{
|
||||||
$form = new DesignForm($this, $design, $this->selfUrl());
|
$form = new DesignForm($this, $design, $this->selfUrl());
|
||||||
$form->show();
|
$form->show();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,7 +97,6 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function handlePost()
|
function handlePost()
|
||||||
{
|
{
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
@ -111,8 +108,10 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
&& empty($_POST)
|
&& empty($_POST)
|
||||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||||
) {
|
) {
|
||||||
$msg = _('The server was unable to handle that much POST ' .
|
// TRANS: Form validation error in design settings form. POST should remain untranslated.
|
||||||
'data (%s bytes) due to its current configuration.');
|
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
||||||
|
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
||||||
|
intval($_SERVER['CONTENT_LENGTH']));
|
||||||
|
|
||||||
$this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
$this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||||
return;
|
return;
|
||||||
|
@ -132,6 +131,7 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
} else if ($this->arg('defaults')) {
|
} else if ($this->arg('defaults')) {
|
||||||
$this->restoreDefaults();
|
$this->restoreDefaults();
|
||||||
} else {
|
} else {
|
||||||
|
// TRANS: Unknown form validation error in design settings form.
|
||||||
$this->showForm(_('Unexpected form submission.'));
|
$this->showForm(_('Unexpected form submission.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,6 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function showStylesheets()
|
function showStylesheets()
|
||||||
{
|
{
|
||||||
parent::showStylesheets();
|
parent::showStylesheets();
|
||||||
|
@ -153,7 +152,6 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function showScripts()
|
function showScripts()
|
||||||
{
|
{
|
||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
|
@ -171,7 +169,6 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
*
|
*
|
||||||
* @return nothing
|
* @return nothing
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function saveBackgroundImage($design)
|
function saveBackgroundImage($design)
|
||||||
{
|
{
|
||||||
// Now that we have a Design ID we can add a file to the design.
|
// Now that we have a Design ID we can add a file to the design.
|
||||||
|
@ -217,6 +214,7 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
|
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
common_log_db_error($design, 'UPDATE', __FILE__);
|
common_log_db_error($design, 'UPDATE', __FILE__);
|
||||||
|
// TRANS: Error message displayed if design settings could not be saved.
|
||||||
$this->showForm(_('Couldn\'t update your design.'));
|
$this->showForm(_('Couldn\'t update your design.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -228,7 +226,6 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
*
|
*
|
||||||
* @return nothing
|
* @return nothing
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function restoreDefaults()
|
function restoreDefaults()
|
||||||
{
|
{
|
||||||
$design = $this->getWorkingDesign();
|
$design = $this->getWorkingDesign();
|
||||||
|
@ -239,12 +236,13 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||||
|
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
common_log_db_error($design, 'DELETE', __FILE__);
|
common_log_db_error($design, 'DELETE', __FILE__);
|
||||||
|
// TRANS: Error message displayed if design settings could not be saved after clicking "Use defaults".
|
||||||
$this->showForm(_('Couldn\'t update your design.'));
|
$this->showForm(_('Couldn\'t update your design.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TRANS: Success message displayed if design settings were saved after clicking "Use defaults".
|
||||||
$this->showForm(_('Design defaults restored.'), true);
|
$this->showForm(_('Design defaults restored.'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,17 @@ require_once 'markdown.php';
|
||||||
|
|
||||||
// XXX: other formats here
|
// XXX: other formats here
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Avoid the NICKNAME_FMT constant; use the Nickname class instead.
|
||||||
|
*
|
||||||
|
* Nickname::DISPLAY_FMT is more suitable for inserting into regexes;
|
||||||
|
* note that it includes the [] and repeating bits, so should be wrapped
|
||||||
|
* directly in a capture paren usually.
|
||||||
|
*
|
||||||
|
* For validation, use Nickname::normalize(), Nickname::isValid() etc.
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
define('NICKNAME_FMT', VALIDATE_NUM.VALIDATE_ALPHA_LOWER);
|
define('NICKNAME_FMT', VALIDATE_NUM.VALIDATE_ALPHA_LOWER);
|
||||||
|
|
||||||
require_once INSTALLDIR.'/lib/util.php';
|
require_once INSTALLDIR.'/lib/util.php';
|
||||||
|
|
|
@ -119,9 +119,16 @@ class HTMLOutputter extends XMLOutputter
|
||||||
|
|
||||||
$language = $this->getLanguage();
|
$language = $this->getLanguage();
|
||||||
|
|
||||||
$this->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
|
$attrs = array(
|
||||||
|
'xmlns' => 'http://www.w3.org/1999/xhtml',
|
||||||
'xml:lang' => $language,
|
'xml:lang' => $language,
|
||||||
'lang' => $language));
|
'lang' => $language
|
||||||
|
);
|
||||||
|
|
||||||
|
if (Event::handle('StartHtmlElement', array($this, &$attrs))) {
|
||||||
|
$this->elementStart('html', $attrs);
|
||||||
|
Event::handle('EndHtmlElement', array($this, &$attrs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLanguage()
|
function getLanguage()
|
||||||
|
|
|
@ -115,10 +115,46 @@ class ImageFile
|
||||||
return new ImageFile(null, $_FILES[$param]['tmp_name']);
|
return new ImageFile(null, $_FILES[$param]['tmp_name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compat interface for old code generating avatar thumbnails...
|
||||||
|
* Saves the scaled file directly into the avatar area.
|
||||||
|
*
|
||||||
|
* @param int $size target width & height -- must be square
|
||||||
|
* @param int $x (default 0) upper-left corner to crop from
|
||||||
|
* @param int $y (default 0) upper-left corner to crop from
|
||||||
|
* @param int $w (default full) width of image area to crop
|
||||||
|
* @param int $h (default full) height of image area to crop
|
||||||
|
* @return string filename
|
||||||
|
*/
|
||||||
function resize($size, $x = 0, $y = 0, $w = null, $h = null)
|
function resize($size, $x = 0, $y = 0, $w = null, $h = null)
|
||||||
|
{
|
||||||
|
$targetType = $this->preferredType($this->type);
|
||||||
|
$outname = Avatar::filename($this->id,
|
||||||
|
image_type_to_extension($targetType),
|
||||||
|
$size,
|
||||||
|
common_timestamp());
|
||||||
|
$outpath = Avatar::path($outname);
|
||||||
|
$this->resizeTo($outpath, $size, $size, $x, $y, $w, $h);
|
||||||
|
return $outname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and save a thumbnail image.
|
||||||
|
*
|
||||||
|
* @param string $outpath
|
||||||
|
* @param int $width target width
|
||||||
|
* @param int $height target height
|
||||||
|
* @param int $x (default 0) upper-left corner to crop from
|
||||||
|
* @param int $y (default 0) upper-left corner to crop from
|
||||||
|
* @param int $w (default full) width of image area to crop
|
||||||
|
* @param int $h (default full) height of image area to crop
|
||||||
|
* @return string full local filesystem filename
|
||||||
|
*/
|
||||||
|
function resizeTo($outpath, $width, $height, $x=0, $y=0, $w=null, $h=null)
|
||||||
{
|
{
|
||||||
$w = ($w === null) ? $this->width:$w;
|
$w = ($w === null) ? $this->width:$w;
|
||||||
$h = ($h === null) ? $this->height:$h;
|
$h = ($h === null) ? $this->height:$h;
|
||||||
|
$targetType = $this->preferredType($this->type);
|
||||||
|
|
||||||
if (!file_exists($this->filepath)) {
|
if (!file_exists($this->filepath)) {
|
||||||
throw new Exception(_('Lost our file.'));
|
throw new Exception(_('Lost our file.'));
|
||||||
|
@ -126,20 +162,16 @@ class ImageFile
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't crop/scale if it isn't necessary
|
// Don't crop/scale if it isn't necessary
|
||||||
if ($size === $this->width
|
if ($width === $this->width
|
||||||
&& $size === $this->height
|
&& $height === $this->height
|
||||||
&& $x === 0
|
&& $x === 0
|
||||||
&& $y === 0
|
&& $y === 0
|
||||||
&& $w === $this->width
|
&& $w === $this->width
|
||||||
&& $h === $this->height) {
|
&& $h === $this->height
|
||||||
|
&& $this->type == $targetType) {
|
||||||
|
|
||||||
$outname = Avatar::filename($this->id,
|
|
||||||
image_type_to_extension($this->type),
|
|
||||||
$size,
|
|
||||||
common_timestamp());
|
|
||||||
$outpath = Avatar::path($outname);
|
|
||||||
@copy($this->filepath, $outpath);
|
@copy($this->filepath, $outpath);
|
||||||
return $outname;
|
return $outpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($this->type) {
|
switch ($this->type) {
|
||||||
|
@ -166,7 +198,7 @@ class ImageFile
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$image_dest = imagecreatetruecolor($size, $size);
|
$image_dest = imagecreatetruecolor($width, $height);
|
||||||
|
|
||||||
if ($this->type == IMAGETYPE_GIF || $this->type == IMAGETYPE_PNG || $this->type == IMAGETYPE_BMP) {
|
if ($this->type == IMAGETYPE_GIF || $this->type == IMAGETYPE_PNG || $this->type == IMAGETYPE_BMP) {
|
||||||
|
|
||||||
|
@ -189,30 +221,9 @@ class ImageFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
imagecopyresampled($image_dest, $image_src, 0, 0, $x, $y, $size, $size, $w, $h);
|
imagecopyresampled($image_dest, $image_src, 0, 0, $x, $y, $width, $height, $w, $h);
|
||||||
|
|
||||||
if($this->type == IMAGETYPE_BMP) {
|
switch ($targetType) {
|
||||||
//we don't want to save BMP... it's an inefficient, rare, antiquated format
|
|
||||||
//save png instead
|
|
||||||
$this->type = IMAGETYPE_PNG;
|
|
||||||
} else if($this->type == IMAGETYPE_WBMP) {
|
|
||||||
//we don't want to save WBMP... it's a rare format that we can't guarantee clients will support
|
|
||||||
//save png instead
|
|
||||||
$this->type = IMAGETYPE_PNG;
|
|
||||||
} else if($this->type == IMAGETYPE_XBM) {
|
|
||||||
//we don't want to save XBM... it's a rare format that we can't guarantee clients will support
|
|
||||||
//save png instead
|
|
||||||
$this->type = IMAGETYPE_PNG;
|
|
||||||
}
|
|
||||||
|
|
||||||
$outname = Avatar::filename($this->id,
|
|
||||||
image_type_to_extension($this->type),
|
|
||||||
$size,
|
|
||||||
common_timestamp());
|
|
||||||
|
|
||||||
$outpath = Avatar::path($outname);
|
|
||||||
|
|
||||||
switch ($this->type) {
|
|
||||||
case IMAGETYPE_GIF:
|
case IMAGETYPE_GIF:
|
||||||
imagegif($image_dest, $outpath);
|
imagegif($image_dest, $outpath);
|
||||||
break;
|
break;
|
||||||
|
@ -230,7 +241,31 @@ class ImageFile
|
||||||
imagedestroy($image_src);
|
imagedestroy($image_src);
|
||||||
imagedestroy($image_dest);
|
imagedestroy($image_dest);
|
||||||
|
|
||||||
return $outname;
|
return $outpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Several obscure file types should be normalized to PNG on resize.
|
||||||
|
*
|
||||||
|
* @param int $type
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
function preferredType($type)
|
||||||
|
{
|
||||||
|
if($type == IMAGETYPE_BMP) {
|
||||||
|
//we don't want to save BMP... it's an inefficient, rare, antiquated format
|
||||||
|
//save png instead
|
||||||
|
return IMAGETYPE_PNG;
|
||||||
|
} else if($type == IMAGETYPE_WBMP) {
|
||||||
|
//we don't want to save WBMP... it's a rare format that we can't guarantee clients will support
|
||||||
|
//save png instead
|
||||||
|
return IMAGETYPE_PNG;
|
||||||
|
} else if($type == IMAGETYPE_XBM) {
|
||||||
|
//we don't want to save XBM... it's a rare format that we can't guarantee clients will support
|
||||||
|
//save png instead
|
||||||
|
return IMAGETYPE_PNG;
|
||||||
|
}
|
||||||
|
return $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
function unlink()
|
function unlink()
|
||||||
|
|
108
lib/inlineattachmentlist.php
Normal file
108
lib/inlineattachmentlist.php
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* widget for displaying notice attachments thumbnails
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category UI
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Brion Vibber <brion@status.net>
|
||||||
|
* @copyright 2010 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
class InlineAttachmentList extends AttachmentList
|
||||||
|
{
|
||||||
|
function showListStart()
|
||||||
|
{
|
||||||
|
$this->out->elementStart('div', array('class' => 'entry-content thumbnails'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function showListEnd()
|
||||||
|
{
|
||||||
|
$this->out->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a new list item for the current attachment
|
||||||
|
*
|
||||||
|
* @param File $notice the current attachment
|
||||||
|
*
|
||||||
|
* @return ListItem a list item for displaying the attachment
|
||||||
|
*/
|
||||||
|
function newListItem($attachment)
|
||||||
|
{
|
||||||
|
return new InlineAttachmentListItem($attachment, $this->out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InlineAttachmentListItem extends AttachmentListItem
|
||||||
|
{
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
if ($this->attachment->isEnclosure()) {
|
||||||
|
parent::show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLink() {
|
||||||
|
$this->out->elementStart('a', $this->linkAttr());
|
||||||
|
$this->showRepresentation();
|
||||||
|
$this->out->elementEnd('a');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build HTML attributes for the link
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function linkAttr()
|
||||||
|
{
|
||||||
|
$attr = parent::linkAttr();
|
||||||
|
$attr['class'] = 'attachment-thumbnail';
|
||||||
|
return $attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* start a single notice.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function showStart()
|
||||||
|
{
|
||||||
|
// XXX: RDFa
|
||||||
|
// TODO: add notice_type class e.g., notice_video, notice_image
|
||||||
|
$this->out->elementStart('span', array('class' => 'inline-attachment'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finish the notice
|
||||||
|
*
|
||||||
|
* Close the last elements in the notice list item
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function showEnd()
|
||||||
|
{
|
||||||
|
$this->out->elementEnd('span');
|
||||||
|
}
|
||||||
|
}
|
|
@ -101,6 +101,10 @@ class JSONSearchResultsList
|
||||||
$this->max_id = (int)$this->notice->id;
|
$this->max_id = (int)$this->notice->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->since_id && $this->notice->id <= $this->since_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ($cnt > $this->rpp) {
|
if ($cnt > $this->rpp) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ class MailHandler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$msg = $this->cleanup_msg($msg);
|
$msg = $this->cleanup_msg($msg);
|
||||||
$msg = common_shorten_links($msg);
|
$msg = $user->shortenLinks($msg);
|
||||||
if (Notice::contentTooLong($msg)) {
|
if (Notice::contentTooLong($msg)) {
|
||||||
$this->error($from, sprintf(_('That\'s too long. Maximum notice size is %d character.',
|
$this->error($from, sprintf(_('That\'s too long. Maximum notice size is %d character.',
|
||||||
'That\'s too long. Maximum notice size is %d characters.',
|
'That\'s too long. Maximum notice size is %d characters.',
|
||||||
|
|
|
@ -48,11 +48,14 @@ class MediaFile
|
||||||
{
|
{
|
||||||
if ($user == null) {
|
if ($user == null) {
|
||||||
$this->user = common_current_user();
|
$this->user = common_current_user();
|
||||||
|
} else {
|
||||||
|
$this->user = $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->filename = $filename;
|
$this->filename = $filename;
|
||||||
$this->mimetype = $mimetype;
|
$this->mimetype = $mimetype;
|
||||||
$this->fileRecord = $this->storeFile();
|
$this->fileRecord = $this->storeFile();
|
||||||
|
$this->thumbnailRecord = $this->storeThumbnail();
|
||||||
|
|
||||||
$this->fileurl = common_local_url('attachment',
|
$this->fileurl = common_local_url('attachment',
|
||||||
array('attachment' => $this->fileRecord->id));
|
array('attachment' => $this->fileRecord->id));
|
||||||
|
@ -102,6 +105,52 @@ class MediaFile
|
||||||
return $file;
|
return $file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate and store a thumbnail image for the uploaded file, if applicable.
|
||||||
|
*
|
||||||
|
* @return File_thumbnail or null
|
||||||
|
*/
|
||||||
|
function storeThumbnail()
|
||||||
|
{
|
||||||
|
if (substr($this->mimetype, 0, strlen('image/')) != 'image/') {
|
||||||
|
// @fixme video thumbs would be nice!
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$image = new ImageFile($this->fileRecord->id,
|
||||||
|
File::path($this->filename));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Unsupported image type.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$outname = File::filename($this->user->getProfile(), 'thumb-' . $this->filename, $this->mimetype);
|
||||||
|
$outpath = File::path($outname);
|
||||||
|
|
||||||
|
$maxWidth = common_config('attachments', 'thumb_width');
|
||||||
|
$maxHeight = common_config('attachments', 'thumb_height');
|
||||||
|
list($width, $height) = $this->scaleToFit($image->width, $image->height, $maxWidth, $maxHeight);
|
||||||
|
|
||||||
|
$image->resizeTo($outpath, $width, $height);
|
||||||
|
File_thumbnail::saveThumbnail($this->fileRecord->id,
|
||||||
|
File::url($outname),
|
||||||
|
$width,
|
||||||
|
$height);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scaleToFit($width, $height, $maxWidth, $maxHeight)
|
||||||
|
{
|
||||||
|
$aspect = $maxWidth / $maxHeight;
|
||||||
|
$w1 = $maxWidth;
|
||||||
|
$h1 = intval($height * $maxWidth / $width);
|
||||||
|
if ($h1 > $maxHeight) {
|
||||||
|
$w2 = intval($width * $maxHeight / $height);
|
||||||
|
$h2 = $maxHeight;
|
||||||
|
return array($w2, $h2);
|
||||||
|
}
|
||||||
|
return array($w1, $h1);
|
||||||
|
}
|
||||||
|
|
||||||
function rememberFile($file, $short)
|
function rememberFile($file, $short)
|
||||||
{
|
{
|
||||||
$this->maybeAddRedir($file->id, $short);
|
$this->maybeAddRedir($file->id, $short);
|
||||||
|
@ -278,6 +327,9 @@ class MediaFile
|
||||||
static function getUploadedFileType($f, $originalFilename=false) {
|
static function getUploadedFileType($f, $originalFilename=false) {
|
||||||
require_once 'MIME/Type.php';
|
require_once 'MIME/Type.php';
|
||||||
require_once 'MIME/Type/Extension.php';
|
require_once 'MIME/Type/Extension.php';
|
||||||
|
|
||||||
|
// We have to disable auto handling of PEAR errors
|
||||||
|
PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
|
||||||
$mte = new MIME_Type_Extension();
|
$mte = new MIME_Type_Extension();
|
||||||
|
|
||||||
$cmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd');
|
$cmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd');
|
||||||
|
@ -330,6 +382,8 @@ class MediaFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($supported === true || in_array($filetype, $supported)) {
|
if ($supported === true || in_array($filetype, $supported)) {
|
||||||
|
// Restore PEAR error handlers for our DB code...
|
||||||
|
PEAR::staticPopErrorHandling();
|
||||||
return $filetype;
|
return $filetype;
|
||||||
}
|
}
|
||||||
$media = MIME_Type::getMedia($filetype);
|
$media = MIME_Type::getMedia($filetype);
|
||||||
|
@ -344,6 +398,8 @@ class MediaFile
|
||||||
// TRANS: %s is the file type that was denied.
|
// TRANS: %s is the file type that was denied.
|
||||||
$hint = sprintf(_('"%s" is not a supported file type on this server.'), $filetype);
|
$hint = sprintf(_('"%s" is not a supported file type on this server.'), $filetype);
|
||||||
}
|
}
|
||||||
|
// Restore PEAR error handlers for our DB code...
|
||||||
|
PEAR::staticPopErrorHandling();
|
||||||
throw new ClientException($hint);
|
throw new ClientException($hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,8 @@ class MessageForm extends Form
|
||||||
$mutual_users = $user->mutuallySubscribedUsers();
|
$mutual_users = $user->mutuallySubscribedUsers();
|
||||||
|
|
||||||
$mutual = array();
|
$mutual = array();
|
||||||
|
// TRANS Label entry in drop-down selection box in direct-message inbox/outbox. This is the default entry in the drop-down box, doubling as instructions and a brake against accidental submissions with the first user in the list.
|
||||||
|
$mutual[0] = _('Select recipient:');
|
||||||
|
|
||||||
while ($mutual_users->fetch()) {
|
while ($mutual_users->fetch()) {
|
||||||
if ($mutual_users->id != $user->id) {
|
if ($mutual_users->id != $user->id) {
|
||||||
|
@ -143,6 +145,11 @@ class MessageForm extends Form
|
||||||
$mutual_users->free();
|
$mutual_users->free();
|
||||||
unset($mutual_users);
|
unset($mutual_users);
|
||||||
|
|
||||||
|
if (count($mutual) == 1) {
|
||||||
|
// TRANS Entry in drop-down selection box in direct-message inbox/outbox when no one is available to message.
|
||||||
|
$mutual[0] = _('No mutual subscribers.');
|
||||||
|
}
|
||||||
|
|
||||||
$this->out->dropdown('to', _('To'), $mutual, null, false,
|
$this->out->dropdown('to', _('To'), $mutual, null, false,
|
||||||
($this->to) ? $this->to->id : null);
|
($this->to) ? $this->to->id : null);
|
||||||
|
|
||||||
|
|
176
lib/nickname.php
Normal file
176
lib/nickname.php
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, 2009, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Nickname
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Regex fragment for pulling an arbitrarily-formated nickname.
|
||||||
|
*
|
||||||
|
* Not guaranteed to be valid after normalization; run the string through
|
||||||
|
* Nickname::normalize() to get the canonical form, or Nickname::isValid()
|
||||||
|
* if you just need to check if it's properly formatted.
|
||||||
|
*
|
||||||
|
* This and CANONICAL_FMT replace the old NICKNAME_FMT, but be aware
|
||||||
|
* that these should not be enclosed in []s.
|
||||||
|
*/
|
||||||
|
const DISPLAY_FMT = '[0-9a-zA-Z_]+';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regex fragment for checking a canonical nickname.
|
||||||
|
*
|
||||||
|
* Any non-matching string is not a valid canonical/normalized nickname.
|
||||||
|
* Matching strings are valid and canonical form, but may still be
|
||||||
|
* unavailable for registration due to blacklisting et.
|
||||||
|
*
|
||||||
|
* Only the canonical forms should be stored as keys in the database;
|
||||||
|
* there are multiple possible denormalized forms for each valid
|
||||||
|
* canonical-form name.
|
||||||
|
*
|
||||||
|
* This and DISPLAY_FMT replace the old NICKNAME_FMT, but be aware
|
||||||
|
* that these should not be enclosed in []s.
|
||||||
|
*/
|
||||||
|
const CANONICAL_FMT = '[0-9a-z]{1,64}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of characters in a canonical-form nickname.
|
||||||
|
*/
|
||||||
|
const MAX_LEN = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nice simple check of whether the given string is a valid input nickname,
|
||||||
|
* which can be normalized into an internally canonical form.
|
||||||
|
*
|
||||||
|
* Note that valid nicknames may be in use or reserved.
|
||||||
|
*
|
||||||
|
* @param string $str
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function isValid($str)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
self::normalize($str);
|
||||||
|
return true;
|
||||||
|
} catch (NicknameException $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate an input nickname string, and normalize it to its canonical form.
|
||||||
|
* The canonical form will be returned, or an exception thrown if invalid.
|
||||||
|
*
|
||||||
|
* @param string $str
|
||||||
|
* @return string Normalized canonical form of $str
|
||||||
|
*
|
||||||
|
* @throws NicknameException (base class)
|
||||||
|
* @throws NicknameInvalidException
|
||||||
|
* @throws NicknameEmptyException
|
||||||
|
* @throws NicknameTooLongException
|
||||||
|
*/
|
||||||
|
public static function normalize($str)
|
||||||
|
{
|
||||||
|
$str = trim($str);
|
||||||
|
$str = str_replace('_', '', $str);
|
||||||
|
$str = mb_strtolower($str);
|
||||||
|
|
||||||
|
$len = mb_strlen($str);
|
||||||
|
if ($len < 1) {
|
||||||
|
throw new NicknameEmptyException();
|
||||||
|
} else if ($len > self::MAX_LEN) {
|
||||||
|
throw new NicknameTooLongException();
|
||||||
|
}
|
||||||
|
if (!self::isCanonical($str)) {
|
||||||
|
throw new NicknameInvalidException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the given string a valid canonical nickname form?
|
||||||
|
*
|
||||||
|
* @param string $str
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function isCanonical($str)
|
||||||
|
{
|
||||||
|
return preg_match('/^(?:' . self::CANONICAL_FMT . ')$/', $str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NicknameException extends ClientException
|
||||||
|
{
|
||||||
|
function __construct($msg=null, $code=400)
|
||||||
|
{
|
||||||
|
if ($msg === null) {
|
||||||
|
$msg = $this->defaultMessage();
|
||||||
|
}
|
||||||
|
parent::__construct($msg, $code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default localized message for this type of exception.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function defaultMessage()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NicknameInvalidException extends NicknameException {
|
||||||
|
/**
|
||||||
|
* Default localized message for this type of exception.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function defaultMessage()
|
||||||
|
{
|
||||||
|
// TRANS: Validation error in form for registration, profile and group settings, etc.
|
||||||
|
return _('Nickname must have only lowercase letters and numbers and no spaces.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NicknameEmptyException extends NicknameException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Default localized message for this type of exception.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function defaultMessage()
|
||||||
|
{
|
||||||
|
// TRANS: Validation error in form for registration, profile and group settings, etc.
|
||||||
|
return _('Nickname cannot be empty.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NicknameTooLongException extends NicknameInvalidException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Default localized message for this type of exception.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function defaultMessage()
|
||||||
|
{
|
||||||
|
// TRANS: Validation error in form for registration, profile and group settings, etc.
|
||||||
|
return sprintf(_m('Nickname cannot be more than %d character long.',
|
||||||
|
'Nickname cannot be more than %d characters long.',
|
||||||
|
Nickname::MAX_LEN),
|
||||||
|
Nickname::MAX_LEN);
|
||||||
|
}
|
||||||
|
}
|
|
@ -208,6 +208,7 @@ class NoticeListItem extends Widget
|
||||||
$this->showStart();
|
$this->showStart();
|
||||||
if (Event::handle('StartShowNoticeItem', array($this))) {
|
if (Event::handle('StartShowNoticeItem', array($this))) {
|
||||||
$this->showNotice();
|
$this->showNotice();
|
||||||
|
$this->showNoticeAttachments();
|
||||||
$this->showNoticeInfo();
|
$this->showNoticeInfo();
|
||||||
$this->showNoticeOptions();
|
$this->showNoticeOptions();
|
||||||
Event::handle('EndShowNoticeItem', array($this));
|
Event::handle('EndShowNoticeItem', array($this));
|
||||||
|
@ -327,11 +328,8 @@ class NoticeListItem extends Widget
|
||||||
|
|
||||||
function showAvatar()
|
function showAvatar()
|
||||||
{
|
{
|
||||||
if ('shownotice' === $this->out->trimmed('action')) {
|
|
||||||
$avatar_size = AVATAR_PROFILE_SIZE;
|
|
||||||
} else {
|
|
||||||
$avatar_size = AVATAR_STREAM_SIZE;
|
$avatar_size = AVATAR_STREAM_SIZE;
|
||||||
}
|
|
||||||
$avatar = $this->profile->getAvatar($avatar_size);
|
$avatar = $this->profile->getAvatar($avatar_size);
|
||||||
|
|
||||||
$this->out->element('img', array('src' => ($avatar) ?
|
$this->out->element('img', array('src' => ($avatar) ?
|
||||||
|
@ -386,6 +384,13 @@ class NoticeListItem extends Widget
|
||||||
$this->out->elementEnd('p');
|
$this->out->elementEnd('p');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showNoticeAttachments() {
|
||||||
|
if (common_config('attachments', 'show_thumbs')) {
|
||||||
|
$al = new InlineAttachmentList($this->notice, $this->out);
|
||||||
|
$al->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* show the link to the main page for the notice
|
* show the link to the main page for the notice
|
||||||
*
|
*
|
||||||
|
|
318
lib/oembedhelper.php
Normal file
318
lib/oembedhelper.php
Normal file
|
@ -0,0 +1,318 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008-2010, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class to wrap basic oEmbed lookups.
|
||||||
|
*
|
||||||
|
* Blacklisted hosts will use an alternate lookup method:
|
||||||
|
* - Twitpic
|
||||||
|
*
|
||||||
|
* Whitelisted hosts will use known oEmbed API endpoints:
|
||||||
|
* - Flickr, YFrog
|
||||||
|
*
|
||||||
|
* Sites that provide discovery links will use them directly; a bug
|
||||||
|
* in use of discovery links with query strings is worked around.
|
||||||
|
*
|
||||||
|
* Others will fall back to oohembed (unless disabled).
|
||||||
|
* The API endpoint can be configured or disabled through config
|
||||||
|
* as 'oohembed'/'endpoint'.
|
||||||
|
*/
|
||||||
|
class oEmbedHelper
|
||||||
|
{
|
||||||
|
protected static $apiMap = array(
|
||||||
|
'flickr.com' => 'http://www.flickr.com/services/oembed/',
|
||||||
|
'yfrog.com' => 'http://www.yfrog.com/api/oembed',
|
||||||
|
);
|
||||||
|
protected static $functionMap = array(
|
||||||
|
'twitpic.com' => 'oEmbedHelper::twitPic',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform or fake an oEmbed lookup for the given resource.
|
||||||
|
*
|
||||||
|
* Some known hosts are whitelisted with API endpoints where we
|
||||||
|
* know they exist but autodiscovery data isn't available.
|
||||||
|
* If autodiscovery links are missing and we don't recognize the
|
||||||
|
* host, we'll pass it to oohembed.com's public service which
|
||||||
|
* will either proxy or fake info on a lot of sites.
|
||||||
|
*
|
||||||
|
* A few hosts are blacklisted due to known problems with oohembed,
|
||||||
|
* in which case we'll look up the info another way and return
|
||||||
|
* equivalent data.
|
||||||
|
*
|
||||||
|
* Throws exceptions on failure.
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param array $params
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
public static function getObject($url, $params=array())
|
||||||
|
{
|
||||||
|
$host = parse_url($url, PHP_URL_HOST);
|
||||||
|
if (substr($host, 0, 4) == 'www.') {
|
||||||
|
$host = substr($host, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blacklist: systems with no oEmbed API of their own, which are
|
||||||
|
// either missing from or broken on oohembed.com's proxy.
|
||||||
|
// we know how to look data up in another way...
|
||||||
|
if (array_key_exists($host, self::$functionMap)) {
|
||||||
|
$func = self::$functionMap[$host];
|
||||||
|
return call_user_func($func, $url, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whitelist: known API endpoints for sites that don't provide discovery...
|
||||||
|
if (array_key_exists($host, self::$apiMap)) {
|
||||||
|
$api = self::$apiMap[$host];
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$api = self::discover($url);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Discovery failed... fall back to oohembed if enabled.
|
||||||
|
$oohembed = common_config('oohembed', 'endpoint');
|
||||||
|
if ($oohembed) {
|
||||||
|
$api = $oohembed;
|
||||||
|
} else {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self::getObjectFrom($api, $url, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform basic discovery.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static function discover($url)
|
||||||
|
{
|
||||||
|
// @fixme ideally skip this for non-HTML stuff!
|
||||||
|
$body = self::http($url);
|
||||||
|
return self::discoverFromHTML($url, $body);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partially ripped from OStatus' FeedDiscovery class.
|
||||||
|
*
|
||||||
|
* @param string $url source URL, used to resolve relative links
|
||||||
|
* @param string $body HTML body text
|
||||||
|
* @return mixed string with URL or false if no target found
|
||||||
|
*/
|
||||||
|
static function discoverFromHTML($url, $body)
|
||||||
|
{
|
||||||
|
// DOMDocument::loadHTML may throw warnings on unrecognized elements,
|
||||||
|
// and notices on unrecognized namespaces.
|
||||||
|
$old = error_reporting(error_reporting() & ~(E_WARNING | E_NOTICE));
|
||||||
|
$dom = new DOMDocument();
|
||||||
|
$ok = $dom->loadHTML($body);
|
||||||
|
error_reporting($old);
|
||||||
|
|
||||||
|
if (!$ok) {
|
||||||
|
throw new oEmbedHelper_BadHtmlException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok... now on to the links!
|
||||||
|
$feeds = array(
|
||||||
|
'application/json+oembed' => false,
|
||||||
|
);
|
||||||
|
|
||||||
|
$nodes = $dom->getElementsByTagName('link');
|
||||||
|
for ($i = 0; $i < $nodes->length; $i++) {
|
||||||
|
$node = $nodes->item($i);
|
||||||
|
if ($node->hasAttributes()) {
|
||||||
|
$rel = $node->attributes->getNamedItem('rel');
|
||||||
|
$type = $node->attributes->getNamedItem('type');
|
||||||
|
$href = $node->attributes->getNamedItem('href');
|
||||||
|
if ($rel && $type && $href) {
|
||||||
|
$rel = array_filter(explode(" ", $rel->value));
|
||||||
|
$type = trim($type->value);
|
||||||
|
$href = trim($href->value);
|
||||||
|
|
||||||
|
if (in_array('alternate', $rel) && array_key_exists($type, $feeds) && empty($feeds[$type])) {
|
||||||
|
// Save the first feed found of each type...
|
||||||
|
$feeds[$type] = $href;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the highest-priority feed found
|
||||||
|
foreach ($feeds as $type => $url) {
|
||||||
|
if ($url) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new oEmbedHelper_DiscoveryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actually do an oEmbed lookup to a particular API endpoint.
|
||||||
|
*
|
||||||
|
* @param string $api oEmbed API endpoint URL
|
||||||
|
* @param string $url target URL to look up info about
|
||||||
|
* @param array $params
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
static function getObjectFrom($api, $url, $params=array())
|
||||||
|
{
|
||||||
|
$params['url'] = $url;
|
||||||
|
$params['format'] = 'json';
|
||||||
|
$data = self::json($api, $params);
|
||||||
|
return self::normalize($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize oEmbed format.
|
||||||
|
*
|
||||||
|
* @param object $orig
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
static function normalize($orig)
|
||||||
|
{
|
||||||
|
$data = clone($orig);
|
||||||
|
|
||||||
|
if (empty($data->type)) {
|
||||||
|
throw new Exception('Invalid oEmbed data: no type field.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data->type == 'image') {
|
||||||
|
// YFrog does this.
|
||||||
|
$data->type = 'photo';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data->thumbnail_url)) {
|
||||||
|
if (!isset($data->thumbnail_width)) {
|
||||||
|
// !?!?!
|
||||||
|
$data->thumbnail_width = common_config('attachments', 'thumb_width');
|
||||||
|
$data->thumbnail_height = common_config('attachments', 'thumb_height');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using a local function for twitpic lookups, as oohembed's adapter
|
||||||
|
* doesn't return a valid result:
|
||||||
|
* http://code.google.com/p/oohembed/issues/detail?id=19
|
||||||
|
*
|
||||||
|
* This code fetches metadata from Twitpic's own API, and attempts
|
||||||
|
* to guess proper thumbnail size from the original's size.
|
||||||
|
*
|
||||||
|
* @todo respect maxwidth and maxheight params
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param array $params
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
static function twitPic($url, $params=array())
|
||||||
|
{
|
||||||
|
$matches = array();
|
||||||
|
if (preg_match('!twitpic\.com/(\w+)!', $url, $matches)) {
|
||||||
|
$id = $matches[1];
|
||||||
|
} else {
|
||||||
|
throw new Exception("Invalid twitpic URL");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab metadata from twitpic's API...
|
||||||
|
// http://dev.twitpic.com/docs/2/media_show
|
||||||
|
$data = self::json('http://api.twitpic.com/2/media/show.json',
|
||||||
|
array('id' => $id));
|
||||||
|
$oembed = (object)array('type' => 'photo',
|
||||||
|
'url' => 'http://twitpic.com/show/full/' . $data->short_id,
|
||||||
|
'width' => $data->width,
|
||||||
|
'height' => $data->height);
|
||||||
|
if (!empty($data->message)) {
|
||||||
|
$oembed->title = $data->message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thumbnail is cropped and scaled to 150x150 box:
|
||||||
|
// http://dev.twitpic.com/docs/thumbnails/
|
||||||
|
$thumbSize = 150;
|
||||||
|
$oembed->thumbnail_url = 'http://twitpic.com/show/thumb/' . $data->short_id;
|
||||||
|
$oembed->thumbnail_width = $thumbSize;
|
||||||
|
$oembed->thumbnail_height = $thumbSize;
|
||||||
|
|
||||||
|
return $oembed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch some URL and return JSON data.
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param array $params query-string params
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
static protected function json($url, $params=array())
|
||||||
|
{
|
||||||
|
$data = self::http($url, $params);
|
||||||
|
return json_decode($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hit some web API and return data on success.
|
||||||
|
* @param string $url
|
||||||
|
* @param array $params
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static protected function http($url, $params=array())
|
||||||
|
{
|
||||||
|
$client = HTTPClient::start();
|
||||||
|
if ($params) {
|
||||||
|
$query = http_build_query($params, null, '&');
|
||||||
|
if (strpos($url, '?') === false) {
|
||||||
|
$url .= '?' . $query;
|
||||||
|
} else {
|
||||||
|
$url .= '&' . $query;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$response = $client->get($url);
|
||||||
|
if ($response->isOk()) {
|
||||||
|
return $response->getBody();
|
||||||
|
} else {
|
||||||
|
throw new Exception('Bad HTTP response code: ' . $response->getStatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class oEmbedHelper_Exception extends Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class oEmbedHelper_BadHtmlException extends oEmbedHelper_Exception
|
||||||
|
{
|
||||||
|
function __construct($previous=null)
|
||||||
|
{
|
||||||
|
return parent::__construct('Bad HTML in discovery data.', 0, $previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class oEmbedHelper_DiscoveryException extends oEmbedHelper_Exception
|
||||||
|
{
|
||||||
|
function __construct($previous=null)
|
||||||
|
{
|
||||||
|
return parent::__construct('No oEmbed discovery data.', 0, $previous);
|
||||||
|
}
|
||||||
|
}
|
92
lib/popularity.php
Normal file
92
lib/popularity.php
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Wrapper for fetching lists of popular notices.
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @author Brion Vibber <brion@status.net>
|
||||||
|
* @copyright 2010 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for fetching notices ranked according to popularity,
|
||||||
|
* broken out so it can be called from multiple actions with
|
||||||
|
* less code duplication.
|
||||||
|
*/
|
||||||
|
class Popularity
|
||||||
|
{
|
||||||
|
public $limit = NOTICES_PER_PAGE;
|
||||||
|
public $offset = 0;
|
||||||
|
public $tag = false;
|
||||||
|
public $expiry = 600;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a cached query to fetch notices, whee!
|
||||||
|
*
|
||||||
|
* @return Notice
|
||||||
|
*/
|
||||||
|
function getNotices()
|
||||||
|
{
|
||||||
|
// @fixme there should be a common func for this
|
||||||
|
if (common_config('db', 'type') == 'pgsql') {
|
||||||
|
if (!empty($this->tag)) {
|
||||||
|
$tag = pg_escape_string($this->tag);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!empty($this->tag)) {
|
||||||
|
$tag = mysql_escape_string($this->tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
|
||||||
|
$cutoff = sprintf("fave.modified > '%s'",
|
||||||
|
common_sql_date(time() - common_config('popular', 'cutoff')));
|
||||||
|
$qry = "SELECT notice.*, $weightexpr as weight ";
|
||||||
|
if(isset($tag)) {
|
||||||
|
$qry .= 'FROM notice_tag, notice JOIN fave ON notice.id = fave.notice_id ' .
|
||||||
|
"WHERE $cutoff and notice.id = notice_tag.notice_id and '$tag' = notice_tag.tag";
|
||||||
|
} else {
|
||||||
|
$qry .= 'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
|
||||||
|
"WHERE $cutoff";
|
||||||
|
}
|
||||||
|
$qry .= ' GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' .
|
||||||
|
'notice.rendered,notice.url,notice.created,notice.modified,' .
|
||||||
|
'notice.reply_to,notice.is_local,notice.source,notice.conversation, ' .
|
||||||
|
'notice.lat,notice.lon,location_id,location_ns,notice.repeat_of';
|
||||||
|
$qry .= ' HAVING \'silenced\' NOT IN (SELECT role FROM profile_role WHERE profile_id=notice.profile_id)';
|
||||||
|
$qry .= ' ORDER BY weight DESC';
|
||||||
|
|
||||||
|
$offset = $this->offset;
|
||||||
|
$limit = $this->limit + 1;
|
||||||
|
|
||||||
|
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||||
|
|
||||||
|
$notice = Memcached_DataObject::cachedQuery('Notice',
|
||||||
|
$qry,
|
||||||
|
1200);
|
||||||
|
return $notice;
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,42 +48,13 @@ class PopularNoticeSection extends NoticeSection
|
||||||
{
|
{
|
||||||
function getNotices()
|
function getNotices()
|
||||||
{
|
{
|
||||||
// @fixme there should be a common func for this
|
$pop = new Popularity();
|
||||||
if (common_config('db', 'type') == 'pgsql') {
|
|
||||||
if (!empty($this->out->tag)) {
|
if (!empty($this->out->tag)) {
|
||||||
$tag = pg_escape_string($this->out->tag);
|
$pop->tag = $this->out->tag;
|
||||||
}
|
}
|
||||||
} else {
|
$pop->limit = NOTICES_PER_SECTION;
|
||||||
if (!empty($this->out->tag)) {
|
$pop->expiry = 1200;
|
||||||
$tag = mysql_escape_string($this->out->tag);
|
return $pop->getNotices();
|
||||||
}
|
|
||||||
}
|
|
||||||
$weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
|
|
||||||
$cutoff = sprintf("fave.modified > '%s'",
|
|
||||||
common_sql_date(time() - common_config('popular', 'cutoff')));
|
|
||||||
$qry = "SELECT notice.*, $weightexpr as weight ";
|
|
||||||
if(isset($tag)) {
|
|
||||||
$qry .= 'FROM notice_tag, notice JOIN fave ON notice.id = fave.notice_id ' .
|
|
||||||
"WHERE $cutoff and notice.id = notice_tag.notice_id and '$tag' = notice_tag.tag";
|
|
||||||
} else {
|
|
||||||
$qry .= 'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
|
|
||||||
"WHERE $cutoff";
|
|
||||||
}
|
|
||||||
$qry .= ' GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' .
|
|
||||||
'notice.rendered,notice.url,notice.created,notice.modified,' .
|
|
||||||
'notice.reply_to,notice.is_local,notice.source,notice.conversation, ' .
|
|
||||||
'notice.lat,notice.lon,location_id,location_ns,notice.repeat_of' .
|
|
||||||
' ORDER BY weight DESC';
|
|
||||||
|
|
||||||
$offset = 0;
|
|
||||||
$limit = NOTICES_PER_SECTION + 1;
|
|
||||||
|
|
||||||
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
|
||||||
|
|
||||||
$notice = Memcached_DataObject::cachedQuery('Notice',
|
|
||||||
$qry,
|
|
||||||
1200);
|
|
||||||
return $notice;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
|
|
|
@ -101,7 +101,7 @@ class ProfileAction extends OwnerDesignAction
|
||||||
|
|
||||||
function showSubscriptions()
|
function showSubscriptions()
|
||||||
{
|
{
|
||||||
$profile = $this->user->getSubscriptions(0, PROFILES_PER_MINILIST + 1);
|
$profile = $this->profile->getSubscriptions(0, PROFILES_PER_MINILIST + 1);
|
||||||
|
|
||||||
$this->elementStart('div', array('id' => 'entity_subscriptions',
|
$this->elementStart('div', array('id' => 'entity_subscriptions',
|
||||||
'class' => 'section'));
|
'class' => 'section'));
|
||||||
|
@ -134,7 +134,7 @@ class ProfileAction extends OwnerDesignAction
|
||||||
|
|
||||||
function showSubscribers()
|
function showSubscribers()
|
||||||
{
|
{
|
||||||
$profile = $this->user->getSubscribers(0, PROFILES_PER_MINILIST + 1);
|
$profile = $this->profile->getSubscribers(0, PROFILES_PER_MINILIST + 1);
|
||||||
|
|
||||||
$this->elementStart('div', array('id' => 'entity_subscribers',
|
$this->elementStart('div', array('id' => 'entity_subscribers',
|
||||||
'class' => 'section'));
|
'class' => 'section'));
|
||||||
|
@ -173,7 +173,7 @@ class ProfileAction extends OwnerDesignAction
|
||||||
$subs_count = $this->profile->subscriptionCount();
|
$subs_count = $this->profile->subscriptionCount();
|
||||||
$subbed_count = $this->profile->subscriberCount();
|
$subbed_count = $this->profile->subscriberCount();
|
||||||
$notice_count = $this->profile->noticeCount();
|
$notice_count = $this->profile->noticeCount();
|
||||||
$group_count = $this->user->getGroups()->N;
|
$group_count = $this->profile->getGroups()->N;
|
||||||
$age_days = (time() - strtotime($this->profile->created)) / 86400;
|
$age_days = (time() - strtotime($this->profile->created)) / 86400;
|
||||||
if ($age_days < 1) {
|
if ($age_days < 1) {
|
||||||
// Rather than extrapolating out to a bajillion...
|
// Rather than extrapolating out to a bajillion...
|
||||||
|
@ -241,7 +241,7 @@ class ProfileAction extends OwnerDesignAction
|
||||||
|
|
||||||
function showGroups()
|
function showGroups()
|
||||||
{
|
{
|
||||||
$groups = $this->user->getGroups(0, GROUPS_PER_MINILIST + 1);
|
$groups = $this->profile->getGroups(0, GROUPS_PER_MINILIST + 1);
|
||||||
|
|
||||||
$this->elementStart('div', array('id' => 'entity_groups',
|
$this->elementStart('div', array('id' => 'entity_groups',
|
||||||
'class' => 'section'));
|
'class' => 'section'));
|
||||||
|
@ -249,7 +249,7 @@ class ProfileAction extends OwnerDesignAction
|
||||||
$this->element('h2', null, _('Groups'));
|
$this->element('h2', null, _('Groups'));
|
||||||
|
|
||||||
if ($groups) {
|
if ($groups) {
|
||||||
$gml = new GroupMiniList($groups, $this->user, $this);
|
$gml = new GroupMiniList($groups, $this->profile, $this);
|
||||||
$cnt = $gml->show();
|
$cnt = $gml->show();
|
||||||
if ($cnt == 0) {
|
if ($cnt == 0) {
|
||||||
$this->element('p', null, _('(None)'));
|
$this->element('p', null, _('(None)'));
|
||||||
|
|
171
lib/router.php
171
lib/router.php
|
@ -33,8 +33,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||||
|
|
||||||
require_once 'Net/URL/Mapper.php';
|
require_once 'Net/URL/Mapper.php';
|
||||||
|
|
||||||
class StatusNet_URL_Mapper extends Net_URL_Mapper {
|
class StatusNet_URL_Mapper extends Net_URL_Mapper
|
||||||
|
{
|
||||||
private static $_singleton = null;
|
private static $_singleton = null;
|
||||||
|
private $_actionToPath = array();
|
||||||
|
|
||||||
private function __construct()
|
private function __construct()
|
||||||
{
|
{
|
||||||
|
@ -53,10 +55,47 @@ class StatusNet_URL_Mapper extends Net_URL_Mapper {
|
||||||
$result = null;
|
$result = null;
|
||||||
if (Event::handle('StartConnectPath', array(&$path, &$defaults, &$rules, &$result))) {
|
if (Event::handle('StartConnectPath', array(&$path, &$defaults, &$rules, &$result))) {
|
||||||
$result = parent::connect($path, $defaults, $rules);
|
$result = parent::connect($path, $defaults, $rules);
|
||||||
|
if (array_key_exists('action', $defaults)) {
|
||||||
|
$action = $defaults['action'];
|
||||||
|
} elseif (array_key_exists('action', $rules)) {
|
||||||
|
$action = $rules['action'];
|
||||||
|
} else {
|
||||||
|
$action = null;
|
||||||
|
}
|
||||||
|
$this->_mapAction($action, $result);
|
||||||
Event::handle('EndConnectPath', array($path, $defaults, $rules, $result));
|
Event::handle('EndConnectPath', array($path, $defaults, $rules, $result));
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function _mapAction($action, $path)
|
||||||
|
{
|
||||||
|
if (!array_key_exists($action, $this->_actionToPath)) {
|
||||||
|
$this->_actionToPath[$action] = array();
|
||||||
|
}
|
||||||
|
$this->_actionToPath[$action][] = $path;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generate($values = array(), $qstring = array(), $anchor = '')
|
||||||
|
{
|
||||||
|
if (!array_key_exists('action', $values)) {
|
||||||
|
return parent::generate($values, $qstring, $anchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
$action = $values['action'];
|
||||||
|
|
||||||
|
if (!array_key_exists($action, $this->_actionToPath)) {
|
||||||
|
return parent::generate($values, $qstring, $anchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
$oldPaths = $this->paths;
|
||||||
|
$this->paths = $this->_actionToPath[$action];
|
||||||
|
$result = parent::generate($values, $qstring, $anchor);
|
||||||
|
$this->paths = $oldPaths;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -87,10 +126,42 @@ class Router
|
||||||
|
|
||||||
function __construct()
|
function __construct()
|
||||||
{
|
{
|
||||||
if (!$this->m) {
|
if (empty($this->m)) {
|
||||||
|
if (!common_config('router', 'cache')) {
|
||||||
$this->m = $this->initialize();
|
$this->m = $this->initialize();
|
||||||
|
} else {
|
||||||
|
$k = self::cacheKey();
|
||||||
|
$c = Cache::instance();
|
||||||
|
$m = $c->get($k);
|
||||||
|
if (!empty($m)) {
|
||||||
|
$this->m = $m;
|
||||||
|
} else {
|
||||||
|
$this->m = $this->initialize();
|
||||||
|
$c->set($k, $this->m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a unique hashkey for the router.
|
||||||
|
*
|
||||||
|
* The router's url map can change based on the version of the software
|
||||||
|
* you're running and the plugins that are enabled. To avoid having bad routes
|
||||||
|
* get stuck in the cache, the key includes a list of plugins and the software
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* There can still be problems with a) differences in versions of the plugins and
|
||||||
|
* b) people running code between official versions, but these tend to be more
|
||||||
|
* sophisticated users who can grok what's going on and clear their caches.
|
||||||
|
*
|
||||||
|
* @return string cache key string that should uniquely identify a router
|
||||||
|
*/
|
||||||
|
|
||||||
|
static function cacheKey()
|
||||||
|
{
|
||||||
|
return Cache::codeKey('router');
|
||||||
|
}
|
||||||
|
|
||||||
function initialize()
|
function initialize()
|
||||||
{
|
{
|
||||||
|
@ -151,6 +222,8 @@ class Router
|
||||||
array('action' => 'publicxrds'));
|
array('action' => 'publicxrds'));
|
||||||
$m->connect('.well-known/host-meta',
|
$m->connect('.well-known/host-meta',
|
||||||
array('action' => 'hostmeta'));
|
array('action' => 'hostmeta'));
|
||||||
|
$m->connect('main/xrd',
|
||||||
|
array('action' => 'userxrd'));
|
||||||
|
|
||||||
// these take a code
|
// these take a code
|
||||||
|
|
||||||
|
@ -221,10 +294,10 @@ class Router
|
||||||
$m->connect('notice/new', array('action' => 'newnotice'));
|
$m->connect('notice/new', array('action' => 'newnotice'));
|
||||||
$m->connect('notice/new?replyto=:replyto',
|
$m->connect('notice/new?replyto=:replyto',
|
||||||
array('action' => 'newnotice'),
|
array('action' => 'newnotice'),
|
||||||
array('replyto' => '[A-Za-z0-9_-]+'));
|
array('replyto' => Nickname::DISPLAY_FMT));
|
||||||
$m->connect('notice/new?replyto=:replyto&inreplyto=:inreplyto',
|
$m->connect('notice/new?replyto=:replyto&inreplyto=:inreplyto',
|
||||||
array('action' => 'newnotice'),
|
array('action' => 'newnotice'),
|
||||||
array('replyto' => '[A-Za-z0-9_-]+'),
|
array('replyto' => Nickname::DISPLAY_FMT),
|
||||||
array('inreplyto' => '[0-9]+'));
|
array('inreplyto' => '[0-9]+'));
|
||||||
|
|
||||||
$m->connect('notice/:notice/file',
|
$m->connect('notice/:notice/file',
|
||||||
|
@ -248,7 +321,7 @@ class Router
|
||||||
array('id' => '[0-9]+'));
|
array('id' => '[0-9]+'));
|
||||||
|
|
||||||
$m->connect('message/new', array('action' => 'newmessage'));
|
$m->connect('message/new', array('action' => 'newmessage'));
|
||||||
$m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => '[A-Za-z0-9_-]+'));
|
$m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => Nickname::DISPLAY_FMT));
|
||||||
$m->connect('message/:message',
|
$m->connect('message/:message',
|
||||||
array('action' => 'showmessage'),
|
array('action' => 'showmessage'),
|
||||||
array('message' => '[0-9]+'));
|
array('message' => '[0-9]+'));
|
||||||
|
@ -279,7 +352,7 @@ class Router
|
||||||
foreach (array('edit', 'join', 'leave', 'delete') as $v) {
|
foreach (array('edit', 'join', 'leave', 'delete') as $v) {
|
||||||
$m->connect('group/:nickname/'.$v,
|
$m->connect('group/:nickname/'.$v,
|
||||||
array('action' => $v.'group'),
|
array('action' => $v.'group'),
|
||||||
array('nickname' => '[a-zA-Z0-9]+'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
$m->connect('group/:id/id/'.$v,
|
$m->connect('group/:id/id/'.$v,
|
||||||
array('action' => $v.'group'),
|
array('action' => $v.'group'),
|
||||||
array('id' => '[0-9]+'));
|
array('id' => '[0-9]+'));
|
||||||
|
@ -288,20 +361,20 @@ class Router
|
||||||
foreach (array('members', 'logo', 'rss', 'designsettings') as $n) {
|
foreach (array('members', 'logo', 'rss', 'designsettings') as $n) {
|
||||||
$m->connect('group/:nickname/'.$n,
|
$m->connect('group/:nickname/'.$n,
|
||||||
array('action' => 'group'.$n),
|
array('action' => 'group'.$n),
|
||||||
array('nickname' => '[a-zA-Z0-9]+'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
}
|
}
|
||||||
|
|
||||||
$m->connect('group/:nickname/foaf',
|
$m->connect('group/:nickname/foaf',
|
||||||
array('action' => 'foafgroup'),
|
array('action' => 'foafgroup'),
|
||||||
array('nickname' => '[a-zA-Z0-9]+'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
|
|
||||||
$m->connect('group/:nickname/blocked',
|
$m->connect('group/:nickname/blocked',
|
||||||
array('action' => 'blockedfromgroup'),
|
array('action' => 'blockedfromgroup'),
|
||||||
array('nickname' => '[a-zA-Z0-9]+'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
|
|
||||||
$m->connect('group/:nickname/makeadmin',
|
$m->connect('group/:nickname/makeadmin',
|
||||||
array('action' => 'makeadmin'),
|
array('action' => 'makeadmin'),
|
||||||
array('nickname' => '[a-zA-Z0-9]+'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
|
|
||||||
$m->connect('group/:id/id',
|
$m->connect('group/:id/id',
|
||||||
array('action' => 'groupbyid'),
|
array('action' => 'groupbyid'),
|
||||||
|
@ -309,7 +382,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('group/:nickname',
|
$m->connect('group/:nickname',
|
||||||
array('action' => 'showgroup'),
|
array('action' => 'showgroup'),
|
||||||
array('nickname' => '[a-zA-Z0-9]+'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
|
|
||||||
$m->connect('group/', array('action' => 'groups'));
|
$m->connect('group/', array('action' => 'groups'));
|
||||||
$m->connect('group', array('action' => 'groups'));
|
$m->connect('group', array('action' => 'groups'));
|
||||||
|
@ -335,7 +408,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statuses/friends_timeline/:id.:format',
|
$m->connect('api/statuses/friends_timeline/:id.:format',
|
||||||
array('action' => 'ApiTimelineFriends',
|
array('action' => 'ApiTimelineFriends',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json|rss|atom)'));
|
'format' => '(xml|json|rss|atom)'));
|
||||||
|
|
||||||
$m->connect('api/statuses/home_timeline.:format',
|
$m->connect('api/statuses/home_timeline.:format',
|
||||||
|
@ -344,7 +417,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statuses/home_timeline/:id.:format',
|
$m->connect('api/statuses/home_timeline/:id.:format',
|
||||||
array('action' => 'ApiTimelineHome',
|
array('action' => 'ApiTimelineHome',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json|rss|atom)'));
|
'format' => '(xml|json|rss|atom)'));
|
||||||
|
|
||||||
$m->connect('api/statuses/user_timeline.:format',
|
$m->connect('api/statuses/user_timeline.:format',
|
||||||
|
@ -353,7 +426,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statuses/user_timeline/:id.:format',
|
$m->connect('api/statuses/user_timeline/:id.:format',
|
||||||
array('action' => 'ApiTimelineUser',
|
array('action' => 'ApiTimelineUser',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json|rss|atom)'));
|
'format' => '(xml|json|rss|atom)'));
|
||||||
|
|
||||||
$m->connect('api/statuses/mentions.:format',
|
$m->connect('api/statuses/mentions.:format',
|
||||||
|
@ -362,7 +435,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statuses/mentions/:id.:format',
|
$m->connect('api/statuses/mentions/:id.:format',
|
||||||
array('action' => 'ApiTimelineMentions',
|
array('action' => 'ApiTimelineMentions',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json|rss|atom)'));
|
'format' => '(xml|json|rss|atom)'));
|
||||||
|
|
||||||
$m->connect('api/statuses/replies.:format',
|
$m->connect('api/statuses/replies.:format',
|
||||||
|
@ -371,7 +444,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statuses/replies/:id.:format',
|
$m->connect('api/statuses/replies/:id.:format',
|
||||||
array('action' => 'ApiTimelineMentions',
|
array('action' => 'ApiTimelineMentions',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json|rss|atom)'));
|
'format' => '(xml|json|rss|atom)'));
|
||||||
|
|
||||||
$m->connect('api/statuses/retweeted_by_me.:format',
|
$m->connect('api/statuses/retweeted_by_me.:format',
|
||||||
|
@ -392,7 +465,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statuses/friends/:id.:format',
|
$m->connect('api/statuses/friends/:id.:format',
|
||||||
array('action' => 'ApiUserFriends',
|
array('action' => 'ApiUserFriends',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
|
|
||||||
$m->connect('api/statuses/followers.:format',
|
$m->connect('api/statuses/followers.:format',
|
||||||
|
@ -401,17 +474,17 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statuses/followers/:id.:format',
|
$m->connect('api/statuses/followers/:id.:format',
|
||||||
array('action' => 'ApiUserFollowers',
|
array('action' => 'ApiUserFollowers',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
|
|
||||||
$m->connect('api/statuses/show.:format',
|
$m->connect('api/statuses/show.:format',
|
||||||
array('action' => 'ApiStatusesShow',
|
array('action' => 'ApiStatusesShow',
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json|atom)'));
|
||||||
|
|
||||||
$m->connect('api/statuses/show/:id.:format',
|
$m->connect('api/statuses/show/:id.:format',
|
||||||
array('action' => 'ApiStatusesShow',
|
array('action' => 'ApiStatusesShow',
|
||||||
'id' => '[0-9]+',
|
'id' => '[0-9]+',
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json|atom)'));
|
||||||
|
|
||||||
$m->connect('api/statuses/update.:format',
|
$m->connect('api/statuses/update.:format',
|
||||||
array('action' => 'ApiStatusesUpdate',
|
array('action' => 'ApiStatusesUpdate',
|
||||||
|
@ -444,7 +517,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/users/show/:id.:format',
|
$m->connect('api/users/show/:id.:format',
|
||||||
array('action' => 'ApiUserShow',
|
array('action' => 'ApiUserShow',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
|
|
||||||
// direct messages
|
// direct messages
|
||||||
|
@ -482,12 +555,12 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/friendships/create/:id.:format',
|
$m->connect('api/friendships/create/:id.:format',
|
||||||
array('action' => 'ApiFriendshipsCreate',
|
array('action' => 'ApiFriendshipsCreate',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
|
|
||||||
$m->connect('api/friendships/destroy/:id.:format',
|
$m->connect('api/friendships/destroy/:id.:format',
|
||||||
array('action' => 'ApiFriendshipsDestroy',
|
array('action' => 'ApiFriendshipsDestroy',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
|
|
||||||
// Social graph
|
// Social graph
|
||||||
|
@ -544,17 +617,17 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/favorites/:id.:format',
|
$m->connect('api/favorites/:id.:format',
|
||||||
array('action' => 'ApiTimelineFavorites',
|
array('action' => 'ApiTimelineFavorites',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json|rss|atom)'));
|
'format' => '(xml|json|rss|atom)'));
|
||||||
|
|
||||||
$m->connect('api/favorites/create/:id.:format',
|
$m->connect('api/favorites/create/:id.:format',
|
||||||
array('action' => 'ApiFavoriteCreate',
|
array('action' => 'ApiFavoriteCreate',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
|
|
||||||
$m->connect('api/favorites/destroy/:id.:format',
|
$m->connect('api/favorites/destroy/:id.:format',
|
||||||
array('action' => 'ApiFavoriteDestroy',
|
array('action' => 'ApiFavoriteDestroy',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
// blocks
|
// blocks
|
||||||
|
|
||||||
|
@ -564,7 +637,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/blocks/create/:id.:format',
|
$m->connect('api/blocks/create/:id.:format',
|
||||||
array('action' => 'ApiBlockCreate',
|
array('action' => 'ApiBlockCreate',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
|
|
||||||
$m->connect('api/blocks/destroy.:format',
|
$m->connect('api/blocks/destroy.:format',
|
||||||
|
@ -573,7 +646,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/blocks/destroy/:id.:format',
|
$m->connect('api/blocks/destroy/:id.:format',
|
||||||
array('action' => 'ApiBlockDestroy',
|
array('action' => 'ApiBlockDestroy',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
// help
|
// help
|
||||||
|
|
||||||
|
@ -609,7 +682,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statusnet/groups/timeline/:id.:format',
|
$m->connect('api/statusnet/groups/timeline/:id.:format',
|
||||||
array('action' => 'ApiTimelineGroup',
|
array('action' => 'ApiTimelineGroup',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json|rss|atom)'));
|
'format' => '(xml|json|rss|atom)'));
|
||||||
|
|
||||||
$m->connect('api/statusnet/groups/show.:format',
|
$m->connect('api/statusnet/groups/show.:format',
|
||||||
|
@ -618,12 +691,12 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statusnet/groups/show/:id.:format',
|
$m->connect('api/statusnet/groups/show/:id.:format',
|
||||||
array('action' => 'ApiGroupShow',
|
array('action' => 'ApiGroupShow',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
|
|
||||||
$m->connect('api/statusnet/groups/join.:format',
|
$m->connect('api/statusnet/groups/join.:format',
|
||||||
array('action' => 'ApiGroupJoin',
|
array('action' => 'ApiGroupJoin',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
|
|
||||||
$m->connect('api/statusnet/groups/join/:id.:format',
|
$m->connect('api/statusnet/groups/join/:id.:format',
|
||||||
|
@ -632,7 +705,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statusnet/groups/leave.:format',
|
$m->connect('api/statusnet/groups/leave.:format',
|
||||||
array('action' => 'ApiGroupLeave',
|
array('action' => 'ApiGroupLeave',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
|
|
||||||
$m->connect('api/statusnet/groups/leave/:id.:format',
|
$m->connect('api/statusnet/groups/leave/:id.:format',
|
||||||
|
@ -649,7 +722,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statusnet/groups/list/:id.:format',
|
$m->connect('api/statusnet/groups/list/:id.:format',
|
||||||
array('action' => 'ApiGroupList',
|
array('action' => 'ApiGroupList',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json|rss|atom)'));
|
'format' => '(xml|json|rss|atom)'));
|
||||||
|
|
||||||
$m->connect('api/statusnet/groups/list_all.:format',
|
$m->connect('api/statusnet/groups/list_all.:format',
|
||||||
|
@ -662,7 +735,7 @@ class Router
|
||||||
|
|
||||||
$m->connect('api/statusnet/groups/membership/:id.:format',
|
$m->connect('api/statusnet/groups/membership/:id.:format',
|
||||||
array('action' => 'ApiGroupMembership',
|
array('action' => 'ApiGroupMembership',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => Nickname::DISPLAY_FMT,
|
||||||
'format' => '(xml|json)'));
|
'format' => '(xml|json)'));
|
||||||
|
|
||||||
$m->connect('api/statusnet/groups/create.:format',
|
$m->connect('api/statusnet/groups/create.:format',
|
||||||
|
@ -699,6 +772,13 @@ class Router
|
||||||
$m->connect('api/oauth/authorize',
|
$m->connect('api/oauth/authorize',
|
||||||
array('action' => 'ApiOauthAuthorize'));
|
array('action' => 'ApiOauthAuthorize'));
|
||||||
|
|
||||||
|
$m->connect('api/statusnet/app/service/:id.xml',
|
||||||
|
array('action' => 'ApiAtomService',
|
||||||
|
'id' => Nickname::DISPLAY_FMT));
|
||||||
|
|
||||||
|
$m->connect('api/statusnet/app/service.xml',
|
||||||
|
array('action' => 'ApiAtomService'));
|
||||||
|
|
||||||
// Admin
|
// Admin
|
||||||
|
|
||||||
$m->connect('admin/site', array('action' => 'siteadminpanel'));
|
$m->connect('admin/site', array('action' => 'siteadminpanel'));
|
||||||
|
@ -727,8 +807,7 @@ class Router
|
||||||
|
|
||||||
if (common_config('singleuser', 'enabled')) {
|
if (common_config('singleuser', 'enabled')) {
|
||||||
|
|
||||||
$user = User::singleUser();
|
$nickname = User::singleUserNickname();
|
||||||
$nickname = $user->nickname;
|
|
||||||
|
|
||||||
foreach (array('subscriptions', 'subscribers',
|
foreach (array('subscriptions', 'subscribers',
|
||||||
'all', 'foaf', 'xrds',
|
'all', 'foaf', 'xrds',
|
||||||
|
@ -799,54 +878,54 @@ class Router
|
||||||
'replies', 'inbox', 'outbox', 'microsummary', 'hcard') as $a) {
|
'replies', 'inbox', 'outbox', 'microsummary', 'hcard') as $a) {
|
||||||
$m->connect(':nickname/'.$a,
|
$m->connect(':nickname/'.$a,
|
||||||
array('action' => $a),
|
array('action' => $a),
|
||||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (array('subscriptions', 'subscribers') as $a) {
|
foreach (array('subscriptions', 'subscribers') as $a) {
|
||||||
$m->connect(':nickname/'.$a.'/:tag',
|
$m->connect(':nickname/'.$a.'/:tag',
|
||||||
array('action' => $a),
|
array('action' => $a),
|
||||||
array('tag' => '[a-zA-Z0-9]+',
|
array('tag' => '[a-zA-Z0-9]+',
|
||||||
'nickname' => '[a-zA-Z0-9]{1,64}'));
|
'nickname' => Nickname::DISPLAY_FMT));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (array('rss', 'groups') as $a) {
|
foreach (array('rss', 'groups') as $a) {
|
||||||
$m->connect(':nickname/'.$a,
|
$m->connect(':nickname/'.$a,
|
||||||
array('action' => 'user'.$a),
|
array('action' => 'user'.$a),
|
||||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (array('all', 'replies', 'favorites') as $a) {
|
foreach (array('all', 'replies', 'favorites') as $a) {
|
||||||
$m->connect(':nickname/'.$a.'/rss',
|
$m->connect(':nickname/'.$a.'/rss',
|
||||||
array('action' => $a.'rss'),
|
array('action' => $a.'rss'),
|
||||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
}
|
}
|
||||||
|
|
||||||
$m->connect(':nickname/favorites',
|
$m->connect(':nickname/favorites',
|
||||||
array('action' => 'showfavorites'),
|
array('action' => 'showfavorites'),
|
||||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
|
|
||||||
$m->connect(':nickname/avatar/:size',
|
$m->connect(':nickname/avatar/:size',
|
||||||
array('action' => 'avatarbynickname'),
|
array('action' => 'avatarbynickname'),
|
||||||
array('size' => '(original|96|48|24)',
|
array('size' => '(original|96|48|24)',
|
||||||
'nickname' => '[a-zA-Z0-9]{1,64}'));
|
'nickname' => Nickname::DISPLAY_FMT));
|
||||||
|
|
||||||
$m->connect(':nickname/tag/:tag/rss',
|
$m->connect(':nickname/tag/:tag/rss',
|
||||||
array('action' => 'userrss'),
|
array('action' => 'userrss'),
|
||||||
array('nickname' => '[a-zA-Z0-9]{1,64}'),
|
array('nickname' => Nickname::DISPLAY_FMT),
|
||||||
array('tag' => '[\pL\pN_\-\.]{1,64}'));
|
array('tag' => '[\pL\pN_\-\.]{1,64}'));
|
||||||
|
|
||||||
$m->connect(':nickname/tag/:tag',
|
$m->connect(':nickname/tag/:tag',
|
||||||
array('action' => 'showstream'),
|
array('action' => 'showstream'),
|
||||||
array('nickname' => '[a-zA-Z0-9]{1,64}'),
|
array('nickname' => Nickname::DISPLAY_FMT),
|
||||||
array('tag' => '[\pL\pN_\-\.]{1,64}'));
|
array('tag' => '[\pL\pN_\-\.]{1,64}'));
|
||||||
|
|
||||||
$m->connect(':nickname/rsd.xml',
|
$m->connect(':nickname/rsd.xml',
|
||||||
array('action' => 'rsd'),
|
array('action' => 'rsd'),
|
||||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
|
|
||||||
$m->connect(':nickname',
|
$m->connect(':nickname',
|
||||||
array('action' => 'showstream'),
|
array('action' => 'showstream'),
|
||||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
}
|
}
|
||||||
|
|
||||||
// user stuff
|
// user stuff
|
||||||
|
|
|
@ -52,10 +52,10 @@ class MySQLSearch extends SearchEngine
|
||||||
{
|
{
|
||||||
if ('profile' === $this->table) {
|
if ('profile' === $this->table) {
|
||||||
$this->target->whereAdd('MATCH(nickname, fullname, location, bio, homepage) ' .
|
$this->target->whereAdd('MATCH(nickname, fullname, location, bio, homepage) ' .
|
||||||
'AGAINST (\''.addslashes($q).'\' IN BOOLEAN MODE)');
|
'AGAINST (\''.$this->target->escape($q).'\' IN BOOLEAN MODE)');
|
||||||
if (strtolower($q) != $q) {
|
if (strtolower($q) != $q) {
|
||||||
$this->target->whereAdd('MATCH(nickname, fullname, location, bio, homepage) ' .
|
$this->target->whereAdd('MATCH(nickname, fullname, location, bio, homepage) ' .
|
||||||
'AGAINST (\''.addslashes(strtolower($q)).'\' IN BOOLEAN MODE)', 'OR');
|
'AGAINST (\''.$this->target->escape(strtolower($q)).'\' IN BOOLEAN MODE)', 'OR');
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if ('notice' === $this->table) {
|
} else if ('notice' === $this->table) {
|
||||||
|
@ -64,13 +64,13 @@ class MySQLSearch extends SearchEngine
|
||||||
$this->target->whereAdd('notice.is_local != ' . Notice::GATEWAY);
|
$this->target->whereAdd('notice.is_local != ' . Notice::GATEWAY);
|
||||||
|
|
||||||
if (strtolower($q) != $q) {
|
if (strtolower($q) != $q) {
|
||||||
$this->target->whereAdd("( MATCH(content) AGAINST ('" . addslashes($q) .
|
$this->target->whereAdd("( MATCH(content) AGAINST ('" . $this->target->escape($q) .
|
||||||
"' IN BOOLEAN MODE)) OR ( MATCH(content) " .
|
"' IN BOOLEAN MODE)) OR ( MATCH(content) " .
|
||||||
"AGAINST ('" . addslashes(strtolower($q)) .
|
"AGAINST ('" . $this->target->escape(strtolower($q)) .
|
||||||
"' IN BOOLEAN MODE))");
|
"' IN BOOLEAN MODE))");
|
||||||
} else {
|
} else {
|
||||||
$this->target->whereAdd('MATCH(content) ' .
|
$this->target->whereAdd('MATCH(content) ' .
|
||||||
'AGAINST (\''.addslashes($q).'\' IN BOOLEAN MODE)');
|
'AGAINST (\''.$this->target->escape($q).'\' IN BOOLEAN MODE)');
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -89,9 +89,9 @@ class MySQLLikeSearch extends SearchEngine
|
||||||
' fullname LIKE "%%%1$s%%" OR '.
|
' fullname LIKE "%%%1$s%%" OR '.
|
||||||
' location LIKE "%%%1$s%%" OR '.
|
' location LIKE "%%%1$s%%" OR '.
|
||||||
' bio LIKE "%%%1$s%%" OR '.
|
' bio LIKE "%%%1$s%%" OR '.
|
||||||
' homepage LIKE "%%%1$s%%")', addslashes($q));
|
' homepage LIKE "%%%1$s%%")', $this->target->escape($q, true));
|
||||||
} else if ('notice' === $this->table) {
|
} else if ('notice' === $this->table) {
|
||||||
$qry = sprintf('content LIKE "%%%1$s%%"', addslashes($q));
|
$qry = sprintf('content LIKE "%%%1$s%%"', $this->target->escape($q, true));
|
||||||
} else {
|
} else {
|
||||||
throw new ServerException('Unknown table: ' . $this->table);
|
throw new ServerException('Unknown table: ' . $this->table);
|
||||||
}
|
}
|
||||||
|
@ -107,12 +107,12 @@ class PGSearch extends SearchEngine
|
||||||
function query($q)
|
function query($q)
|
||||||
{
|
{
|
||||||
if ('profile' === $this->table) {
|
if ('profile' === $this->table) {
|
||||||
return $this->target->whereAdd('textsearch @@ plainto_tsquery(\''.addslashes($q).'\')');
|
return $this->target->whereAdd('textsearch @@ plainto_tsquery(\''.$this->target->escape($q).'\')');
|
||||||
} else if ('notice' === $this->table) {
|
} else if ('notice' === $this->table) {
|
||||||
|
|
||||||
// XXX: We need to filter out gateway notices (notice.is_local = -2) --Zach
|
// XXX: We need to filter out gateway notices (notice.is_local = -2) --Zach
|
||||||
|
|
||||||
return $this->target->whereAdd('to_tsvector(\'english\', content) @@ plainto_tsquery(\''.addslashes($q).'\')');
|
return $this->target->whereAdd('to_tsvector(\'english\', content) @@ plainto_tsquery(\''.$this->target->escape($q).'\')');
|
||||||
} else {
|
} else {
|
||||||
throw new ServerException('Unknown table: ' . $this->table);
|
throw new ServerException('Unknown table: ' . $this->table);
|
||||||
}
|
}
|
||||||
|
|
|
@ -396,7 +396,11 @@ class StatusNet
|
||||||
static function isHTTPS()
|
static function isHTTPS()
|
||||||
{
|
{
|
||||||
// There are some exceptions to this; add them here!
|
// There are some exceptions to this; add them here!
|
||||||
return !empty($_SERVER['HTTPS']);
|
if(empty($_SERVER['HTTPS'])) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return $_SERVER['HTTPS'] !== 'off';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Theme
|
class Theme
|
||||||
{
|
{
|
||||||
var $name = null;
|
var $name = null;
|
||||||
|
@ -65,14 +64,14 @@ class Theme
|
||||||
*
|
*
|
||||||
* @param string $name Name of the theme; defaults to config value
|
* @param string $name Name of the theme; defaults to config value
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function __construct($name=null)
|
function __construct($name=null)
|
||||||
{
|
{
|
||||||
if (empty($name)) {
|
if (empty($name)) {
|
||||||
$name = common_config('site', 'theme');
|
$name = common_config('site', 'theme');
|
||||||
}
|
}
|
||||||
if (!self::validName($name)) {
|
if (!self::validName($name)) {
|
||||||
throw new ServerException("Invalid theme name.");
|
// TRANS: Server exception displayed if a theme name was invalid.
|
||||||
|
throw new ServerException(_('Invalid theme name.'));
|
||||||
}
|
}
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
|
|
||||||
|
@ -95,7 +94,6 @@ class Theme
|
||||||
$fulldir = $instroot.'/'.$name;
|
$fulldir = $instroot.'/'.$name;
|
||||||
|
|
||||||
if (file_exists($fulldir) && is_dir($fulldir)) {
|
if (file_exists($fulldir) && is_dir($fulldir)) {
|
||||||
|
|
||||||
$this->dir = $fulldir;
|
$this->dir = $fulldir;
|
||||||
$this->path = $this->relativeThemePath('theme', 'theme', $name);
|
$this->path = $this->relativeThemePath('theme', 'theme', $name);
|
||||||
}
|
}
|
||||||
|
@ -113,11 +111,9 @@ class Theme
|
||||||
*
|
*
|
||||||
* @todo consolidate code with that for other customizable paths
|
* @todo consolidate code with that for other customizable paths
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected function relativeThemePath($group, $fallbackSubdir, $name)
|
protected function relativeThemePath($group, $fallbackSubdir, $name)
|
||||||
{
|
{
|
||||||
if (StatusNet::isHTTPS()) {
|
if (StatusNet::isHTTPS()) {
|
||||||
|
|
||||||
$sslserver = common_config($group, 'sslserver');
|
$sslserver = common_config($group, 'sslserver');
|
||||||
|
|
||||||
if (empty($sslserver)) {
|
if (empty($sslserver)) {
|
||||||
|
@ -140,9 +136,7 @@ class Theme
|
||||||
}
|
}
|
||||||
|
|
||||||
$protocol = 'https';
|
$protocol = 'https';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$path = common_config($group, 'path');
|
$path = common_config($group, 'path');
|
||||||
|
|
||||||
if (empty($path)) {
|
if (empty($path)) {
|
||||||
|
@ -179,7 +173,6 @@ class Theme
|
||||||
*
|
*
|
||||||
* @return string full pathname, like /var/www/mublog/theme/default/logo.png
|
* @return string full pathname, like /var/www/mublog/theme/default/logo.png
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function getFile($relative)
|
function getFile($relative)
|
||||||
{
|
{
|
||||||
return $this->dir.'/'.$relative;
|
return $this->dir.'/'.$relative;
|
||||||
|
@ -192,7 +185,6 @@ class Theme
|
||||||
*
|
*
|
||||||
* @return string full URL, like 'http://example.com/theme/default/logo.png'
|
* @return string full URL, like 'http://example.com/theme/default/logo.png'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function getPath($relative)
|
function getPath($relative)
|
||||||
{
|
{
|
||||||
return $this->path.'/'.$relative;
|
return $this->path.'/'.$relative;
|
||||||
|
@ -258,7 +250,6 @@ class Theme
|
||||||
*
|
*
|
||||||
* @return string File path to the theme file
|
* @return string File path to the theme file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static function file($relative, $name=null)
|
static function file($relative, $name=null)
|
||||||
{
|
{
|
||||||
$theme = new Theme($name);
|
$theme = new Theme($name);
|
||||||
|
@ -273,7 +264,6 @@ class Theme
|
||||||
*
|
*
|
||||||
* @return string URL of the file
|
* @return string URL of the file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static function path($relative, $name=null)
|
static function path($relative, $name=null)
|
||||||
{
|
{
|
||||||
$theme = new Theme($name);
|
$theme = new Theme($name);
|
||||||
|
@ -285,7 +275,6 @@ class Theme
|
||||||
*
|
*
|
||||||
* @return array list of available theme names
|
* @return array list of available theme names
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static function listAvailable()
|
static function listAvailable()
|
||||||
{
|
{
|
||||||
$local = self::subdirsOf(self::localRoot());
|
$local = self::subdirsOf(self::localRoot());
|
||||||
|
@ -305,7 +294,6 @@ class Theme
|
||||||
*
|
*
|
||||||
* @return array relative filenames of subdirs, or empty array
|
* @return array relative filenames of subdirs, or empty array
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected static function subdirsOf($dir)
|
protected static function subdirsOf($dir)
|
||||||
{
|
{
|
||||||
$subdirs = array();
|
$subdirs = array();
|
||||||
|
@ -330,7 +318,6 @@ class Theme
|
||||||
*
|
*
|
||||||
* @return string local root dir for themes
|
* @return string local root dir for themes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected static function localRoot()
|
protected static function localRoot()
|
||||||
{
|
{
|
||||||
$basedir = common_config('local', 'dir');
|
$basedir = common_config('local', 'dir');
|
||||||
|
@ -347,7 +334,6 @@ class Theme
|
||||||
*
|
*
|
||||||
* @return string root dir for StatusNet themes
|
* @return string root dir for StatusNet themes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected static function installRoot()
|
protected static function installRoot()
|
||||||
{
|
{
|
||||||
$instroot = common_config('theme', 'dir');
|
$instroot = common_config('theme', 'dir');
|
||||||
|
|
|
@ -98,6 +98,10 @@ class UserProfile extends Widget
|
||||||
if (Event::handle('StartProfilePageAvatar', array($this->out, $this->profile))) {
|
if (Event::handle('StartProfilePageAvatar', array($this->out, $this->profile))) {
|
||||||
|
|
||||||
$avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
|
$avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||||
|
if (!$avatar) {
|
||||||
|
// hack for remote Twitter users: no 96px, but large Twitter size is 73px
|
||||||
|
$avatar = $this->profile->getAvatar(73);
|
||||||
|
}
|
||||||
|
|
||||||
$this->out->elementStart('dl', 'entity_depiction');
|
$this->out->elementStart('dl', 'entity_depiction');
|
||||||
$this->out->element('dt', null, _('Photo'));
|
$this->out->element('dt', null, _('Photo'));
|
||||||
|
@ -109,10 +113,8 @@ class UserProfile extends Widget
|
||||||
'alt' => $this->profile->nickname));
|
'alt' => $this->profile->nickname));
|
||||||
$this->out->elementEnd('dd');
|
$this->out->elementEnd('dd');
|
||||||
|
|
||||||
$user = User::staticGet('id', $this->profile->id);
|
|
||||||
|
|
||||||
$cur = common_current_user();
|
$cur = common_current_user();
|
||||||
if ($cur && $cur->id == $user->id) {
|
if ($cur && $cur->id == $this->profile->id) {
|
||||||
$this->out->elementStart('dd');
|
$this->out->elementStart('dd');
|
||||||
$this->out->element('a', array('href' => common_local_url('avatarsettings')), _('Edit Avatar'));
|
$this->out->element('a', array('href' => common_local_url('avatarsettings')), _('Edit Avatar'));
|
||||||
$this->out->elementEnd('dd');
|
$this->out->elementEnd('dd');
|
||||||
|
@ -278,7 +280,7 @@ class UserProfile extends Widget
|
||||||
}
|
}
|
||||||
$this->out->elementEnd('li');
|
$this->out->elementEnd('li');
|
||||||
|
|
||||||
if ($cur->mutuallySubscribed($this->user)) {
|
if ($cur->mutuallySubscribed($this->profile)) {
|
||||||
|
|
||||||
// message
|
// message
|
||||||
|
|
||||||
|
@ -290,7 +292,7 @@ class UserProfile extends Widget
|
||||||
|
|
||||||
// nudge
|
// nudge
|
||||||
|
|
||||||
if ($this->user->email && $this->user->emailnotifynudge) {
|
if ($this->user && $this->user->email && $this->user->emailnotifynudge) {
|
||||||
$this->out->elementStart('li', 'entity_nudge');
|
$this->out->elementStart('li', 'entity_nudge');
|
||||||
$nf = new NudgeForm($this->out, $this->user);
|
$nf = new NudgeForm($this->out, $this->user);
|
||||||
$nf->show();
|
$nf->show();
|
||||||
|
@ -319,6 +321,9 @@ class UserProfile extends Widget
|
||||||
}
|
}
|
||||||
$this->out->elementEnd('li');
|
$this->out->elementEnd('li');
|
||||||
|
|
||||||
|
// Some actions won't be applicable to non-local users.
|
||||||
|
$isLocal = !empty($this->user);
|
||||||
|
|
||||||
if ($cur->hasRight(Right::SANDBOXUSER) ||
|
if ($cur->hasRight(Right::SANDBOXUSER) ||
|
||||||
$cur->hasRight(Right::SILENCEUSER) ||
|
$cur->hasRight(Right::SILENCEUSER) ||
|
||||||
$cur->hasRight(Right::DELETEUSER)) {
|
$cur->hasRight(Right::DELETEUSER)) {
|
||||||
|
@ -327,7 +332,7 @@ class UserProfile extends Widget
|
||||||
$this->out->elementStart('ul');
|
$this->out->elementStart('ul');
|
||||||
if ($cur->hasRight(Right::SANDBOXUSER)) {
|
if ($cur->hasRight(Right::SANDBOXUSER)) {
|
||||||
$this->out->elementStart('li', 'entity_sandbox');
|
$this->out->elementStart('li', 'entity_sandbox');
|
||||||
if ($this->user->isSandboxed()) {
|
if ($this->profile->isSandboxed()) {
|
||||||
$usf = new UnSandboxForm($this->out, $this->profile, $r2args);
|
$usf = new UnSandboxForm($this->out, $this->profile, $r2args);
|
||||||
$usf->show();
|
$usf->show();
|
||||||
} else {
|
} else {
|
||||||
|
@ -339,7 +344,7 @@ class UserProfile extends Widget
|
||||||
|
|
||||||
if ($cur->hasRight(Right::SILENCEUSER)) {
|
if ($cur->hasRight(Right::SILENCEUSER)) {
|
||||||
$this->out->elementStart('li', 'entity_silence');
|
$this->out->elementStart('li', 'entity_silence');
|
||||||
if ($this->user->isSilenced()) {
|
if ($this->profile->isSilenced()) {
|
||||||
$usf = new UnSilenceForm($this->out, $this->profile, $r2args);
|
$usf = new UnSilenceForm($this->out, $this->profile, $r2args);
|
||||||
$usf->show();
|
$usf->show();
|
||||||
} else {
|
} else {
|
||||||
|
@ -349,7 +354,7 @@ class UserProfile extends Widget
|
||||||
$this->out->elementEnd('li');
|
$this->out->elementEnd('li');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cur->hasRight(Right::DELETEUSER)) {
|
if ($isLocal && $cur->hasRight(Right::DELETEUSER)) {
|
||||||
$this->out->elementStart('li', 'entity_delete');
|
$this->out->elementStart('li', 'entity_delete');
|
||||||
$df = new DeleteUserForm($this->out, $this->profile, $r2args);
|
$df = new DeleteUserForm($this->out, $this->profile, $r2args);
|
||||||
$df->show();
|
$df->show();
|
||||||
|
@ -359,7 +364,7 @@ class UserProfile extends Widget
|
||||||
$this->out->elementEnd('li');
|
$this->out->elementEnd('li');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cur->hasRight(Right::GRANTROLE)) {
|
if ($isLocal && $cur->hasRight(Right::GRANTROLE)) {
|
||||||
$this->out->elementStart('li', 'entity_role');
|
$this->out->elementStart('li', 'entity_role');
|
||||||
$this->out->element('p', null, _('User role'));
|
$this->out->element('p', null, _('User role'));
|
||||||
$this->out->elementStart('ul');
|
$this->out->elementStart('ul');
|
||||||
|
@ -387,7 +392,7 @@ class UserProfile extends Widget
|
||||||
$r2args['action'] = $action;
|
$r2args['action'] = $action;
|
||||||
|
|
||||||
$this->out->elementStart('li', "entity_role_$role");
|
$this->out->elementStart('li', "entity_role_$role");
|
||||||
if ($this->user->hasRole($role)) {
|
if ($this->profile->hasRole($role)) {
|
||||||
$rf = new RevokeRoleForm($role, $label, $this->out, $this->profile, $r2args);
|
$rf = new RevokeRoleForm($role, $label, $this->out, $this->profile, $r2args);
|
||||||
$rf->show();
|
$rf->show();
|
||||||
} else {
|
} else {
|
||||||
|
|
210
lib/util.php
210
lib/util.php
|
@ -533,14 +533,29 @@ function common_user_cache_hash($user=false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get canonical version of nickname for comparison
|
/**
|
||||||
|
* get canonical version of nickname for comparison
|
||||||
|
*
|
||||||
|
* @param string $nickname
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @throws NicknameException on invalid input
|
||||||
|
* @deprecated call Nickname::normalize() directly.
|
||||||
|
*/
|
||||||
function common_canonical_nickname($nickname)
|
function common_canonical_nickname($nickname)
|
||||||
{
|
{
|
||||||
// XXX: UTF-8 canonicalization (like combining chars)
|
return Nickname::normalize($nickname);
|
||||||
return strtolower($nickname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get canonical version of email for comparison
|
/**
|
||||||
|
* get canonical version of email for comparison
|
||||||
|
*
|
||||||
|
* @fixme actually normalize
|
||||||
|
* @fixme reject invalid input
|
||||||
|
*
|
||||||
|
* @param string $email
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
function common_canonical_email($email)
|
function common_canonical_email($email)
|
||||||
{
|
{
|
||||||
// XXX: canonicalize UTF-8
|
// XXX: canonicalize UTF-8
|
||||||
|
@ -548,15 +563,33 @@ function common_canonical_email($email)
|
||||||
return $email;
|
return $email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partial notice markup rendering step: build links to !group references.
|
||||||
|
*
|
||||||
|
* @param string $text partially rendered HTML
|
||||||
|
* @param Notice $notice in whose context we're working
|
||||||
|
* @return string partially rendered HTML
|
||||||
|
*/
|
||||||
function common_render_content($text, $notice)
|
function common_render_content($text, $notice)
|
||||||
{
|
{
|
||||||
$r = common_render_text($text);
|
$r = common_render_text($text);
|
||||||
$id = $notice->profile_id;
|
$id = $notice->profile_id;
|
||||||
$r = common_linkify_mentions($r, $notice);
|
$r = common_linkify_mentions($r, $notice);
|
||||||
$r = preg_replace('/(^|[\s\.\,\:\;]+)!([A-Za-z0-9]{1,64})/e', "'\\1!'.common_group_link($id, '\\2')", $r);
|
$r = preg_replace('/(^|[\s\.\,\:\;]+)!(' . Nickname::DISPLAY_FMT . ')/e',
|
||||||
|
"'\\1!'.common_group_link($id, '\\2')", $r);
|
||||||
return $r;
|
return $r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds @-mentions within the partially-rendered text section and
|
||||||
|
* turns them into live links.
|
||||||
|
*
|
||||||
|
* Should generally not be called except from common_render_content().
|
||||||
|
*
|
||||||
|
* @param string $text partially-rendered HTML
|
||||||
|
* @param Notice $notice in-progress or complete Notice object for context
|
||||||
|
* @return string partially-rendered HTML
|
||||||
|
*/
|
||||||
function common_linkify_mentions($text, $notice)
|
function common_linkify_mentions($text, $notice)
|
||||||
{
|
{
|
||||||
$mentions = common_find_mentions($text, $notice);
|
$mentions = common_find_mentions($text, $notice);
|
||||||
|
@ -613,6 +646,21 @@ function common_linkify_mention($mention)
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find @-mentions in the given text, using the given notice object as context.
|
||||||
|
* References will be resolved with common_relative_profile() against the user
|
||||||
|
* who posted the notice.
|
||||||
|
*
|
||||||
|
* Note the return data format is internal, to be used for building links and
|
||||||
|
* such. Should not be used directly; rather, call common_linkify_mentions().
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @param Notice $notice notice in whose context we're building links
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
function common_find_mentions($text, $notice)
|
function common_find_mentions($text, $notice)
|
||||||
{
|
{
|
||||||
$mentions = array();
|
$mentions = array();
|
||||||
|
@ -647,20 +695,15 @@ function common_find_mentions($text, $notice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preg_match_all('/^T ([A-Z0-9]{1,64}) /',
|
$matches = common_find_mentions_raw($text);
|
||||||
$text,
|
|
||||||
$tmatches,
|
|
||||||
PREG_OFFSET_CAPTURE);
|
|
||||||
|
|
||||||
preg_match_all('/(?:^|\s+)@(['.NICKNAME_FMT.']{1,64})/',
|
|
||||||
$text,
|
|
||||||
$atmatches,
|
|
||||||
PREG_OFFSET_CAPTURE);
|
|
||||||
|
|
||||||
$matches = array_merge($tmatches[1], $atmatches[1]);
|
|
||||||
|
|
||||||
foreach ($matches as $match) {
|
foreach ($matches as $match) {
|
||||||
$nickname = common_canonical_nickname($match[0]);
|
try {
|
||||||
|
$nickname = Nickname::normalize($match[0]);
|
||||||
|
} catch (NicknameException $e) {
|
||||||
|
// Bogus match? Drop it.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Try to get a profile for this nickname.
|
// Try to get a profile for this nickname.
|
||||||
// Start with conversation context, then go to
|
// Start with conversation context, then go to
|
||||||
|
@ -726,6 +769,31 @@ function common_find_mentions($text, $notice)
|
||||||
return $mentions;
|
return $mentions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the actual regex pulls to find @-mentions in text.
|
||||||
|
* Should generally not be called directly; for use in common_find_mentions.
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @return array of PCRE match arrays
|
||||||
|
*/
|
||||||
|
function common_find_mentions_raw($text)
|
||||||
|
{
|
||||||
|
$tmatches = array();
|
||||||
|
preg_match_all('/^T (' . Nickname::DISPLAY_FMT . ') /',
|
||||||
|
$text,
|
||||||
|
$tmatches,
|
||||||
|
PREG_OFFSET_CAPTURE);
|
||||||
|
|
||||||
|
$atmatches = array();
|
||||||
|
preg_match_all('/(?:^|\s+)@(' . Nickname::DISPLAY_FMT . ')\b/',
|
||||||
|
$text,
|
||||||
|
$atmatches,
|
||||||
|
PREG_OFFSET_CAPTURE);
|
||||||
|
|
||||||
|
$matches = array_merge($tmatches[1], $atmatches[1]);
|
||||||
|
return $matches;
|
||||||
|
}
|
||||||
|
|
||||||
function common_render_text($text)
|
function common_render_text($text)
|
||||||
{
|
{
|
||||||
$r = htmlspecialchars($text);
|
$r = htmlspecialchars($text);
|
||||||
|
@ -737,7 +805,14 @@ function common_render_text($text)
|
||||||
return $r;
|
return $r;
|
||||||
}
|
}
|
||||||
|
|
||||||
function common_replace_urls_callback($text, $callback, $notice_id = null) {
|
/**
|
||||||
|
* Find links in the given text and pass them to the given callback function.
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @param function($text, $arg) $callback: return replacement text
|
||||||
|
* @param mixed $arg: optional argument will be passed on to the callback
|
||||||
|
*/
|
||||||
|
function common_replace_urls_callback($text, $callback, $arg = null) {
|
||||||
// Start off with a regex
|
// Start off with a regex
|
||||||
$regex = '#'.
|
$regex = '#'.
|
||||||
'(?:^|[\s\<\>\(\)\[\]\{\}\\\'\\\";]+)(?![\@\!\#])'.
|
'(?:^|[\s\<\>\(\)\[\]\{\}\\\'\\\";]+)(?![\@\!\#])'.
|
||||||
|
@ -778,10 +853,21 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) {
|
||||||
'#ixu';
|
'#ixu';
|
||||||
//preg_match_all($regex,$text,$matches);
|
//preg_match_all($regex,$text,$matches);
|
||||||
//print_r($matches);
|
//print_r($matches);
|
||||||
return preg_replace_callback($regex, curry('callback_helper',$callback,$notice_id) ,$text);
|
return preg_replace_callback($regex, curry('callback_helper',$callback,$arg) ,$text);
|
||||||
}
|
}
|
||||||
|
|
||||||
function callback_helper($matches, $callback, $notice_id) {
|
/**
|
||||||
|
* Intermediate callback for common_replace_links(), helps resolve some
|
||||||
|
* ambiguous link forms before passing on to the final callback.
|
||||||
|
*
|
||||||
|
* @param array $matches
|
||||||
|
* @param callable $callback
|
||||||
|
* @param mixed $arg optional argument to pass on as second param to callback
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function callback_helper($matches, $callback, $arg=null) {
|
||||||
$url=$matches[1];
|
$url=$matches[1];
|
||||||
$left = strpos($matches[0],$url);
|
$left = strpos($matches[0],$url);
|
||||||
$right = $left+strlen($url);
|
$right = $left+strlen($url);
|
||||||
|
@ -824,11 +910,7 @@ function callback_helper($matches, $callback, $notice_id) {
|
||||||
}
|
}
|
||||||
}while($original_url!=$url);
|
}while($original_url!=$url);
|
||||||
|
|
||||||
if(empty($notice_id)){
|
$result = call_user_func_array($callback, array($url, $arg));
|
||||||
$result = call_user_func_array($callback, array($url));
|
|
||||||
}else{
|
|
||||||
$result = call_user_func_array($callback, array(array($url,$notice_id)) );
|
|
||||||
}
|
|
||||||
return substr($matches[0],0,$left) . $result . substr($matches[0],$right);
|
return substr($matches[0],0,$left) . $result . substr($matches[0],$right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,7 +946,7 @@ function common_linkify($url) {
|
||||||
|
|
||||||
$canon = File_redirection::_canonUrl($url);
|
$canon = File_redirection::_canonUrl($url);
|
||||||
|
|
||||||
$longurl_data = File_redirection::where($canon);
|
$longurl_data = File_redirection::where($canon, common_config('attachments', 'process_links'));
|
||||||
if (is_array($longurl_data)) {
|
if (is_array($longurl_data)) {
|
||||||
$longurl = $longurl_data['url'];
|
$longurl = $longurl_data['url'];
|
||||||
} elseif (is_string($longurl_data)) {
|
} elseif (is_string($longurl_data)) {
|
||||||
|
@ -888,12 +970,14 @@ function common_linkify($url) {
|
||||||
$f = File::staticGet('url', $longurl);
|
$f = File::staticGet('url', $longurl);
|
||||||
|
|
||||||
if (empty($f)) {
|
if (empty($f)) {
|
||||||
|
if (common_config('attachments', 'process_links')) {
|
||||||
// XXX: this writes to the database. :<
|
// XXX: this writes to the database. :<
|
||||||
$f = File::processNew($longurl);
|
$f = File::processNew($longurl);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($f)) {
|
if (!empty($f)) {
|
||||||
if ($f->getEnclosure() || File_oembed::staticGet('file_id',$f->id)) {
|
if ($f->getEnclosure()) {
|
||||||
$is_attachment = true;
|
$is_attachment = true;
|
||||||
$attachment_id = $f->id;
|
$attachment_id = $f->id;
|
||||||
|
|
||||||
|
@ -926,7 +1010,23 @@ function common_linkify($url) {
|
||||||
return XMLStringer::estring('a', $attrs, $url);
|
return XMLStringer::estring('a', $attrs, $url);
|
||||||
}
|
}
|
||||||
|
|
||||||
function common_shorten_links($text, $always = false)
|
/**
|
||||||
|
* Find and shorten links in a given chunk of text if it's longer than the
|
||||||
|
* configured notice content limit (or unconditionally).
|
||||||
|
*
|
||||||
|
* Side effects: may save file and file_redirection records for referenced URLs.
|
||||||
|
*
|
||||||
|
* Pass the $user option or call $user->shortenLinks($text) to ensure the proper
|
||||||
|
* user's options are used; otherwise the current web session user's setitngs
|
||||||
|
* will be used or ur1.ca if there is no active web login.
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @param boolean $always (optional)
|
||||||
|
* @param User $user (optional)
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function common_shorten_links($text, $always = false, User $user=null)
|
||||||
{
|
{
|
||||||
common_debug("common_shorten_links() called");
|
common_debug("common_shorten_links() called");
|
||||||
|
|
||||||
|
@ -938,10 +1038,10 @@ function common_shorten_links($text, $always = false)
|
||||||
|
|
||||||
if ($always || mb_strlen($text) > $maxLength) {
|
if ($always || mb_strlen($text) > $maxLength) {
|
||||||
common_debug("Forcing shortening");
|
common_debug("Forcing shortening");
|
||||||
return common_replace_urls_callback($text, array('File_redirection', 'forceShort'));
|
return common_replace_urls_callback($text, array('File_redirection', 'forceShort'), $user);
|
||||||
} else {
|
} else {
|
||||||
common_debug("Not forcing shortening");
|
common_debug("Not forcing shortening");
|
||||||
return common_replace_urls_callback($text, array('File_redirection', 'makeShort'));
|
return common_replace_urls_callback($text, array('File_redirection', 'makeShort'), $user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1003,9 +1103,9 @@ function common_tag_link($tag)
|
||||||
$canonical = common_canonical_tag($tag);
|
$canonical = common_canonical_tag($tag);
|
||||||
if (common_config('singleuser', 'enabled')) {
|
if (common_config('singleuser', 'enabled')) {
|
||||||
// regular TagAction isn't set up in 1user mode
|
// regular TagAction isn't set up in 1user mode
|
||||||
$user = User::singleUser();
|
$nickname = User::singleUserNickname();
|
||||||
$url = common_local_url('showstream',
|
$url = common_local_url('showstream',
|
||||||
array('nickname' => $user->nickname,
|
array('nickname' => $nickname,
|
||||||
'tag' => $canonical));
|
'tag' => $canonical));
|
||||||
} else {
|
} else {
|
||||||
$url = common_local_url('tag', array('tag' => $canonical));
|
$url = common_local_url('tag', array('tag' => $canonical));
|
||||||
|
@ -1030,6 +1130,13 @@ function common_valid_profile_tag($str)
|
||||||
return preg_match('/^[A-Za-z0-9_\-\.]{1,64}$/', $str);
|
return preg_match('/^[A-Za-z0-9_\-\.]{1,64}$/', $str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param <type> $sender_id
|
||||||
|
* @param <type> $nickname
|
||||||
|
* @return <type>
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
function common_group_link($sender_id, $nickname)
|
function common_group_link($sender_id, $nickname)
|
||||||
{
|
{
|
||||||
$sender = Profile::staticGet($sender_id);
|
$sender = Profile::staticGet($sender_id);
|
||||||
|
@ -1052,13 +1159,37 @@ function common_group_link($sender_id, $nickname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve an ambiguous profile nickname reference, checking in following order:
|
||||||
|
* - profiles that $sender subscribes to
|
||||||
|
* - profiles that subscribe to $sender
|
||||||
|
* - local user profiles
|
||||||
|
*
|
||||||
|
* WARNING: does not validate or normalize $nickname -- MUST BE PRE-VALIDATED
|
||||||
|
* OR THERE MAY BE A RISK OF SQL INJECTION ATTACKS. THIS FUNCTION DOES NOT
|
||||||
|
* ESCAPE SQL.
|
||||||
|
*
|
||||||
|
* @fixme validate input
|
||||||
|
* @fixme escape SQL
|
||||||
|
* @fixme fix or remove mystery third parameter
|
||||||
|
* @fixme is $sender a User or Profile?
|
||||||
|
*
|
||||||
|
* @param <type> $sender the user or profile in whose context we're looking
|
||||||
|
* @param string $nickname validated nickname of
|
||||||
|
* @param <type> $dt unused mystery parameter; in Notice reply-to handling a timestamp is passed.
|
||||||
|
*
|
||||||
|
* @return Profile or null
|
||||||
|
*/
|
||||||
function common_relative_profile($sender, $nickname, $dt=null)
|
function common_relative_profile($sender, $nickname, $dt=null)
|
||||||
{
|
{
|
||||||
|
// Will throw exception on invalid input.
|
||||||
|
$nickname = Nickname::normalize($nickname);
|
||||||
|
|
||||||
// Try to find profiles this profile is subscribed to that have this nickname
|
// Try to find profiles this profile is subscribed to that have this nickname
|
||||||
$recipient = new Profile();
|
$recipient = new Profile();
|
||||||
// XXX: use a join instead of a subquery
|
// XXX: use a join instead of a subquery
|
||||||
$recipient->whereAdd('EXISTS (SELECT subscribed from subscription where subscriber = '.$sender->id.' and subscribed = id)', 'AND');
|
$recipient->whereAdd('EXISTS (SELECT subscribed from subscription where subscriber = '.intval($sender->id).' and subscribed = id)', 'AND');
|
||||||
$recipient->whereAdd("nickname = '" . trim($nickname) . "'", 'AND');
|
$recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND');
|
||||||
if ($recipient->find(true)) {
|
if ($recipient->find(true)) {
|
||||||
// XXX: should probably differentiate between profiles with
|
// XXX: should probably differentiate between profiles with
|
||||||
// the same name by date of most recent update
|
// the same name by date of most recent update
|
||||||
|
@ -1067,8 +1198,8 @@ function common_relative_profile($sender, $nickname, $dt=null)
|
||||||
// Try to find profiles that listen to this profile and that have this nickname
|
// Try to find profiles that listen to this profile and that have this nickname
|
||||||
$recipient = new Profile();
|
$recipient = new Profile();
|
||||||
// XXX: use a join instead of a subquery
|
// XXX: use a join instead of a subquery
|
||||||
$recipient->whereAdd('EXISTS (SELECT subscriber from subscription where subscribed = '.$sender->id.' and subscriber = id)', 'AND');
|
$recipient->whereAdd('EXISTS (SELECT subscriber from subscription where subscribed = '.intval($sender->id).' and subscriber = id)', 'AND');
|
||||||
$recipient->whereAdd("nickname = '" . trim($nickname) . "'", 'AND');
|
$recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND');
|
||||||
if ($recipient->find(true)) {
|
if ($recipient->find(true)) {
|
||||||
// XXX: should probably differentiate between profiles with
|
// XXX: should probably differentiate between profiles with
|
||||||
// the same name by date of most recent update
|
// the same name by date of most recent update
|
||||||
|
@ -1512,6 +1643,7 @@ function common_request_id()
|
||||||
function common_log($priority, $msg, $filename=null)
|
function common_log($priority, $msg, $filename=null)
|
||||||
{
|
{
|
||||||
if(Event::handle('StartLog', array(&$priority, &$msg, &$filename))){
|
if(Event::handle('StartLog', array(&$priority, &$msg, &$filename))){
|
||||||
|
$msg = (empty($filename)) ? $msg : basename($filename) . ' - ' . $msg;
|
||||||
$msg = '[' . common_request_id() . '] ' . $msg;
|
$msg = '[' . common_request_id() . '] ' . $msg;
|
||||||
$logfile = common_config('site', 'logfile');
|
$logfile = common_config('site', 'logfile');
|
||||||
if ($logfile) {
|
if ($logfile) {
|
||||||
|
@ -1923,15 +2055,13 @@ function common_database_tablename($tablename)
|
||||||
* or ur1.ca if configured, or not at all if no shortening is set up.
|
* or ur1.ca if configured, or not at all if no shortening is set up.
|
||||||
*
|
*
|
||||||
* @param string $long_url original URL
|
* @param string $long_url original URL
|
||||||
|
* @param User $user to specify a particular user's options
|
||||||
* @param boolean $force Force shortening (used when notice is too long)
|
* @param boolean $force Force shortening (used when notice is too long)
|
||||||
*
|
|
||||||
* @return string may return the original URL if shortening failed
|
* @return string may return the original URL if shortening failed
|
||||||
*
|
*
|
||||||
* @fixme provide a way to specify a particular shortener
|
* @fixme provide a way to specify a particular shortener
|
||||||
* @fixme provide a way to specify to use a given user's shortening preferences
|
|
||||||
*/
|
*/
|
||||||
|
function common_shorten_url($long_url, User $user=null, $force = false)
|
||||||
function common_shorten_url($long_url, $force = false)
|
|
||||||
{
|
{
|
||||||
common_debug("Shortening URL '$long_url' (force = $force)");
|
common_debug("Shortening URL '$long_url' (force = $force)");
|
||||||
|
|
||||||
|
|
135
lib/xrdaction.php
Normal file
135
lib/xrdaction.php
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2010, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package OStatusPlugin
|
||||||
|
* @maintainer James Walker <james@status.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
class XrdAction extends Action
|
||||||
|
{
|
||||||
|
const PROFILEPAGE = 'http://webfinger.net/rel/profile-page';
|
||||||
|
const UPDATESFROM = 'http://schemas.google.com/g/2010#updates-from';
|
||||||
|
const HCARD = 'http://microformats.org/profile/hcard';
|
||||||
|
|
||||||
|
public $uri;
|
||||||
|
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
public $xrd;
|
||||||
|
|
||||||
|
function handle()
|
||||||
|
{
|
||||||
|
$nick = $this->user->nickname;
|
||||||
|
$profile = $this->user->getProfile();
|
||||||
|
|
||||||
|
if (empty($this->xrd)) {
|
||||||
|
$xrd = new XRD();
|
||||||
|
} else {
|
||||||
|
$xrd = $this->xrd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($xrd->subject)) {
|
||||||
|
$xrd->subject = self::normalize($this->uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Event::handle('StartXrdActionAliases', array(&$xrd, $this->user))) {
|
||||||
|
|
||||||
|
// Possible aliases for the user
|
||||||
|
|
||||||
|
$uris = array($this->user->uri, $profile->profileurl);
|
||||||
|
|
||||||
|
// FIXME: Webfinger generation code should live somewhere on its own
|
||||||
|
|
||||||
|
$path = common_config('site', 'path');
|
||||||
|
|
||||||
|
if (empty($path)) {
|
||||||
|
$uris[] = sprintf('acct:%s@%s', $nick, common_config('site', 'server'));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($uris as $uri) {
|
||||||
|
if ($uri != $xrd->subject) {
|
||||||
|
$xrd->alias[] = $uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Event::handle('EndXrdActionAliases', array(&$xrd, $this->user));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Event::handle('StartXrdActionLinks', array(&$xrd, $this->user))) {
|
||||||
|
|
||||||
|
$xrd->links[] = array('rel' => self::PROFILEPAGE,
|
||||||
|
'type' => 'text/html',
|
||||||
|
'href' => $profile->profileurl);
|
||||||
|
|
||||||
|
// hCard
|
||||||
|
$xrd->links[] = array('rel' => self::HCARD,
|
||||||
|
'type' => 'text/html',
|
||||||
|
'href' => common_local_url('hcard', array('nickname' => $nick)));
|
||||||
|
|
||||||
|
// XFN
|
||||||
|
$xrd->links[] = array('rel' => 'http://gmpg.org/xfn/11',
|
||||||
|
'type' => 'text/html',
|
||||||
|
'href' => $profile->profileurl);
|
||||||
|
// FOAF
|
||||||
|
$xrd->links[] = array('rel' => 'describedby',
|
||||||
|
'type' => 'application/rdf+xml',
|
||||||
|
'href' => common_local_url('foaf',
|
||||||
|
array('nickname' => $nick)));
|
||||||
|
|
||||||
|
|
||||||
|
Event::handle('EndXrdActionLinks', array(&$xrd, $this->user));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
header('Content-type: application/xrd+xml');
|
||||||
|
print $xrd->toXML();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a "user id" make sure it's normalized to either a webfinger
|
||||||
|
* acct: uri or a profile HTTP URL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static function normalize($user_id)
|
||||||
|
{
|
||||||
|
if (substr($user_id, 0, 5) == 'http:' ||
|
||||||
|
substr($user_id, 0, 6) == 'https:' ||
|
||||||
|
substr($user_id, 0, 5) == 'acct:') {
|
||||||
|
return $user_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strpos($user_id, '@') !== FALSE) {
|
||||||
|
return 'acct:' . $user_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'http://' . $user_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isWebfinger($user_id)
|
||||||
|
{
|
||||||
|
$uri = self::normalize($user_id);
|
||||||
|
|
||||||
|
return (substr($uri, 0, 5) == 'acct:');
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user