57f51eeaf85c49e85e96a3eeeaa5d54563609513.svn-base 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. <?php namespace Maze\Template\Parse;
  2. use Maze\Template\Parse;
  3. use Maze\Template\Compile;
  4. use Maze\Http\Output;
  5. use Sunra\PhpSimple\HtmlDomParser;
  6. use Maze\Debug\Process as Debug;
  7. use Maze\Config\Lang;
  8. class Dom implements Parse
  9. {
  10. /**
  11. * current
  12. *
  13. * @var object
  14. */
  15. protected $current;
  16. /**
  17. * data
  18. *
  19. * @var string
  20. */
  21. protected $data;
  22. /**
  23. * expression
  24. *
  25. * @var string
  26. */
  27. protected $expression;
  28. /**
  29. * attr
  30. *
  31. * @var string
  32. */
  33. protected $attr = 'outertext';
  34. /**
  35. * compile
  36. *
  37. * @var \Maze\Template\Compile
  38. */
  39. protected $compile;
  40. /**
  41. * dom
  42. *
  43. * @var \Sunra\PhpSimple\HtmlDomParser
  44. */
  45. protected $dom;
  46. /**
  47. * temp dom
  48. *
  49. * @var \Sunra\PhpSimple\HtmlDomParser
  50. */
  51. protected $temp;
  52. /**
  53. * __construct
  54. *
  55. * @return mixed
  56. */
  57. public function __construct(Compile $compile)
  58. {
  59. $this->compile = $compile;
  60. $this->load($this->compile->template());
  61. }
  62. /**
  63. * load file or string
  64. * @param string $file
  65. *
  66. * @return mixed
  67. */
  68. public function load($value)
  69. {
  70. if(is_file($value))
  71. {
  72. $this->dom = HtmlDomParser::file_get_html($value);
  73. }
  74. else
  75. {
  76. $this->dom = HtmlDomParser::str_get_html($value);
  77. }
  78. $this->filter();
  79. $this->import();
  80. }
  81. /**
  82. * make
  83. * @param array $param
  84. *
  85. * @return mixed
  86. */
  87. public function make($param)
  88. {
  89. $this->current($param[0]);
  90. $this->data = $param[1];
  91. if($this->current) $this->expression = $this->current->innertext;
  92. if(isset($param[2]) && is_array($param[2]))
  93. {
  94. $this->child($param[2]);
  95. }
  96. elseif(isset($param[2]) && $param[2] == 'none' && $this->current && is_string($this->data))
  97. {
  98. $value = $this->data;
  99. if(strpos($this->data, 'Maze::') === false)
  100. {
  101. $value = '<{Maze::load("'.$this->data.'")}>';
  102. }
  103. $value = str_replace('<{', '<{if(!', $value);
  104. $value = str_replace('}>', '):}>', $value);
  105. $this->current->style = $this->compile->content($value . 'display:none;<{endif;}>');
  106. }
  107. $this->handle();
  108. }
  109. /**
  110. * get
  111. *
  112. * @return string
  113. */
  114. public function get()
  115. {
  116. return $this->dom->save();
  117. }
  118. /**
  119. * child
  120. * @param array $child
  121. *
  122. * @return array
  123. */
  124. public function child($child)
  125. {
  126. $this->attr = 'outertext';
  127. if($this->current && $child)
  128. {
  129. $this->expression = '';
  130. foreach($child as $k => $v)
  131. {
  132. if($k == 'self')
  133. {
  134. $this->attribute($v, $this->current);
  135. }
  136. elseif($k == 'parent')
  137. {
  138. $parent = $this->current->parent();
  139. if(isset($v['number']) && $v['number'] >= 2)
  140. {
  141. for($i = 2; $i <= $v['number']; $i++)
  142. {
  143. $parent = $parent->parent();
  144. }
  145. }
  146. $this->attribute($v, $parent);
  147. }
  148. else
  149. {
  150. if(strpos($k, '|') !== false)
  151. {
  152. list($k, $index) = explode('|', $k);
  153. }
  154. else
  155. {
  156. $index = 0;
  157. if(isset($v['key']))
  158. {
  159. $index = $v['key'];unset($v['key']);
  160. }
  161. }
  162. $this->attribute($v, $this->current->find($k, $index));
  163. }
  164. }
  165. }
  166. }
  167. /**
  168. * filter
  169. *
  170. * @return mixed
  171. */
  172. private function filter()
  173. {
  174. $dom = $this->dom->find('filter');
  175. foreach($dom as $k => $v)
  176. {
  177. $dom[$k]->outertext = '';
  178. }
  179. }
  180. /**
  181. * import
  182. *
  183. * @return mixed
  184. */
  185. private function import()
  186. {
  187. $dom = $this->dom->find('.include');
  188. foreach($dom as $k => $v)
  189. {
  190. if(isset($v->path)) $v->file = $v->path . $v->file;
  191. $v->outertext = $this->compile->load($v->file, $v->system);
  192. }
  193. }
  194. /**
  195. * attribute
  196. * @param array|string $value
  197. * @param object $dom
  198. * @param array $data
  199. *
  200. * @return mixed
  201. */
  202. private function attribute($value, $dom, $data = false)
  203. {
  204. if(is_array($value))
  205. {
  206. foreach($value as $k => $v)
  207. {
  208. if($k == 'html')
  209. {
  210. $data = $v;
  211. }
  212. else
  213. {
  214. $index = 0;
  215. if(strpos($k, '|') !== false)
  216. {
  217. list($k, $index) = explode('|', $k);
  218. }
  219. $this->plugin($dom, $k, $v, $index);
  220. }
  221. }
  222. if($this->temp) $this->temp = null;
  223. }
  224. else
  225. {
  226. $data = $value;
  227. }
  228. //if($data) $dom->outertext = $this->compile->handle($data, $dom->outertext);
  229. if($data) $dom->innertext = $this->compile->content($data);
  230. }
  231. /**
  232. * plugin
  233. * @param object $dom
  234. * @param string $attribute
  235. * @param string $value
  236. * @param int $index
  237. *
  238. * @return mixed
  239. */
  240. private function plugin($dom, $attribute, $value, $index = 0)
  241. {
  242. if(is_array($value))
  243. {
  244. $key = '{data}';
  245. $child = $dom->find($attribute, $index);
  246. if(!$child)
  247. {
  248. if(!$this->temp)
  249. {
  250. # 这里因为dom类对append支持的不好,所以只能重新读取一次
  251. if($index > 0)
  252. {
  253. # 当有一个节点时,后续的所有节点均使用第一个节点为模板
  254. $this->temp = HtmlDomParser::str_get_html($dom->innertext);
  255. }
  256. else
  257. {
  258. # 清空原有父节点的全部内容
  259. $dom->innertext = '';
  260. # 当没有节点时,直接创建
  261. $this->temp = HtmlDomParser::str_get_html("<$attribute></$attribute>");
  262. }
  263. }
  264. $child = $this->temp->find($attribute, 0);
  265. }
  266. /*
  267. foreach($value as $k => $v)
  268. {
  269. if($k != $key)
  270. {
  271. $this->plugin($child, $k, $v);
  272. }
  273. }
  274. */
  275. $this->attribute($value, $child);
  276. if(isset($value[$key]))
  277. {
  278. $dom->innertext = $this->compile->logic($value[$key], $child->outertext);
  279. }
  280. if($this->temp)
  281. {
  282. $dom->innertext .= $this->temp->innertext;
  283. }
  284. return;
  285. }
  286. if($attribute == 'html')
  287. {
  288. $attribute = 'innertext';
  289. }
  290. # modal
  291. elseif($attribute == 'modal')
  292. {
  293. $dom->{'data-am-modal'} = '{target: \'#maze_modal\', closeViaDimmer: 0}';
  294. $dom->{'href'} = '#maze_modal';
  295. $dom->{'data-toggle'} = 'modal';
  296. $attribute = 'onclick';
  297. if(strpos($value, '|') !== false)
  298. {
  299. $temp = explode('|', $value);
  300. $dom->{'data-modal-title'} = $temp[0];
  301. $dom->{'data-modal-content'} = $temp[1];
  302. }
  303. else
  304. {
  305. $dom->{'data-modal-title'} = '提醒您';
  306. $dom->{'data-modal-content'} = $value;
  307. }
  308. $value = '$(\'#maze_modal_title\').html($(this).attr(\'data-modal-title\'));$(\'#maze_modal_body\').html($(this).attr(\'data-modal-content\'))';
  309. }
  310. $value = $this->compile->content($value, $this->data);
  311. if(strpos($attribute, '++') !== false)
  312. {
  313. $attribute = str_replace('++', '', $attribute);
  314. if(!strstr($dom->$attribute, $value))
  315. {
  316. $dom->$attribute = $dom->$attribute . $value;
  317. }
  318. }
  319. elseif(strpos($attribute, '--') !== false)
  320. {
  321. $attribute = str_replace('--', '', $attribute);
  322. if(strpos($dom->$attribute, $value) !== false)
  323. {
  324. $dom->$attribute = str_replace($value, '', $dom->$attribute);
  325. }
  326. }
  327. else
  328. {
  329. $dom->$attribute = $value;
  330. }
  331. }
  332. /**
  333. * parse
  334. * @param string $parse
  335. *
  336. * @return mixed
  337. */
  338. private function parse(& $parse)
  339. {
  340. if(strpos($parse, '@') !== false)
  341. {
  342. $temp = explode('@', $parse);
  343. $parse = $temp[0];
  344. $array = array
  345. (
  346. 'html' => 'innertext',
  347. );
  348. $this->attr = isset($array[$temp[1]]) ? $array[$temp[1]] : $temp[1];
  349. }
  350. }
  351. /**
  352. * current
  353. * @param array $parse
  354. *
  355. * @return mixed
  356. */
  357. private function current($parse)
  358. {
  359. //$this->attr = 'outertext';
  360. $this->attr = 'innertext';
  361. if(is_array($parse))
  362. {
  363. $this->parse($parse[0]);
  364. $this->current = $this->dom->find($parse[0], $parse[1]);
  365. }
  366. else
  367. {
  368. $this->parse($parse);
  369. $dom = $this->dom->find($parse);
  370. if($dom)
  371. {
  372. foreach($dom as $k => $v)
  373. {
  374. if($k == 0)
  375. {
  376. $this->current = $v;
  377. }
  378. else
  379. {
  380. $dom[$k]->outertext = '';
  381. }
  382. }
  383. }
  384. else
  385. {
  386. //Output::abert('dom_exists', $parse);
  387. Debug::log(Lang::get('dom_exists', $parse));
  388. }
  389. }
  390. if(!$this->current)
  391. {
  392. //Output::abert('dom_exists', $parse);
  393. Debug::log(Lang::get('dom_exists', $parse));
  394. }
  395. return $this;
  396. }
  397. /**
  398. * handle
  399. *
  400. * @return array
  401. */
  402. private function handle()
  403. {
  404. if($this->current)
  405. {
  406. //echo $this->current->outertext;die;
  407. $this->current->{$this->attr} = $this->compile->handle($this->data, $this->current->{$this->attr}, $this->expression);
  408. }
  409. }
  410. }