1344 lines
42 KiB
PHP
1344 lines
42 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* phpQuery is a server-side, chainable, CSS3 selector driven
|
||
|
* Document Object Model (DOM) API based on jQuery JavaScript Library.
|
||
|
*
|
||
|
* @version 0.9.5
|
||
|
* @link http://code.google.com/p/phpquery/
|
||
|
* @link http://phpquery-library.blogspot.com/
|
||
|
* @link http://jquery.com/
|
||
|
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
|
||
|
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||
|
* @package phpQuery
|
||
|
*/
|
||
|
|
||
|
// class names for instanceof
|
||
|
// TODO move them as class constants into phpQuery
|
||
|
define('DOMDOCUMENT', 'DOMDocument');
|
||
|
define('DOMELEMENT', 'DOMElement');
|
||
|
define('DOMNODELIST', 'DOMNodeList');
|
||
|
define('DOMNODE', 'DOMNode');
|
||
|
require_once(dirname(__FILE__).'/phpQuery/DOMEvent.php');
|
||
|
require_once(dirname(__FILE__).'/phpQuery/DOMDocumentWrapper.php');
|
||
|
require_once(dirname(__FILE__).'/phpQuery/phpQueryEvents.php');
|
||
|
require_once(dirname(__FILE__).'/phpQuery/Callback.php');
|
||
|
require_once(dirname(__FILE__).'/phpQuery/phpQueryObject.php');
|
||
|
require_once(dirname(__FILE__).'/phpQuery/compat/mbstring.php');
|
||
|
/**
|
||
|
* Static namespace for phpQuery functions.
|
||
|
*
|
||
|
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
|
||
|
* @package phpQuery
|
||
|
*/
|
||
|
abstract class phpQuery {
|
||
|
/**
|
||
|
* XXX: Workaround for mbstring problems
|
||
|
*
|
||
|
* @var bool
|
||
|
*/
|
||
|
public static $mbstringSupport = true;
|
||
|
public static $debug = false;
|
||
|
public static $documents = array();
|
||
|
public static $defaultDocumentID = null;
|
||
|
// public static $defaultDoctype = 'html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"';
|
||
|
/**
|
||
|
* Applies only to HTML.
|
||
|
*
|
||
|
* @var unknown_type
|
||
|
*/
|
||
|
public static $defaultDoctype = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||
|
"http://www.w3.org/TR/html4/loose.dtd">';
|
||
|
public static $defaultCharset = 'UTF-8';
|
||
|
/**
|
||
|
* Static namespace for plugins.
|
||
|
*
|
||
|
* @var object
|
||
|
*/
|
||
|
public static $plugins = array();
|
||
|
/**
|
||
|
* List of loaded plugins.
|
||
|
*
|
||
|
* @var unknown_type
|
||
|
*/
|
||
|
public static $pluginsLoaded = array();
|
||
|
public static $pluginsMethods = array();
|
||
|
public static $pluginsStaticMethods = array();
|
||
|
public static $extendMethods = array();
|
||
|
/**
|
||
|
* @TODO implement
|
||
|
*/
|
||
|
public static $extendStaticMethods = array();
|
||
|
/**
|
||
|
* Hosts allowed for AJAX connections.
|
||
|
* Dot '.' means $_SERVER['HTTP_HOST'] (if any).
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
public static $ajaxAllowedHosts = array(
|
||
|
'.'
|
||
|
);
|
||
|
/**
|
||
|
* AJAX settings.
|
||
|
*
|
||
|
* @var array
|
||
|
* XXX should it be static or not ?
|
||
|
*/
|
||
|
public static $ajaxSettings = array(
|
||
|
'url' => '',//TODO
|
||
|
'global' => true,
|
||
|
'type' => "GET",
|
||
|
'timeout' => null,
|
||
|
'contentType' => "application/x-www-form-urlencoded",
|
||
|
'processData' => true,
|
||
|
// 'async' => true,
|
||
|
'data' => null,
|
||
|
'username' => null,
|
||
|
'password' => null,
|
||
|
'dataType' => null,
|
||
|
'ifModified' => null,
|
||
|
'accepts' => array(
|
||
|
'xml' => "application/xml, text/xml",
|
||
|
'html' => "text/html",
|
||
|
'script' => "text/javascript, application/javascript",
|
||
|
'json' => "application/json, text/javascript",
|
||
|
'text' => "text/plain",
|
||
|
'_default' => "*/*"
|
||
|
)
|
||
|
);
|
||
|
public static $lastModified = null;
|
||
|
public static $active = 0;
|
||
|
public static $dumpCount = 0;
|
||
|
/**
|
||
|
* Multi-purpose function.
|
||
|
* Use pq() as shortcut.
|
||
|
*
|
||
|
* In below examples, $pq is any result of pq(); function.
|
||
|
*
|
||
|
* 1. Import markup into existing document (without any attaching):
|
||
|
* - Import into selected document:
|
||
|
* pq('<div/>') // DOESNT accept text nodes at beginning of input string !
|
||
|
* - Import into document with ID from $pq->getDocumentID():
|
||
|
* pq('<div/>', $pq->getDocumentID())
|
||
|
* - Import into same document as DOMNode belongs to:
|
||
|
* pq('<div/>', DOMNode)
|
||
|
* - Import into document from phpQuery object:
|
||
|
* pq('<div/>', $pq)
|
||
|
*
|
||
|
* 2. Run query:
|
||
|
* - Run query on last selected document:
|
||
|
* pq('div.myClass')
|
||
|
* - Run query on document with ID from $pq->getDocumentID():
|
||
|
* pq('div.myClass', $pq->getDocumentID())
|
||
|
* - Run query on same document as DOMNode belongs to and use node(s)as root for query:
|
||
|
* pq('div.myClass', DOMNode)
|
||
|
* - Run query on document from phpQuery object
|
||
|
* and use object's stack as root node(s) for query:
|
||
|
* pq('div.myClass', $pq)
|
||
|
*
|
||
|
* @param string|DOMNode|DOMNodeList|array $arg1 HTML markup, CSS Selector, DOMNode or array of DOMNodes
|
||
|
* @param string|phpQueryObject|DOMNode $context DOM ID from $pq->getDocumentID(), phpQuery object (determines also query root) or DOMNode (determines also query root)
|
||
|
*
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery|QueryTemplatesPhpQuery|false
|
||
|
* phpQuery object or false in case of error.
|
||
|
*/
|
||
|
public static function pq($arg1, $context = null) {
|
||
|
if ($arg1 instanceof DOMNODE && ! isset($context)) {
|
||
|
foreach(phpQuery::$documents as $documentWrapper) {
|
||
|
$compare = $arg1 instanceof DOMDocument
|
||
|
? $arg1 : $arg1->ownerDocument;
|
||
|
if ($documentWrapper->document->isSameNode($compare))
|
||
|
$context = $documentWrapper->id;
|
||
|
}
|
||
|
}
|
||
|
if (! $context) {
|
||
|
$domId = self::$defaultDocumentID;
|
||
|
if (! $domId)
|
||
|
throw new Exception("Can't use last created DOM, because there isn't any. Use phpQuery::newDocument() first.");
|
||
|
// } else if (is_object($context) && ($context instanceof PHPQUERY || is_subclass_of($context, 'phpQueryObject')))
|
||
|
} else if (is_object($context) && $context instanceof phpQueryObject)
|
||
|
$domId = $context->getDocumentID();
|
||
|
else if ($context instanceof DOMDOCUMENT) {
|
||
|
$domId = self::getDocumentID($context);
|
||
|
if (! $domId) {
|
||
|
//throw new Exception('Orphaned DOMDocument');
|
||
|
$domId = self::newDocument($context)->getDocumentID();
|
||
|
}
|
||
|
} else if ($context instanceof DOMNODE) {
|
||
|
$domId = self::getDocumentID($context);
|
||
|
if (! $domId) {
|
||
|
throw new Exception('Orphaned DOMNode');
|
||
|
// $domId = self::newDocument($context->ownerDocument);
|
||
|
}
|
||
|
} else
|
||
|
$domId = $context;
|
||
|
if ($arg1 instanceof phpQueryObject) {
|
||
|
// if (is_object($arg1) && (get_class($arg1) == 'phpQueryObject' || $arg1 instanceof PHPQUERY || is_subclass_of($arg1, 'phpQueryObject'))) {
|
||
|
/**
|
||
|
* Return $arg1 or import $arg1 stack if document differs:
|
||
|
* pq(pq('<div/>'))
|
||
|
*/
|
||
|
if ($arg1->getDocumentID() == $domId)
|
||
|
return $arg1;
|
||
|
$class = get_class($arg1);
|
||
|
// support inheritance by passing old object to overloaded constructor
|
||
|
$phpQuery = $class != 'phpQuery'
|
||
|
? new $class($arg1, $domId)
|
||
|
: new phpQueryObject($domId);
|
||
|
$phpQuery->elements = array();
|
||
|
foreach($arg1->elements as $node)
|
||
|
$phpQuery->elements[] = $phpQuery->document->importNode($node, true);
|
||
|
return $phpQuery;
|
||
|
} else if ($arg1 instanceof DOMNODE || (is_array($arg1) && isset($arg1[0]) && $arg1[0] instanceof DOMNODE)) {
|
||
|
/*
|
||
|
* Wrap DOM nodes with phpQuery object, import into document when needed:
|
||
|
* pq(array($domNode1, $domNode2))
|
||
|
*/
|
||
|
$phpQuery = new phpQueryObject($domId);
|
||
|
if (!($arg1 instanceof DOMNODELIST) && ! is_array($arg1))
|
||
|
$arg1 = array($arg1);
|
||
|
$phpQuery->elements = array();
|
||
|
foreach($arg1 as $node) {
|
||
|
$sameDocument = $node->ownerDocument instanceof DOMDOCUMENT
|
||
|
&& ! $node->ownerDocument->isSameNode($phpQuery->document);
|
||
|
$phpQuery->elements[] = $sameDocument
|
||
|
? $phpQuery->document->importNode($node, true)
|
||
|
: $node;
|
||
|
}
|
||
|
return $phpQuery;
|
||
|
} else if (self::isMarkup($arg1)) {
|
||
|
/**
|
||
|
* Import HTML:
|
||
|
* pq('<div/>')
|
||
|
*/
|
||
|
$phpQuery = new phpQueryObject($domId);
|
||
|
return $phpQuery->newInstance(
|
||
|
$phpQuery->documentWrapper->import($arg1)
|
||
|
);
|
||
|
} else {
|
||
|
/**
|
||
|
* Run CSS query:
|
||
|
* pq('div.myClass')
|
||
|
*/
|
||
|
$phpQuery = new phpQueryObject($domId);
|
||
|
// if ($context && ($context instanceof PHPQUERY || is_subclass_of($context, 'phpQueryObject')))
|
||
|
if ($context && $context instanceof phpQueryObject)
|
||
|
$phpQuery->elements = $context->elements;
|
||
|
else if ($context && $context instanceof DOMNODELIST) {
|
||
|
$phpQuery->elements = array();
|
||
|
foreach($context as $node)
|
||
|
$phpQuery->elements[] = $node;
|
||
|
} else if ($context && $context instanceof DOMNODE)
|
||
|
$phpQuery->elements = array($context);
|
||
|
return $phpQuery->find($arg1);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Sets default document to $id. Document has to be loaded prior
|
||
|
* to using this method.
|
||
|
* $id can be retrived via getDocumentID() or getDocumentIDRef().
|
||
|
*
|
||
|
* @param unknown_type $id
|
||
|
*/
|
||
|
public static function selectDocument($id) {
|
||
|
$id = self::getDocumentID($id);
|
||
|
self::debug("Selecting document '$id' as default one");
|
||
|
self::$defaultDocumentID = self::getDocumentID($id);
|
||
|
}
|
||
|
/**
|
||
|
* Returns document with id $id or last used as phpQueryObject.
|
||
|
* $id can be retrived via getDocumentID() or getDocumentIDRef().
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @see phpQuery::selectDocument()
|
||
|
* @param unknown_type $id
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
*/
|
||
|
public static function getDocument($id = null) {
|
||
|
if ($id)
|
||
|
phpQuery::selectDocument($id);
|
||
|
else
|
||
|
$id = phpQuery::$defaultDocumentID;
|
||
|
return new phpQueryObject($id);
|
||
|
}
|
||
|
/**
|
||
|
* Creates new document from markup.
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @param unknown_type $markup
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
*/
|
||
|
public static function newDocument($markup = null, $contentType = null) {
|
||
|
if (! $markup)
|
||
|
$markup = '';
|
||
|
$documentID = phpQuery::createDocumentWrapper($markup, $contentType);
|
||
|
return new phpQueryObject($documentID);
|
||
|
}
|
||
|
/**
|
||
|
* Creates new document from markup.
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @param unknown_type $markup
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
*/
|
||
|
public static function newDocumentHTML($markup = null, $charset = null) {
|
||
|
$contentType = $charset
|
||
|
? ";charset=$charset"
|
||
|
: '';
|
||
|
return self::newDocument($markup, "text/html{$contentType}");
|
||
|
}
|
||
|
/**
|
||
|
* Creates new document from markup.
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @param unknown_type $markup
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
*/
|
||
|
public static function newDocumentXML($markup = null, $charset = null) {
|
||
|
$contentType = $charset
|
||
|
? ";charset=$charset"
|
||
|
: '';
|
||
|
return self::newDocument($markup, "text/xml{$contentType}");
|
||
|
}
|
||
|
/**
|
||
|
* Creates new document from markup.
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @param unknown_type $markup
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
*/
|
||
|
public static function newDocumentXHTML($markup = null, $charset = null) {
|
||
|
$contentType = $charset
|
||
|
? ";charset=$charset"
|
||
|
: '';
|
||
|
return self::newDocument($markup, "application/xhtml+xml{$contentType}");
|
||
|
}
|
||
|
/**
|
||
|
* Creates new document from markup.
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @param unknown_type $markup
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
*/
|
||
|
public static function newDocumentPHP($markup = null, $contentType = "text/html") {
|
||
|
// TODO pass charset to phpToMarkup if possible (use DOMDocumentWrapper function)
|
||
|
$markup = phpQuery::phpToMarkup($markup, self::$defaultCharset);
|
||
|
return self::newDocument($markup, $contentType);
|
||
|
}
|
||
|
public static function phpToMarkup($php, $charset = 'utf-8') {
|
||
|
$regexes = array(
|
||
|
'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)<'.'?php?(.*?)(?:\\?>)([^\']*)\'@s',
|
||
|
'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)<'.'?php?(.*?)(?:\\?>)([^"]*)"@s',
|
||
|
);
|
||
|
foreach($regexes as $regex)
|
||
|
while (preg_match($regex, $php, $matches)) {
|
||
|
$php = preg_replace_callback(
|
||
|
$regex,
|
||
|
// create_function('$m, $charset = "'.$charset.'"',
|
||
|
// 'return $m[1].$m[2]
|
||
|
// .htmlspecialchars("<"."?php".$m[4]."?".">", ENT_QUOTES|ENT_NOQUOTES, $charset)
|
||
|
// .$m[5].$m[2];'
|
||
|
// ),
|
||
|
array('phpQuery', '_phpToMarkupCallback'),
|
||
|
$php
|
||
|
);
|
||
|
}
|
||
|
$regex = '@(^|>[^<]*)+?(<\?php(.*?)(\?>))@s';
|
||
|
//preg_match_all($regex, $php, $matches);
|
||
|
//var_dump($matches);
|
||
|
$php = preg_replace($regex, '\\1<php><!-- \\3 --></php>', $php);
|
||
|
return $php;
|
||
|
}
|
||
|
public static function _phpToMarkupCallback($php, $charset = 'utf-8') {
|
||
|
return $m[1].$m[2]
|
||
|
.htmlspecialchars("<"."?php".$m[4]."?".">", ENT_QUOTES|ENT_NOQUOTES, $charset)
|
||
|
.$m[5].$m[2];
|
||
|
}
|
||
|
public static function _markupToPHPCallback($m) {
|
||
|
return "<"."?php ".htmlspecialchars_decode($m[1])." ?".">";
|
||
|
}
|
||
|
/**
|
||
|
* Converts document markup containing PHP code generated by phpQuery::php()
|
||
|
* into valid (executable) PHP code syntax.
|
||
|
*
|
||
|
* @param string|phpQueryObject $content
|
||
|
* @return string PHP code.
|
||
|
*/
|
||
|
public static function markupToPHP($content) {
|
||
|
if ($content instanceof phpQueryObject)
|
||
|
$content = $content->markupOuter();
|
||
|
/* <php>...</php> to <?php...? > */
|
||
|
$content = preg_replace_callback(
|
||
|
'@<php>\s*<!--(.*?)-->\s*</php>@s',
|
||
|
// create_function('$m',
|
||
|
// 'return "<'.'?php ".htmlspecialchars_decode($m[1])." ?'.'>";'
|
||
|
// ),
|
||
|
array('phpQuery', '_markupToPHPCallback'),
|
||
|
$content
|
||
|
);
|
||
|
/* <node attr='< ?php ? >'> extra space added to save highlighters */
|
||
|
$regexes = array(
|
||
|
'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)(?:<|%3C)\\?(?:php)?(.*?)(?:\\?(?:>|%3E))([^\']*)\'@s',
|
||
|
'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)(?:<|%3C)\\?(?:php)?(.*?)(?:\\?(?:>|%3E))([^"]*)"@s',
|
||
|
);
|
||
|
foreach($regexes as $regex)
|
||
|
while (preg_match($regex, $content))
|
||
|
$content = preg_replace_callback(
|
||
|
$regex,
|
||
|
create_function('$m',
|
||
|
'return $m[1].$m[2].$m[3]."<?php "
|
||
|
.str_replace(
|
||
|
array("%20", "%3E", "%09", " ", "	", "%7B", "%24", "%7D", "%22", "%5B", "%5D"),
|
||
|
array(" ", ">", " ", "\n", " ", "{", "$", "}", \'"\', "[", "]"),
|
||
|
htmlspecialchars_decode($m[4])
|
||
|
)
|
||
|
." ?>".$m[5].$m[2];'
|
||
|
),
|
||
|
$content
|
||
|
);
|
||
|
return $content;
|
||
|
}
|
||
|
/**
|
||
|
* Creates new document from file $file.
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @param string $file URLs allowed. See File wrapper page at php.net for more supported sources.
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
*/
|
||
|
public static function newDocumentFile($file, $contentType = null) {
|
||
|
$documentID = self::createDocumentWrapper(
|
||
|
file_get_contents($file), $contentType
|
||
|
);
|
||
|
return new phpQueryObject($documentID);
|
||
|
}
|
||
|
/**
|
||
|
* Creates new document from markup.
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @param unknown_type $markup
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
*/
|
||
|
public static function newDocumentFileHTML($file, $charset = null) {
|
||
|
$contentType = $charset
|
||
|
? ";charset=$charset"
|
||
|
: '';
|
||
|
return self::newDocumentFile($file, "text/html{$contentType}");
|
||
|
}
|
||
|
/**
|
||
|
* Creates new document from markup.
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @param unknown_type $markup
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
*/
|
||
|
public static function newDocumentFileXML($file, $charset = null) {
|
||
|
$contentType = $charset
|
||
|
? ";charset=$charset"
|
||
|
: '';
|
||
|
return self::newDocumentFile($file, "text/xml{$contentType}");
|
||
|
}
|
||
|
/**
|
||
|
* Creates new document from markup.
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @param unknown_type $markup
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
*/
|
||
|
public static function newDocumentFileXHTML($file, $charset = null) {
|
||
|
$contentType = $charset
|
||
|
? ";charset=$charset"
|
||
|
: '';
|
||
|
return self::newDocumentFile($file, "application/xhtml+xml{$contentType}");
|
||
|
}
|
||
|
/**
|
||
|
* Creates new document from markup.
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @param unknown_type $markup
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
*/
|
||
|
public static function newDocumentFilePHP($file, $contentType = null) {
|
||
|
return self::newDocumentPHP(file_get_contents($file), $contentType);
|
||
|
}
|
||
|
/**
|
||
|
* Reuses existing DOMDocument object.
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @param $document DOMDocument
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
* @TODO support DOMDocument
|
||
|
*/
|
||
|
public static function loadDocument($document) {
|
||
|
// TODO
|
||
|
die('TODO loadDocument');
|
||
|
}
|
||
|
/**
|
||
|
* Enter description here...
|
||
|
*
|
||
|
* @param unknown_type $html
|
||
|
* @param unknown_type $domId
|
||
|
* @return unknown New DOM ID
|
||
|
* @todo support PHP tags in input
|
||
|
* @todo support passing DOMDocument object from self::loadDocument
|
||
|
*/
|
||
|
protected static function createDocumentWrapper($html, $contentType = null, $documentID = null) {
|
||
|
if (function_exists('domxml_open_mem'))
|
||
|
throw new Exception("Old PHP4 DOM XML extension detected. phpQuery won't work until this extension is enabled.");
|
||
|
// $id = $documentID
|
||
|
// ? $documentID
|
||
|
// : md5(microtime());
|
||
|
$document = null;
|
||
|
if ($html instanceof DOMDOCUMENT) {
|
||
|
if (self::getDocumentID($html)) {
|
||
|
// document already exists in phpQuery::$documents, make a copy
|
||
|
$document = clone $html;
|
||
|
} else {
|
||
|
// new document, add it to phpQuery::$documents
|
||
|
$wrapper = new DOMDocumentWrapper($html, $contentType, $documentID);
|
||
|
}
|
||
|
} else {
|
||
|
$wrapper = new DOMDocumentWrapper($html, $contentType, $documentID);
|
||
|
}
|
||
|
// $wrapper->id = $id;
|
||
|
// bind document
|
||
|
phpQuery::$documents[$wrapper->id] = $wrapper;
|
||
|
// remember last loaded document
|
||
|
phpQuery::selectDocument($wrapper->id);
|
||
|
return $wrapper->id;
|
||
|
}
|
||
|
/**
|
||
|
* Extend class namespace.
|
||
|
*
|
||
|
* @param string|array $target
|
||
|
* @param array $source
|
||
|
* @TODO support string $source
|
||
|
* @return unknown_type
|
||
|
*/
|
||
|
public static function extend($target, $source) {
|
||
|
switch($target) {
|
||
|
case 'phpQueryObject':
|
||
|
$targetRef = &self::$extendMethods;
|
||
|
$targetRef2 = &self::$pluginsMethods;
|
||
|
break;
|
||
|
case 'phpQuery':
|
||
|
$targetRef = &self::$extendStaticMethods;
|
||
|
$targetRef2 = &self::$pluginsStaticMethods;
|
||
|
break;
|
||
|
default:
|
||
|
throw new Exception("Unsupported \$target type");
|
||
|
}
|
||
|
if (is_string($source))
|
||
|
$source = array($source => $source);
|
||
|
foreach($source as $method => $callback) {
|
||
|
if (isset($targetRef[$method])) {
|
||
|
// throw new Exception
|
||
|
self::debug("Duplicate method '{$method}', can\'t extend '{$target}'");
|
||
|
continue;
|
||
|
}
|
||
|
if (isset($targetRef2[$method])) {
|
||
|
// throw new Exception
|
||
|
self::debug("Duplicate method '{$method}' from plugin '{$targetRef2[$method]}',"
|
||
|
." can\'t extend '{$target}'");
|
||
|
continue;
|
||
|
}
|
||
|
$targetRef[$method] = $callback;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
/**
|
||
|
* Extend phpQuery with $class from $file.
|
||
|
*
|
||
|
* @param string $class Extending class name. Real class name can be prepended phpQuery_.
|
||
|
* @param string $file Filename to include. Defaults to "{$class}.php".
|
||
|
*/
|
||
|
public static function plugin($class, $file = null) {
|
||
|
// TODO $class checked agains phpQuery_$class
|
||
|
// if (strpos($class, 'phpQuery') === 0)
|
||
|
// $class = substr($class, 8);
|
||
|
if (in_array($class, self::$pluginsLoaded))
|
||
|
return true;
|
||
|
if (! $file)
|
||
|
$file = $class.'.php';
|
||
|
$objectClassExists = class_exists('phpQueryObjectPlugin_'.$class);
|
||
|
$staticClassExists = class_exists('phpQueryPlugin_'.$class);
|
||
|
if (! $objectClassExists && ! $staticClassExists)
|
||
|
require_once($file);
|
||
|
self::$pluginsLoaded[] = $class;
|
||
|
// static methods
|
||
|
if (class_exists('phpQueryPlugin_'.$class)) {
|
||
|
$realClass = 'phpQueryPlugin_'.$class;
|
||
|
$vars = get_class_vars($realClass);
|
||
|
$loop = isset($vars['phpQueryMethods'])
|
||
|
&& ! is_null($vars['phpQueryMethods'])
|
||
|
? $vars['phpQueryMethods']
|
||
|
: get_class_methods($realClass);
|
||
|
foreach($loop as $method) {
|
||
|
if ($method == '__initialize')
|
||
|
continue;
|
||
|
if (! is_callable(array($realClass, $method)))
|
||
|
continue;
|
||
|
if (isset(self::$pluginsStaticMethods[$method])) {
|
||
|
throw new Exception("Duplicate method '{$method}' from plugin '{$c}' conflicts with same method from plugin '".self::$pluginsStaticMethods[$method]."'");
|
||
|
return;
|
||
|
}
|
||
|
self::$pluginsStaticMethods[$method] = $class;
|
||
|
}
|
||
|
if (method_exists($realClass, '__initialize'))
|
||
|
call_user_func_array(array($realClass, '__initialize'), array());
|
||
|
}
|
||
|
// object methods
|
||
|
if (class_exists('phpQueryObjectPlugin_'.$class)) {
|
||
|
$realClass = 'phpQueryObjectPlugin_'.$class;
|
||
|
$vars = get_class_vars($realClass);
|
||
|
$loop = isset($vars['phpQueryMethods'])
|
||
|
&& ! is_null($vars['phpQueryMethods'])
|
||
|
? $vars['phpQueryMethods']
|
||
|
: get_class_methods($realClass);
|
||
|
foreach($loop as $method) {
|
||
|
if (! is_callable(array($realClass, $method)))
|
||
|
continue;
|
||
|
if (isset(self::$pluginsMethods[$method])) {
|
||
|
throw new Exception("Duplicate method '{$method}' from plugin '{$c}' conflicts with same method from plugin '".self::$pluginsMethods[$method]."'");
|
||
|
continue;
|
||
|
}
|
||
|
self::$pluginsMethods[$method] = $class;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
/**
|
||
|
* Unloades all or specified document from memory.
|
||
|
*
|
||
|
* @param mixed $documentID @see phpQuery::getDocumentID() for supported types.
|
||
|
*/
|
||
|
public static function unloadDocuments($id = null) {
|
||
|
if (isset($id)) {
|
||
|
if ($id = self::getDocumentID($id))
|
||
|
unset(phpQuery::$documents[$id]);
|
||
|
} else {
|
||
|
foreach(phpQuery::$documents as $k => $v) {
|
||
|
unset(phpQuery::$documents[$k]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Parses phpQuery object or HTML result against PHP tags and makes them active.
|
||
|
*
|
||
|
* @param phpQuery|string $content
|
||
|
* @deprecated
|
||
|
* @return string
|
||
|
*/
|
||
|
public static function unsafePHPTags($content) {
|
||
|
return self::markupToPHP($content);
|
||
|
}
|
||
|
public static function DOMNodeListToArray($DOMNodeList) {
|
||
|
$array = array();
|
||
|
if (! $DOMNodeList)
|
||
|
return $array;
|
||
|
foreach($DOMNodeList as $node)
|
||
|
$array[] = $node;
|
||
|
return $array;
|
||
|
}
|
||
|
/**
|
||
|
* Checks if $input is HTML string, which has to start with '<'.
|
||
|
*
|
||
|
* @deprecated
|
||
|
* @param String $input
|
||
|
* @return Bool
|
||
|
* @todo still used ?
|
||
|
*/
|
||
|
public static function isMarkup($input) {
|
||
|
return ! is_array($input) && substr(trim($input), 0, 1) == '<';
|
||
|
}
|
||
|
public static function debug($text) {
|
||
|
if (self::$debug)
|
||
|
print var_dump($text);
|
||
|
}
|
||
|
/**
|
||
|
* Make an AJAX request.
|
||
|
*
|
||
|
* @param array See $options http://docs.jquery.com/Ajax/jQuery.ajax#toptions
|
||
|
* Additional options are:
|
||
|
* 'document' - document for global events, @see phpQuery::getDocumentID()
|
||
|
* 'referer' - implemented
|
||
|
* 'requested_with' - TODO; not implemented (X-Requested-With)
|
||
|
* @return Zend_Http_Client
|
||
|
* @link http://docs.jquery.com/Ajax/jQuery.ajax
|
||
|
*
|
||
|
* @TODO $options['cache']
|
||
|
* @TODO $options['processData']
|
||
|
* @TODO $options['xhr']
|
||
|
* @TODO $options['data'] as string
|
||
|
* @TODO XHR interface
|
||
|
*/
|
||
|
public static function ajax($options = array(), $xhr = null) {
|
||
|
$options = array_merge(
|
||
|
self::$ajaxSettings, $options
|
||
|
);
|
||
|
$documentID = isset($options['document'])
|
||
|
? self::getDocumentID($options['document'])
|
||
|
: null;
|
||
|
if ($xhr) {
|
||
|
// reuse existing XHR object, but clean it up
|
||
|
$client = $xhr;
|
||
|
// $client->setParameterPost(null);
|
||
|
// $client->setParameterGet(null);
|
||
|
$client->setAuth(false);
|
||
|
$client->setHeaders("If-Modified-Since", null);
|
||
|
$client->setHeaders("Referer", null);
|
||
|
$client->resetParameters();
|
||
|
} else {
|
||
|
// create new XHR object
|
||
|
require_once('Zend/Http/Client.php');
|
||
|
$client = new Zend_Http_Client();
|
||
|
$client->setCookieJar();
|
||
|
}
|
||
|
if (isset($options['timeout']))
|
||
|
$client->setConfig(array(
|
||
|
'timeout' => $options['timeout'],
|
||
|
));
|
||
|
// 'maxredirects' => 0,
|
||
|
foreach(self::$ajaxAllowedHosts as $k => $host)
|
||
|
if ($host == '.' && isset($_SERVER['HTTP_HOST']))
|
||
|
self::$ajaxAllowedHosts[$k] = $_SERVER['HTTP_HOST'];
|
||
|
$host = parse_url($options['url'], PHP_URL_HOST);
|
||
|
if (! in_array($host, self::$ajaxAllowedHosts)) {
|
||
|
throw new Exception("Request not permitted, host '$host' not present in "
|
||
|
."phpQuery::\$ajaxAllowedHosts");
|
||
|
}
|
||
|
// JSONP
|
||
|
$jsre = "/=\\?(&|$)/";
|
||
|
if (isset($options['dataType']) && $options['dataType'] == 'jsonp') {
|
||
|
$jsonpCallbackParam = $options['jsonp']
|
||
|
? $options['jsonp'] : 'callback';
|
||
|
if (strtolower($options['type']) == 'get') {
|
||
|
if (! preg_match($jsre, $options['url'])) {
|
||
|
$sep = strpos($options['url'], '?')
|
||
|
? '&' : '?';
|
||
|
$options['url'] .= "$sep$jsonpCallbackParam=?";
|
||
|
}
|
||
|
} else if ($options['data']) {
|
||
|
$jsonp = false;
|
||
|
foreach($options['data'] as $n => $v) {
|
||
|
if ($v == '?')
|
||
|
$jsonp = true;
|
||
|
}
|
||
|
if (! $jsonp) {
|
||
|
$options['data'][$jsonpCallbackParam] = '?';
|
||
|
}
|
||
|
}
|
||
|
$options['dataType'] = 'json';
|
||
|
}
|
||
|
if (isset($options['dataType']) && $options['dataType'] == 'json') {
|
||
|
$jsonpCallback = 'json_'.md5(microtime());
|
||
|
$jsonpData = $jsonpUrl = false;
|
||
|
if ($options['data']) {
|
||
|
foreach($options['data'] as $n => $v) {
|
||
|
if ($v == '?')
|
||
|
$jsonpData = $n;
|
||
|
}
|
||
|
}
|
||
|
if (preg_match($jsre, $options['url']))
|
||
|
$jsonpUrl = true;
|
||
|
if ($jsonpData !== false || $jsonpUrl) {
|
||
|
// remember callback name for httpData()
|
||
|
$options['_jsonp'] = $jsonpCallback;
|
||
|
if ($jsonpData !== false)
|
||
|
$options['data'][$jsonpData] = $jsonpCallback;
|
||
|
if ($jsonpUrl)
|
||
|
$options['url'] = preg_replace($jsre, "=$jsonpCallback\\1", $options['url']);
|
||
|
}
|
||
|
}
|
||
|
$client->setUri($options['url']);
|
||
|
$client->setMethod(strtoupper($options['type']));
|
||
|
if (isset($options['referer']) && $options['referer'])
|
||
|
$client->setHeaders('Referer', $options['referer']);
|
||
|
$client->setHeaders(array(
|
||
|
// 'content-type' => $options['contentType'],
|
||
|
'User-Agent' => 'Mozilla/5.0 (X11; U; Linux x86; en-US; rv:1.9.0.5) Gecko'
|
||
|
.'/2008122010 Firefox/3.0.5',
|
||
|
// TODO custom charset
|
||
|
'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
|
||
|
// 'Connection' => 'keep-alive',
|
||
|
// 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||
|
'Accept-Language' => 'en-us,en;q=0.5',
|
||
|
));
|
||
|
if ($options['username'])
|
||
|
$client->setAuth($options['username'], $options['password']);
|
||
|
if (isset($options['ifModified']) && $options['ifModified'])
|
||
|
$client->setHeaders("If-Modified-Since",
|
||
|
self::$lastModified
|
||
|
? self::$lastModified
|
||
|
: "Thu, 01 Jan 1970 00:00:00 GMT"
|
||
|
);
|
||
|
$client->setHeaders("Accept",
|
||
|
isset($options['dataType'])
|
||
|
&& isset(self::$ajaxSettings['accepts'][ $options['dataType'] ])
|
||
|
? self::$ajaxSettings['accepts'][ $options['dataType'] ].", */*"
|
||
|
: self::$ajaxSettings['accepts']['_default']
|
||
|
);
|
||
|
// TODO $options['processData']
|
||
|
if ($options['data'] instanceof phpQueryObject) {
|
||
|
$serialized = $options['data']->serializeArray($options['data']);
|
||
|
$options['data'] = array();
|
||
|
foreach($serialized as $r)
|
||
|
$options['data'][ $r['name'] ] = $r['value'];
|
||
|
}
|
||
|
if (strtolower($options['type']) == 'get') {
|
||
|
$client->setParameterGet($options['data']);
|
||
|
} else if (strtolower($options['type']) == 'post') {
|
||
|
$client->setEncType($options['contentType']);
|
||
|
$client->setParameterPost($options['data']);
|
||
|
}
|
||
|
if (self::$active == 0 && $options['global'])
|
||
|
phpQueryEvents::trigger($documentID, 'ajaxStart');
|
||
|
self::$active++;
|
||
|
// beforeSend callback
|
||
|
if (isset($options['beforeSend']) && $options['beforeSend'])
|
||
|
phpQuery::callbackRun($options['beforeSend'], array($client));
|
||
|
// ajaxSend event
|
||
|
if ($options['global'])
|
||
|
phpQueryEvents::trigger($documentID, 'ajaxSend', array($client, $options));
|
||
|
if (phpQuery::$debug) {
|
||
|
self::debug("{$options['type']}: {$options['url']}\n");
|
||
|
self::debug("Options: <pre>".var_export($options, true)."</pre>\n");
|
||
|
// if ($client->getCookieJar())
|
||
|
// self::debug("Cookies: <pre>".var_export($client->getCookieJar()->getMatchingCookies($options['url']), true)."</pre>\n");
|
||
|
}
|
||
|
// request
|
||
|
$response = $client->request();
|
||
|
if (phpQuery::$debug) {
|
||
|
self::debug('Status: '.$response->getStatus().' / '.$response->getMessage());
|
||
|
self::debug($client->getLastRequest());
|
||
|
self::debug($response->getHeaders());
|
||
|
}
|
||
|
if ($response->isSuccessful()) {
|
||
|
// XXX tempolary
|
||
|
self::$lastModified = $response->getHeader('Last-Modified');
|
||
|
$data = self::httpData($response->getBody(), $options['dataType'], $options);
|
||
|
if (isset($options['success']) && $options['success'])
|
||
|
phpQuery::callbackRun($options['success'], array($data, $response->getStatus(), $options));
|
||
|
if ($options['global'])
|
||
|
phpQueryEvents::trigger($documentID, 'ajaxSuccess', array($client, $options));
|
||
|
} else {
|
||
|
if (isset($options['error']) && $options['error'])
|
||
|
phpQuery::callbackRun($options['error'], array($client, $response->getStatus(), $response->getMessage()));
|
||
|
if ($options['global'])
|
||
|
phpQueryEvents::trigger($documentID, 'ajaxError', array($client, /*$response->getStatus(),*/$response->getMessage(), $options));
|
||
|
}
|
||
|
if (isset($options['complete']) && $options['complete'])
|
||
|
phpQuery::callbackRun($options['complete'], array($client, $response->getStatus()));
|
||
|
if ($options['global'])
|
||
|
phpQueryEvents::trigger($documentID, 'ajaxComplete', array($client, $options));
|
||
|
if ($options['global'] && ! --self::$active)
|
||
|
phpQueryEvents::trigger($documentID, 'ajaxStop');
|
||
|
return $client;
|
||
|
// if (is_null($domId))
|
||
|
// $domId = self::$defaultDocumentID ? self::$defaultDocumentID : false;
|
||
|
// return new phpQueryAjaxResponse($response, $domId);
|
||
|
}
|
||
|
protected static function httpData($data, $type, $options) {
|
||
|
if (isset($options['dataFilter']) && $options['dataFilter'])
|
||
|
$data = self::callbackRun($options['dataFilter'], array($data, $type));
|
||
|
if (is_string($data)) {
|
||
|
if ($type == "json") {
|
||
|
if (isset($options['_jsonp']) && $options['_jsonp']) {
|
||
|
$data = preg_replace('/^\s*\w+\((.*)\)\s*$/s', '$1', $data);
|
||
|
}
|
||
|
$data = self::parseJSON($data);
|
||
|
}
|
||
|
}
|
||
|
return $data;
|
||
|
}
|
||
|
/**
|
||
|
* Enter description here...
|
||
|
*
|
||
|
* @param array|phpQuery $data
|
||
|
*
|
||
|
*/
|
||
|
public static function param($data) {
|
||
|
return http_build_query($data, null, '&');
|
||
|
}
|
||
|
public static function get($url, $data = null, $callback = null, $type = null) {
|
||
|
if (!is_array($data)) {
|
||
|
$callback = $data;
|
||
|
$data = null;
|
||
|
}
|
||
|
// TODO some array_values on this shit
|
||
|
return phpQuery::ajax(array(
|
||
|
'type' => 'GET',
|
||
|
'url' => $url,
|
||
|
'data' => $data,
|
||
|
'success' => $callback,
|
||
|
'dataType' => $type,
|
||
|
));
|
||
|
}
|
||
|
public static function post($url, $data = null, $callback = null, $type = null) {
|
||
|
if (!is_array($data)) {
|
||
|
$callback = $data;
|
||
|
$data = null;
|
||
|
}
|
||
|
return phpQuery::ajax(array(
|
||
|
'type' => 'POST',
|
||
|
'url' => $url,
|
||
|
'data' => $data,
|
||
|
'success' => $callback,
|
||
|
'dataType' => $type,
|
||
|
));
|
||
|
}
|
||
|
public static function getJSON($url, $data = null, $callback = null) {
|
||
|
if (!is_array($data)) {
|
||
|
$callback = $data;
|
||
|
$data = null;
|
||
|
}
|
||
|
// TODO some array_values on this shit
|
||
|
return phpQuery::ajax(array(
|
||
|
'type' => 'GET',
|
||
|
'url' => $url,
|
||
|
'data' => $data,
|
||
|
'success' => $callback,
|
||
|
'dataType' => 'json',
|
||
|
));
|
||
|
}
|
||
|
public static function ajaxSetup($options) {
|
||
|
self::$ajaxSettings = array_merge(
|
||
|
self::$ajaxSettings,
|
||
|
$options
|
||
|
);
|
||
|
}
|
||
|
public static function ajaxAllowHost($host1, $host2 = null, $host3 = null) {
|
||
|
$loop = is_array($host1)
|
||
|
? $host1
|
||
|
: func_get_args();
|
||
|
foreach($loop as $host) {
|
||
|
if ($host && ! in_array($host, phpQuery::$ajaxAllowedHosts)) {
|
||
|
phpQuery::$ajaxAllowedHosts[] = $host;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public static function ajaxAllowURL($url1, $url2 = null, $url3 = null) {
|
||
|
$loop = is_array($url1)
|
||
|
? $url1
|
||
|
: func_get_args();
|
||
|
foreach($loop as $url)
|
||
|
phpQuery::ajaxAllowHost(parse_url($url, PHP_URL_HOST));
|
||
|
}
|
||
|
/**
|
||
|
* Returns JSON representation of $data.
|
||
|
*
|
||
|
* @static
|
||
|
* @param mixed $data
|
||
|
* @return string
|
||
|
*/
|
||
|
public static function toJSON($data) {
|
||
|
if (function_exists('json_encode'))
|
||
|
return json_encode($data);
|
||
|
require_once('Zend/Json/Encoder.php');
|
||
|
return Zend_Json_Encoder::encode($data);
|
||
|
}
|
||
|
/**
|
||
|
* Parses JSON into proper PHP type.
|
||
|
*
|
||
|
* @static
|
||
|
* @param string $json
|
||
|
* @return mixed
|
||
|
*/
|
||
|
public static function parseJSON($json) {
|
||
|
if (function_exists('json_decode')) {
|
||
|
$return = json_decode(trim($json), true);
|
||
|
// json_decode and UTF8 issues
|
||
|
if (isset($return))
|
||
|
return $return;
|
||
|
}
|
||
|
require_once('Zend/Json/Decoder.php');
|
||
|
return Zend_Json_Decoder::decode($json);
|
||
|
}
|
||
|
/**
|
||
|
* Returns source's document ID.
|
||
|
*
|
||
|
* @param $source DOMNode|phpQueryObject
|
||
|
* @return string
|
||
|
*/
|
||
|
public static function getDocumentID($source) {
|
||
|
if ($source instanceof DOMDOCUMENT) {
|
||
|
foreach(phpQuery::$documents as $id => $document) {
|
||
|
if ($source->isSameNode($document->document))
|
||
|
return $id;
|
||
|
}
|
||
|
} else if ($source instanceof DOMNODE) {
|
||
|
foreach(phpQuery::$documents as $id => $document) {
|
||
|
if ($source->ownerDocument->isSameNode($document->document))
|
||
|
return $id;
|
||
|
}
|
||
|
} else if ($source instanceof phpQueryObject)
|
||
|
return $source->getDocumentID();
|
||
|
else if (is_string($source) && isset(phpQuery::$documents[$source]))
|
||
|
return $source;
|
||
|
}
|
||
|
/**
|
||
|
* Get DOMDocument object related to $source.
|
||
|
* Returns null if such document doesn't exist.
|
||
|
*
|
||
|
* @param $source DOMNode|phpQueryObject|string
|
||
|
* @return string
|
||
|
*/
|
||
|
public static function getDOMDocument($source) {
|
||
|
if ($source instanceof DOMDOCUMENT)
|
||
|
return $source;
|
||
|
$source = self::getDocumentID($source);
|
||
|
return $source
|
||
|
? self::$documents[$id]['document']
|
||
|
: null;
|
||
|
}
|
||
|
|
||
|
// UTILITIES
|
||
|
// http://docs.jquery.com/Utilities
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @return unknown_type
|
||
|
* @link http://docs.jquery.com/Utilities/jQuery.makeArray
|
||
|
*/
|
||
|
public static function makeArray($obj) {
|
||
|
$array = array();
|
||
|
if (is_object($object) && $object instanceof DOMNODELIST) {
|
||
|
foreach($object as $value)
|
||
|
$array[] = $value;
|
||
|
} else if (is_object($object) && ! ($object instanceof Iterator)) {
|
||
|
foreach(get_object_vars($object) as $name => $value)
|
||
|
$array[0][$name] = $value;
|
||
|
} else {
|
||
|
foreach($object as $name => $value)
|
||
|
$array[0][$name] = $value;
|
||
|
}
|
||
|
return $array;
|
||
|
}
|
||
|
public static function inArray($value, $array) {
|
||
|
return in_array($value, $array);
|
||
|
}
|
||
|
/**
|
||
|
*
|
||
|
* @param $object
|
||
|
* @param $callback
|
||
|
* @return unknown_type
|
||
|
* @link http://docs.jquery.com/Utilities/jQuery.each
|
||
|
*/
|
||
|
public static function each($object, $callback, $param1 = null, $param2 = null, $param3 = null) {
|
||
|
$paramStructure = null;
|
||
|
if (func_num_args() > 2) {
|
||
|
$paramStructure = func_get_args();
|
||
|
$paramStructure = array_slice($paramStructure, 2);
|
||
|
}
|
||
|
if (is_object($object) && ! ($object instanceof Iterator)) {
|
||
|
foreach(get_object_vars($object) as $name => $value)
|
||
|
phpQuery::callbackRun($callback, array($name, $value), $paramStructure);
|
||
|
} else {
|
||
|
foreach($object as $name => $value)
|
||
|
phpQuery::callbackRun($callback, array($name, $value), $paramStructure);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
*
|
||
|
* @link http://docs.jquery.com/Utilities/jQuery.map
|
||
|
*/
|
||
|
public static function map($array, $callback, $param1 = null, $param2 = null, $param3 = null) {
|
||
|
$result = array();
|
||
|
$paramStructure = null;
|
||
|
if (func_num_args() > 2) {
|
||
|
$paramStructure = func_get_args();
|
||
|
$paramStructure = array_slice($paramStructure, 2);
|
||
|
}
|
||
|
foreach($array as $v) {
|
||
|
$vv = phpQuery::callbackRun($callback, array($v), $paramStructure);
|
||
|
// $callbackArgs = $args;
|
||
|
// foreach($args as $i => $arg) {
|
||
|
// $callbackArgs[$i] = $arg instanceof CallbackParam
|
||
|
// ? $v
|
||
|
// : $arg;
|
||
|
// }
|
||
|
// $vv = call_user_func_array($callback, $callbackArgs);
|
||
|
if (is_array($vv)) {
|
||
|
foreach($vv as $vvv)
|
||
|
$result[] = $vvv;
|
||
|
} else if ($vv !== null) {
|
||
|
$result[] = $vv;
|
||
|
}
|
||
|
}
|
||
|
return $result;
|
||
|
}
|
||
|
/**
|
||
|
*
|
||
|
* @param $callback Callback
|
||
|
* @param $params
|
||
|
* @param $paramStructure
|
||
|
* @return unknown_type
|
||
|
*/
|
||
|
public static function callbackRun($callback, $params = array(), $paramStructure = null) {
|
||
|
if (! $callback)
|
||
|
return;
|
||
|
if ($callback instanceof CallbackParameterToReference) {
|
||
|
// TODO support ParamStructure to select which $param push to reference
|
||
|
if (isset($params[0]))
|
||
|
$callback->callback = $params[0];
|
||
|
return true;
|
||
|
}
|
||
|
if ($callback instanceof Callback) {
|
||
|
$paramStructure = $callback->params;
|
||
|
$callback = $callback->callback;
|
||
|
}
|
||
|
if (! $paramStructure)
|
||
|
return call_user_func_array($callback, $params);
|
||
|
$p = 0;
|
||
|
foreach($paramStructure as $i => $v) {
|
||
|
$paramStructure[$i] = $v instanceof CallbackParam
|
||
|
? $params[$p++]
|
||
|
: $v;
|
||
|
}
|
||
|
return call_user_func_array($callback, $paramStructure);
|
||
|
}
|
||
|
/**
|
||
|
* Merge 2 phpQuery objects.
|
||
|
* @param array $one
|
||
|
* @param array $two
|
||
|
* @protected
|
||
|
* @todo node lists, phpQueryObject
|
||
|
*/
|
||
|
public static function merge($one, $two) {
|
||
|
$elements = $one->elements;
|
||
|
foreach($two->elements as $node) {
|
||
|
$exists = false;
|
||
|
foreach($elements as $node2) {
|
||
|
if ($node2->isSameNode($node))
|
||
|
$exists = true;
|
||
|
}
|
||
|
if (! $exists)
|
||
|
$elements[] = $node;
|
||
|
}
|
||
|
return $elements;
|
||
|
// $one = $one->newInstance();
|
||
|
// $one->elements = $elements;
|
||
|
// return $one;
|
||
|
}
|
||
|
/**
|
||
|
*
|
||
|
* @param $array
|
||
|
* @param $callback
|
||
|
* @param $invert
|
||
|
* @return unknown_type
|
||
|
* @link http://docs.jquery.com/Utilities/jQuery.grep
|
||
|
*/
|
||
|
public static function grep($array, $callback, $invert = false) {
|
||
|
$result = array();
|
||
|
foreach($array as $k => $v) {
|
||
|
$r = call_user_func_array($callback, array($v, $k));
|
||
|
if ($r === !(bool)$invert)
|
||
|
$result[] = $v;
|
||
|
}
|
||
|
return $result;
|
||
|
}
|
||
|
public static function unique($array) {
|
||
|
return array_unique($array);
|
||
|
}
|
||
|
/**
|
||
|
*
|
||
|
* @param $function
|
||
|
* @return unknown_type
|
||
|
* @TODO there are problems with non-static methods, second parameter pass it
|
||
|
* but doesnt verify is method is really callable
|
||
|
*/
|
||
|
public static function isFunction($function) {
|
||
|
return is_callable($function);
|
||
|
}
|
||
|
public static function trim($str) {
|
||
|
return trim($str);
|
||
|
}
|
||
|
/* PLUGINS NAMESPACE */
|
||
|
/**
|
||
|
*
|
||
|
* @param $url
|
||
|
* @param $callback
|
||
|
* @param $param1
|
||
|
* @param $param2
|
||
|
* @param $param3
|
||
|
* @return phpQueryObject
|
||
|
*/
|
||
|
public static function browserGet($url, $callback, $param1 = null, $param2 = null, $param3 = null) {
|
||
|
if (self::plugin('WebBrowser')) {
|
||
|
$params = func_get_args();
|
||
|
return self::callbackRun(array(self::$plugins, 'browserGet'), $params);
|
||
|
} else {
|
||
|
self::debug('WebBrowser plugin not available...');
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
*
|
||
|
* @param $url
|
||
|
* @param $data
|
||
|
* @param $callback
|
||
|
* @param $param1
|
||
|
* @param $param2
|
||
|
* @param $param3
|
||
|
* @return phpQueryObject
|
||
|
*/
|
||
|
public static function browserPost($url, $data, $callback, $param1 = null, $param2 = null, $param3 = null) {
|
||
|
if (self::plugin('WebBrowser')) {
|
||
|
$params = func_get_args();
|
||
|
return self::callbackRun(array(self::$plugins, 'browserPost'), $params);
|
||
|
} else {
|
||
|
self::debug('WebBrowser plugin not available...');
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
*
|
||
|
* @param $ajaxSettings
|
||
|
* @param $callback
|
||
|
* @param $param1
|
||
|
* @param $param2
|
||
|
* @param $param3
|
||
|
* @return phpQueryObject
|
||
|
*/
|
||
|
public static function browser($ajaxSettings, $callback, $param1 = null, $param2 = null, $param3 = null) {
|
||
|
if (self::plugin('WebBrowser')) {
|
||
|
$params = func_get_args();
|
||
|
return self::callbackRun(array(self::$plugins, 'browser'), $params);
|
||
|
} else {
|
||
|
self::debug('WebBrowser plugin not available...');
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
*
|
||
|
* @param $code
|
||
|
* @return string
|
||
|
*/
|
||
|
public static function php($code) {
|
||
|
return self::code('php', $code);
|
||
|
}
|
||
|
/**
|
||
|
*
|
||
|
* @param $type
|
||
|
* @param $code
|
||
|
* @return string
|
||
|
*/
|
||
|
public static function code($type, $code) {
|
||
|
return "<$type><!-- ".trim($code)." --></$type>";
|
||
|
}
|
||
|
|
||
|
public static function __callStatic($method, $params) {
|
||
|
return call_user_func_array(
|
||
|
array(phpQuery::$plugins, $method),
|
||
|
$params
|
||
|
);
|
||
|
}
|
||
|
protected static function dataSetupNode($node, $documentID) {
|
||
|
// search are return if alredy exists
|
||
|
foreach(phpQuery::$documents[$documentID]->dataNodes as $dataNode) {
|
||
|
if ($node->isSameNode($dataNode))
|
||
|
return $dataNode;
|
||
|
}
|
||
|
// if doesn't, add it
|
||
|
phpQuery::$documents[$documentID]->dataNodes[] = $node;
|
||
|
return $node;
|
||
|
}
|
||
|
protected static function dataRemoveNode($node, $documentID) {
|
||
|
// search are return if alredy exists
|
||
|
foreach(phpQuery::$documents[$documentID]->dataNodes as $k => $dataNode) {
|
||
|
if ($node->isSameNode($dataNode)) {
|
||
|
unset(self::$documents[$documentID]->dataNodes[$k]);
|
||
|
unset(self::$documents[$documentID]->data[ $dataNode->dataID ]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public static function data($node, $name, $data, $documentID = null) {
|
||
|
if (! $documentID)
|
||
|
// TODO check if this works
|
||
|
$documentID = self::getDocumentID($node);
|
||
|
$document = phpQuery::$documents[$documentID];
|
||
|
$node = self::dataSetupNode($node, $documentID);
|
||
|
if (! isset($node->dataID))
|
||
|
$node->dataID = ++phpQuery::$documents[$documentID]->uuid;
|
||
|
$id = $node->dataID;
|
||
|
if (! isset($document->data[$id]))
|
||
|
$document->data[$id] = array();
|
||
|
if (! is_null($data))
|
||
|
$document->data[$id][$name] = $data;
|
||
|
if ($name) {
|
||
|
if (isset($document->data[$id][$name]))
|
||
|
return $document->data[$id][$name];
|
||
|
} else
|
||
|
return $id;
|
||
|
}
|
||
|
public static function removeData($node, $name, $documentID) {
|
||
|
if (! $documentID)
|
||
|
// TODO check if this works
|
||
|
$documentID = self::getDocumentID($node);
|
||
|
$document = phpQuery::$documents[$documentID];
|
||
|
$node = self::dataSetupNode($node, $documentID);
|
||
|
$id = $node->dataID;
|
||
|
if ($name) {
|
||
|
if (isset($document->data[$id][$name]))
|
||
|
unset($document->data[$id][$name]);
|
||
|
$name = null;
|
||
|
foreach($document->data[$id] as $name)
|
||
|
break;
|
||
|
if (! $name)
|
||
|
self::removeData($node, $name, $documentID);
|
||
|
} else {
|
||
|
self::dataRemoveNode($node, $documentID);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Plugins static namespace class.
|
||
|
*
|
||
|
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
|
||
|
* @package phpQuery
|
||
|
* @todo move plugin methods here (as statics)
|
||
|
*/
|
||
|
class phpQueryPlugins {
|
||
|
public function __call($method, $args) {
|
||
|
if (isset(phpQuery::$extendStaticMethods[$method])) {
|
||
|
$return = call_user_func_array(
|
||
|
phpQuery::$extendStaticMethods[$method],
|
||
|
$args
|
||
|
);
|
||
|
} else if (isset(phpQuery::$pluginsStaticMethods[$method])) {
|
||
|
$class = phpQuery::$pluginsStaticMethods[$method];
|
||
|
$realClass = "phpQueryPlugin_$class";
|
||
|
$return = call_user_func_array(
|
||
|
array($realClass, $method),
|
||
|
$args
|
||
|
);
|
||
|
return isset($return)
|
||
|
? $return
|
||
|
: $this;
|
||
|
} else
|
||
|
throw new Exception("Method '{$method}' doesnt exist");
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Shortcut to phpQuery::pq($arg1, $context)
|
||
|
* Chainable.
|
||
|
*
|
||
|
* @see phpQuery::pq()
|
||
|
* @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
|
||
|
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
|
||
|
* @package phpQuery
|
||
|
*/
|
||
|
function pq($arg1, $context = null) {
|
||
|
$args = func_get_args();
|
||
|
return call_user_func_array(
|
||
|
array('phpQuery', 'pq'),
|
||
|
$args
|
||
|
);
|
||
|
}
|
||
|
// add plugins dir and Zend framework to include path
|
||
|
set_include_path(
|
||
|
get_include_path()
|
||
|
.PATH_SEPARATOR.dirname(__FILE__).'/phpQuery/'
|
||
|
.PATH_SEPARATOR.dirname(__FILE__).'/phpQuery/plugins/'
|
||
|
);
|
||
|
// why ? no __call nor __get for statics in php...
|
||
|
// XXX __callStatic will be available in PHP 5.3
|
||
|
phpQuery::$plugins = new phpQueryPlugins();
|
||
|
// include bootstrap file (personal library config)
|
||
|
if (file_exists(dirname(__FILE__).'/phpQuery/bootstrap.php'))
|
||
|
require_once dirname(__FILE__).'/phpQuery/bootstrap.php';
|