2016-04-16 21:07:48 +00:00
< ? 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' );
/**
* DOMEvent class .
*
* Based on
* @ link http :// developer . mozilla . org / En / DOM : event
* @ author Tobiasz Cudnik < tobiasz . cudnik / gmail . com >
* @ package phpQuery
* @ todo implement ArrayAccess ?
*/
class DOMEvent {
/**
* Returns a boolean indicating whether the event bubbles up through the DOM or not .
*
* @ var unknown_type
*/
public $bubbles = true ;
/**
* Returns a boolean indicating whether the event is cancelable .
*
* @ var unknown_type
*/
public $cancelable = true ;
/**
* Returns a reference to the currently registered target for the event .
*
* @ var unknown_type
*/
public $currentTarget ;
/**
* Returns detail about the event , depending on the type of event .
*
* @ var unknown_type
* @ link http :// developer . mozilla . org / en / DOM / event . detail
*/
public $detail ; // ???
/**
* Used to indicate which phase of the event flow is currently being evaluated .
*
* NOT IMPLEMENTED
*
* @ var unknown_type
* @ link http :// developer . mozilla . org / en / DOM / event . eventPhase
*/
public $eventPhase ; // ???
/**
* The explicit original target of the event ( Mozilla - specific ) .
*
* NOT IMPLEMENTED
*
* @ var unknown_type
*/
public $explicitOriginalTarget ; // moz only
/**
* The original target of the event , before any retargetings ( Mozilla - specific ) .
*
* NOT IMPLEMENTED
*
* @ var unknown_type
*/
public $originalTarget ; // moz only
/**
* Identifies a secondary target for the event .
*
* @ var unknown_type
*/
public $relatedTarget ;
/**
* Returns a reference to the target to which the event was originally dispatched .
*
* @ var unknown_type
*/
public $target ;
/**
* Returns the time that the event was created .
*
* @ var unknown_type
*/
public $timeStamp ;
/**
* Returns the name of the event ( case - insensitive ) .
*/
public $type ;
public $runDefault = true ;
public $data = null ;
public function __construct ( $data ) {
foreach ( $data as $k => $v ) {
$this -> $k = $v ;
}
if ( ! $this -> timeStamp )
$this -> timeStamp = time ();
}
/**
* Cancels the event ( if it is cancelable ) .
*
*/
public function preventDefault () {
$this -> runDefault = false ;
}
/**
* Stops the propagation of events further along in the DOM .
*
*/
public function stopPropagation () {
$this -> bubbles = false ;
}
}
/**
* DOMDocumentWrapper class simplifies work with DOMDocument .
*
* Know bug :
* - in XHTML fragments , < br /> changes to < br clear = " none " />
*
* @ todo check XML catalogs compatibility
* @ author Tobiasz Cudnik < tobiasz . cudnik / gmail . com >
* @ package phpQuery
*/
class DOMDocumentWrapper {
/**
* @ var DOMDocument
*/
public $document ;
public $id ;
/**
* @ todo Rewrite as method and quess if null .
* @ var unknown_type
*/
public $contentType = '' ;
public $xpath ;
public $uuid = 0 ;
public $data = array ();
public $dataNodes = array ();
public $events = array ();
public $eventsNodes = array ();
public $eventsGlobal = array ();
/**
* @ TODO iframes support http :// code . google . com / p / phpquery / issues / detail ? id = 28
* @ var unknown_type
*/
public $frames = array ();
/**
* Document root , by default equals to document itself .
* Used by documentFragments .
*
* @ var DOMNode
*/
public $root ;
public $isDocumentFragment ;
public $isXML = false ;
public $isXHTML = false ;
public $isHTML = false ;
public $charset ;
public function __construct ( $markup = null , $contentType = null , $newDocumentID = null ) {
if ( isset ( $markup ))
$this -> load ( $markup , $contentType , $newDocumentID );
$this -> id = $newDocumentID
? $newDocumentID
: md5 ( microtime ());
}
public function load ( $markup , $contentType = null , $newDocumentID = null ) {
// phpQuery::$documents[$id] = $this;
$this -> contentType = strtolower ( $contentType );
if ( $markup instanceof DOMDOCUMENT ) {
$this -> document = $markup ;
$this -> root = $this -> document ;
$this -> charset = $this -> document -> encoding ;
// TODO isDocumentFragment
} else {
$loaded = $this -> loadMarkup ( $markup );
}
if ( $loaded ) {
// $this->document->formatOutput = true;
$this -> document -> preserveWhiteSpace = true ;
$this -> xpath = new DOMXPath ( $this -> document );
$this -> afterMarkupLoad ();
return true ;
// remember last loaded document
// return phpQuery::selectDocument($id);
}
return false ;
}
protected function afterMarkupLoad () {
if ( $this -> isXHTML ) {
$this -> xpath -> registerNamespace ( " html " , " http://www.w3.org/1999/xhtml " );
}
}
protected function loadMarkup ( $markup ) {
$loaded = false ;
if ( $this -> contentType ) {
self :: debug ( " Load markup for content type { $this -> contentType } " );
// content determined by contentType
list ( $contentType , $charset ) = $this -> contentTypeToArray ( $this -> contentType );
switch ( $contentType ) {
case 'text/html' :
phpQuery :: debug ( " Loading HTML, content type ' { $this -> contentType } ' " );
$loaded = $this -> loadMarkupHTML ( $markup , $charset );
break ;
case 'text/xml' :
case 'application/xhtml+xml' :
phpQuery :: debug ( " Loading XML, content type ' { $this -> contentType } ' " );
$loaded = $this -> loadMarkupXML ( $markup , $charset );
break ;
default :
// for feeds or anything that sometimes doesn't use text/xml
if ( strpos ( 'xml' , $this -> contentType ) !== false ) {
phpQuery :: debug ( " Loading XML, content type ' { $this -> contentType } ' " );
$loaded = $this -> loadMarkupXML ( $markup , $charset );
} else
phpQuery :: debug ( " Could not determine document type from content type ' { $this -> contentType } ' " );
}
} else {
// content type autodetection
if ( $this -> isXML ( $markup )) {
phpQuery :: debug ( " Loading XML, isXML() == true " );
$loaded = $this -> loadMarkupXML ( $markup );
if ( ! $loaded && $this -> isXHTML ) {
phpQuery :: debug ( 'Loading as XML failed, trying to load as HTML, isXHTML == true' );
$loaded = $this -> loadMarkupHTML ( $markup );
}
} else {
phpQuery :: debug ( " Loading HTML, isXML() == false " );
$loaded = $this -> loadMarkupHTML ( $markup );
}
}
return $loaded ;
}
protected function loadMarkupReset () {
$this -> isXML = $this -> isXHTML = $this -> isHTML = false ;
}
protected function documentCreate ( $charset , $version = '1.0' ) {
if ( ! $version )
$version = '1.0' ;
$this -> document = new DOMDocument ( $version , $charset );
$this -> charset = $this -> document -> encoding ;
// $this->document->encoding = $charset;
$this -> document -> formatOutput = true ;
$this -> document -> preserveWhiteSpace = true ;
}
protected function loadMarkupHTML ( $markup , $requestedCharset = null ) {
if ( phpQuery :: $debug )
phpQuery :: debug ( 'Full markup load (HTML): ' . substr ( $markup , 0 , 250 ));
$this -> loadMarkupReset ();
$this -> isHTML = true ;
if ( ! isset ( $this -> isDocumentFragment ))
$this -> isDocumentFragment = self :: isDocumentFragmentHTML ( $markup );
$charset = null ;
$documentCharset = $this -> charsetFromHTML ( $markup );
$addDocumentCharset = false ;
if ( $documentCharset ) {
$charset = $documentCharset ;
$markup = $this -> charsetFixHTML ( $markup );
} else if ( $requestedCharset ) {
$charset = $requestedCharset ;
}
if ( ! $charset )
$charset = phpQuery :: $defaultCharset ;
// HTTP 1.1 says that the default charset is ISO-8859-1
// @see http://www.w3.org/International/O-HTTP-charset
if ( ! $documentCharset ) {
$documentCharset = 'ISO-8859-1' ;
$addDocumentCharset = true ;
}
// Should be careful here, still need 'magic encoding detection' since lots of pages have other 'default encoding'
// Worse, some pages can have mixed encodings... we'll try not to worry about that
$requestedCharset = strtoupper ( $requestedCharset );
$documentCharset = strtoupper ( $documentCharset );
phpQuery :: debug ( " DOC: $documentCharset REQ: $requestedCharset " );
if ( $requestedCharset && $documentCharset && $requestedCharset !== $documentCharset ) {
phpQuery :: debug ( " CHARSET CONVERT " );
// Document Encoding Conversion
// http://code.google.com/p/phpquery/issues/detail?id=86
if ( function_exists ( 'mb_detect_encoding' )) {
$possibleCharsets = array ( $documentCharset , $requestedCharset , 'AUTO' );
$docEncoding = mb_detect_encoding ( $markup , implode ( ', ' , $possibleCharsets ));
if ( ! $docEncoding )
$docEncoding = $documentCharset ; // ok trust the document
phpQuery :: debug ( " DETECTED ' $docEncoding ' " );
// Detected does not match what document says...
if ( $docEncoding !== $documentCharset ) {
// Tricky..
}
if ( $docEncoding !== $requestedCharset ) {
phpQuery :: debug ( " CONVERT $docEncoding => $requestedCharset " );
$markup = mb_convert_encoding ( $markup , $requestedCharset , $docEncoding );
$markup = $this -> charsetAppendToHTML ( $markup , $requestedCharset );
$charset = $requestedCharset ;
}
} else {
phpQuery :: debug ( " TODO: charset conversion without mbstring... " );
}
}
$return = false ;
if ( $this -> isDocumentFragment ) {
phpQuery :: debug ( " Full markup load (HTML), DocumentFragment detected, using charset ' $charset ' " );
$return = $this -> documentFragmentLoadMarkup ( $this , $charset , $markup );
} else {
if ( $addDocumentCharset ) {
phpQuery :: debug ( " Full markup load (HTML), appending charset: ' $charset ' " );
$markup = $this -> charsetAppendToHTML ( $markup , $charset );
}
phpQuery :: debug ( " Full markup load (HTML), documentCreate(' $charset ') " );
$this -> documentCreate ( $charset );
$return = phpQuery :: $debug === 2
? $this -> document -> loadHTML ( $markup )
: @ $this -> document -> loadHTML ( $markup );
if ( $return )
$this -> root = $this -> document ;
}
if ( $return && ! $this -> contentType )
$this -> contentType = 'text/html' ;
return $return ;
}
protected function loadMarkupXML ( $markup , $requestedCharset = null ) {
if ( phpQuery :: $debug )
phpQuery :: debug ( 'Full markup load (XML): ' . substr ( $markup , 0 , 250 ));
$this -> loadMarkupReset ();
$this -> isXML = true ;
// check agains XHTML in contentType or markup
$isContentTypeXHTML = $this -> isXHTML ();
$isMarkupXHTML = $this -> isXHTML ( $markup );
if ( $isContentTypeXHTML || $isMarkupXHTML ) {
self :: debug ( 'Full markup load (XML), XHTML detected' );
$this -> isXHTML = true ;
}
// determine document fragment
if ( ! isset ( $this -> isDocumentFragment ))
$this -> isDocumentFragment = $this -> isXHTML
? self :: isDocumentFragmentXHTML ( $markup )
: self :: isDocumentFragmentXML ( $markup );
// this charset will be used
$charset = null ;
// charset from XML declaration @var string
$documentCharset = $this -> charsetFromXML ( $markup );
if ( ! $documentCharset ) {
if ( $this -> isXHTML ) {
// this is XHTML, try to get charset from content-type meta header
$documentCharset = $this -> charsetFromHTML ( $markup );
if ( $documentCharset ) {
phpQuery :: debug ( " Full markup load (XML), appending XHTML charset ' $documentCharset ' " );
$this -> charsetAppendToXML ( $markup , $documentCharset );
$charset = $documentCharset ;
}
}
if ( ! $documentCharset ) {
// if still no document charset...
$charset = $requestedCharset ;
}
} else if ( $requestedCharset ) {
$charset = $requestedCharset ;
}
if ( ! $charset ) {
$charset = phpQuery :: $defaultCharset ;
}
if ( $requestedCharset && $documentCharset && $requestedCharset != $documentCharset ) {
// TODO place for charset conversion
// $charset = $requestedCharset;
}
$return = false ;
if ( $this -> isDocumentFragment ) {
phpQuery :: debug ( " Full markup load (XML), DocumentFragment detected, using charset ' $charset ' " );
$return = $this -> documentFragmentLoadMarkup ( $this , $charset , $markup );
} else {
// FIXME ???
if ( $isContentTypeXHTML && ! $isMarkupXHTML )
if ( ! $documentCharset ) {
phpQuery :: debug ( " Full markup load (XML), appending charset ' $charset ' " );
$markup = $this -> charsetAppendToXML ( $markup , $charset );
}
// see http://pl2.php.net/manual/en/book.dom.php#78929
// LIBXML_DTDLOAD (>= PHP 5.1)
// does XML ctalogues works with LIBXML_NONET
// $this->document->resolveExternals = true;
// TODO test LIBXML_COMPACT for performance improvement
// create document
$this -> documentCreate ( $charset );
if ( phpversion () < 5.1 ) {
$this -> document -> resolveExternals = true ;
$return = phpQuery :: $debug === 2
? $this -> document -> loadXML ( $markup )
: @ $this -> document -> loadXML ( $markup );
} else {
/** @link http://pl2.php.net/manual/en/libxml.constants.php */
$libxmlStatic = phpQuery :: $debug === 2
? LIBXML_DTDLOAD | LIBXML_DTDATTR | LIBXML_NONET
: LIBXML_DTDLOAD | LIBXML_DTDATTR | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_NOERROR ;
$return = $this -> document -> loadXML ( $markup , $libxmlStatic );
// if (! $return)
// $return = $this->document->loadHTML($markup);
}
if ( $return )
$this -> root = $this -> document ;
}
if ( $return ) {
if ( ! $this -> contentType ) {
if ( $this -> isXHTML )
$this -> contentType = 'application/xhtml+xml' ;
else
$this -> contentType = 'text/xml' ;
}
return $return ;
} else {
throw new Exception ( " Error loading XML markup " );
}
}
protected function isXHTML ( $markup = null ) {
if ( ! isset ( $markup )) {
return strpos ( $this -> contentType , 'xhtml' ) !== false ;
}
// XXX ok ?
return strpos ( $markup , " <!DOCTYPE html " ) !== false ;
// return stripos($doctype, 'xhtml') !== false;
// $doctype = isset($dom->doctype) && is_object($dom->doctype)
// ? $dom->doctype->publicId
// : self::$defaultDoctype;
}
protected function isXML ( $markup ) {
// return strpos($markup, '<?xml') !== false && stripos($markup, 'xhtml') === false;
return strpos ( substr ( $markup , 0 , 100 ), '<' . '?xml' ) !== false ;
}
protected function contentTypeToArray ( $contentType ) {
$matches = explode ( ';' , trim ( strtolower ( $contentType )));
if ( isset ( $matches [ 1 ])) {
$matches [ 1 ] = explode ( '=' , $matches [ 1 ]);
// strip 'charset='
$matches [ 1 ] = isset ( $matches [ 1 ][ 1 ]) && trim ( $matches [ 1 ][ 1 ])
? $matches [ 1 ][ 1 ]
: $matches [ 1 ][ 0 ];
} else
$matches [ 1 ] = null ;
return $matches ;
}
/**
*
* @ param $markup
* @ return array contentType , charset
*/
protected function contentTypeFromHTML ( $markup ) {
$matches = array ();
// find meta tag
preg_match ( '@<meta[^>]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i' ,
$markup , $matches
);
if ( ! isset ( $matches [ 0 ]))
return array ( null , null );
// get attr 'content'
preg_match ( '@content\\s*=\\s*(["|\'])(.+?)\\1@' , $matches [ 0 ], $matches );
if ( ! isset ( $matches [ 0 ]))
return array ( null , null );
return $this -> contentTypeToArray ( $matches [ 2 ]);
}
protected function charsetFromHTML ( $markup ) {
$contentType = $this -> contentTypeFromHTML ( $markup );
return $contentType [ 1 ];
}
protected function charsetFromXML ( $markup ) {
$matches ;
// find declaration
preg_match ( '@<' . '?xml[^>]+encoding\\s*=\\s*(["|\'])(.*?)\\1@i' ,
$markup , $matches
);
return isset ( $matches [ 2 ])
? strtolower ( $matches [ 2 ])
: null ;
}
/**
* Repositions meta [ type = charset ] at the start of head . Bypasses DOMDocument bug .
*
* @ link http :// code . google . com / p / phpquery / issues / detail ? id = 80
* @ param $html
*/
protected function charsetFixHTML ( $markup ) {
$matches = array ();
// find meta tag
preg_match ( '@\s*<meta[^>]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i' ,
$markup , $matches , PREG_OFFSET_CAPTURE
);
if ( ! isset ( $matches [ 0 ]))
return ;
$metaContentType = $matches [ 0 ][ 0 ];
$markup = substr ( $markup , 0 , $matches [ 0 ][ 1 ])
. substr ( $markup , $matches [ 0 ][ 1 ] + strlen ( $metaContentType ));
$headStart = stripos ( $markup , '<head>' );
$markup = substr ( $markup , 0 , $headStart + 6 ) . $metaContentType
. substr ( $markup , $headStart + 6 );
return $markup ;
}
protected function charsetAppendToHTML ( $html , $charset , $xhtml = false ) {
// remove existing meta[type=content-type]
$html = preg_replace ( '@\s*<meta[^>]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i' , '' , $html );
$meta = '<meta http-equiv="Content-Type" content="text/html;charset='
. $charset . '" '
. ( $xhtml ? '/' : '' )
. '>' ;
if ( strpos ( $html , '<head' ) === false ) {
2017-09-19 17:23:37 +00:00
if ( strpos ( $html , '<html' ) === false ) {
2016-04-16 21:07:48 +00:00
return $meta . $html ;
} else {
return preg_replace (
'@<html(.*?)(?(?<!\?)>)@s' ,
" <html \\ 1><head> { $meta } </head> " ,
$html
);
}
} else {
return preg_replace (
'@<head(.*?)(?(?<!\?)>)@s' ,
'<head\\1>' . $meta ,
$html
);
}
}
protected function charsetAppendToXML ( $markup , $charset ) {
$declaration = '<' . '?xml version="1.0" encoding="' . $charset . '"?' . '>' ;
return $declaration . $markup ;
}
public static function isDocumentFragmentHTML ( $markup ) {
return stripos ( $markup , '<html' ) === false && stripos ( $markup , '<!doctype' ) === false ;
}
public static function isDocumentFragmentXML ( $markup ) {
return stripos ( $markup , '<' . '?xml' ) === false ;
}
public static function isDocumentFragmentXHTML ( $markup ) {
return self :: isDocumentFragmentHTML ( $markup );
}
public function importAttr ( $value ) {
// TODO
}
/**
*
* @ param $source
* @ param $target
* @ param $sourceCharset
* @ return array Array of imported nodes .
*/
public function import ( $source , $sourceCharset = null ) {
// TODO charset conversions
$return = array ();
if ( $source instanceof DOMNODE && ! ( $source instanceof DOMNODELIST ))
$source = array ( $source );
// if (is_array($source)) {
// foreach($source as $node) {
// if (is_string($node)) {
// // string markup
// $fake = $this->documentFragmentCreate($node, $sourceCharset);
// if ($fake === false)
// throw new Exception("Error loading documentFragment markup");
// else
// $return = array_merge($return,
// $this->import($fake->root->childNodes)
// );
// } else {
// $return[] = $this->document->importNode($node, true);
// }
// }
// return $return;
// } else {
// // string markup
// $fake = $this->documentFragmentCreate($source, $sourceCharset);
// if ($fake === false)
// throw new Exception("Error loading documentFragment markup");
// else
// return $this->import($fake->root->childNodes);
// }
if ( is_array ( $source ) || $source instanceof DOMNODELIST ) {
// dom nodes
self :: debug ( 'Importing nodes to document' );
foreach ( $source as $node )
$return [] = $this -> document -> importNode ( $node , true );
} else {
// string markup
$fake = $this -> documentFragmentCreate ( $source , $sourceCharset );
if ( $fake === false )
throw new Exception ( " Error loading documentFragment markup " );
else
return $this -> import ( $fake -> root -> childNodes );
}
return $return ;
}
/**
* Creates new document fragment .
*
* @ param $source
* @ return DOMDocumentWrapper
*/
protected function documentFragmentCreate ( $source , $charset = null ) {
$fake = new DOMDocumentWrapper ();
$fake -> contentType = $this -> contentType ;
$fake -> isXML = $this -> isXML ;
$fake -> isHTML = $this -> isHTML ;
$fake -> isXHTML = $this -> isXHTML ;
$fake -> root = $fake -> document ;
if ( ! $charset )
$charset = $this -> charset ;
// $fake->documentCreate($this->charset);
if ( $source instanceof DOMNODE && ! ( $source instanceof DOMNODELIST ))
$source = array ( $source );
if ( is_array ( $source ) || $source instanceof DOMNODELIST ) {
// dom nodes
// load fake document
if ( ! $this -> documentFragmentLoadMarkup ( $fake , $charset ))
return false ;
$nodes = $fake -> import ( $source );
foreach ( $nodes as $node )
$fake -> root -> appendChild ( $node );
} else {
// string markup
$this -> documentFragmentLoadMarkup ( $fake , $charset , $source );
}
return $fake ;
}
/**
*
* @ param $document DOMDocumentWrapper
* @ param $markup
* @ return $document
*/
private function documentFragmentLoadMarkup ( $fragment , $charset , $markup = null ) {
// TODO error handling
// TODO copy doctype
// tempolary turn off
$fragment -> isDocumentFragment = false ;
if ( $fragment -> isXML ) {
if ( $fragment -> isXHTML ) {
// add FAKE element to set default namespace
$fragment -> loadMarkupXML ( '<?xml version="1.0" encoding="' . $charset . '"?>'
. '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '
. '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
. '<fake xmlns="http://www.w3.org/1999/xhtml">' . $markup . '</fake>' );
$fragment -> root = $fragment -> document -> firstChild -> nextSibling ;
} else {
$fragment -> loadMarkupXML ( '<?xml version="1.0" encoding="' . $charset . '"?><fake>' . $markup . '</fake>' );
$fragment -> root = $fragment -> document -> firstChild ;
}
} else {
$markup2 = phpQuery :: $defaultDoctype . '<html><head><meta http-equiv="Content-Type" content="text/html;charset='
. $charset . '"></head>' ;
$noBody = strpos ( $markup , '<body' ) === false ;
if ( $noBody )
$markup2 .= '<body>' ;
$markup2 .= $markup ;
if ( $noBody )
$markup2 .= '</body>' ;
$markup2 .= '</html>' ;
$fragment -> loadMarkupHTML ( $markup2 );
// TODO resolv body tag merging issue
$fragment -> root = $noBody
? $fragment -> document -> firstChild -> nextSibling -> firstChild -> nextSibling
: $fragment -> document -> firstChild -> nextSibling -> firstChild -> nextSibling ;
}
if ( ! $fragment -> root )
return false ;
$fragment -> isDocumentFragment = true ;
return true ;
}
protected function documentFragmentToMarkup ( $fragment ) {
phpQuery :: debug ( 'documentFragmentToMarkup' );
$tmp = $fragment -> isDocumentFragment ;
$fragment -> isDocumentFragment = false ;
$markup = $fragment -> markup ();
if ( $fragment -> isXML ) {
$markup = substr ( $markup , 0 , strrpos ( $markup , '</fake>' ));
if ( $fragment -> isXHTML ) {
$markup = substr ( $markup , strpos ( $markup , '<fake' ) + 43 );
} else {
$markup = substr ( $markup , strpos ( $markup , '<fake>' ) + 6 );
}
} else {
$markup = substr ( $markup , strpos ( $markup , '<body>' ) + 6 );
$markup = substr ( $markup , 0 , strrpos ( $markup , '</body>' ));
}
$fragment -> isDocumentFragment = $tmp ;
if ( phpQuery :: $debug )
phpQuery :: debug ( 'documentFragmentToMarkup: ' . substr ( $markup , 0 , 150 ));
return $markup ;
}
/**
* Return document markup , starting with optional $nodes as root .
*
* @ param $nodes DOMNode | DOMNodeList
* @ return string
*/
public function markup ( $nodes = null , $innerMarkup = false ) {
if ( isset ( $nodes ) && count ( $nodes ) == 1 && $nodes [ 0 ] instanceof DOMDOCUMENT )
$nodes = null ;
if ( isset ( $nodes )) {
$markup = '' ;
if ( ! is_array ( $nodes ) && ! ( $nodes instanceof DOMNODELIST ) )
$nodes = array ( $nodes );
if ( $this -> isDocumentFragment && ! $innerMarkup )
foreach ( $nodes as $i => $node )
if ( $node -> isSameNode ( $this -> root )) {
// var_dump($node);
$nodes = array_slice ( $nodes , 0 , $i )
+ phpQuery :: DOMNodeListToArray ( $node -> childNodes )
+ array_slice ( $nodes , $i + 1 );
}
if ( $this -> isXML && ! $innerMarkup ) {
self :: debug ( " Getting outerXML with charset ' { $this -> charset } ' " );
// we need outerXML, so we can benefit from
// $node param support in saveXML()
foreach ( $nodes as $node )
$markup .= $this -> document -> saveXML ( $node );
} else {
$loop = array ();
if ( $innerMarkup )
foreach ( $nodes as $node ) {
if ( $node -> childNodes )
foreach ( $node -> childNodes as $child )
$loop [] = $child ;
else
$loop [] = $node ;
}
else
$loop = $nodes ;
self :: debug ( " Getting markup, moving selected nodes ( " . count ( $loop ) . " ) to new DocumentFragment " );
$fake = $this -> documentFragmentCreate ( $loop );
$markup = $this -> documentFragmentToMarkup ( $fake );
}
if ( $this -> isXHTML ) {
self :: debug ( " Fixing XHTML " );
$markup = self :: markupFixXHTML ( $markup );
}
self :: debug ( " Markup: " . substr ( $markup , 0 , 250 ));
return $markup ;
} else {
if ( $this -> isDocumentFragment ) {
// documentFragment, html only...
self :: debug ( " Getting markup, DocumentFragment detected " );
// return $this->markup(
//// $this->document->getElementsByTagName('body')->item(0)
// $this->document->root, true
// );
$markup = $this -> documentFragmentToMarkup ( $this );
// no need for markupFixXHTML, as it's done thought markup($nodes) method
return $markup ;
} else {
self :: debug ( " Getting markup ( " . ( $this -> isXML ? 'XML' : 'HTML' ) . " ), final with charset ' { $this -> charset } ' " );
$markup = $this -> isXML
? $this -> document -> saveXML ()
: $this -> document -> saveHTML ();
if ( $this -> isXHTML ) {
self :: debug ( " Fixing XHTML " );
$markup = self :: markupFixXHTML ( $markup );
}
self :: debug ( " Markup: " . substr ( $markup , 0 , 250 ));
return $markup ;
}
}
}
protected static function markupFixXHTML ( $markup ) {
$markup = self :: expandEmptyTag ( 'script' , $markup );
$markup = self :: expandEmptyTag ( 'select' , $markup );
$markup = self :: expandEmptyTag ( 'textarea' , $markup );
return $markup ;
}
public static function debug ( $text ) {
phpQuery :: debug ( $text );
}
/**
* expandEmptyTag
*
* @ param $tag
* @ param $xml
* @ return unknown_type
* @ author mjaque at ilkebenson dot com
* @ link http :// php . net / manual / en / domdocument . savehtml . php #81256
*/
public static function expandEmptyTag ( $tag , $xml ){
$indice = 0 ;
while ( $indice < strlen ( $xml )){
$pos = strpos ( $xml , " < $tag " , $indice );
if ( $pos ){
$posCierre = strpos ( $xml , " > " , $pos );
if ( $xml [ $posCierre - 1 ] == " / " ){
$xml = substr_replace ( $xml , " ></ $tag > " , $posCierre - 1 , 2 );
}
$indice = $posCierre ;
}
else break ;
}
return $xml ;
}
}
/**
* Event handling class .
*
* @ author Tobiasz Cudnik
* @ package phpQuery
* @ static
*/
abstract class phpQueryEvents {
/**
* Trigger a type of event on every matched element .
*
* @ param DOMNode | phpQueryObject | string $document
* @ param unknown_type $type
* @ param unknown_type $data
*
* @ TODO exclusive events ( with ! )
* @ TODO global events ( test )
* @ TODO support more than event in $type ( space - separated )
*/
public static function trigger ( $document , $type , $data = array (), $node = null ) {
// trigger: function(type, data, elem, donative, extra) {
$documentID = phpQuery :: getDocumentID ( $document );
$namespace = null ;
if ( strpos ( $type , '.' ) !== false )
list ( $name , $namespace ) = explode ( '.' , $type );
else
$name = $type ;
if ( ! $node ) {
if ( self :: issetGlobal ( $documentID , $type )) {
$pq = phpQuery :: getDocument ( $documentID );
// TODO check add($pq->document)
$pq -> find ( '*' ) -> add ( $pq -> document )
-> trigger ( $type , $data );
}
} else {
if ( isset ( $data [ 0 ]) && $data [ 0 ] instanceof DOMEvent ) {
$event = $data [ 0 ];
$event -> relatedTarget = $event -> target ;
$event -> target = $node ;
$data = array_slice ( $data , 1 );
} else {
$event = new DOMEvent ( array (
'type' => $type ,
'target' => $node ,
'timeStamp' => time (),
));
}
$i = 0 ;
while ( $node ) {
// TODO whois
phpQuery :: debug ( " Triggering " . ( $i ? " bubbled " : '' ) . " event ' { $type } ' on "
. " node \n " ); //.phpQueryObject::whois($node)."\n");
$event -> currentTarget = $node ;
$eventNode = self :: getNode ( $documentID , $node );
if ( isset ( $eventNode -> eventHandlers )) {
foreach ( $eventNode -> eventHandlers as $eventType => $handlers ) {
$eventNamespace = null ;
if ( strpos ( $type , '.' ) !== false )
list ( $eventName , $eventNamespace ) = explode ( '.' , $eventType );
else
$eventName = $eventType ;
if ( $name != $eventName )
continue ;
if ( $namespace && $eventNamespace && $namespace != $eventNamespace )
continue ;
foreach ( $handlers as $handler ) {
phpQuery :: debug ( " Calling event handler \n " );
$event -> data = $handler [ 'data' ]
? $handler [ 'data' ]
: null ;
$params = array_merge ( array ( $event ), $data );
$return = phpQuery :: callbackRun ( $handler [ 'callback' ], $params );
if ( $return === false ) {
$event -> bubbles = false ;
}
}
}
}
// to bubble or not to bubble...
if ( ! $event -> bubbles )
break ;
$node = $node -> parentNode ;
$i ++ ;
}
}
}
/**
* Binds a handler to one or more events ( like click ) for each matched element .
* Can also bind custom events .
*
* @ param DOMNode | phpQueryObject | string $document
* @ param unknown_type $type
* @ param unknown_type $data Optional
* @ param unknown_type $callback
*
* @ TODO support '!' ( exclusive ) events
* @ TODO support more than event in $type ( space - separated )
* @ TODO support binding to global events
*/
public static function add ( $document , $node , $type , $data , $callback = null ) {
phpQuery :: debug ( " Binding ' $type ' event " );
$documentID = phpQuery :: getDocumentID ( $document );
// if (is_null($callback) && is_callable($data)) {
// $callback = $data;
// $data = null;
// }
$eventNode = self :: getNode ( $documentID , $node );
if ( ! $eventNode )
$eventNode = self :: setNode ( $documentID , $node );
if ( ! isset ( $eventNode -> eventHandlers [ $type ]))
$eventNode -> eventHandlers [ $type ] = array ();
$eventNode -> eventHandlers [ $type ][] = array (
'callback' => $callback ,
'data' => $data ,
);
}
/**
* Enter description here ...
*
* @ param DOMNode | phpQueryObject | string $document
* @ param unknown_type $type
* @ param unknown_type $callback
*
* @ TODO namespace events
* @ TODO support more than event in $type ( space - separated )
*/
public static function remove ( $document , $node , $type = null , $callback = null ) {
$documentID = phpQuery :: getDocumentID ( $document );
$eventNode = self :: getNode ( $documentID , $node );
if ( is_object ( $eventNode ) && isset ( $eventNode -> eventHandlers [ $type ])) {
if ( $callback ) {
foreach ( $eventNode -> eventHandlers [ $type ] as $k => $handler )
if ( $handler [ 'callback' ] == $callback )
unset ( $eventNode -> eventHandlers [ $type ][ $k ]);
} else {
unset ( $eventNode -> eventHandlers [ $type ]);
}
}
}
protected static function getNode ( $documentID , $node ) {
foreach ( phpQuery :: $documents [ $documentID ] -> eventsNodes as $eventNode ) {
if ( $node -> isSameNode ( $eventNode ))
return $eventNode ;
}
}
protected static function setNode ( $documentID , $node ) {
phpQuery :: $documents [ $documentID ] -> eventsNodes [] = $node ;
return phpQuery :: $documents [ $documentID ] -> eventsNodes [
count ( phpQuery :: $documents [ $documentID ] -> eventsNodes ) - 1
];
}
protected static function issetGlobal ( $documentID , $type ) {
return isset ( phpQuery :: $documents [ $documentID ])
? in_array ( $type , phpQuery :: $documents [ $documentID ] -> eventsGlobal )
: false ;
}
}
interface ICallbackNamed {
function hasName ();
function getName ();
}
/**
* Callback class introduces currying - like pattern .
*
* Example :
* function foo ( $param1 , $param2 , $param3 ) {
* var_dump ( $param1 , $param2 , $param3 );
* }
* $fooCurried = new Callback ( 'foo' ,
* 'param1 is now statically set' ,
* new CallbackParam , new CallbackParam
* );
* phpQuery :: callbackRun ( $fooCurried ,
* array ( 'param2 value' , 'param3 value'
* );
*
* Callback class is supported in all phpQuery methods which accepts callbacks .
*
* @ link http :// code . google . com / p / phpquery / wiki / Callbacks #Param_Structures
* @ author Tobiasz Cudnik < tobiasz . cudnik / gmail . com >
*
* @ TODO ? ? ? return fake forwarding function created via create_function
* @ TODO honor paramStructure
*/
class Callback
implements ICallbackNamed {
public $callback = null ;
public $params = null ;
protected $name ;
public function __construct ( $callback , $param1 = null , $param2 = null ,
$param3 = null ) {
$params = func_get_args ();
$params = array_slice ( $params , 1 );
if ( $callback instanceof Callback ) {
// TODO implement recurention
} else {
$this -> callback = $callback ;
$this -> params = $params ;
}
}
public function getName () {
return 'Callback: ' . $this -> name ;
}
public function hasName () {
return isset ( $this -> name ) && $this -> name ;
}
public function setName ( $name ) {
$this -> name = $name ;
return $this ;
}
// TODO test me
// public function addParams() {
// $params = func_get_args();
// return new Callback($this->callback, $this->params+$params);
// }
}
/**
* Shorthand for new Callback ( create_function ( ... ), ... );
*
* @ author Tobiasz Cudnik < tobiasz . cudnik / gmail . com >
*/
class CallbackBody extends Callback {
public function __construct ( $paramList , $code , $param1 = null , $param2 = null ,
$param3 = null ) {
$params = func_get_args ();
$params = array_slice ( $params , 2 );
$this -> callback = create_function ( $paramList , $code );
$this -> params = $params ;
}
}
/**
* Callback type which on execution returns reference passed during creation .
*
* @ author Tobiasz Cudnik < tobiasz . cudnik / gmail . com >
*/
class CallbackReturnReference extends Callback
implements ICallbackNamed {
protected $reference ;
public function __construct ( & $reference , $name = null ){
$this -> reference =& $reference ;
$this -> callback = array ( $this , 'callback' );
}
public function callback () {
return $this -> reference ;
}
public function getName () {
return 'Callback: ' . $this -> name ;
}
public function hasName () {
return isset ( $this -> name ) && $this -> name ;
}
}
/**
* Callback type which on execution returns value passed during creation .
*
* @ author Tobiasz Cudnik < tobiasz . cudnik / gmail . com >
*/
class CallbackReturnValue extends Callback
implements ICallbackNamed {
protected $value ;
protected $name ;
public function __construct ( $value , $name = null ){
$this -> value =& $value ;
$this -> name = $name ;
$this -> callback = array ( $this , 'callback' );
}
public function callback () {
return $this -> value ;
}
public function __toString () {
return $this -> getName ();
}
public function getName () {
return 'Callback: ' . $this -> name ;
}
public function hasName () {
return isset ( $this -> name ) && $this -> name ;
}
}
/**
* CallbackParameterToReference can be used when we don ' t really want a callback ,
* only parameter passed to it . CallbackParameterToReference takes first
* parameter ' s value and passes it to reference .
*
* @ author Tobiasz Cudnik < tobiasz . cudnik / gmail . com >
*/
class CallbackParameterToReference extends Callback {
/**
* @ param $reference
* @ TODO implement $paramIndex ;
* param index choose which callback param will be passed to reference
*/
public function __construct ( & $reference ){
$this -> callback =& $reference ;
}
}
//class CallbackReference extends Callback {
// /**
// *
// * @param $reference
// * @param $paramIndex
// * @todo implement $paramIndex; param index choose which callback param will be passed to reference
// */
// public function __construct(&$reference, $name = null){
// $this->callback =& $reference;
// }
//}
class CallbackParam {}
/**
* Class representing phpQuery objects .
*
* @ author Tobiasz Cudnik < tobiasz . cudnik / gmail . com >
* @ package phpQuery
* @ method phpQueryObject clone () clone ()
* @ method phpQueryObject empty () empty ()
* @ method phpQueryObject next () next ( $selector = null )
* @ method phpQueryObject prev () prev ( $selector = null )
* @ property Int $length
*/
class phpQueryObject
implements Iterator , Countable , ArrayAccess {
public $documentID = null ;
/**
* DOMDocument class .
*
* @ var DOMDocument
*/
public $document = null ;
public $charset = null ;
/**
*
* @ var DOMDocumentWrapper
*/
public $documentWrapper = null ;
/**
* XPath interface .
*
* @ var DOMXPath
*/
public $xpath = null ;
/**
* Stack of selected elements .
* @ TODO refactor to -> nodes
* @ var array
*/
public $elements = array ();
/**
* @ access private
*/
protected $elementsBackup = array ();
/**
* @ access private
*/
protected $previous = null ;
/**
* @ access private
* @ TODO deprecate
*/
protected $root = array ();
/**
* Indicated if doument is just a fragment ( no < html > tag ) .
*
* Every document is realy a full document , so even documentFragments can
* be queried against < html > , but getDocument ( id ) -> htmlOuter () will return
* only contents of < body >.
*
* @ var bool
*/
public $documentFragment = true ;
/**
* Iterator interface helper
* @ access private
*/
protected $elementsInterator = array ();
/**
* Iterator interface helper
* @ access private
*/
protected $valid = false ;
/**
* Iterator interface helper
* @ access private
*/
protected $current = null ;
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function __construct ( $documentID ) {
// if ($documentID instanceof self)
// var_dump($documentID->getDocumentID());
$id = $documentID instanceof self
? $documentID -> getDocumentID ()
: $documentID ;
// var_dump($id);
if ( ! isset ( phpQuery :: $documents [ $id ] )) {
// var_dump(phpQuery::$documents);
throw new Exception ( " Document with ID ' { $id } ' isn't loaded. Use phpQuery::newDocument( \$ html) or phpQuery::newDocumentFile( \$ file) first. " );
}
$this -> documentID = $id ;
$this -> documentWrapper =& phpQuery :: $documents [ $id ];
$this -> document =& $this -> documentWrapper -> document ;
$this -> xpath =& $this -> documentWrapper -> xpath ;
$this -> charset =& $this -> documentWrapper -> charset ;
$this -> documentFragment =& $this -> documentWrapper -> isDocumentFragment ;
// TODO check $this->DOM->documentElement;
// $this->root = $this->document->documentElement;
$this -> root =& $this -> documentWrapper -> root ;
// $this->toRoot();
$this -> elements = array ( $this -> root );
}
/**
*
* @ access private
* @ param $attr
* @ return unknown_type
*/
public function __get ( $attr ) {
switch ( $attr ) {
// FIXME doesnt work at all ?
case 'length' :
return $this -> size ();
break ;
default :
return $this -> $attr ;
}
}
/**
* Saves actual object to $var by reference .
* Useful when need to break chain .
* @ param phpQueryObject $var
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function toReference ( & $var ) {
return $var = $this ;
}
public function documentFragment ( $state = null ) {
if ( $state ) {
phpQuery :: $documents [ $this -> getDocumentID ()][ 'documentFragment' ] = $state ;
return $this ;
}
return $this -> documentFragment ;
}
/**
* @ access private
* @ TODO documentWrapper
*/
protected function isRoot ( $node ) {
// return $node instanceof DOMDOCUMENT || $node->tagName == 'html';
return $node instanceof DOMDOCUMENT
|| ( $node instanceof DOMELEMENT && $node -> tagName == 'html' )
|| $this -> root -> isSameNode ( $node );
}
/**
* @ access private
*/
protected function stackIsRoot () {
return $this -> size () == 1 && $this -> isRoot ( $this -> elements [ 0 ]);
}
/**
* Enter description here ...
* NON JQUERY METHOD
*
* Watch out , it doesn ' t creates new instance , can be reverted with end () .
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function toRoot () {
$this -> elements = array ( $this -> root );
return $this ;
// return $this->newInstance(array($this->root));
}
/**
* Saves object ' s DocumentID to $var by reference .
* < code >
* $myDocumentId ;
* phpQuery :: newDocument ( '<div/>' )
* -> getDocumentIDRef ( $myDocumentId )
* -> find ( 'div' ) ->...
* </ code >
*
* @ param unknown_type $domId
* @ see phpQuery :: newDocument
* @ see phpQuery :: newDocumentFile
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function getDocumentIDRef ( & $documentID ) {
$documentID = $this -> getDocumentID ();
return $this ;
}
/**
* Returns object with stack set to document root .
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function getDocument () {
return phpQuery :: getDocument ( $this -> getDocumentID ());
}
/**
*
* @ return DOMDocument
*/
public function getDOMDocument () {
return $this -> document ;
}
/**
* Get object ' s Document ID .
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function getDocumentID () {
return $this -> documentID ;
}
/**
* Unloads whole document from memory .
* CAUTION ! None further operations will be possible on this document .
* All objects refering to it will be useless .
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function unloadDocument () {
phpQuery :: unloadDocuments ( $this -> getDocumentID ());
}
public function isHTML () {
return $this -> documentWrapper -> isHTML ;
}
public function isXHTML () {
return $this -> documentWrapper -> isXHTML ;
}
public function isXML () {
return $this -> documentWrapper -> isXML ;
}
/**
* Enter description here ...
*
* @ link http :// docs . jquery . com / Ajax / serialize
* @ return string
*/
public function serialize () {
return phpQuery :: param ( $this -> serializeArray ());
}
/**
* Enter description here ...
*
* @ link http :// docs . jquery . com / Ajax / serializeArray
* @ return array
*/
public function serializeArray ( $submit = null ) {
$source = $this -> filter ( 'form, input, select, textarea' )
-> find ( 'input, select, textarea' )
-> andSelf ()
-> not ( 'form' );
$return = array ();
// $source->dumpDie();
foreach ( $source as $input ) {
$input = phpQuery :: pq ( $input );
if ( $input -> is ( '[disabled]' ))
continue ;
if ( ! $input -> is ( '[name]' ))
continue ;
if ( $input -> is ( '[type=checkbox]' ) && ! $input -> is ( '[checked]' ))
continue ;
// jquery diff
if ( $submit && $input -> is ( '[type=submit]' )) {
if ( $submit instanceof DOMELEMENT && ! $input -> elements [ 0 ] -> isSameNode ( $submit ))
continue ;
else if ( is_string ( $submit ) && $input -> attr ( 'name' ) != $submit )
continue ;
}
$return [] = array (
'name' => $input -> attr ( 'name' ),
'value' => $input -> val (),
);
}
return $return ;
}
/**
* @ access private
*/
protected function debug ( $in ) {
if ( ! phpQuery :: $debug )
return ;
print ( '<pre>' );
print_r ( $in );
// file debug
// file_put_contents(dirname(__FILE__).'/phpQuery.log', print_r($in, true)."\n", FILE_APPEND);
// quite handy debug trace
// if ( is_array($in))
// print_r(array_slice(debug_backtrace(), 3));
print ( " </pre> \n " );
}
/**
* @ access private
*/
protected function isRegexp ( $pattern ) {
return in_array (
$pattern [ mb_strlen ( $pattern ) - 1 ],
array ( '^' , '*' , '$' )
);
}
/**
* Determines if $char is really a char .
*
* @ param string $char
* @ return bool
* @ todo rewrite me to charcode range ! ;)
* @ access private
*/
protected function isChar ( $char ) {
return extension_loaded ( 'mbstring' ) && phpQuery :: $mbstringSupport
? mb_eregi ( '\w' , $char )
: preg_match ( '@\w@' , $char );
}
/**
* @ access private
*/
protected function parseSelector ( $query ) {
// clean spaces
// TODO include this inside parsing ?
$query = trim (
preg_replace ( '@\s+@' , ' ' ,
preg_replace ( '@\s*(>|\\+|~)\s*@' , '\\1' , $query )
)
);
$queries = array ( array ());
if ( ! $query )
return $queries ;
$return =& $queries [ 0 ];
$specialChars = array ( '>' , ' ' );
// $specialCharsMapping = array('/' => '>');
$specialCharsMapping = array ();
$strlen = mb_strlen ( $query );
$classChars = array ( '.' , '-' );
$pseudoChars = array ( '-' );
$tagChars = array ( '*' , '|' , '-' );
// split multibyte string
// http://code.google.com/p/phpquery/issues/detail?id=76
$_query = array ();
for ( $i = 0 ; $i < $strlen ; $i ++ )
$_query [] = mb_substr ( $query , $i , 1 );
$query = $_query ;
// it works, but i dont like it...
$i = 0 ;
while ( $i < $strlen ) {
$c = $query [ $i ];
$tmp = '' ;
// TAG
if ( $this -> isChar ( $c ) || in_array ( $c , $tagChars )) {
while ( isset ( $query [ $i ])
&& ( $this -> isChar ( $query [ $i ]) || in_array ( $query [ $i ], $tagChars ))) {
$tmp .= $query [ $i ];
$i ++ ;
}
$return [] = $tmp ;
// IDs
} else if ( $c == '#' ) {
$i ++ ;
while ( isset ( $query [ $i ]) && ( $this -> isChar ( $query [ $i ]) || $query [ $i ] == '-' )) {
$tmp .= $query [ $i ];
$i ++ ;
}
$return [] = '#' . $tmp ;
// SPECIAL CHARS
} else if ( in_array ( $c , $specialChars )) {
$return [] = $c ;
$i ++ ;
// MAPPED SPECIAL MULTICHARS
// } else if ( $c.$query[$i+1] == '//') {
// $return[] = ' ';
// $i = $i+2;
// MAPPED SPECIAL CHARS
} else if ( isset ( $specialCharsMapping [ $c ])) {
$return [] = $specialCharsMapping [ $c ];
$i ++ ;
// COMMA
} else if ( $c == ',' ) {
$queries [] = array ();
$return =& $queries [ count ( $queries ) - 1 ];
$i ++ ;
while ( isset ( $query [ $i ]) && $query [ $i ] == ' ' )
$i ++ ;
// CLASSES
} else if ( $c == '.' ) {
while ( isset ( $query [ $i ]) && ( $this -> isChar ( $query [ $i ]) || in_array ( $query [ $i ], $classChars ))) {
$tmp .= $query [ $i ];
$i ++ ;
}
$return [] = $tmp ;
// ~ General Sibling Selector
} else if ( $c == '~' ) {
$spaceAllowed = true ;
$tmp .= $query [ $i ++ ];
while ( isset ( $query [ $i ])
&& ( $this -> isChar ( $query [ $i ])
|| in_array ( $query [ $i ], $classChars )
|| $query [ $i ] == '*'
|| ( $query [ $i ] == ' ' && $spaceAllowed )
)) {
if ( $query [ $i ] != ' ' )
$spaceAllowed = false ;
$tmp .= $query [ $i ];
$i ++ ;
}
$return [] = $tmp ;
// + Adjacent sibling selectors
} else if ( $c == '+' ) {
$spaceAllowed = true ;
$tmp .= $query [ $i ++ ];
while ( isset ( $query [ $i ])
&& ( $this -> isChar ( $query [ $i ])
|| in_array ( $query [ $i ], $classChars )
|| $query [ $i ] == '*'
|| ( $spaceAllowed && $query [ $i ] == ' ' )
)) {
if ( $query [ $i ] != ' ' )
$spaceAllowed = false ;
$tmp .= $query [ $i ];
$i ++ ;
}
$return [] = $tmp ;
// ATTRS
} else if ( $c == '[' ) {
$stack = 1 ;
$tmp .= $c ;
while ( isset ( $query [ ++ $i ])) {
$tmp .= $query [ $i ];
if ( $query [ $i ] == '[' ) {
$stack ++ ;
} else if ( $query [ $i ] == ']' ) {
$stack -- ;
if ( ! $stack )
break ;
}
}
$return [] = $tmp ;
$i ++ ;
// PSEUDO CLASSES
} else if ( $c == ':' ) {
$stack = 1 ;
$tmp .= $query [ $i ++ ];
while ( isset ( $query [ $i ]) && ( $this -> isChar ( $query [ $i ]) || in_array ( $query [ $i ], $pseudoChars ))) {
$tmp .= $query [ $i ];
$i ++ ;
}
// with arguments ?
if ( isset ( $query [ $i ]) && $query [ $i ] == '(' ) {
$tmp .= $query [ $i ];
$stack = 1 ;
while ( isset ( $query [ ++ $i ])) {
$tmp .= $query [ $i ];
if ( $query [ $i ] == '(' ) {
$stack ++ ;
} else if ( $query [ $i ] == ')' ) {
$stack -- ;
if ( ! $stack )
break ;
}
}
$return [] = $tmp ;
$i ++ ;
} else {
$return [] = $tmp ;
}
} else {
$i ++ ;
}
}
foreach ( $queries as $k => $q ) {
if ( isset ( $q [ 0 ])) {
if ( isset ( $q [ 0 ][ 0 ]) && $q [ 0 ][ 0 ] == ':' )
array_unshift ( $queries [ $k ], '*' );
if ( $q [ 0 ] != '>' )
array_unshift ( $queries [ $k ], ' ' );
}
}
return $queries ;
}
/**
* Return matched DOM nodes .
*
* @ param int $index
* @ return array | DOMElement Single DOMElement or array of DOMElement .
*/
public function get ( $index = null , $callback1 = null , $callback2 = null , $callback3 = null ) {
$return = isset ( $index )
? ( isset ( $this -> elements [ $index ]) ? $this -> elements [ $index ] : null )
: $this -> elements ;
// pass thou callbacks
$args = func_get_args ();
$args = array_slice ( $args , 1 );
foreach ( $args as $callback ) {
if ( is_array ( $return ))
foreach ( $return as $k => $v )
$return [ $k ] = phpQuery :: callbackRun ( $callback , array ( $v ));
else
$return = phpQuery :: callbackRun ( $callback , array ( $return ));
}
return $return ;
}
/**
* Return matched DOM nodes .
* jQuery difference .
*
* @ param int $index
* @ return array | string Returns string if $index != null
* @ todo implement callbacks
* @ todo return only arrays ?
* @ todo maybe other name ...
*/
public function getString ( $index = null , $callback1 = null , $callback2 = null , $callback3 = null ) {
if ( $index )
$return = $this -> eq ( $index ) -> text ();
else {
$return = array ();
for ( $i = 0 ; $i < $this -> size (); $i ++ ) {
$return [] = $this -> eq ( $i ) -> text ();
}
}
// pass thou callbacks
$args = func_get_args ();
$args = array_slice ( $args , 1 );
foreach ( $args as $callback ) {
$return = phpQuery :: callbackRun ( $callback , array ( $return ));
}
return $return ;
}
/**
* Return matched DOM nodes .
* jQuery difference .
*
* @ param int $index
* @ return array | string Returns string if $index != null
* @ todo implement callbacks
* @ todo return only arrays ?
* @ todo maybe other name ...
*/
public function getStrings ( $index = null , $callback1 = null , $callback2 = null , $callback3 = null ) {
if ( $index )
$return = $this -> eq ( $index ) -> text ();
else {
$return = array ();
for ( $i = 0 ; $i < $this -> size (); $i ++ ) {
$return [] = $this -> eq ( $i ) -> text ();
}
// pass thou callbacks
$args = func_get_args ();
$args = array_slice ( $args , 1 );
}
foreach ( $args as $callback ) {
if ( is_array ( $return ))
foreach ( $return as $k => $v )
$return [ $k ] = phpQuery :: callbackRun ( $callback , array ( $v ));
else
$return = phpQuery :: callbackRun ( $callback , array ( $return ));
}
return $return ;
}
/**
* Returns new instance of actual class .
*
* @ param array $newStack Optional . Will replace old stack with new and move old one to history . c
*/
public function newInstance ( $newStack = null ) {
$class = get_class ( $this );
// support inheritance by passing old object to overloaded constructor
$new = $class != 'phpQuery'
? new $class ( $this , $this -> getDocumentID ())
: new phpQueryObject ( $this -> getDocumentID ());
$new -> previous = $this ;
if ( is_null ( $newStack )) {
$new -> elements = $this -> elements ;
if ( $this -> elementsBackup )
$this -> elements = $this -> elementsBackup ;
} else if ( is_string ( $newStack )) {
$new -> elements = phpQuery :: pq ( $newStack , $this -> getDocumentID ()) -> stack ();
} else {
$new -> elements = $newStack ;
}
return $new ;
}
/**
* Enter description here ...
*
* In the future , when PHP will support XLS 2.0 , then we would do that this way :
* contains ( tokenize ( @ class , '\s' ), " something " )
* @ param unknown_type $class
* @ param unknown_type $node
* @ return boolean
* @ access private
*/
protected function matchClasses ( $class , $node ) {
// multi-class
if ( mb_strpos ( $class , '.' , 1 )) {
$classes = explode ( '.' , substr ( $class , 1 ));
$classesCount = count ( $classes );
$nodeClasses = explode ( ' ' , $node -> getAttribute ( 'class' ) );
$nodeClassesCount = count ( $nodeClasses );
if ( $classesCount > $nodeClassesCount )
return false ;
$diff = count (
array_diff (
$classes ,
$nodeClasses
)
);
if ( ! $diff )
return true ;
// single-class
} else {
return in_array (
// strip leading dot from class name
substr ( $class , 1 ),
// get classes for element as array
explode ( ' ' , $node -> getAttribute ( 'class' ) )
);
}
}
/**
* @ access private
*/
protected function runQuery ( $XQuery , $selector = null , $compare = null ) {
if ( $compare && ! method_exists ( $this , $compare ))
return false ;
$stack = array ();
if ( ! $this -> elements )
$this -> debug ( 'Stack empty, skipping...' );
// var_dump($this->elements[0]->nodeType);
// element, document
foreach ( $this -> stack ( array ( 1 , 9 , 13 )) as $k => $stackNode ) {
$detachAfter = false ;
// to work on detached nodes we need temporary place them somewhere
// thats because context xpath queries sucks ;]
$testNode = $stackNode ;
while ( $testNode ) {
if ( ! $testNode -> parentNode && ! $this -> isRoot ( $testNode )) {
$this -> root -> appendChild ( $testNode );
$detachAfter = $testNode ;
break ;
}
$testNode = isset ( $testNode -> parentNode )
? $testNode -> parentNode
: null ;
}
// XXX tmp ?
$xpath = $this -> documentWrapper -> isXHTML
? $this -> getNodeXpath ( $stackNode , 'html' )
: $this -> getNodeXpath ( $stackNode );
// FIXME pseudoclasses-only query, support XML
$query = $XQuery == '//' && $xpath == '/html[1]'
? '//*'
: $xpath . $XQuery ;
$this -> debug ( " XPATH: { $query } " );
// run query, get elements
$nodes = $this -> xpath -> query ( $query );
$this -> debug ( " QUERY FETCHED " );
if ( ! $nodes -> length )
$this -> debug ( 'Nothing found' );
$debug = array ();
foreach ( $nodes as $node ) {
$matched = false ;
if ( $compare ) {
phpQuery :: $debug ?
$this -> debug ( " Found: " . $this -> whois ( $node ) . " , comparing with { $compare } () " )
: null ;
$phpQueryDebug = phpQuery :: $debug ;
phpQuery :: $debug = false ;
// TODO ??? use phpQuery::callbackRun()
if ( call_user_func_array ( array ( $this , $compare ), array ( $selector , $node )))
$matched = true ;
phpQuery :: $debug = $phpQueryDebug ;
} else {
$matched = true ;
}
if ( $matched ) {
if ( phpQuery :: $debug )
$debug [] = $this -> whois ( $node );
$stack [] = $node ;
}
}
if ( phpQuery :: $debug ) {
$this -> debug ( " Matched " . count ( $debug ) . " : " . implode ( ', ' , $debug ));
}
if ( $detachAfter )
$this -> root -> removeChild ( $detachAfter );
}
$this -> elements = $stack ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function find ( $selectors , $context = null , $noHistory = false ) {
if ( ! $noHistory )
// backup last stack /for end()/
$this -> elementsBackup = $this -> elements ;
// allow to define context
// TODO combine code below with phpQuery::pq() context guessing code
// as generic function
if ( $context ) {
if ( ! is_array ( $context ) && $context instanceof DOMELEMENT )
$this -> elements = array ( $context );
else if ( is_array ( $context )) {
$this -> elements = array ();
foreach ( $context as $c )
if ( $c instanceof DOMELEMENT )
$this -> elements [] = $c ;
} else if ( $context instanceof self )
$this -> elements = $context -> elements ;
}
$queries = $this -> parseSelector ( $selectors );
$this -> debug ( array ( 'FIND' , $selectors , $queries ));
$XQuery = '' ;
// remember stack state because of multi-queries
$oldStack = $this -> elements ;
// here we will be keeping found elements
$stack = array ();
foreach ( $queries as $selector ) {
$this -> elements = $oldStack ;
$delimiterBefore = false ;
foreach ( $selector as $s ) {
// TAG
$isTag = extension_loaded ( 'mbstring' ) && phpQuery :: $mbstringSupport
? mb_ereg_match ( '^[\w|\||-]+$' , $s ) || $s == '*'
: preg_match ( '@^[\w|\||-]+$@' , $s ) || $s == '*' ;
if ( $isTag ) {
if ( $this -> isXML ()) {
// namespace support
if ( mb_strpos ( $s , '|' ) !== false ) {
$ns = $tag = null ;
list ( $ns , $tag ) = explode ( '|' , $s );
$XQuery .= " $ns : $tag " ;
} else if ( $s == '*' ) {
$XQuery .= " * " ;
} else {
$XQuery .= " *[local-name()=' $s '] " ;
}
} else {
$XQuery .= $s ;
}
// ID
} else if ( $s [ 0 ] == '#' ) {
if ( $delimiterBefore )
$XQuery .= '*' ;
$XQuery .= " [@id=' " . substr ( $s , 1 ) . " '] " ;
// ATTRIBUTES
} else if ( $s [ 0 ] == '[' ) {
if ( $delimiterBefore )
$XQuery .= '*' ;
// strip side brackets
$attr = trim ( $s , '][' );
$execute = false ;
// attr with specifed value
if ( mb_strpos ( $s , '=' )) {
$value = null ;
list ( $attr , $value ) = explode ( '=' , $attr );
$value = trim ( $value , " ' \" " );
if ( $this -> isRegexp ( $attr )) {
// cut regexp character
$attr = substr ( $attr , 0 , - 1 );
$execute = true ;
$XQuery .= " [@ { $attr } ] " ;
} else {
$XQuery .= " [@ { $attr } =' { $value } '] " ;
}
// attr without specified value
} else {
$XQuery .= " [@ { $attr } ] " ;
}
if ( $execute ) {
$this -> runQuery ( $XQuery , $s , 'is' );
$XQuery = '' ;
if ( ! $this -> length ())
break ;
}
// CLASSES
} else if ( $s [ 0 ] == '.' ) {
// TODO use return $this->find("./self::*[contains(concat(\" \",@class,\" \"), \" $class \")]");
// thx wizDom ;)
if ( $delimiterBefore )
$XQuery .= '*' ;
$XQuery .= '[@class]' ;
$this -> runQuery ( $XQuery , $s , 'matchClasses' );
$XQuery = '' ;
if ( ! $this -> length () )
break ;
// ~ General Sibling Selector
} else if ( $s [ 0 ] == '~' ) {
$this -> runQuery ( $XQuery );
$XQuery = '' ;
$this -> elements = $this
-> siblings (
substr ( $s , 1 )
) -> elements ;
if ( ! $this -> length () )
break ;
// + Adjacent sibling selectors
} else if ( $s [ 0 ] == '+' ) {
// TODO /following-sibling::
$this -> runQuery ( $XQuery );
$XQuery = '' ;
$subSelector = substr ( $s , 1 );
$subElements = $this -> elements ;
$this -> elements = array ();
foreach ( $subElements as $node ) {
// search first DOMElement sibling
$test = $node -> nextSibling ;
while ( $test && ! ( $test instanceof DOMELEMENT ))
$test = $test -> nextSibling ;
if ( $test && $this -> is ( $subSelector , $test ))
$this -> elements [] = $test ;
}
if ( ! $this -> length () )
break ;
// PSEUDO CLASSES
} else if ( $s [ 0 ] == ':' ) {
// TODO optimization for :first :last
if ( $XQuery ) {
$this -> runQuery ( $XQuery );
$XQuery = '' ;
}
if ( ! $this -> length ())
break ;
$this -> pseudoClasses ( $s );
if ( ! $this -> length ())
break ;
// DIRECT DESCENDANDS
} else if ( $s == '>' ) {
$XQuery .= '/' ;
$delimiterBefore = 2 ;
// ALL DESCENDANDS
} else if ( $s == ' ' ) {
$XQuery .= '//' ;
$delimiterBefore = 2 ;
// ERRORS
} else {
phpQuery :: debug ( " Unrecognized token ' $s ' " );
}
$delimiterBefore = $delimiterBefore === 2 ;
}
// run query if any
if ( $XQuery && $XQuery != '//' ) {
$this -> runQuery ( $XQuery );
$XQuery = '' ;
}
foreach ( $this -> elements as $node )
if ( ! $this -> elementsContainsNode ( $node , $stack ))
$stack [] = $node ;
}
$this -> elements = $stack ;
return $this -> newInstance ();
}
/**
* @ todo create API for classes with pseudoselectors
* @ access private
*/
protected function pseudoClasses ( $class ) {
// TODO clean args parsing ?
$class = ltrim ( $class , ':' );
$haveArgs = mb_strpos ( $class , '(' );
if ( $haveArgs !== false ) {
$args = substr ( $class , $haveArgs + 1 , - 1 );
$class = substr ( $class , 0 , $haveArgs );
}
switch ( $class ) {
case 'even' :
case 'odd' :
$stack = array ();
foreach ( $this -> elements as $i => $node ) {
if ( $class == 'even' && ( $i % 2 ) == 0 )
$stack [] = $node ;
else if ( $class == 'odd' && $i % 2 )
$stack [] = $node ;
}
$this -> elements = $stack ;
break ;
case 'eq' :
$k = intval ( $args );
$this -> elements = isset ( $this -> elements [ $k ] )
? array ( $this -> elements [ $k ] )
: array ();
break ;
case 'gt' :
$this -> elements = array_slice ( $this -> elements , $args + 1 );
break ;
case 'lt' :
$this -> elements = array_slice ( $this -> elements , 0 , $args + 1 );
break ;
case 'first' :
if ( isset ( $this -> elements [ 0 ]))
$this -> elements = array ( $this -> elements [ 0 ]);
break ;
case 'last' :
if ( $this -> elements )
$this -> elements = array ( $this -> elements [ count ( $this -> elements ) - 1 ]);
break ;
/* case 'parent' :
$stack = array ();
foreach ( $this -> elements as $node ) {
if ( $node -> childNodes -> length )
$stack [] = $node ;
}
$this -> elements = $stack ;
break ; */
case 'contains' :
$text = trim ( $args , " \" ' " );
$stack = array ();
foreach ( $this -> elements as $node ) {
if ( mb_stripos ( $node -> textContent , $text ) === false )
continue ;
$stack [] = $node ;
}
$this -> elements = $stack ;
break ;
case 'not' :
$selector = self :: unQuote ( $args );
$this -> elements = $this -> not ( $selector ) -> stack ();
break ;
case 'slice' :
// TODO jQuery difference ?
$args = explode ( ',' ,
str_replace ( ', ' , ',' , trim ( $args , " \" ' " ))
);
$start = $args [ 0 ];
$end = isset ( $args [ 1 ])
? $args [ 1 ]
: null ;
if ( $end > 0 )
$end = $end - $start ;
$this -> elements = array_slice ( $this -> elements , $start , $end );
break ;
case 'has' :
$selector = trim ( $args , " \" ' " );
$stack = array ();
foreach ( $this -> stack ( 1 ) as $el ) {
if ( $this -> find ( $selector , $el , true ) -> length )
$stack [] = $el ;
}
$this -> elements = $stack ;
break ;
case 'submit' :
case 'reset' :
$this -> elements = phpQuery :: merge (
$this -> map ( array ( $this , 'is' ),
" input[type= $class ] " , new CallbackParam ()
),
$this -> map ( array ( $this , 'is' ),
" button[type= $class ] " , new CallbackParam ()
)
);
break ;
// $stack = array();
// foreach($this->elements as $node)
// if ($node->is('input[type=submit]') || $node->is('button[type=submit]'))
// $stack[] = $el;
// $this->elements = $stack;
case 'input' :
$this -> elements = $this -> map (
array ( $this , 'is' ),
'input' , new CallbackParam ()
) -> elements ;
break ;
case 'password' :
case 'checkbox' :
case 'radio' :
case 'hidden' :
case 'image' :
case 'file' :
$this -> elements = $this -> map (
array ( $this , 'is' ),
" input[type= $class ] " , new CallbackParam ()
) -> elements ;
break ;
case 'parent' :
$this -> elements = $this -> map (
create_function ( '$node' , '
return $node instanceof DOMELEMENT && $node -> childNodes -> length
? $node : null ; ' )
) -> elements ;
break ;
case 'empty' :
$this -> elements = $this -> map (
create_function ( '$node' , '
return $node instanceof DOMELEMENT && $node -> childNodes -> length
? null : $node ; ' )
) -> elements ;
break ;
case 'disabled' :
case 'selected' :
case 'checked' :
$this -> elements = $this -> map (
array ( $this , 'is' ),
" [ $class ] " , new CallbackParam ()
) -> elements ;
break ;
case 'enabled' :
$this -> elements = $this -> map (
create_function ( '$node' , '
return pq ( $node ) -> not ( " :disabled " ) ? $node : null ; ' )
) -> elements ;
break ;
case 'header' :
$this -> elements = $this -> map (
create_function ( '$node' ,
' $isHeader = isset ( $node -> tagName ) && in_array ( $node -> tagName , array (
" h1 " , " h2 " , " h3 " , " h4 " , " h5 " , " h6 " , " h7 "
));
return $isHeader
? $node
: null ; ' )
) -> elements ;
// $this->elements = $this->map(
// create_function('$node', '$node = pq($node);
// return $node->is("h1")
// || $node->is("h2")
// || $node->is("h3")
// || $node->is("h4")
// || $node->is("h5")
// || $node->is("h6")
// || $node->is("h7")
// ? $node
// : null;')
// )->elements;
break ;
case 'only-child' :
$this -> elements = $this -> map (
create_function ( '$node' ,
'return pq($node)->siblings()->size() == 0 ? $node : null;' )
) -> elements ;
break ;
case 'first-child' :
$this -> elements = $this -> map (
create_function ( '$node' , 'return pq($node)->prevAll()->size() == 0 ? $node : null;' )
) -> elements ;
break ;
case 'last-child' :
$this -> elements = $this -> map (
create_function ( '$node' , 'return pq($node)->nextAll()->size() == 0 ? $node : null;' )
) -> elements ;
break ;
case 'nth-child' :
$param = trim ( $args , " \" ' " );
if ( ! $param )
break ;
// nth-child(n+b) to nth-child(1n+b)
if ( $param { 0 } == 'n' )
$param = '1' . $param ;
// :nth-child(index/even/odd/equation)
if ( $param == 'even' || $param == 'odd' )
$mapped = $this -> map (
create_function ( '$node, $param' ,
' $index = pq ( $node ) -> prevAll () -> size () + 1 ;
if ( $param == " even " && ( $index % 2 ) == 0 )
return $node ;
else if ( $param == " odd " && $index % 2 == 1 )
return $node ;
else
return null ; ' ),
new CallbackParam (), $param
);
else if ( mb_strlen ( $param ) > 1 && $param { 1 } == 'n' )
// an+b
$mapped = $this -> map (
create_function ( '$node, $param' ,
' $prevs = pq ( $node ) -> prevAll () -> size ();
$index = 1 + $prevs ;
$b = mb_strlen ( $param ) > 3
? $param { 3 }
: 0 ;
$a = $param { 0 };
if ( $b && $param { 2 } == " - " )
$b = - $b ;
if ( $a > 0 ) {
return ( $index - $b ) % $a == 0
? $node
: null ;
phpQuery :: debug ( $a . " * " . floor ( $index / $a ) . " + $b -1 == " . ( $a * floor ( $index / $a ) + $b - 1 ) . " ?= $prevs " );
return $a * floor ( $index / $a ) + $b - 1 == $prevs
? $node
: null ;
} else if ( $a == 0 )
return $index == $b
? $node
: null ;
else
// negative value
return $index <= $b
? $node
: null ;
// if (! $b)
// return $index%$a == 0
// ? $node
// : null;
// else
// return ($index-$b)%$a == 0
// ? $node
// : null;
' ),
new CallbackParam (), $param
);
else
// index
$mapped = $this -> map (
create_function ( '$node, $index' ,
' $prevs = pq ( $node ) -> prevAll () -> size ();
if ( $prevs && $prevs == $index - 1 )
return $node ;
else if ( ! $prevs && $index == 1 )
return $node ;
else
return null ; ' ),
new CallbackParam (), $param
);
$this -> elements = $mapped -> elements ;
break ;
default :
$this -> debug ( " Unknown pseudoclass ' { $class } ', skipping... " );
}
}
/**
* @ access private
*/
protected function __pseudoClassParam ( $paramsString ) {
// TODO;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function is ( $selector , $nodes = null ) {
phpQuery :: debug ( array ( " Is: " , $selector ));
if ( ! $selector )
return false ;
$oldStack = $this -> elements ;
$returnArray = false ;
if ( $nodes && is_array ( $nodes )) {
$this -> elements = $nodes ;
} else if ( $nodes )
$this -> elements = array ( $nodes );
$this -> filter ( $selector , true );
$stack = $this -> elements ;
$this -> elements = $oldStack ;
if ( $nodes )
return $stack ? $stack : null ;
return ( bool ) count ( $stack );
}
/**
* Enter description here ...
* jQuery difference .
*
* Callback :
* - $index int
* - $node DOMNode
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ link http :// docs . jquery . com / Traversing / filter
*/
public function filterCallback ( $callback , $_skipHistory = false ) {
if ( ! $_skipHistory ) {
$this -> elementsBackup = $this -> elements ;
$this -> debug ( " Filtering by callback " );
}
$newStack = array ();
foreach ( $this -> elements as $index => $node ) {
$result = phpQuery :: callbackRun ( $callback , array ( $index , $node ));
if ( is_null ( $result ) || ( ! is_null ( $result ) && $result ))
$newStack [] = $node ;
}
$this -> elements = $newStack ;
return $_skipHistory
? $this
: $this -> newInstance ();
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ link http :// docs . jquery . com / Traversing / filter
*/
public function filter ( $selectors , $_skipHistory = false ) {
if ( $selectors instanceof Callback OR $selectors instanceof Closure )
return $this -> filterCallback ( $selectors , $_skipHistory );
if ( ! $_skipHistory )
$this -> elementsBackup = $this -> elements ;
$notSimpleSelector = array ( ' ' , '>' , '~' , '+' , '/' );
if ( ! is_array ( $selectors ))
$selectors = $this -> parseSelector ( $selectors );
if ( ! $_skipHistory )
$this -> debug ( array ( " Filtering: " , $selectors ));
$finalStack = array ();
foreach ( $selectors as $selector ) {
$stack = array ();
if ( ! $selector )
break ;
// avoid first space or /
if ( in_array ( $selector [ 0 ], $notSimpleSelector ))
$selector = array_slice ( $selector , 1 );
// PER NODE selector chunks
foreach ( $this -> stack () as $node ) {
$break = false ;
foreach ( $selector as $s ) {
if ( ! ( $node instanceof DOMELEMENT )) {
// all besides DOMElement
if ( $s [ 0 ] == '[' ) {
$attr = trim ( $s , '[]' );
if ( mb_strpos ( $attr , '=' )) {
list ( $attr , $val ) = explode ( '=' , $attr );
if ( $attr == 'nodeType' && $node -> nodeType != $val )
$break = true ;
}
} else
$break = true ;
} else {
// DOMElement only
// ID
if ( $s [ 0 ] == '#' ) {
if ( $node -> getAttribute ( 'id' ) != substr ( $s , 1 ) )
$break = true ;
// CLASSES
} else if ( $s [ 0 ] == '.' ) {
if ( ! $this -> matchClasses ( $s , $node ) )
$break = true ;
// ATTRS
} else if ( $s [ 0 ] == '[' ) {
// strip side brackets
$attr = trim ( $s , '[]' );
if ( mb_strpos ( $attr , '=' )) {
list ( $attr , $val ) = explode ( '=' , $attr );
$val = self :: unQuote ( $val );
if ( $attr == 'nodeType' ) {
if ( $val != $node -> nodeType )
$break = true ;
} else if ( $this -> isRegexp ( $attr )) {
$val = extension_loaded ( 'mbstring' ) && phpQuery :: $mbstringSupport
? quotemeta ( trim ( $val , '"\'' ))
: preg_quote ( trim ( $val , '"\'' ), '@' );
// switch last character
switch ( substr ( $attr , - 1 )) {
// quotemeta used insted of preg_quote
// http://code.google.com/p/phpquery/issues/detail?id=76
case '^' :
$pattern = '^' . $val ;
break ;
case '*' :
$pattern = '.*' . $val . '.*' ;
break ;
case '$' :
$pattern = '.*' . $val . '$' ;
break ;
}
// cut last character
$attr = substr ( $attr , 0 , - 1 );
$isMatch = extension_loaded ( 'mbstring' ) && phpQuery :: $mbstringSupport
? mb_ereg_match ( $pattern , $node -> getAttribute ( $attr ))
: preg_match ( " @ { $pattern } @ " , $node -> getAttribute ( $attr ));
if ( ! $isMatch )
$break = true ;
} else if ( $node -> getAttribute ( $attr ) != $val )
$break = true ;
} else if ( ! $node -> hasAttribute ( $attr ))
$break = true ;
// PSEUDO CLASSES
} else if ( $s [ 0 ] == ':' ) {
// skip
// TAG
} else if ( trim ( $s )) {
if ( $s != '*' ) {
// TODO namespaces
if ( isset ( $node -> tagName )) {
if ( $node -> tagName != $s )
$break = true ;
} else if ( $s == 'html' && ! $this -> isRoot ( $node ))
$break = true ;
}
// AVOID NON-SIMPLE SELECTORS
} else if ( in_array ( $s , $notSimpleSelector )) {
$break = true ;
$this -> debug ( array ( 'Skipping non simple selector' , $selector ));
}
}
if ( $break )
break ;
}
// if element passed all chunks of selector - add it to new stack
if ( ! $break )
$stack [] = $node ;
}
$tmpStack = $this -> elements ;
$this -> elements = $stack ;
// PER ALL NODES selector chunks
foreach ( $selector as $s )
// PSEUDO CLASSES
if ( $s [ 0 ] == ':' )
$this -> pseudoClasses ( $s );
foreach ( $this -> elements as $node )
// XXX it should be merged without duplicates
// but jQuery doesnt do that
$finalStack [] = $node ;
$this -> elements = $tmpStack ;
}
$this -> elements = $finalStack ;
if ( $_skipHistory ) {
return $this ;
} else {
$this -> debug ( " Stack length after filter(): " . count ( $finalStack ));
return $this -> newInstance ();
}
}
/**
*
* @ param $value
* @ return unknown_type
* @ TODO implement in all methods using passed parameters
*/
protected static function unQuote ( $value ) {
return $value [ 0 ] == '\'' || $value [ 0 ] == '"'
? substr ( $value , 1 , - 1 )
: $value ;
}
/**
* Enter description here ...
*
* @ link http :// docs . jquery . com / Ajax / load
* @ return phpQuery | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ todo Support $selector
*/
public function load ( $url , $data = null , $callback = null ) {
if ( $data && ! is_array ( $data )) {
$callback = $data ;
$data = null ;
}
if ( mb_strpos ( $url , ' ' ) !== false ) {
$matches = null ;
if ( extension_loaded ( 'mbstring' ) && phpQuery :: $mbstringSupport )
mb_ereg ( '^([^ ]+) (.*)$' , $url , $matches );
else
preg_match ( '^([^ ]+) (.*)$' , $url , $matches );
$url = $matches [ 1 ];
$selector = $matches [ 2 ];
// FIXME this sucks, pass as callback param
$this -> _loadSelector = $selector ;
}
$ajax = array (
'url' => $url ,
'type' => $data ? 'POST' : 'GET' ,
'data' => $data ,
'complete' => $callback ,
'success' => array ( $this , '__loadSuccess' )
);
phpQuery :: ajax ( $ajax );
return $this ;
}
/**
* @ access private
* @ param $html
* @ return unknown_type
*/
public function __loadSuccess ( $html ) {
if ( $this -> _loadSelector ) {
$html = phpQuery :: newDocument ( $html ) -> find ( $this -> _loadSelector );
unset ( $this -> _loadSelector );
}
foreach ( $this -> stack ( 1 ) as $node ) {
phpQuery :: pq ( $node , $this -> getDocumentID ())
-> markup ( $html );
}
}
/**
* Enter description here ...
*
* @ return phpQuery | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ todo
*/
public function css () {
// TODO
return $this ;
}
/**
* @ todo
*
*/
public function show (){
// TODO
return $this ;
}
/**
* @ todo
*
*/
public function hide (){
// TODO
return $this ;
}
/**
* Trigger a type of event on every matched element .
*
* @ param unknown_type $type
* @ param unknown_type $data
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ TODO support more than event in $type ( space - separated )
*/
public function trigger ( $type , $data = array ()) {
foreach ( $this -> elements as $node )
phpQueryEvents :: trigger ( $this -> getDocumentID (), $type , $data , $node );
return $this ;
}
/**
* This particular method triggers all bound event handlers on an element ( for a specific event type ) WITHOUT executing the browsers default actions .
*
* @ param unknown_type $type
* @ param unknown_type $data
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ TODO
*/
public function triggerHandler ( $type , $data = array ()) {
// TODO;
}
/**
* Binds a handler to one or more events ( like click ) for each matched element .
* Can also bind custom events .
*
* @ param unknown_type $type
* @ param unknown_type $data Optional
* @ param unknown_type $callback
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ TODO support '!' ( exclusive ) events
* @ TODO support more than event in $type ( space - separated )
*/
public function bind ( $type , $data , $callback = null ) {
// TODO check if $data is callable, not using is_callable
if ( ! isset ( $callback )) {
$callback = $data ;
$data = null ;
}
foreach ( $this -> elements as $node )
phpQueryEvents :: add ( $this -> getDocumentID (), $node , $type , $data , $callback );
return $this ;
}
/**
* Enter description here ...
*
* @ param unknown_type $type
* @ param unknown_type $callback
* @ return unknown
* @ TODO namespace events
* @ TODO support more than event in $type ( space - separated )
*/
public function unbind ( $type = null , $callback = null ) {
foreach ( $this -> elements as $node )
phpQueryEvents :: remove ( $this -> getDocumentID (), $node , $type , $callback );
return $this ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function change ( $callback = null ) {
if ( $callback )
return $this -> bind ( 'change' , $callback );
return $this -> trigger ( 'change' );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function submit ( $callback = null ) {
if ( $callback )
return $this -> bind ( 'submit' , $callback );
return $this -> trigger ( 'submit' );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function click ( $callback = null ) {
if ( $callback )
return $this -> bind ( 'click' , $callback );
return $this -> trigger ( 'click' );
}
/**
* Enter description here ...
*
* @ param String | phpQuery
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function wrapAllOld ( $wrapper ) {
$wrapper = pq ( $wrapper ) -> _clone ();
if ( ! $wrapper -> length () || ! $this -> length () )
return $this ;
$wrapper -> insertBefore ( $this -> elements [ 0 ]);
$deepest = $wrapper -> elements [ 0 ];
while ( $deepest -> firstChild && $deepest -> firstChild instanceof DOMELEMENT )
$deepest = $deepest -> firstChild ;
pq ( $deepest ) -> append ( $this );
return $this ;
}
/**
* Enter description here ...
*
* TODO testme ...
* @ param String | phpQuery
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function wrapAll ( $wrapper ) {
if ( ! $this -> length ())
return $this ;
return phpQuery :: pq ( $wrapper , $this -> getDocumentID ())
-> clone ()
-> insertBefore ( $this -> get ( 0 ))
-> map ( array ( $this , '___wrapAllCallback' ))
-> append ( $this );
}
/**
*
* @ param $node
* @ return unknown_type
* @ access private
*/
public function ___wrapAllCallback ( $node ) {
$deepest = $node ;
while ( $deepest -> firstChild && $deepest -> firstChild instanceof DOMELEMENT )
$deepest = $deepest -> firstChild ;
return $deepest ;
}
/**
* Enter description here ...
* NON JQUERY METHOD
*
* @ param String | phpQuery
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function wrapAllPHP ( $codeBefore , $codeAfter ) {
return $this
-> slice ( 0 , 1 )
-> beforePHP ( $codeBefore )
-> end ()
-> slice ( - 1 )
-> afterPHP ( $codeAfter )
-> end ();
}
/**
* Enter description here ...
*
* @ param String | phpQuery
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function wrap ( $wrapper ) {
foreach ( $this -> stack () as $node )
phpQuery :: pq ( $node , $this -> getDocumentID ()) -> wrapAll ( $wrapper );
return $this ;
}
/**
* Enter description here ...
*
* @ param String | phpQuery
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function wrapPHP ( $codeBefore , $codeAfter ) {
foreach ( $this -> stack () as $node )
phpQuery :: pq ( $node , $this -> getDocumentID ()) -> wrapAllPHP ( $codeBefore , $codeAfter );
return $this ;
}
/**
* Enter description here ...
*
* @ param String | phpQuery
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function wrapInner ( $wrapper ) {
foreach ( $this -> stack () as $node )
phpQuery :: pq ( $node , $this -> getDocumentID ()) -> contents () -> wrapAll ( $wrapper );
return $this ;
}
/**
* Enter description here ...
*
* @ param String | phpQuery
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function wrapInnerPHP ( $codeBefore , $codeAfter ) {
foreach ( $this -> stack ( 1 ) as $node )
phpQuery :: pq ( $node , $this -> getDocumentID ()) -> contents ()
-> wrapAllPHP ( $codeBefore , $codeAfter );
return $this ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ testme Support for text nodes
*/
public function contents () {
$stack = array ();
foreach ( $this -> stack ( 1 ) as $el ) {
// FIXME (fixed) http://code.google.com/p/phpquery/issues/detail?id=56
// if (! isset($el->childNodes))
// continue;
foreach ( $el -> childNodes as $node ) {
$stack [] = $node ;
}
}
return $this -> newInstance ( $stack );
}
/**
* Enter description here ...
*
* jQuery difference .
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function contentsUnwrap () {
foreach ( $this -> stack ( 1 ) as $node ) {
if ( ! $node -> parentNode )
continue ;
$childNodes = array ();
// any modification in DOM tree breaks childNodes iteration, so cache them first
foreach ( $node -> childNodes as $chNode )
$childNodes [] = $chNode ;
foreach ( $childNodes as $chNode )
// $node->parentNode->appendChild($chNode);
$node -> parentNode -> insertBefore ( $chNode , $node );
$node -> parentNode -> removeChild ( $node );
}
return $this ;
}
/**
* Enter description here ...
*
* jQuery difference .
*/
public function switchWith ( $markup ) {
$markup = pq ( $markup , $this -> getDocumentID ());
$content = null ;
foreach ( $this -> stack ( 1 ) as $node ) {
pq ( $node )
-> contents () -> toReference ( $content ) -> end ()
-> replaceWith ( $markup -> clone () -> append ( $content ));
}
return $this ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function eq ( $num ) {
$oldStack = $this -> elements ;
$this -> elementsBackup = $this -> elements ;
$this -> elements = array ();
if ( isset ( $oldStack [ $num ]) )
$this -> elements [] = $oldStack [ $num ];
return $this -> newInstance ();
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function size () {
return count ( $this -> elements );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ deprecated Use length as attribute
*/
public function length () {
return $this -> size ();
}
public function count () {
return $this -> size ();
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ todo $level
*/
public function end ( $level = 1 ) {
// $this->elements = array_pop( $this->history );
// return $this;
// $this->previous->DOM = $this->DOM;
// $this->previous->XPath = $this->XPath;
return $this -> previous
? $this -> previous
: $this ;
}
/**
* Enter description here ...
* Normal use -> clone () .
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ access private
*/
public function _clone () {
$newStack = array ();
//pr(array('copy... ', $this->whois()));
//$this->dumpHistory('copy');
$this -> elementsBackup = $this -> elements ;
foreach ( $this -> elements as $node ) {
$newStack [] = $node -> cloneNode ( true );
}
$this -> elements = $newStack ;
return $this -> newInstance ();
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function replaceWithPHP ( $code ) {
return $this -> replaceWith ( phpQuery :: php ( $code ));
}
/**
* Enter description here ...
*
* @ param String | phpQuery $content
* @ link http :// docs . jquery . com / Manipulation / replaceWith #content
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function replaceWith ( $content ) {
return $this -> after ( $content ) -> remove ();
}
/**
* Enter description here ...
*
* @ param String $selector
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ todo this works ?
*/
public function replaceAll ( $selector ) {
foreach ( phpQuery :: pq ( $selector , $this -> getDocumentID ()) as $node )
phpQuery :: pq ( $node , $this -> getDocumentID ())
-> after ( $this -> _clone ())
-> remove ();
return $this ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function remove ( $selector = null ) {
$loop = $selector
? $this -> filter ( $selector ) -> elements
: $this -> elements ;
foreach ( $loop as $node ) {
if ( ! $node -> parentNode )
continue ;
if ( isset ( $node -> tagName ))
$this -> debug ( " Removing ' { $node -> tagName } ' " );
$node -> parentNode -> removeChild ( $node );
// Mutation event
$event = new DOMEvent ( array (
'target' => $node ,
'type' => 'DOMNodeRemoved'
));
phpQueryEvents :: trigger ( $this -> getDocumentID (),
$event -> type , array ( $event ), $node
);
}
return $this ;
}
protected function markupEvents ( $newMarkup , $oldMarkup , $node ) {
if ( $node -> tagName == 'textarea' && $newMarkup != $oldMarkup ) {
$event = new DOMEvent ( array (
'target' => $node ,
'type' => 'change'
));
phpQueryEvents :: trigger ( $this -> getDocumentID (),
$event -> type , array ( $event ), $node
);
}
}
/**
* jQuey difference
*
* @ param $markup
* @ return unknown_type
* @ TODO trigger change event for textarea
*/
public function markup ( $markup = null , $callback1 = null , $callback2 = null , $callback3 = null ) {
$args = func_get_args ();
if ( $this -> documentWrapper -> isXML )
return call_user_func_array ( array ( $this , 'xml' ), $args );
else
return call_user_func_array ( array ( $this , 'html' ), $args );
}
/**
* jQuey difference
*
* @ param $markup
* @ return unknown_type
*/
public function markupOuter ( $callback1 = null , $callback2 = null , $callback3 = null ) {
$args = func_get_args ();
if ( $this -> documentWrapper -> isXML )
return call_user_func_array ( array ( $this , 'xmlOuter' ), $args );
else
return call_user_func_array ( array ( $this , 'htmlOuter' ), $args );
}
/**
* Enter description here ...
*
* @ param unknown_type $html
* @ return string | phpQuery | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ TODO force html result
*/
public function html ( $html = null , $callback1 = null , $callback2 = null , $callback3 = null ) {
if ( isset ( $html )) {
// INSERT
$nodes = $this -> documentWrapper -> import ( $html );
$this -> empty ();
foreach ( $this -> stack ( 1 ) as $alreadyAdded => $node ) {
// for now, limit events for textarea
if (( $this -> isXHTML () || $this -> isHTML ()) && $node -> tagName == 'textarea' )
$oldHtml = pq ( $node , $this -> getDocumentID ()) -> markup ();
foreach ( $nodes as $newNode ) {
$node -> appendChild ( $alreadyAdded
? $newNode -> cloneNode ( true )
: $newNode
);
}
// for now, limit events for textarea
if (( $this -> isXHTML () || $this -> isHTML ()) && $node -> tagName == 'textarea' )
$this -> markupEvents ( $html , $oldHtml , $node );
}
return $this ;
} else {
// FETCH
$return = $this -> documentWrapper -> markup ( $this -> elements , true );
$args = func_get_args ();
foreach ( array_slice ( $args , 1 ) as $callback ) {
$return = phpQuery :: callbackRun ( $callback , array ( $return ));
}
return $return ;
}
}
/**
* @ TODO force xml result
*/
public function xml ( $xml = null , $callback1 = null , $callback2 = null , $callback3 = null ) {
$args = func_get_args ();
return call_user_func_array ( array ( $this , 'html' ), $args );
}
/**
* Enter description here ...
* @ TODO force html result
*
* @ return String
*/
public function htmlOuter ( $callback1 = null , $callback2 = null , $callback3 = null ) {
$markup = $this -> documentWrapper -> markup ( $this -> elements );
// pass thou callbacks
$args = func_get_args ();
foreach ( $args as $callback ) {
$markup = phpQuery :: callbackRun ( $callback , array ( $markup ));
}
return $markup ;
}
/**
* @ TODO force xml result
*/
public function xmlOuter ( $callback1 = null , $callback2 = null , $callback3 = null ) {
$args = func_get_args ();
return call_user_func_array ( array ( $this , 'htmlOuter' ), $args );
}
public function __toString () {
return $this -> markupOuter ();
}
/**
* Just like html (), but returns markup with VALID ( dangerous ) PHP tags .
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ todo support returning markup with PHP tags when called without param
*/
public function php ( $code = null ) {
return $this -> markupPHP ( $code );
}
/**
* Enter description here ...
*
* @ param $code
* @ return unknown_type
*/
public function markupPHP ( $code = null ) {
return isset ( $code )
? $this -> markup ( phpQuery :: php ( $code ))
: phpQuery :: markupToPHP ( $this -> markup ());
}
/**
* Enter description here ...
*
* @ param $code
* @ return unknown_type
*/
public function markupOuterPHP () {
return phpQuery :: markupToPHP ( $this -> markupOuter ());
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function children ( $selector = null ) {
$stack = array ();
foreach ( $this -> stack ( 1 ) as $node ) {
// foreach($node->getElementsByTagName('*') as $newNode) {
foreach ( $node -> childNodes as $newNode ) {
if ( $newNode -> nodeType != 1 )
continue ;
if ( $selector && ! $this -> is ( $selector , $newNode ))
continue ;
if ( $this -> elementsContainsNode ( $newNode , $stack ))
continue ;
$stack [] = $newNode ;
}
}
$this -> elementsBackup = $this -> elements ;
$this -> elements = $stack ;
return $this -> newInstance ();
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function ancestors ( $selector = null ) {
return $this -> children ( $selector );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function append ( $content ) {
return $this -> insert ( $content , __FUNCTION__ );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function appendPHP ( $content ) {
return $this -> insert ( " <php><!-- { $content } --></php> " , 'append' );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function appendTo ( $seletor ) {
return $this -> insert ( $seletor , __FUNCTION__ );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function prepend ( $content ) {
return $this -> insert ( $content , __FUNCTION__ );
}
/**
* Enter description here ...
*
* @ todo accept many arguments , which are joined , arrays maybe also
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function prependPHP ( $content ) {
return $this -> insert ( " <php><!-- { $content } --></php> " , 'prepend' );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function prependTo ( $seletor ) {
return $this -> insert ( $seletor , __FUNCTION__ );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function before ( $content ) {
return $this -> insert ( $content , __FUNCTION__ );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function beforePHP ( $content ) {
return $this -> insert ( " <php><!-- { $content } --></php> " , 'before' );
}
/**
* Enter description here ...
*
* @ param String | phpQuery
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function insertBefore ( $seletor ) {
return $this -> insert ( $seletor , __FUNCTION__ );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function after ( $content ) {
return $this -> insert ( $content , __FUNCTION__ );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function afterPHP ( $content ) {
return $this -> insert ( " <php><!-- { $content } --></php> " , 'after' );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function insertAfter ( $seletor ) {
return $this -> insert ( $seletor , __FUNCTION__ );
}
/**
* Internal insert method . Don ' t use it .
*
* @ param unknown_type $target
* @ param unknown_type $type
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ access private
*/
public function insert ( $target , $type ) {
$this -> debug ( " Inserting data with ' { $type } ' " );
$to = false ;
switch ( $type ) {
case 'appendTo' :
case 'prependTo' :
case 'insertBefore' :
case 'insertAfter' :
$to = true ;
}
switch ( gettype ( $target )) {
case 'string' :
$insertFrom = $insertTo = array ();
if ( $to ) {
// INSERT TO
$insertFrom = $this -> elements ;
if ( phpQuery :: isMarkup ( $target )) {
// $target is new markup, import it
$insertTo = $this -> documentWrapper -> import ( $target );
// insert into selected element
} else {
// $tagret is a selector
$thisStack = $this -> elements ;
$this -> toRoot ();
$insertTo = $this -> find ( $target ) -> elements ;
$this -> elements = $thisStack ;
}
} else {
// INSERT FROM
$insertTo = $this -> elements ;
$insertFrom = $this -> documentWrapper -> import ( $target );
}
break ;
case 'object' :
$insertFrom = $insertTo = array ();
// phpQuery
if ( $target instanceof self ) {
if ( $to ) {
$insertTo = $target -> elements ;
if ( $this -> documentFragment && $this -> stackIsRoot ())
// get all body children
// $loop = $this->find('body > *')->elements;
// TODO test it, test it hard...
// $loop = $this->newInstance($this->root)->find('> *')->elements;
$loop = $this -> root -> childNodes ;
else
$loop = $this -> elements ;
// import nodes if needed
$insertFrom = $this -> getDocumentID () == $target -> getDocumentID ()
? $loop
: $target -> documentWrapper -> import ( $loop );
} else {
$insertTo = $this -> elements ;
if ( $target -> documentFragment && $target -> stackIsRoot () )
// get all body children
// $loop = $target->find('body > *')->elements;
$loop = $target -> root -> childNodes ;
else
$loop = $target -> elements ;
// import nodes if needed
$insertFrom = $this -> getDocumentID () == $target -> getDocumentID ()
? $loop
: $this -> documentWrapper -> import ( $loop );
}
// DOMNODE
} elseif ( $target instanceof DOMNODE ) {
// import node if needed
// if ( $target->ownerDocument != $this->DOM )
// $target = $this->DOM->importNode($target, true);
if ( $to ) {
$insertTo = array ( $target );
if ( $this -> documentFragment && $this -> stackIsRoot ())
// get all body children
$loop = $this -> root -> childNodes ;
// $loop = $this->find('body > *')->elements;
else
$loop = $this -> elements ;
foreach ( $loop as $fromNode )
// import nodes if needed
$insertFrom [] = ! $fromNode -> ownerDocument -> isSameNode ( $target -> ownerDocument )
? $target -> ownerDocument -> importNode ( $fromNode , true )
: $fromNode ;
} else {
// import node if needed
if ( ! $target -> ownerDocument -> isSameNode ( $this -> document ))
$target = $this -> document -> importNode ( $target , true );
$insertTo = $this -> elements ;
$insertFrom [] = $target ;
}
}
break ;
}
phpQuery :: debug ( " From " . count ( $insertFrom ) . " ; To " . count ( $insertTo ) . " nodes " );
foreach ( $insertTo as $insertNumber => $toNode ) {
// we need static relative elements in some cases
switch ( $type ) {
case 'prependTo' :
case 'prepend' :
$firstChild = $toNode -> firstChild ;
break ;
case 'insertAfter' :
case 'after' :
$nextSibling = $toNode -> nextSibling ;
break ;
}
foreach ( $insertFrom as $fromNode ) {
// clone if inserted already before
$insert = $insertNumber
? $fromNode -> cloneNode ( true )
: $fromNode ;
switch ( $type ) {
case 'appendTo' :
case 'append' :
// $toNode->insertBefore(
// $fromNode,
// $toNode->lastChild->nextSibling
// );
$toNode -> appendChild ( $insert );
$eventTarget = $insert ;
break ;
case 'prependTo' :
case 'prepend' :
$toNode -> insertBefore (
$insert ,
$firstChild
);
break ;
case 'insertBefore' :
case 'before' :
if ( ! $toNode -> parentNode )
throw new Exception ( " No parentNode, can't do { $type } () " );
else
$toNode -> parentNode -> insertBefore (
$insert ,
$toNode
);
break ;
case 'insertAfter' :
case 'after' :
if ( ! $toNode -> parentNode )
throw new Exception ( " No parentNode, can't do { $type } () " );
else
$toNode -> parentNode -> insertBefore (
$insert ,
$nextSibling
);
break ;
}
// Mutation event
$event = new DOMEvent ( array (
'target' => $insert ,
'type' => 'DOMNodeInserted'
));
phpQueryEvents :: trigger ( $this -> getDocumentID (),
$event -> type , array ( $event ), $insert
);
}
}
return $this ;
}
/**
* Enter description here ...
*
* @ return Int
*/
public function index ( $subject ) {
$index = - 1 ;
$subject = $subject instanceof phpQueryObject
? $subject -> elements [ 0 ]
: $subject ;
foreach ( $this -> newInstance () as $k => $node ) {
if ( $node -> isSameNode ( $subject ))
$index = $k ;
}
return $index ;
}
/**
* Enter description here ...
*
* @ param unknown_type $start
* @ param unknown_type $end
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ testme
*/
public function slice ( $start , $end = null ) {
// $last = count($this->elements)-1;
// $end = $end
// ? min($end, $last)
// : $last;
// if ($start < 0)
// $start = $last+$start;
// if ($start > $last)
// return array();
if ( $end > 0 )
$end = $end - $start ;
return $this -> newInstance (
array_slice ( $this -> elements , $start , $end )
);
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function reverse () {
$this -> elementsBackup = $this -> elements ;
$this -> elements = array_reverse ( $this -> elements );
return $this -> newInstance ();
}
/**
* Return joined text content .
* @ return String
*/
public function text ( $text = null , $callback1 = null , $callback2 = null , $callback3 = null ) {
if ( isset ( $text ))
return $this -> html ( htmlspecialchars ( $text ));
$args = func_get_args ();
$args = array_slice ( $args , 1 );
$return = '' ;
foreach ( $this -> elements as $node ) {
$text = $node -> textContent ;
if ( count ( $this -> elements ) > 1 && $text )
$text .= " \n " ;
foreach ( $args as $callback ) {
$text = phpQuery :: callbackRun ( $callback , array ( $text ));
}
$return .= $text ;
}
return $return ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function plugin ( $class , $file = null ) {
phpQuery :: plugin ( $class , $file );
return $this ;
}
/**
* Deprecated , use $pq -> plugin () instead .
*
* @ deprecated
* @ param $class
* @ param $file
* @ return unknown_type
*/
public static function extend ( $class , $file = null ) {
return $this -> plugin ( $class , $file );
}
/**
*
* @ access private
* @ param $method
* @ param $args
* @ return unknown_type
*/
public function __call ( $method , $args ) {
$aliasMethods = array ( 'clone' , 'empty' );
if ( isset ( phpQuery :: $extendMethods [ $method ])) {
array_unshift ( $args , $this );
return phpQuery :: callbackRun (
phpQuery :: $extendMethods [ $method ], $args
);
} else if ( isset ( phpQuery :: $pluginsMethods [ $method ])) {
array_unshift ( $args , $this );
$class = phpQuery :: $pluginsMethods [ $method ];
$realClass = " phpQueryObjectPlugin_ $class " ;
$return = call_user_func_array (
array ( $realClass , $method ),
$args
);
// XXX deprecate ?
return is_null ( $return )
? $this
: $return ;
} else if ( in_array ( $method , $aliasMethods )) {
return call_user_func_array ( array ( $this , '_' . $method ), $args );
} else
throw new Exception ( " Method ' { $method } ' doesnt exist " );
}
/**
* Safe rename of next () .
*
* Use it ONLY when need to call next () on an iterated object ( in same time ) .
* Normaly there is no need to do such thing ;)
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ access private
*/
public function _next ( $selector = null ) {
return $this -> newInstance (
$this -> getElementSiblings ( 'nextSibling' , $selector , true )
);
}
/**
* Use prev () and next () .
*
* @ deprecated
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ access private
*/
public function _prev ( $selector = null ) {
return $this -> prev ( $selector );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function prev ( $selector = null ) {
return $this -> newInstance (
$this -> getElementSiblings ( 'previousSibling' , $selector , true )
);
}
/**
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ todo
*/
public function prevAll ( $selector = null ) {
return $this -> newInstance (
$this -> getElementSiblings ( 'previousSibling' , $selector )
);
}
/**
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ todo FIXME : returns source elements insted of next siblings
*/
public function nextAll ( $selector = null ) {
return $this -> newInstance (
$this -> getElementSiblings ( 'nextSibling' , $selector )
);
}
/**
* @ access private
*/
protected function getElementSiblings ( $direction , $selector = null , $limitToOne = false ) {
$stack = array ();
$count = 0 ;
foreach ( $this -> stack () as $node ) {
$test = $node ;
while ( isset ( $test -> { $direction }) && $test -> { $direction }) {
$test = $test -> { $direction };
if ( ! $test instanceof DOMELEMENT )
continue ;
$stack [] = $test ;
if ( $limitToOne )
break ;
}
}
if ( $selector ) {
$stackOld = $this -> elements ;
$this -> elements = $stack ;
$stack = $this -> filter ( $selector , true ) -> stack ();
$this -> elements = $stackOld ;
}
return $stack ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function siblings ( $selector = null ) {
$stack = array ();
$siblings = array_merge (
$this -> getElementSiblings ( 'previousSibling' , $selector ),
$this -> getElementSiblings ( 'nextSibling' , $selector )
);
foreach ( $siblings as $node ) {
if ( ! $this -> elementsContainsNode ( $node , $stack ))
$stack [] = $node ;
}
return $this -> newInstance ( $stack );
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function not ( $selector = null ) {
if ( is_string ( $selector ))
phpQuery :: debug ( array ( 'not' , $selector ));
else
phpQuery :: debug ( 'not' );
$stack = array ();
if ( $selector instanceof self || $selector instanceof DOMNODE ) {
foreach ( $this -> stack () as $node ) {
if ( $selector instanceof self ) {
$matchFound = false ;
foreach ( $selector -> stack () as $notNode ) {
if ( $notNode -> isSameNode ( $node ))
$matchFound = true ;
}
if ( ! $matchFound )
$stack [] = $node ;
} else if ( $selector instanceof DOMNODE ) {
if ( ! $selector -> isSameNode ( $node ))
$stack [] = $node ;
} else {
if ( ! $this -> is ( $selector ))
$stack [] = $node ;
}
}
} else {
$orgStack = $this -> stack ();
$matched = $this -> filter ( $selector , true ) -> stack ();
// $matched = array();
// // simulate OR in filter() instead of AND 5y
// foreach($this->parseSelector($selector) as $s) {
// $matched = array_merge($matched,
// $this->filter(array($s))->stack()
// );
// }
foreach ( $orgStack as $node )
if ( ! $this -> elementsContainsNode ( $node , $matched ))
$stack [] = $node ;
}
return $this -> newInstance ( $stack );
}
/**
* Enter description here ...
*
* @ param string | phpQueryObject
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function add ( $selector = null ) {
if ( ! $selector )
return $this ;
$stack = array ();
$this -> elementsBackup = $this -> elements ;
$found = phpQuery :: pq ( $selector , $this -> getDocumentID ());
$this -> merge ( $found -> elements );
return $this -> newInstance ();
}
/**
* @ access private
*/
protected function merge () {
foreach ( func_get_args () as $nodes )
foreach ( $nodes as $newNode )
if ( ! $this -> elementsContainsNode ( $newNode ) )
$this -> elements [] = $newNode ;
}
/**
* @ access private
* TODO refactor to stackContainsNode
*/
protected function elementsContainsNode ( $nodeToCheck , $elementsStack = null ) {
$loop = ! is_null ( $elementsStack )
? $elementsStack
: $this -> elements ;
foreach ( $loop as $node ) {
if ( $node -> isSameNode ( $nodeToCheck ) )
return true ;
}
return false ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function parent ( $selector = null ) {
$stack = array ();
foreach ( $this -> elements as $node )
if ( $node -> parentNode && ! $this -> elementsContainsNode ( $node -> parentNode , $stack ) )
$stack [] = $node -> parentNode ;
$this -> elementsBackup = $this -> elements ;
$this -> elements = $stack ;
if ( $selector )
$this -> filter ( $selector , true );
return $this -> newInstance ();
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function parents ( $selector = null ) {
$stack = array ();
if ( ! $this -> elements )
$this -> debug ( 'parents() - stack empty' );
foreach ( $this -> elements as $node ) {
$test = $node ;
while ( $test -> parentNode ) {
$test = $test -> parentNode ;
if ( $this -> isRoot ( $test ))
break ;
if ( ! $this -> elementsContainsNode ( $test , $stack )) {
$stack [] = $test ;
continue ;
}
}
}
$this -> elementsBackup = $this -> elements ;
$this -> elements = $stack ;
if ( $selector )
$this -> filter ( $selector , true );
return $this -> newInstance ();
}
/**
* Internal stack iterator .
*
* @ access private
*/
public function stack ( $nodeTypes = null ) {
if ( ! isset ( $nodeTypes ))
return $this -> elements ;
if ( ! is_array ( $nodeTypes ))
$nodeTypes = array ( $nodeTypes );
$return = array ();
foreach ( $this -> elements as $node ) {
if ( in_array ( $node -> nodeType , $nodeTypes ))
$return [] = $node ;
}
return $return ;
}
// TODO phpdoc; $oldAttr is result of hasAttribute, before any changes
protected function attrEvents ( $attr , $oldAttr , $oldValue , $node ) {
// skip events for XML documents
if ( ! $this -> isXHTML () && ! $this -> isHTML ())
return ;
$event = null ;
// identify
$isInputValue = $node -> tagName == 'input'
&& (
in_array ( $node -> getAttribute ( 'type' ),
array ( 'text' , 'password' , 'hidden' ))
|| ! $node -> getAttribute ( 'type' )
);
$isRadio = $node -> tagName == 'input'
&& $node -> getAttribute ( 'type' ) == 'radio' ;
$isCheckbox = $node -> tagName == 'input'
&& $node -> getAttribute ( 'type' ) == 'checkbox' ;
$isOption = $node -> tagName == 'option' ;
if ( $isInputValue && $attr == 'value' && $oldValue != $node -> getAttribute ( $attr )) {
$event = new DOMEvent ( array (
'target' => $node ,
'type' => 'change'
));
} else if (( $isRadio || $isCheckbox ) && $attr == 'checked' && (
// check
( ! $oldAttr && $node -> hasAttribute ( $attr ))
// un-check
|| ( ! $node -> hasAttribute ( $attr ) && $oldAttr )
)) {
$event = new DOMEvent ( array (
'target' => $node ,
'type' => 'change'
));
} else if ( $isOption && $node -> parentNode && $attr == 'selected' && (
// select
( ! $oldAttr && $node -> hasAttribute ( $attr ))
// un-select
|| ( ! $node -> hasAttribute ( $attr ) && $oldAttr )
)) {
$event = new DOMEvent ( array (
'target' => $node -> parentNode ,
'type' => 'change'
));
}
if ( $event ) {
phpQueryEvents :: trigger ( $this -> getDocumentID (),
$event -> type , array ( $event ), $node
);
}
}
public function attr ( $attr = null , $value = null ) {
foreach ( $this -> stack ( 1 ) as $node ) {
if ( ! is_null ( $value )) {
$loop = $attr == '*'
? $this -> getNodeAttrs ( $node )
: array ( $attr );
foreach ( $loop as $a ) {
$oldValue = $node -> getAttribute ( $a );
$oldAttr = $node -> hasAttribute ( $a );
// TODO raises an error when charset other than UTF-8
// while document's charset is also not UTF-8
@ $node -> setAttribute ( $a , $value );
$this -> attrEvents ( $a , $oldAttr , $oldValue , $node );
}
} else if ( $attr == '*' ) {
// jQuery difference
$return = array ();
foreach ( $node -> attributes as $n => $v )
$return [ $n ] = $v -> value ;
return $return ;
} else
return $node -> hasAttribute ( $attr )
? $node -> getAttribute ( $attr )
: null ;
}
return is_null ( $value )
? '' : $this ;
}
/**
* @ access private
*/
protected function getNodeAttrs ( $node ) {
$return = array ();
foreach ( $node -> attributes as $n => $o )
$return [] = $n ;
return $return ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ todo check CDATA ? ? ?
*/
public function attrPHP ( $attr , $code ) {
if ( ! is_null ( $code )) {
$value = '<' . '?php ' . $code . ' ?' . '>' ;
// TODO tempolary solution
// http://code.google.com/p/phpquery/issues/detail?id=17
// if (function_exists('mb_detect_encoding') && mb_detect_encoding($value) == 'ASCII')
// $value = mb_convert_encoding($value, 'UTF-8', 'HTML-ENTITIES');
}
foreach ( $this -> stack ( 1 ) as $node ) {
if ( ! is_null ( $code )) {
// $attrNode = $this->DOM->createAttribute($attr);
$node -> setAttribute ( $attr , $value );
// $attrNode->value = $value;
// $node->appendChild($attrNode);
} else if ( $attr == '*' ) {
// jQuery diff
$return = array ();
foreach ( $node -> attributes as $n => $v )
$return [ $n ] = $v -> value ;
return $return ;
} else
return $node -> getAttribute ( $attr );
}
return $this ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function removeAttr ( $attr ) {
foreach ( $this -> stack ( 1 ) as $node ) {
$loop = $attr == '*'
? $this -> getNodeAttrs ( $node )
: array ( $attr );
foreach ( $loop as $a ) {
$oldValue = $node -> getAttribute ( $a );
$node -> removeAttribute ( $a );
$this -> attrEvents ( $a , $oldValue , null , $node );
}
}
return $this ;
}
/**
* Return form element value .
*
* @ return String Fields value .
*/
public function val ( $val = null ) {
if ( ! isset ( $val )) {
if ( $this -> eq ( 0 ) -> is ( 'select' )) {
$selected = $this -> eq ( 0 ) -> find ( 'option[selected=selected]' );
if ( $selected -> is ( '[value]' ))
return $selected -> attr ( 'value' );
else
return $selected -> text ();
} else if ( $this -> eq ( 0 ) -> is ( 'textarea' ))
return $this -> eq ( 0 ) -> markup ();
else
return $this -> eq ( 0 ) -> attr ( 'value' );
} else {
$_val = null ;
foreach ( $this -> stack ( 1 ) as $node ) {
$node = pq ( $node , $this -> getDocumentID ());
if ( is_array ( $val ) && in_array ( $node -> attr ( 'type' ), array ( 'checkbox' , 'radio' ))) {
$isChecked = in_array ( $node -> attr ( 'value' ), $val )
|| in_array ( $node -> attr ( 'name' ), $val );
if ( $isChecked )
$node -> attr ( 'checked' , 'checked' );
else
$node -> removeAttr ( 'checked' );
} else if ( $node -> get ( 0 ) -> tagName == 'select' ) {
if ( ! isset ( $_val )) {
$_val = array ();
if ( ! is_array ( $val ))
$_val = array (( string ) $val );
else
foreach ( $val as $v )
$_val [] = $v ;
}
foreach ( $node [ 'option' ] -> stack ( 1 ) as $option ) {
$option = pq ( $option , $this -> getDocumentID ());
$selected = false ;
// XXX: workaround for string comparsion, see issue #96
// http://code.google.com/p/phpquery/issues/detail?id=96
$selected = is_null ( $option -> attr ( 'value' ))
? in_array ( $option -> markup (), $_val )
: in_array ( $option -> attr ( 'value' ), $_val );
// $optionValue = $option->attr('value');
// $optionText = $option->text();
// $optionTextLenght = mb_strlen($optionText);
// foreach($_val as $v)
// if ($optionValue == $v)
// $selected = true;
// else if ($optionText == $v && $optionTextLenght == mb_strlen($v))
// $selected = true;
if ( $selected )
$option -> attr ( 'selected' , 'selected' );
else
$option -> removeAttr ( 'selected' );
}
} else if ( $node -> get ( 0 ) -> tagName == 'textarea' )
$node -> markup ( $val );
else
$node -> attr ( 'value' , $val );
}
}
return $this ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function andSelf () {
if ( $this -> previous )
$this -> elements = array_merge ( $this -> elements , $this -> previous -> elements );
return $this ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function addClass ( $className ) {
if ( ! $className )
return $this ;
foreach ( $this -> stack ( 1 ) as $node ) {
if ( ! $this -> is ( " . $className " , $node ))
$node -> setAttribute (
'class' ,
trim ( $node -> getAttribute ( 'class' ) . ' ' . $className )
);
}
return $this ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function addClassPHP ( $className ) {
foreach ( $this -> stack ( 1 ) as $node ) {
$classes = $node -> getAttribute ( 'class' );
$newValue = $classes
? $classes . ' <' . '?php ' . $className . ' ?' . '>'
: '<' . '?php ' . $className . ' ?' . '>' ;
$node -> setAttribute ( 'class' , $newValue );
}
return $this ;
}
/**
* Enter description here ...
*
* @ param string $className
* @ return bool
*/
public function hasClass ( $className ) {
foreach ( $this -> stack ( 1 ) as $node ) {
if ( $this -> is ( " . $className " , $node ))
return true ;
}
return false ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function removeClass ( $className ) {
foreach ( $this -> stack ( 1 ) as $node ) {
$classes = explode ( ' ' , $node -> getAttribute ( 'class' ));
if ( in_array ( $className , $classes )) {
$classes = array_diff ( $classes , array ( $className ));
if ( $classes )
$node -> setAttribute ( 'class' , implode ( ' ' , $classes ));
else
$node -> removeAttribute ( 'class' );
}
}
return $this ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function toggleClass ( $className ) {
foreach ( $this -> stack ( 1 ) as $node ) {
if ( $this -> is ( $node , '.' . $className ))
$this -> removeClass ( $className );
else
$this -> addClass ( $className );
}
return $this ;
}
/**
* Proper name without underscore ( just -> empty ()) also works .
*
* Removes all child nodes from the set of matched elements .
*
* Example :
* pq ( " p " ) . _empty ()
*
* HTML :
* < p > Hello , < span > Person </ span > < a href = " # " > and person </ a ></ p >
*
* Result :
* [ < p ></ p > ]
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ access private
*/
public function _empty () {
foreach ( $this -> stack ( 1 ) as $node ) {
// thx to 'dave at dgx dot cz'
$node -> nodeValue = '' ;
}
return $this ;
}
/**
* Enter description here ...
*
* @ param array | string $callback Expects $node as first param , $index as second
* @ param array $scope External variables passed to callback . Use compact ( 'varName1' , 'varName2' ... ) and extract ( $scope )
* @ param array $arg1 Will ba passed as third and futher args to callback .
* @ param array $arg2 Will ba passed as fourth and futher args to callback , and so on ...
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function each ( $callback , $param1 = null , $param2 = null , $param3 = null ) {
$paramStructure = null ;
if ( func_num_args () > 1 ) {
$paramStructure = func_get_args ();
$paramStructure = array_slice ( $paramStructure , 1 );
}
foreach ( $this -> elements as $v )
phpQuery :: callbackRun ( $callback , array ( $v ), $paramStructure );
return $this ;
}
/**
* Run callback on actual object .
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function callback ( $callback , $param1 = null , $param2 = null , $param3 = null ) {
$params = func_get_args ();
$params [ 0 ] = $this ;
phpQuery :: callbackRun ( $callback , $params );
return $this ;
}
/**
* Enter description here ...
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
* @ todo add $scope and $args as in each () ? ? ?
*/
public function map ( $callback , $param1 = null , $param2 = null , $param3 = null ) {
// $stack = array();
//// foreach($this->newInstance() as $node) {
// foreach($this->newInstance() as $node) {
// $result = call_user_func($callback, $node);
// if ($result)
// $stack[] = $result;
// }
$params = func_get_args ();
array_unshift ( $params , $this -> elements );
return $this -> newInstance (
call_user_func_array ( array ( 'phpQuery' , 'map' ), $params )
// phpQuery::map($this->elements, $callback)
);
}
/**
* Enter description here ...
*
* @ param < type > $key
* @ param < type > $value
*/
public function data ( $key , $value = null ) {
if ( ! isset ( $value )) {
// TODO? implement specific jQuery behavior od returning parent values
// is child which we look up doesn't exist
return phpQuery :: data ( $this -> get ( 0 ), $key , $value , $this -> getDocumentID ());
} else {
foreach ( $this as $node )
phpQuery :: data ( $node , $key , $value , $this -> getDocumentID ());
return $this ;
}
}
/**
* Enter description here ...
*
* @ param < type > $key
*/
public function removeData ( $key ) {
foreach ( $this as $node )
phpQuery :: removeData ( $node , $key , $this -> getDocumentID ());
return $this ;
}
// INTERFACE IMPLEMENTATIONS
// ITERATOR INTERFACE
/**
* @ access private
*/
public function rewind (){
$this -> debug ( 'iterating foreach' );
// phpQuery::selectDocument($this->getDocumentID());
$this -> elementsBackup = $this -> elements ;
$this -> elementsInterator = $this -> elements ;
$this -> valid = isset ( $this -> elements [ 0 ] )
? 1 : 0 ;
// $this->elements = $this->valid
// ? array($this->elements[0])
// : array();
$this -> current = 0 ;
}
/**
* @ access private
*/
public function current (){
return $this -> elementsInterator [ $this -> current ];
}
/**
* @ access private
*/
public function key (){
return $this -> current ;
}
/**
* Double - function method .
*
* First : main iterator interface method .
* Second : Returning next sibling , alias for _next () .
*
* Proper functionality is choosed automagicaly .
*
* @ see phpQueryObject :: _next ()
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*/
public function next ( $cssSelector = null ){
// if ($cssSelector || $this->valid)
// return $this->_next($cssSelector);
$this -> valid = isset ( $this -> elementsInterator [ $this -> current + 1 ] )
? true
: false ;
if ( ! $this -> valid && $this -> elementsInterator ) {
$this -> elementsInterator = null ;
} else if ( $this -> valid ) {
$this -> current ++ ;
} else {
return $this -> _next ( $cssSelector );
}
}
/**
* @ access private
*/
public function valid (){
return $this -> valid ;
}
// ITERATOR INTERFACE END
// ARRAYACCESS INTERFACE
/**
* @ access private
*/
public function offsetExists ( $offset ) {
return $this -> find ( $offset ) -> size () > 0 ;
}
/**
* @ access private
*/
public function offsetGet ( $offset ) {
return $this -> find ( $offset );
}
/**
* @ access private
*/
public function offsetSet ( $offset , $value ) {
// $this->find($offset)->replaceWith($value);
$this -> find ( $offset ) -> html ( $value );
}
/**
* @ access private
*/
public function offsetUnset ( $offset ) {
// empty
throw new Exception ( " Can't do unset, use array interface only for calling queries and replacing HTML. " );
}
// ARRAYACCESS INTERFACE END
/**
* Returns node ' s XPath .
*
* @ param unknown_type $oneNode
* @ return string
* @ TODO use native getNodePath is avaible
* @ access private
*/
protected function getNodeXpath ( $oneNode = null , $namespace = null ) {
$return = array ();
$loop = $oneNode
? array ( $oneNode )
: $this -> elements ;
// if ($namespace)
// $namespace .= ':';
foreach ( $loop as $node ) {
if ( $node instanceof DOMDOCUMENT ) {
$return [] = '' ;
continue ;
}
$xpath = array ();
while ( ! ( $node instanceof DOMDOCUMENT )) {
$i = 1 ;
$sibling = $node ;
while ( $sibling -> previousSibling ) {
$sibling = $sibling -> previousSibling ;
$isElement = $sibling instanceof DOMELEMENT ;
if ( $isElement && $sibling -> tagName == $node -> tagName )
$i ++ ;
}
$xpath [] = $this -> isXML ()
? " *[local-name()=' { $node -> tagName } '][ { $i } ] "
: " { $node -> tagName } [ { $i } ] " ;
$node = $node -> parentNode ;
}
$xpath = join ( '/' , array_reverse ( $xpath ));
$return [] = '/' . $xpath ;
}
return $oneNode
? $return [ 0 ]
: $return ;
}
// HELPERS
public function whois ( $oneNode = null ) {
$return = array ();
$loop = $oneNode
? array ( $oneNode )
: $this -> elements ;
foreach ( $loop as $node ) {
if ( isset ( $node -> tagName )) {
$tag = in_array ( $node -> tagName , array ( 'php' , 'js' ))
? strtoupper ( $node -> tagName )
: $node -> tagName ;
$return [] = $tag
. ( $node -> getAttribute ( 'id' )
? '#' . $node -> getAttribute ( 'id' ) : '' )
. ( $node -> getAttribute ( 'class' )
? '.' . join ( '.' , split ( ' ' , $node -> getAttribute ( 'class' ))) : '' )
. ( $node -> getAttribute ( 'name' )
? '[name="' . $node -> getAttribute ( 'name' ) . '"]' : '' )
. ( $node -> getAttribute ( 'value' ) && strpos ( $node -> getAttribute ( 'value' ), '<' . '?php' ) === false
? '[value="' . substr ( str_replace ( " \n " , '' , $node -> getAttribute ( 'value' )), 0 , 15 ) . '"]' : '' )
. ( $node -> getAttribute ( 'value' ) && strpos ( $node -> getAttribute ( 'value' ), '<' . '?php' ) !== false
? '[value=PHP]' : '' )
. ( $node -> getAttribute ( 'selected' )
? '[selected]' : '' )
. ( $node -> getAttribute ( 'checked' )
? '[checked]' : '' )
;
} else if ( $node instanceof DOMTEXT ) {
if ( trim ( $node -> textContent ))
$return [] = 'Text:' . substr ( str_replace ( " \n " , ' ' , $node -> textContent ), 0 , 15 );
} else {
}
}
return $oneNode && isset ( $return [ 0 ])
? $return [ 0 ]
: $return ;
}
/**
* Dump htmlOuter and preserve chain . Usefull for debugging .
*
* @ return phpQueryObject | QueryTemplatesSource | QueryTemplatesParse | QueryTemplatesSourceQuery
*
*/
public function dump () {
print 'DUMP #' . ( phpQuery :: $dumpCount ++ ) . ' ' ;
$debug = phpQuery :: $debug ;
phpQuery :: $debug = false ;
// print __FILE__.':'.__LINE__."\n";
var_dump ( $this -> htmlOuter ());
return $this ;
}
public function dumpWhois () {
print 'DUMP #' . ( phpQuery :: $dumpCount ++ ) . ' ' ;
$debug = phpQuery :: $debug ;
phpQuery :: $debug = false ;
// print __FILE__.':'.__LINE__."\n";
var_dump ( 'whois' , $this -> whois ());
phpQuery :: $debug = $debug ;
return $this ;
}
public function dumpLength () {
print 'DUMP #' . ( phpQuery :: $dumpCount ++ ) . ' ' ;
$debug = phpQuery :: $debug ;
phpQuery :: $debug = false ;
// print __FILE__.':'.__LINE__."\n";
var_dump ( 'length' , $this -> length ());
phpQuery :: $debug = $debug ;
return $this ;
}
public function dumpTree ( $html = true , $title = true ) {
$output = $title
? 'DUMP #' . ( phpQuery :: $dumpCount ++ ) . " \n " : '' ;
$debug = phpQuery :: $debug ;
phpQuery :: $debug = false ;
foreach ( $this -> stack () as $node )
$output .= $this -> __dumpTree ( $node );
phpQuery :: $debug = $debug ;
print $html
? nl2br ( str_replace ( ' ' , ' ' , $output ))
: $output ;
return $this ;
}
private function __dumpTree ( $node , $intend = 0 ) {
$whois = $this -> whois ( $node );
$return = '' ;
if ( $whois )
$return .= str_repeat ( ' - ' , $intend ) . $whois . " \n " ;
if ( isset ( $node -> childNodes ))
foreach ( $node -> childNodes as $chNode )
$return .= $this -> __dumpTree ( $chNode , $intend + 1 );
return $return ;
}
/**
* Dump htmlOuter and stop script execution . Usefull for debugging .
*
*/
public function dumpDie () {
print __FILE__ . ':' . __LINE__ ;
var_dump ( $this -> htmlOuter ());
die ();
}
}
// -- Multibyte Compatibility functions ---------------------------------------
// http://svn.iphonewebdev.com/lace/lib/mb_compat.php
/**
* mb_internal_encoding ()
*
* Included for mbstring pseudo - compatability .
*/
if ( ! function_exists ( 'mb_internal_encoding' ))
{
function mb_internal_encoding ( $enc ) { return true ; }
}
/**
* mb_regex_encoding ()
*
* Included for mbstring pseudo - compatability .
*/
if ( ! function_exists ( 'mb_regex_encoding' ))
{
function mb_regex_encoding ( $enc ) { return true ; }
}
/**
* mb_strlen ()
*
* Included for mbstring pseudo - compatability .
*/
if ( ! function_exists ( 'mb_strlen' ))
{
function mb_strlen ( $str )
{
return strlen ( $str );
}
}
/**
* mb_strpos ()
*
* Included for mbstring pseudo - compatability .
*/
if ( ! function_exists ( 'mb_strpos' ))
{
function mb_strpos ( $haystack , $needle , $offset = 0 )
{
return strpos ( $haystack , $needle , $offset );
}
}
/**
* mb_stripos ()
*
* Included for mbstring pseudo - compatability .
*/
if ( ! function_exists ( 'mb_stripos' ))
{
function mb_stripos ( $haystack , $needle , $offset = 0 )
{
return stripos ( $haystack , $needle , $offset );
}
}
/**
* mb_substr ()
*
* Included for mbstring pseudo - compatability .
*/
if ( ! function_exists ( 'mb_substr' ))
{
function mb_substr ( $str , $start , $length = 0 )
{
return substr ( $str , $start , $length );
}
}
/**
* mb_substr_count ()
*
* Included for mbstring pseudo - compatability .
*/
if ( ! function_exists ( 'mb_substr_count' ))
{
function mb_substr_count ( $haystack , $needle )
{
return substr_count ( $haystack , $needle );
}
}
/**
* 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 ,
'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' ))
2017-09-19 17:23:37 +00:00
require_once dirname ( __FILE__ ) . '/phpQuery/bootstrap.php' ;