v1.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <?php
  2. /**
  3. * The picker widget class file of zin module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
  6. * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author sunhao<sunhao@easycorp.ltd>
  8. * @package zin
  9. * @link http://www.zentao.net
  10. */
  11. namespace zin;
  12. /**
  13. * 下拉选择器(picker)部件类。
  14. * The picker widget class.
  15. *
  16. * @author Hao Sun
  17. */
  18. class picker extends wg
  19. {
  20. /**
  21. * Define widget properties.
  22. *
  23. * @var array
  24. * @access protected
  25. */
  26. protected static $defineProps = array(
  27. 'id?: string', // 组件根元素的 ID。
  28. 'formID?: string', // 组件隐藏的表单元素 ID。
  29. 'className?: string|array', // 类名。
  30. 'style?: array', // 样式。
  31. 'width?: string|number', // 宽度。
  32. 'boxClass?: string|array', // 根节点类名。
  33. 'boxStyle?: string|array', // 根节点样式。
  34. 'tagName?: string', // 组件根元素的标签名。
  35. 'attrs?: array', // 附加到组件根元素上的属性。
  36. 'clickType?: "toggle"|"open"', // 点击类型,`toggle` 表示点击按钮时切换显示隐藏,`open` 表示点击按钮时只打。
  37. 'afterRender?: function', // 渲染完成后的回调函数。
  38. 'beforeDestroy?: function', // 销毁前的回调函数。
  39. 'name?: string', // 作为表单项的名称。
  40. 'value?: string|string[]', // 默认值。
  41. 'emptyValue?: string', // 允许的空值,使用逗号分隔多个允许的空值。
  42. 'display?: string|callback', // 触发器上显示的文本。
  43. 'onChange?: function', // 值变更回调函数。
  44. 'beforeChange?: function', // 值变更前的回调函数。
  45. 'disabled?: boolean', // 是否禁用。
  46. 'readonly?: boolean', // 是否只读。
  47. 'multiple?: boolean|number=false', // 是否允许选择多个值,如果指定为数字,则限制多选的数目,默认 `false`。
  48. 'toolbar?: boolean|array', // 设置工具栏。
  49. 'required?: boolean', // 是否必选(不允许空值,不可以被清除)。
  50. 'placeholder?: string', // 选择框上的占位文本。
  51. 'valueSplitter?: string', // 多个值的分隔字符串,默认为 `,`。
  52. 'items: string|array|function', // 列表项或表项获取方法。
  53. 'pinyinKeys?: bool=true', // 启用拼音。
  54. 'menu?: array', // 附加的菜单选项。
  55. 'tree?: array|bool', // 是否启用树形菜单样式。
  56. 'hotkey?: boolean', // 是否启用快捷键。
  57. 'cache?: boolean', // 当使用动态选项列表时是否启用缓存,默认 true。
  58. 'search?: boolean|number', // 是否启用搜索。
  59. 'searchDelay?: number', // 搜索延迟时间,单位:毫秒。
  60. 'searchHint?: string', // 搜索提示文本。
  61. 'searchEmptyHint?: string', // 搜索不到匹配项的提示。
  62. 'shareSelections?: string', // 共享选中状态。
  63. 'onDeselect?: function', // 当取消选择值时的回调函数。
  64. 'onSelect?: function', // 当选择值时的回调函数。
  65. 'onClear?: function', // 当清空值时的回调函数。
  66. 'popContainer?: string', // 下拉面板容器元素。
  67. 'popWidth?: number|"auto"|"100%"', // 菜单宽度,如果设置为 `'100%'` 则与选择框宽度一致,默认 `'100%'`。
  68. 'popHeight?: number|"auto"', // 菜单高度,默认 `'auto'`。
  69. 'popMaxHeight?: number', // 菜单最大高度,默认 `300`。
  70. 'popMinHeight?: number', // 菜单最小高度,默认 `32`。
  71. 'popMaxWidth?: number', // 菜单最大宽度,当宽度设置为 `'auto'` 时生效。
  72. 'popMinWidth?: number', // 菜单最小宽度,当宽度设置为 `'auto'` 时生效,默认 50。
  73. 'popPlacement?: "auto"|"bottom"|"top"|"bottom-start"|"top-end"', // 菜单方向,默认 `'auto'`。
  74. 'popClass?: string|array', // 菜单类名。
  75. 'popStyle?: array', // 菜单样式。
  76. 'onPopShow?: function', // 菜单显示时的回调函数。
  77. 'onPopShown?: function', // 菜单显示后的回调函数。
  78. 'onPopHide?: function', // 菜单隐藏时的回调函数。
  79. 'onPopHidden?: function', // 菜单隐藏后的回调函数。
  80. 'maxItemsCount?: int=200' // 最大显示条目数。
  81. );
  82. /**
  83. * Get picker component properties.
  84. *
  85. * @access protected
  86. * @return array
  87. */
  88. protected function getPickerProps()
  89. {
  90. list($pickerProps, $restProps) = $this->props->split(array_keys(static::definedPropsList()));
  91. $items = empty($pickerProps['items']) ? array() : $pickerProps['items'];
  92. if(is_array($items) && isset($items['url']) && isset($items['method'])) $items = (object)$items;
  93. $pickerItems = is_array($items) ? array() : $items;
  94. $hasZeroValue = false;
  95. $defaultValue = isset($pickerProps['value']) ? $pickerProps['value'] : (isset($pickerProps['defaultValue']) ? $pickerProps['defaultValue'] : '');
  96. $pinyinKeys = $this->prop('pinyinKeys');
  97. if(empty($items) && isset($pickerProps['value'])) $pickerProps['value'] = '';
  98. if(is_array($defaultValue)) $defaultValue = implode($this->prop('valueSplitter', ','), $defaultValue);
  99. if(is_array($items) && !empty($items))
  100. {
  101. $pinyinItems = ($pinyinKeys && !isset($item['keys']) && class_exists('common')) ? common::convert2Pinyin($items) : array();
  102. foreach($items as $key => $item)
  103. {
  104. if(!is_array($item)) $item = array('text' => $item, 'value' => $key);
  105. if(isset($item['value']) && !is_string($item['value'])) $item['value'] = strval($item['value']);
  106. if(isset($item['value']) && $item['value'] === '0') $hasZeroValue = true;
  107. if(!is_array($item['text'])) $item['keys'] = zget($pinyinItems, $item['text'], zget($item, 'keys', ''));
  108. if(is_array($item['text']) && isset($item['hint']) && !is_array($item['hint'])) $item['keys'] = zget($pinyinItems, $item['hint'], zget($item, 'keys', ''));
  109. $pickerItems[] = $item;
  110. }
  111. }
  112. if(!isset($pickerProps['emptyValue'])) $pickerProps['emptyValue'] = ($hasZeroValue || "$defaultValue" !== '0') ? '' : '0,';
  113. if(isset($pickerProps['id']))
  114. {
  115. $pickerProps['_id'] = $pickerProps['id'];
  116. unset($pickerProps['id']);
  117. }
  118. else
  119. {
  120. $pickerProps['_id'] = $this->gid . (isset($pickerProps['name']) ? ('_' . $pickerProps['name']) : '');
  121. }
  122. if(!isset($pickerProps['style'])) $pickerProps['style'] = array();
  123. if(!isset($pickerProps['class'])) $pickerProps['class'] = array();
  124. if(isset($pickerProps['width']))
  125. {
  126. $width = $pickerProps['width'];
  127. unset($pickerProps['width']);
  128. if(is_numeric($width)) $restProps['style']['width'] = "{$width}px";
  129. elseif(str_ends_with($width, 'px')) $restProps['style']['width'] = $width;
  130. else $restProps['class'][] = "w-$width";
  131. }
  132. if(isset($pickerProps['boxStyle']))
  133. {
  134. $restProps['style'] = array_merge($restProps['style'], $pickerProps['boxStyle']);
  135. unset($pickerProps['boxStyle']);
  136. }
  137. if(isset($pickerProps['boxClass']))
  138. {
  139. $restProps['class'][] = $pickerProps['boxClass'];
  140. unset($pickerProps['class']);
  141. }
  142. global $config;
  143. $name = isset($pickerProps['name']) ? $pickerProps['name'] : '';
  144. if(isset($config->moreLinks[$name])) $pickerItems = $config->moreLinks[$name];
  145. $pickerProps['_props'] = $restProps;
  146. $pickerProps['items'] = $pickerItems;
  147. $pickerProps['defaultValue'] = $defaultValue;
  148. return $pickerProps;
  149. }
  150. /**
  151. * Build the widget.
  152. *
  153. * @access protected
  154. * @return node
  155. */
  156. protected function build()
  157. {
  158. return zui::picker
  159. (
  160. set::_class('form-group-wrapper picker-box'),
  161. set::_map(array('value' => 'defaultValue', 'formID' => 'id')),
  162. set($this->getPickerProps()),
  163. $this->children()
  164. );
  165. }
  166. }