on.class.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. <?php
  2. /**
  3. * The events binding class file of zin lib.
  4. *
  5. * @copyright Copyright 2023 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
  6. * @author Hao Sun <sunhao@easycorp.ltd>
  7. * @package zin
  8. * @version $Id
  9. * @link https://www.zentao.net
  10. */
  11. namespace zin;
  12. require_once __DIR__ . DS . 'zin.func.php';
  13. require_once __DIR__ . DS . 'jscallback.class.php';
  14. use zin\node;
  15. /**
  16. * Events binding class.
  17. */
  18. class on extends jsCallback
  19. {
  20. /**
  21. * The event name.
  22. * 事件名称。
  23. *
  24. * @access public
  25. * @var string
  26. */
  27. public $event;
  28. /**
  29. * As a delegate event selector。
  30. * 作为委托事件选择器。
  31. *
  32. * @access public
  33. * @var array
  34. */
  35. public $selector;
  36. /**
  37. * Whether is compatible mode.
  38. * 是否为兼容模式。
  39. *
  40. * @access public
  41. * @var bool
  42. */
  43. public $compatible = false;
  44. /**
  45. * @var mixed[]
  46. */
  47. public $options = array();
  48. /**
  49. * The constructor.
  50. * 构造函数。
  51. *
  52. * @access public
  53. * @param string $event Event name.
  54. * @param string|null $selector As a delegate event selector.
  55. * @param array $options Event options.
  56. */
  57. public function __construct($event, $selector = null, $options = null)
  58. {
  59. parent::__construct('event', 'args');
  60. $options = $options ? $options : array();
  61. if(str_contains($event, '__'))
  62. {
  63. list($event, $flags) = explode('__', $event);
  64. if(str_contains($flags, 'stop')) $options['stop'] = true;
  65. if(str_contains($flags, 'prevent')) $options['prevent'] = true;
  66. if(str_contains($flags, 'self')) $options['self'] = true;
  67. }
  68. $this->options = $options;
  69. $this->selector = $selector;
  70. $this->event = $event;
  71. }
  72. /**
  73. * Set to prevent event default behavior.
  74. * 设置阻止事件默认行为选项。
  75. *
  76. * @access public
  77. * @param bool $prevent Whether prevent event default behavior.
  78. * @return self
  79. */
  80. public function prevent($prevent = true)
  81. {
  82. $this->options['prevent'] = $prevent;
  83. return $this;
  84. }
  85. /**
  86. * Set to stop event propagation.
  87. * 设置停止事件冒泡选项。
  88. *
  89. * @access public
  90. * @param bool $stop Whether stop event propagation.
  91. * @return self
  92. */
  93. public function stop($stop = true)
  94. {
  95. $this->options['stop'] = $stop;
  96. return $this;
  97. }
  98. /**
  99. * Set to only trigger event on self element.
  100. * 设置只在自身元素上触发事件选项。
  101. *
  102. * @access public
  103. * @param bool $self Whether only trigger event on self element.
  104. * @return self
  105. */
  106. public function self($self = true)
  107. {
  108. $this->options['self'] = $self;
  109. return $this;
  110. }
  111. /**
  112. * Set to only trigger event once.
  113. * 设置只触发一次事件选项。
  114. *
  115. * @access public
  116. * @param bool $once Whether only trigger event once.
  117. * @return self
  118. */
  119. public function once($once = true)
  120. {
  121. $this->options['once'] = $once;
  122. return $this;
  123. }
  124. /**
  125. * Set the selector.
  126. * 设置选择器。
  127. *
  128. * @access public
  129. * @param string $selector The selector.
  130. * @return self
  131. */
  132. public function selector($selector)
  133. {
  134. $this->selector = $selector;
  135. return $this;
  136. }
  137. /**
  138. * Convert to js code.
  139. * 转换为 js 代码。
  140. *
  141. * @access public
  142. * @param string $joiner The joiner of each line.
  143. * @return string
  144. */
  145. public function toJS($joiner = "\n")
  146. {
  147. if($this->event === 'init') return parent::buildBody($joiner);
  148. $options = $this->options;
  149. $bindMethod = (isset($options['once']) && $options['once']) ? 'one' : 'on';
  150. $selector = $this->selector ? (',' . json_encode($this->selector)) : '';
  151. $callback = parent::toJS($joiner);
  152. $events = array_map(function($event){return $event . '.zin.on';}, explode('_', $this->event));
  153. $events = implode(' ', $events);
  154. return "\$element.$bindMethod('$events'$selector,$callback);";
  155. }
  156. /**
  157. * Build body code.
  158. * 构建函数体代码。
  159. *
  160. * @access public
  161. * @param string $joiner The joiner of each line.
  162. * @return string
  163. * @override
  164. */
  165. public function buildBody($joiner = "\n")
  166. {
  167. $options = $this->options;
  168. $self = isset($options['self']) ? $options['self'] : false;
  169. $prevent = isset($options['prevent']) ? $options['prevent'] : false;
  170. $stop = isset($options['stop']) ? $options['stop'] : false;
  171. $arrow = $this->isArrowFunc;
  172. $codes = array();
  173. if(!$arrow) $codes[] = "const \$this = $(this);";
  174. $codes[] = "const target = event.target;";
  175. if($self && !$arrow) $codes[] = "if(target !== this) return;";
  176. if($prevent) $codes[] = "event.preventDefault();";
  177. if($stop) $codes[] = "event.stopPropagation();";
  178. $codes[] = parent::buildBody($joiner);
  179. return implode($joiner, $codes);
  180. }
  181. /**
  182. * Apply to node.
  183. * 应用到部件。
  184. *
  185. * @access public
  186. * @param node $node The node instance.
  187. * @param string $blockName The block name.
  188. * @return void
  189. * @override
  190. */
  191. public function apply($node, $blockName)
  192. {
  193. if($this->compatible)
  194. {
  195. $options = $this->options;
  196. $options['selector'] = $this->selector;
  197. $options['handler'] = parent::buildBody('');
  198. $node->bindEvent($this->event, $options);
  199. return;
  200. }
  201. $node->bindEvent($this->event, $this);
  202. }
  203. /**
  204. * Bind the "change" event to widget.
  205. * 绑定 "change" 事件到部件。
  206. *
  207. * @access public
  208. * @param null|string|jsCallback $selectorOrCallback
  209. * @param null|array|string $handlerOrOptions
  210. * @return on
  211. * @static
  212. */
  213. public static function change($selectorOrCallback = null, $handlerOrOptions = null)
  214. {
  215. return static::bind('change', $selectorOrCallback, $handlerOrOptions);
  216. }
  217. /**
  218. * Bind the "click" event to widget.
  219. * 绑定 "click" 事件到部件。
  220. *
  221. * @access public
  222. * @param null|string|jsCallback $selectorOrCallback
  223. * @param null|array|string $handlerOrOptions
  224. * @return on
  225. * @static
  226. */
  227. public static function click($selectorOrCallback = null, $handlerOrOptions = null)
  228. {
  229. return static::bind('click', $selectorOrCallback, $handlerOrOptions);
  230. }
  231. /**
  232. * Bind the "dbclick" event to widget.
  233. * 绑定 "dbclick" 事件到部件。
  234. *
  235. * @access public
  236. * @param null|string|jsCallback $selectorOrCallback
  237. * @param null|array|string $handlerOrOptions
  238. * @return on
  239. * @static
  240. */
  241. public static function dbclick($selectorOrCallback = null, $handlerOrOptions = null)
  242. {
  243. return static::bind('dbclick', $selectorOrCallback, $handlerOrOptions);
  244. }
  245. /**
  246. * Bind the "focus" event to widget.
  247. * 绑定 "focus" 事件到部件。
  248. *
  249. * @access public
  250. * @param null|string|jsCallback $selectorOrCallback
  251. * @param null|array|string $handlerOrOptions
  252. * @return on
  253. * @static
  254. */
  255. public static function mouseenter($selectorOrCallback = null, $handlerOrOptions = null)
  256. {
  257. return static::bind('mouseenter', $selectorOrCallback, $handlerOrOptions);
  258. }
  259. /**
  260. * Bind the "mouseleave" event to widget.
  261. * 绑定 "mouseleave" 事件到部件。
  262. *
  263. * @access public
  264. * @param null|string|jsCallback $selectorOrCallback
  265. * @param null|array|string $handlerOrOptions
  266. * @return on
  267. * @static
  268. */
  269. public static function mouseleave($selectorOrCallback = null, $handlerOrOptions = null)
  270. {
  271. return static::bind('mouseleave', $selectorOrCallback, $handlerOrOptions);
  272. }
  273. /**
  274. * Bind the "focus" event to widget.
  275. * 绑定 "focus" 事件到部件。
  276. *
  277. * @access public
  278. * @param null|string|jsCallback $selectorOrCallback
  279. * @param null|array|string $handlerOrOptions
  280. * @return on
  281. * @static
  282. */
  283. public static function inited($selectorOrCallback = null, $handlerOrOptions = null)
  284. {
  285. return static::bind('inited', $selectorOrCallback, $handlerOrOptions);
  286. }
  287. /**
  288. * Bind the "focus" event to widget.
  289. * 绑定 "focus" 事件到部件。
  290. *
  291. * @access public
  292. * @param null|string|jsCallback $selectorOrCallback
  293. * @param null|array|string $handlerOrOptions
  294. * @return on
  295. * @static
  296. * @param string $event
  297. */
  298. public static function bind($event, $selectorOrCallback = null, $handlerOrOptions = null)
  299. {
  300. if($selectorOrCallback instanceof jsCallback)
  301. {
  302. return static::fromCallback($selectorOrCallback, $event, null, $handlerOrOptions);
  303. }
  304. if($handlerOrOptions instanceof jsCallback)
  305. {
  306. return static::fromCallback($handlerOrOptions, $event, $selectorOrCallback);
  307. }
  308. return on($event, $selectorOrCallback, $handlerOrOptions);
  309. }
  310. /**
  311. * Create on instance from callback.
  312. * 从回调创建 on 实例。
  313. *
  314. * @access public
  315. * @param jsCallback $callback
  316. * @param string $event
  317. * @param string $selector
  318. * @param array $options
  319. * @return on
  320. * @static
  321. */
  322. public static function fromCallback($callback, $event, $selector = null, $options = null)
  323. {
  324. if(!($callback instanceof on))
  325. {
  326. $on = new on($event, $selector, $options);
  327. $on->appendCode($callback->buildBody());
  328. $on->args(...$callback->funcArgs);
  329. $on->name($callback->funcName);
  330. return $on;
  331. }
  332. $callback->event = $event;
  333. if(!is_null($selector)) $callback->selector = $selector;
  334. if(!is_null($options)) $callback->options = array_merge($callback->options, $options);
  335. return $callback;
  336. }
  337. /**
  338. * Bind event to widget with magic method.
  339. * 绑定事件到部件,使用魔术方法。
  340. *
  341. * @access public
  342. * @param string $event
  343. * @param array $args
  344. * @return on
  345. * @static
  346. */
  347. public static function __callStatic($event, $args)
  348. {
  349. list($selectorOrCallback, $options) = array_merge($args, array(null, null));
  350. return static::bind($event, $selectorOrCallback, $options);
  351. }
  352. }
  353. /**
  354. * Add event listener to widget element.
  355. *
  356. * @param string $event
  357. * @param null|string $selectorOrHandler
  358. * @param null|array|string $handlerOrOptions
  359. * @return on
  360. */
  361. function on($event, $selectorOrHandler = null, $handlerOrOptions = null)
  362. {
  363. $options = array();
  364. $selector = null;
  365. $handler = null;
  366. if(is_string($selectorOrHandler))
  367. {
  368. if(is_string($handlerOrOptions))
  369. {
  370. $selector = $selectorOrHandler;
  371. $handler = $handlerOrOptions;
  372. }
  373. else
  374. {
  375. if(str_contains('.#[', $selectorOrHandler[0])) $selector = $selectorOrHandler;
  376. else $handler = $selectorOrHandler;
  377. }
  378. }
  379. if(is_array($handlerOrOptions)) $options = array_merge($options, $handlerOrOptions);
  380. if(str_contains($event, '__'))
  381. {
  382. list($event, $flags) = explode('__', $event);
  383. if(str_contains($flags, 'stop')) $options['stop'] = true;
  384. if(str_contains($flags, 'prevent')) $options['prevent'] = true;
  385. if(str_contains($flags, 'self')) $options['self'] = true;
  386. }
  387. $on = new on($event, $selector, $options);
  388. if(!is_null($handler))
  389. {
  390. $on->compatible = true;
  391. $on->appendCode($handler);
  392. }
  393. return $on;
  394. }