resource-selector.js 12 KB

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