resource-selector.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. (function (w) {
  2. let NONE = '';
  3. function ResourceSelector(options) {
  4. let Dcat = w.Dcat;
  5. options = $.extend({
  6. title: '选择', // 弹窗标题
  7. selector: '', // 选择按钮选择器
  8. column: '', // 字段名称
  9. source: '', // 资源地址
  10. maxItem: 1, // 最大选项数量,0为不限制
  11. area: ['80%', '90%'],
  12. queryName: '_resource_',
  13. items: {}, // 默认选中项,key => value 键值对
  14. placeholder: '', // input placeholder
  15. showCloseButton: false,
  16. lang: {
  17. close: Dcat.lang.close || '关闭',
  18. exceed_max_item: Dcat.lang.exceed_max_item || '您已超出最大可选择的数量',
  19. selected_options: Dcat.lang.selected_options || '已选中:num个选项',
  20. },
  21. displayerContainer: null, // 选项展示容器dom对象
  22. hiddenInput: null, // 隐藏表单dom对象
  23. displayer: null, // 自定义选中项渲染方法
  24. disabled: false,
  25. clearAllClass: '',
  26. clearOneClass: '',
  27. window: null,
  28. }, options);
  29. options.window = options.window || (top || w);
  30. let self = ResourceSelector,
  31. column = options.column,
  32. cls = column.replace(/[\[\]]*/g, '') + (Math.random().toString(36).substr(2)),
  33. layer = options.window.layer,
  34. $input = getQueryDomObject(options.displayerContainer) || $(options.selector).parents('.select-resource').find('div[name="' + column + '"]'),
  35. $hidden = getQueryDomObject(options.hiddenInput) || $('input[name="' + column + '"]'),
  36. tagClearClass = options.clearOneClass || (cls + '-tag-clear-button'),
  37. clearClass = options.clearAllClass || (cls + '-clear-button'),
  38. maxItem = options.maxItem,
  39. originalItems = options.items,
  40. iframeWin,
  41. layerIdx,
  42. $layerWin;
  43. options.clearOneClass = tagClearClass;
  44. options.clearAllClass = clearClass;
  45. $(options.selector).click(function () {
  46. if (options.disabled) return;
  47. if (layerIdx) {
  48. $layerWin.show();
  49. clickCheckedItems();
  50. return;
  51. }
  52. $(document).one('pjax:complete', function () {// 跳转新页面时移除弹窗
  53. layer.close(layerIdx);
  54. $layerWin.remove();
  55. layerIdx = $layerWin = null;
  56. });
  57. layerIdx = layer.open({
  58. type: 2,
  59. title: options.title,
  60. shadeClose: true,
  61. maxmin: false,
  62. resize: false,
  63. shade: false,
  64. scrollbar: false,
  65. skin: 'select-resource',
  66. area: formatArea(options.area),
  67. content: `${options.source}?${options.queryName}=1`,
  68. btn: options.showCloseButton ? [options.closeButtonText] : null,
  69. success: function (layero) {
  70. iframeWin = options.window[layero.find('iframe')[0]['name']];
  71. // 绑定勾选默认选项事件
  72. bindCheckedDefaultEvent(iframeWin);
  73. },
  74. yes: function () {
  75. $layerWin.hide();
  76. return false;
  77. },
  78. cancel: function () {
  79. $layerWin.hide();
  80. return false;
  81. }
  82. });
  83. $layerWin = options.window.$('#layui-layer' + layerIdx);
  84. });
  85. function getQueryDomObject(value) {
  86. if (! value) {
  87. return;
  88. }
  89. return typeof value === 'object' ? value : $(value);
  90. }
  91. /**
  92. * 多选
  93. */
  94. function multipleSelect($this) {
  95. let id = $this.data('id'),
  96. label = $this.data('label') || id,
  97. exist = Dcat.helpers.isset(originalItems, id);
  98. if ($this.prop('checked')) {
  99. if (!exist) {
  100. originalItems[id] = label;
  101. }
  102. } else if (exist) {
  103. delete originalItems[id];
  104. }
  105. if (maxItem > 0 && Dcat.helpers.len(originalItems) > maxItem) {
  106. unchecked($this);
  107. delete originalItems[id];
  108. // 多选项判断最大长度
  109. return Dcat.warning(options.exceedMaxItemTip);
  110. }
  111. renderTags(originalItems);
  112. }
  113. // 单选
  114. function select($this) {
  115. let id = $this.data('id'),
  116. label = $this.data('label') || id;
  117. getAllCheckboxes().each(function () {
  118. if ($(this).data('id') != id) {
  119. unchecked($(this));
  120. }
  121. });
  122. originalItems = {};
  123. if ($this.prop('checked')) {
  124. originalItems[id] = label;
  125. }
  126. renderTags(originalItems);
  127. }
  128. /**
  129. * 显示选项内容
  130. *
  131. * @param items
  132. */
  133. function renderTags(items) {
  134. let ids = [];
  135. for (let id in items) {
  136. ids.push(id);
  137. }
  138. // 显示勾选的选项内容
  139. displayInputDiv(items);
  140. setSelectedId(ids);
  141. // 绑定清除事件
  142. $('.' + clearClass).click(clearAllTags);
  143. $('.' + tagClearClass).click(clearTag);
  144. }
  145. function setSelectedId(ids) {
  146. $hidden.val(ids.length ? ids.join(',') : NONE);
  147. }
  148. /**
  149. * 显示勾选的选项内容
  150. */
  151. function displayInputDiv(tag) {
  152. if (options.displayer) {
  153. if (typeof options.displayer == 'string' && Dcat.helpers.isset(self.displayers, options.displayer)) {
  154. return self.displayers[options.displayer](tag, $input, options);
  155. }
  156. // 自定义选中内容渲染
  157. return options.displayer(tag, $input, options);
  158. }
  159. return self.displayers.default(tag, $input, options);
  160. }
  161. function bindCheckedDefaultEvent(iframeWin) {
  162. Dcat.ready(function () {
  163. clickCheckedItems();
  164. getAllCheckboxes().change(function () {
  165. if (maxItem == 1) {
  166. select($(this));
  167. } else {
  168. multipleSelect($(this));
  169. }
  170. });
  171. if (maxItem == 1) {
  172. // 单选模式禁用全选按钮
  173. $(layer.getChildFrame('.checkbox-grid .select-all', layerIdx)).click(function () {
  174. return false;
  175. });
  176. }
  177. }, iframeWin);
  178. }
  179. function unchecked($ckb) {
  180. $ckb.parents('tr').css('background-color', '');
  181. $ckb.prop('checked', false);
  182. }
  183. // 勾选默认选项
  184. function clickCheckedItems() {
  185. setTimeout(function () {
  186. let ckb = layer.getChildFrame('tbody .checkbox-grid input[type="checkbox"]:checked', layerIdx);
  187. unchecked(ckb);
  188. for (let id in originalItems) {
  189. layer.getChildFrame('.checkbox-grid input[data-id="'+id+'"]', layerIdx).click();
  190. }
  191. }, 10);
  192. }
  193. function getAllCheckboxes() {
  194. return $(layer.getChildFrame('.checkbox-grid input[type="checkbox"]:not(.select-all)', layerIdx));
  195. }
  196. /**
  197. * 清除所有选项
  198. */
  199. function clearTag() {
  200. delete originalItems[$(this).data('id')];
  201. renderTags(originalItems);
  202. }
  203. /**
  204. * 清除所有选项
  205. */
  206. function clearAllTags() {
  207. originalItems = {};
  208. renderTags(originalItems);
  209. }
  210. function formatArea(area) {
  211. if (w.screen.width <= 750) {
  212. return ['100%', '100%'];
  213. }
  214. return area;
  215. }
  216. renderTags(originalItems);
  217. }
  218. ResourceSelector.displayers = {
  219. default: function (tag, $input, opts) {
  220. let place = '<span class="default-text" style="opacity:0.75">' + (opts.placeholder || $input.attr('placeholder')) + '</span>',
  221. maxItem = opts.maxItem;
  222. function init() {
  223. if (! Dcat.helpers.len(tag)) {
  224. return $input.html(place);
  225. }
  226. if (maxItem == 1) {
  227. return $input.html(buildOne(tag[Object.keys(tag)[0]]));
  228. }
  229. $input.html(buildMany(tag));
  230. }
  231. function buildMany(tag) {
  232. let html = [];
  233. for (let i in tag) {
  234. if (maxItem > 2 || !maxItem) {
  235. let strVar = "";
  236. strVar += "<li class=\"select2-selection__choice\" >";
  237. strVar += tag[i] + " <span data-id=\"" + i + "\" class=\"select2-selection__choice__remove ";
  238. strVar += opts.clearOneClass +"\" role=\"presentation\"> ×</span>";
  239. strVar += "</li>";
  240. html.push(strVar);
  241. } else {
  242. html.push(
  243. "<a class='label label-primary'>" + tag[i] + " " +
  244. "<span data-id=" + i + " class='" + opts.clearOneClass +
  245. "' style='font-weight:bold;cursor:pointer;font-size:14px'>×</span></a>"
  246. )
  247. }
  248. }
  249. if (!(maxItem > 2 || !maxItem)) {
  250. return buildOne(html.join('&nbsp;'));
  251. }
  252. html.unshift('<span class="select2-selection__clear '+opts.clearAllClass+'">×</span>');
  253. html = '<ul class="select2-selection__rendered">' + html.join('') + '</ul>';
  254. return html;
  255. }
  256. /**
  257. * 单个选项样式
  258. *
  259. * @param tag
  260. * @returns {string}
  261. */
  262. function buildOne(tag) {
  263. let clearButton = "<div class='pull-right "+opts.clearAllClass+"' style='font-weight:bold;cursor:pointer'>×</div>";
  264. return ""+tag+""+clearButton;
  265. }
  266. init();
  267. },
  268. // list模式
  269. navList: function (tag, $input, opts) {
  270. let place = '<span style="opacity:0.75">' + (opts.placeholder || $input.attr('placeholder')) + '</span>',
  271. maxItem = opts.maxItem;
  272. function init() {
  273. let $app = $(opts.selector).parents('.select-resource').find('app');
  274. $app.html('');
  275. if (! Dcat.helpers.len(tag)) {
  276. return $input.html(place);
  277. }
  278. if (maxItem == 1) {
  279. return $input.html(buildOne(tag[Object.keys(tag)[0]]));
  280. }
  281. $input.html(buildOne(opts.lang.selected_options.replace(':num', Dcat.helpers.len(tag))));
  282. $app.html(buildMany(tag));
  283. }
  284. function buildMany(tag) {
  285. let html = [];
  286. for (let i in tag) {
  287. let strVar = "";
  288. strVar += "<li>";
  289. strVar += "<a class='pull-left'>" + tag[i] + "</a><a data-id='" + i + "' class='pull-right red text-danger ";
  290. strVar += opts.clearOneClass +"' ><i class='fa fa-close'></i></a>";
  291. strVar += "<span class='clearfix'></span></li>";
  292. html.push(strVar);
  293. }
  294. html = '<ul class="nav nav-pills nav-stacked" >' + html.join('') + '</ul>';
  295. return html;
  296. }
  297. function buildOne(tag) {
  298. let clearButton = "<div class='pull-right "+opts.clearAllClass+"' style='font-weight:bold;cursor:pointer'>×</div>";
  299. return tag + clearButton;
  300. }
  301. init();
  302. }
  303. };
  304. Dcat.ResourceSelector = ResourceSelector;
  305. })(window);