resource-selector.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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.parents('.input-group').find('input[type="hidden"]'),
  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. $('html').css({'overflow': 'auto'});
  73. // 绑定勾选默认选项事件
  74. bindCheckedDefaultEvent(iframeWin);
  75. },
  76. yes: function () {
  77. $layerWin.hide();
  78. return false;
  79. },
  80. cancel: function () {
  81. $layerWin.hide();
  82. return false;
  83. }
  84. });
  85. $layerWin = options.window.$('#layui-layer' + layerIdx);
  86. });
  87. function getQueryDomObject(value) {
  88. if (! value) {
  89. return;
  90. }
  91. return typeof value === 'object' ? value : $(value);
  92. }
  93. /**
  94. * 多选
  95. */
  96. function multipleSelect($this) {
  97. let id = $this.data('id'),
  98. label = $this.data('label') || id,
  99. exist = Dcat.helpers.isset(originalItems, id);
  100. if ($this.prop('checked')) {
  101. if (!exist) {
  102. originalItems[id] = label;
  103. }
  104. } else if (exist) {
  105. delete originalItems[id];
  106. }
  107. if (maxItem > 0 && Dcat.helpers.len(originalItems) > maxItem) {
  108. unchecked($this);
  109. delete originalItems[id];
  110. // 多选项判断最大长度
  111. return Dcat.warning(options.lang.exceed_max_item);
  112. }
  113. renderTags(originalItems);
  114. }
  115. // 单选
  116. function select($this) {
  117. let id = $this.data('id'),
  118. label = $this.data('label') || id;
  119. getAllCheckboxes().each(function () {
  120. if ($(this).data('id') != id) {
  121. unchecked($(this));
  122. }
  123. });
  124. originalItems = {};
  125. if ($this.prop('checked')) {
  126. originalItems[id] = label;
  127. }
  128. renderTags(originalItems);
  129. }
  130. /**
  131. * 显示选项内容
  132. *
  133. * @param items
  134. */
  135. function renderTags(items) {
  136. let ids = [];
  137. for (let id in items) {
  138. ids.push(id);
  139. }
  140. // 显示勾选的选项内容
  141. displayInputDiv(items);
  142. setSelectedId(ids);
  143. // 绑定清除事件
  144. $('.' + clearClass).click(clearAllTags);
  145. $('.' + tagClearClass).click(clearTag);
  146. }
  147. function setSelectedId(ids) {
  148. $hidden.val(ids.length ? ids.join(',') : NONE);
  149. }
  150. /**
  151. * 显示勾选的选项内容
  152. */
  153. function displayInputDiv(tag) {
  154. if (options.displayer) {
  155. if (typeof options.displayer == 'string' && Dcat.helpers.isset(self.displayers, options.displayer)) {
  156. return self.displayers[options.displayer](tag, $input, options);
  157. }
  158. // 自定义选中内容渲染
  159. return options.displayer(tag, $input, options);
  160. }
  161. return self.displayers.default(tag, $input, options);
  162. }
  163. function bindCheckedDefaultEvent(iframeWin) {
  164. Dcat.ready(function () {
  165. clickCheckedItems();
  166. getAllCheckboxes().change(function () {
  167. if (maxItem == 1) {
  168. select($(this));
  169. } else {
  170. multipleSelect($(this));
  171. }
  172. });
  173. if (maxItem == 1) {
  174. // 单选模式禁用全选按钮
  175. $(layer.getChildFrame('.checkbox-grid .select-all', layerIdx)).click(function () {
  176. return false;
  177. });
  178. }
  179. }, iframeWin);
  180. }
  181. function unchecked($ckb) {
  182. $ckb.parents('tr').css('background-color', '');
  183. $ckb.prop('checked', false);
  184. }
  185. // 勾选默认选项
  186. function clickCheckedItems() {
  187. setTimeout(function () {
  188. let ckb = layer.getChildFrame('tbody .checkbox-grid input[type="checkbox"]:checked', layerIdx);
  189. unchecked(ckb);
  190. for (let id in originalItems) {
  191. layer.getChildFrame('.checkbox-grid input[data-id="'+id+'"]', layerIdx).click();
  192. }
  193. }, 10);
  194. }
  195. function getAllCheckboxes() {
  196. return $(layer.getChildFrame('.checkbox-grid input[type="checkbox"]:not(.select-all)', layerIdx));
  197. }
  198. /**
  199. * 清除所有选项
  200. */
  201. function clearTag() {
  202. delete originalItems[$(this).data('id')];
  203. renderTags(originalItems);
  204. }
  205. /**
  206. * 清除所有选项
  207. */
  208. function clearAllTags() {
  209. originalItems = {};
  210. renderTags(originalItems);
  211. }
  212. function formatArea(area) {
  213. if (w.screen.width <= 750) {
  214. return ['100%', '100%'];
  215. }
  216. return area;
  217. }
  218. renderTags(originalItems);
  219. }
  220. ResourceSelector.displayers = {
  221. default: function (tag, $input, opts) {
  222. let place = '<span class="default-text" style="opacity:0.75">' + (opts.placeholder || $input.attr('placeholder')) + '</span>',
  223. maxItem = opts.maxItem;
  224. function init() {
  225. if (! Dcat.helpers.len(tag)) {
  226. return $input.html(place);
  227. }
  228. if (maxItem == 1) {
  229. return $input.html(buildOne(tag[Object.keys(tag)[0]]));
  230. }
  231. $input.html(buildMany(tag));
  232. }
  233. function buildMany(tag) {
  234. let html = [];
  235. for (let i in tag) {
  236. if (maxItem > 2 || !maxItem) {
  237. let strVar = "";
  238. strVar += "<li class=\"select2-selection__choice\" >";
  239. strVar += tag[i] + " <span data-id=\"" + i + "\" class=\"select2-selection__choice__remove ";
  240. strVar += opts.clearOneClass +"\" role=\"presentation\"> ×</span>";
  241. strVar += "</li>";
  242. html.push(strVar);
  243. } else {
  244. html.push(
  245. "<a class='label label-primary'>" + tag[i] + " " +
  246. "<span data-id=" + i + " class='" + opts.clearOneClass +
  247. "' style='font-weight:bold;cursor:pointer;font-size:14px'>×</span></a>"
  248. )
  249. }
  250. }
  251. if (!(maxItem > 2 || !maxItem)) {
  252. return buildOne(html.join('&nbsp;'));
  253. }
  254. html.unshift('<span class="select2-selection__clear '+opts.clearAllClass+'">×</span>');
  255. html = '<ul class="select2-selection__rendered">' + html.join('') + '</ul>';
  256. return html;
  257. }
  258. /**
  259. * 单个选项样式
  260. *
  261. * @param tag
  262. * @returns {string}
  263. */
  264. function buildOne(tag) {
  265. let clearButton = "<div class='pull-right "+opts.clearAllClass+"' style='font-weight:bold;cursor:pointer'>×</div>";
  266. return ""+tag+""+clearButton;
  267. }
  268. init();
  269. },
  270. // list模式
  271. navList: function (tag, $input, opts) {
  272. let place = '<span style="opacity:0.75">' + (opts.placeholder || $input.attr('placeholder')) + '</span>',
  273. maxItem = opts.maxItem;
  274. function init() {
  275. let $app = $(opts.selector).parents('.select-resource').find('app');
  276. $app.html('');
  277. if (! Dcat.helpers.len(tag)) {
  278. return $input.html(place);
  279. }
  280. if (maxItem == 1) {
  281. return $input.html(buildOne(tag[Object.keys(tag)[0]]));
  282. }
  283. $input.html(buildOne(opts.lang.selected_options.replace(':num', Dcat.helpers.len(tag))));
  284. $app.html(buildMany(tag));
  285. }
  286. function buildMany(tag) {
  287. let html = [];
  288. for (let i in tag) {
  289. let strVar = "";
  290. strVar += "<li>";
  291. strVar += "<a class='pull-left'>" + tag[i] + "</a><a data-id='" + i + "' class='pull-right red text-danger ";
  292. strVar += opts.clearOneClass +"' ><i class='fa fa-close'></i></a>";
  293. strVar += "<span class='clearfix'></span></li>";
  294. html.push(strVar);
  295. }
  296. html = '<ul class="nav nav-pills nav-stacked" >' + html.join('') + '</ul>';
  297. return html;
  298. }
  299. function buildOne(tag) {
  300. let clearButton = "<div class='pull-right "+opts.clearAllClass+"' style='font-weight:bold;cursor:pointer'>×</div>";
  301. return tag + clearButton;
  302. }
  303. init();
  304. }
  305. };
  306. Dcat.ResourceSelector = ResourceSelector;
  307. })(window);