PluginProbe
WPJAM Basic / trunk
WPJAM Basic vtrunk
wpjam-basic / static / script.js

script.js in WPJAM Basic trunk, at static/script.js

1,999 lines 61.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 jQuery(function($){
2 $.fn.wpjam_each = function(cb){
3 return this.each((i, el) => cb($(el), i));
4 };
5
6 $.fn.wpjam_on = function(name, selector, callback, options){
7 let cb = !_.isFunction(callback) && $.fn[callback] ? (e, ...args) => $(e.currentTarget)[callback](e, ...args) : callback;
8
9 let {type, wait=300, ...data} = options || {};
10
11 if(type == 'throttle'){
12 cb = _.throttle(cb, wait);
13 }else if(type == 'debounce' || ['submit', 'change', 'click'].includes(name)){
14 cb = _.debounce(cb, wait, true);
15 }
16
17 return this.on(name+'.wpjam', (!selector || selector === 'body') ? null : selector, data, cb);
18 };
19
20 $.fn.wpjam_init = function(){
21 let filter = this.is('body') ? ':not(form *)' : '';
22 let rules = $.fn.wpjam_init.rules = $.fn.wpjam_init.rules || [
23 [null, '[data-indeterminate]', $el => $el.prop('indeterminate', true).removeAttr('data-indeterminate')]
24 ];
25
26 filter && _.each(Object.keys($.fn), handle => {
27 if(handle.startsWith('wpjam_') && _.every(rules, (r) => r[0] !== handle)){
28 let {selector, events} = $.fn[handle];
29
30 rules.push([handle, selector]);
31
32 _.each(events, event => $('body').wpjam_on(event.name, event.selector || selector, handle, event));
33 }
34 });
35
36 _.each(rules, ([handle, sel, cb])=> sel && this.find(sel.split(',').map(s => s.trim()+filter).join(',')).wpjam_each($el => cb ? cb($el) : $el[handle]()));
37
38 filter && this.find('form').wpjam_each($el => $el.data('initialized') || $el.data('initialized', true).wpjam_init());
39
40 return this;
41 };
42
43 $.fn.wpjam_highlight = function(type){
44 if(type){
45 this.attr('data-highlight', type);
46
47 return type == 'delete' ? this : this.hide().fadeIn(1000);
48 }
49
50 return this.removeAttr('data-highlight');
51 };
52
53 $.fn.wpjam_remove = function(cb){
54 return this.fadeOut(400, ()=> this.remove() && cb && cb());
55 };
56
57 $.fn.wpjam_control = function(){
58 let $field = !this.data('type') && this.is(':checkbox, :radio') ? this.closest('.wpjam-choice') : [];
59
60 return $field[0] ? $field : this;
61 };
62
63 $.fn.wpjam_field = function(){
64 let {type, key, value, button_text: btn, multiple: mu, ...data} = this.data();
65
66 let id = this.attr('id');
67 let name = this.attr('name')+(mu ? '[]' : '');
68 let $wrap;
69
70 if(type == 'color'){
71 $wrap = this.attr('type', 'text').addClass('expandable').val(value).wpColorPicker().closest('.wp-picker-container');
72
73 $wrap.prepend($('<label>').append(['.before', '> button', '> span', '.after'].map(s => $wrap.find(s)))).append($wrap.next('.description'));
74
75 btn && $wrap.find('.wp-color-result-text').text(btn);
76 }else if(type == 'timestamp'){
77 if(value){
78 let pad2 = num => (num.toString().length < 2 ? '0' : '')+num;
79 let date = new Date(+value*1000);
80
81 this.val(date.getFullYear()+'-'+pad2(date.getMonth()+1)+'-'+pad2(date.getDate())+'T'+pad2(date.getHours())+':'+pad2(date.getMinutes()));
82 }
83
84 this.attr('type', 'datetime-local');
85 }else if(type == 'toggle'){
86 value && this.prop('checked', true);
87 }else if(['img', 'image', 'file'].includes(type)){
88 if(!this.closest('.wpjam-'+type)[0]){
89 $wrap = this.wrap('<div class="wpjam-'+type+'">').parent();
90
91 if(!wpjam.upload_files){
92 this.prop('disabled', true);
93 $wrap.addClass('disabled');
94 }
95
96 this.after('<a class="add-media button"><span class="dashicons dashicons-admin-media"></span>'+btn+'</a>');
97
98 (type == 'img' ? this.parent() : this.next('a.button')).on('click.wpjam', (e)=> {
99 $(e.target).is('.del-img') ? this.data('value', '').wpjam_field() : this.wpjam_media(value => this.data('value', value).wpjam_field());
100 });
101 }
102
103 if(type == 'img'){
104 this.prevAll('img, a.del-img')[value ? 'remove' : 'wpjam_remove']();
105 this.val(value ? value.value : '').before(value ? '<img src="'+value.url+data.thumb_args+'" /><a class="del-img dashicons dashicons-no-alt"></a>' : '');
106 }else{
107 this.val(value);
108 }
109 }else if(type == 'uploader'){
110 $wrap = this.add(this.prev('.before')).add(this.next('.after')).wrapAll('<div class="wpjam-uploader">').parent();
111
112 this.before($('<label class="button">'+btn+'</label>').append($('<input type="file" accept="'+this.attr('accept')+'" hidden>').on('change', e => {
113 e.target.files[0] && this.wpjam_upload(e.target.files[0]);
114 e.target.value = '';
115 })));
116
117 data.drag_drop && $wrap.addClass('drag-drop').append([
118 '<p class="drag-drop-info">'+wp.i18n.__('Drop files to upload', 'default')+'</p>',
119 $('<p class="drag-drop-buttons"></p>').append(this)
120 ]).on('dragover', e => {
121 e.preventDefault();
122 $wrap.addClass('drag-over');
123 }).on('dragleave drop', e => {
124 $wrap.removeClass('drag-over');
125 }).on('drop', e=> {
126 e.preventDefault();
127 this.wpjam_upload(e.originalEvent.dataTransfer.files[0]);
128 });
129
130 this.wpjam_label();
131 }else if(type == 'textarea'){
132 this.addClass('expandable');
133 }else if(type == 'editor'){
134 if(data.editor){
135 if(wp.editor){
136 wp.editor.remove(id);
137 wp.editor.initialize(id, {...data.editor, mediaButtons: wpjam.upload_files});
138
139 this.attr({rows: 10, cols: 40});
140 }else{
141 console.log('请在页面加载 add_action(\'admin_footer\', \'wp_enqueue_editor\');');
142 }
143 }
144 }else if(type == 'cascade'){
145 let keys = ['data-data_type', 'data-query_args', 'data-filter_key'];
146 let attr = _.object(keys, _.map(keys, k => this.attr(k)));
147
148 this.addClass('wpjam-cascade').removeAttr(keys.join(' '));
149
150 _.each(data.options, (options, i)=> {
151 let $select = $('<select>', {id: id+'_'+i, name: name+'[]'}).addClass('field-key-'+key+'_'+i).appendTo(this).wpjam_options(options);
152
153 if(options.length){
154 value[i] && $select.val(value[i]);
155 }else{
156 i > 0 && $select.addClass('hidden');
157 }
158
159 i > 0 && $select.attr(attr).wpjam_show_if(key+'_'+(i-1), '!=', '');
160 });
161 }else if(['select', 'radio', 'checkbox'].includes(type)){
162 let options = data.options || [];
163
164 if(data.custom){
165 let {title, by, key: ck, ...attr} = data.custom;
166
167 let keys = options.flatMap(o => o.options ? o.options.map(c => String(c.value)) : [String(o.value)]);
168 let diff = [].concat(value || []).filter(v => !keys.includes(String(v)));
169 let $input = $('<input>').attr({...attr, name, required: 'required'}).addClass('field-key-'+ck).wpjam_show_if(key, by);
170
171 this.wpjam_options([...options, {value: by, label: title}]);
172
173 if(diff.length){
174 $input.val(diff[0]);
175
176 value = mu ? [...[].concat(value).filter(v => keys.includes(String(v))), by] : by;
177 }
178
179 type === 'select' ? this.after(['&emsp;', $input]) : this.append($input);
180 }else{
181 this.wpjam_options(options);
182 }
183
184 if(this.is('select')){
185 this.val(value != null && this.find(`option[value="${value}"]`)[0] ? value : this.find('option:first').val());
186 }else{
187 let $btn = type === 'select' && $('<button>', {type: 'button', text: data.show_option_all || '请选择'}).prop('popoverTargetElement', this[0]).insertBefore(this.attr('popover', 'auto').wrap('<div class="mu-select"></div>'));
188
189 this.addClass('wpjam-choice direction-'+(data.direction || ($btn || data.sep ? 'column' : 'row')));
190
191 this.on('change.wpjam', 'input', (e)=> {
192 let $el = $(e.target);
193
194 $el.is(':checkbox') ? $el.trigger('validate.wpjam') : this.find('label').removeClass('checked');
195
196 $el.closest('label').toggleClass('checked', $el.is(':checked'));
197
198 $btn && $btn.text(this.find('label.checked').toArray().map(el => $(el).text().trim()).join(', ') || data.show_option_all || '请选择');
199 });
200
201 this.find(':checkbox')[0] && this.attr('data-validation', true).on('validate.wpjam', (e)=> {
202 let $el = $(e.target);
203
204 this.find(':checkbox').toArray().forEach(el => el.setCustomValidity(''));
205
206 _.each($el.is('input') ? [$el.is(':checked') ? 'max' : 'min'] : ['min', 'max'], type => {
207 let v = this.wpjam_schema(type+'Items');
208 let [c, m] = type === 'max' ? ['>', '最多'] : ['<', '至少'];
209
210 if(v && wpjam.compare(this.find(':checkbox:checked').length, c, v)){
211 let el = $el.is('input') ? $el[0] : this.find(':checkbox')[0];
212
213 return el.setCustomValidity(m+`选择${v}`), el.reportValidity(), false;
214 }
215 });
216 });
217
218 this.attr('id', id+'_options').find([].concat(value === null ? [] : value).map(v => `input[value="${v}"]`).join(',')).trigger("click");
219 }
220 }else{
221 this.is('.tiny-text, .small-text') && this.addClass('expandable');
222 }
223
224 if($wrap){
225 let show_if = $wrap.find('[data-show_if]').attr('data-show_if');
226
227 show_if && $wrap.attr('data-show_if', show_if);
228
229 $wrap.addClass(['disabled', 'readonly', 'hidden'].filter(v => this.hasClass(v)));
230 }
231
232 return this.removeAttr('data-value data-options data-custom');
233 };
234
235 $.fn.wpjam_field.selector = 'input[data-type], select[data-type], textarea[data-type], fieldset[data-type]';
236
237 $.fn.wpjam_options = function(options){
238 let $field = this.data('type') ? this : this.closest('[data-type]');
239
240 let {type, value, key, sep, multiple: mu} = $field.data();
241
242 let name = $field.attr('name')+(mu ? '[]' : '');
243 let select = $field.is('select') || type === 'cascade';
244
245 if(type === 'cascade'){
246 options = [{value: '', label: $field.data('show_option_all') || '请选择'}, ...options];
247 }
248
249 return this.append(options.map((opt, i) => {
250 if(opt.options){
251 let {options: go, data={}, ...attr} = opt;
252
253 return select ? $('<optgroup>').attr(attr).wpjam_data(data).appendTo(this).wpjam_options(go) : '';
254 }
255
256 let {label, alias, description, image, class: cls, data={}, ...attr} = opt;
257 let $el = select ? $('<option>', attr) : $('<label>').addClass(cls);
258
259 $el.wpjam_data(data);
260
261 if(description){
262 let $desc = $field.next('p.description');
263
264 ($desc[0] ? $desc : $('<p>').addClass('description').insertAfter($field)).append($('<span>').html(description).wpjam_show_if(key, opt.value));
265 }
266
267 if(select){
268 return $el.val(value !== null && (alias || []).includes(String(value)) ? value : opt.value).text(label);
269 }
270
271 let $input = $('<input>').addClass('field-key-'+key).attr(attr).attr({
272 name,
273 type: mu ? 'checkbox' : 'radio',
274 id: $field.attr('id')+'_'+attr.value
275 });
276
277 $el.attr('for', $input.attr('id')).append($input);
278
279 image && $el.addClass('image-'+$input.attr('type')).append(([].concat(image)).slice(0, 2).map(src => $('<img>').attr({src, alt: label})));
280
281 return $el.append(label).after(select || i == options.length - 1 ? '' : sep);
282 }));
283 };
284
285 $.fn.wpjam_upload = function(file){
286 let {max_size, key: name, nonce} = this.data();
287
288 if(max_size && file.size > max_size){
289 return alert('文件大小不能�
290 '+Math.round(max_size/1024/1024)+'MB');
291 }
292
293 this.after('<div class="media-item"><div class="progress"><div class="percent">0%</div><div class="bar"></div></div></div>').prev('span').remove();
294
295 let data = new FormData();
296 let xhr = new XMLHttpRequest();
297
298 _.each(wpjam.with_page({
299 name,
300 accept: this.attr('accept'),
301 action: 'wpjam-upload',
302 [name]: file,
303 _ajax_nonce: nonce
304 }), (v, k)=> data.append(k, v));
305
306 xhr.upload.onprogress = e => {
307 let p = Math.round(e.loaded/e.total*100);
308
309 this.next('.media-item').find('.bar').width(p*2).end().find('.percent').text(p+'%');
310 };
311
312 xhr.onload = ()=> {
313 let res = JSON.parse(xhr.responseText);
314
315 res.errcode ? alert(res.errmsg) : this.val(res.path).wpjam_label();
316
317 this.next('.media-item').remove();
318 };
319
320 xhr.open('POST', ajaxurl);
321 xhr.send(data);
322 }
323
324 $.fn.wpjam_label = function(){
325 let $label = this.prev('span.query-label');
326
327 if($label[0]){
328 $label.next('input').val('').change().end().wpjam_remove();
329 }else{
330 let tag = this.hasClass('tag-input');
331 let label = this.data('label') || (this.data('type') === 'uploader' ? this.val().split('/').pop() : tag && this.val());
332
333 label && this.before($('<span>', {class:'query-label'}).append([
334 $('<span>', {class:'dashicons del-item'}).on('click', ()=> this.wpjam_label()),
335 tag ? label : $('<span>', {class:'truncate-text', text: label}),
336 ]).addClass(!tag && this.data('class'))).removeData('label').removeAttr('data-label');
337 }
338 };
339
340 $.fn.wpjam_show_if = function(...args){
341 if(args.length > 1){
342 return this.wpjam_data({show_if: _.object(['key', ...(args.length > 2 ? ['compare'] : []), 'value'], args)});
343 }
344
345 let show_if = this.data('show_if');
346
347 if(!show_if){
348 return this;
349 }
350
351 if(!args.length){
352 let key = show_if.key;
353 let sk = show_if.current?.includes('__') && show_if.current.split('__').slice(0,-1).concat(key).join('__');
354 let sib = sk && this.closest('form').find('.field-key-'+sk)[0];
355 let dep = sib || this.closest('form').find('.field-key-'+key)[0] || $('.field-key-'+key)[0] || $('#'+key)[0];
356 let $el = dep ? $(dep).wpjam_control() : '';
357
358 if(dep){
359 this.addClass('dep-on-'+($el.data('dep-id') || $el.attr('data-dep-id', 'dep-'+$.guid++).data('dep-id')));
360
361 if(sib){
362 this.data('show_if', {...show_if, key: sk});
363 }else{
364 sk && this.wpjam_show_if($el.wpjam_val());
365 }
366 }
367
368 return this;
369 }
370
371 let val = args[0];
372 let show = val === null ? false : wpjam.compare(val, show_if);
373
374 this.add(this.nextUntil(':not(br, .after, p.description)')).add(this.prev('.before')).toggleClass('hidden', !show);
375
376 if(this.is('option')){
377 this.prop('disabled', !show).is(':selected') && !show && this.closest('select').prop('selectedIndex', 0).wpjam_depend();
378 }else{
379 (this.is(':input') ? this : this.find(':input')).wpjam_each($el => {
380 $el.closest('.disabled')[0] || $el.prop('disabled', !show);
381
382 if($el.is(this) || $el.parent().is(this)){
383 let {filter_key: fk, query_args: qv} = $el.data() || {};
384
385 if(fk && qv && (!_.has(qv, fk) || (!$el.hasClass('hidden') && val !== null && qv[fk] !== val))){
386 $el.data('query_args', {...qv, [fk] : val ?? ''});
387
388 if(_.has(qv, fk)){
389 if($el.is('select')){
390 return $el.empty().wpjam_query().then(items => (items.length ? $el.wpjam_options(items) : $el.addClass('hidden')).wpjam_depend());
391 }
392
393 $el.is('input') && $el.val('').wpjam_label();
394 }
395 }
396 }
397
398 return $el.wpjam_depend();
399 });
400 }
401
402 return this;
403 };
404
405 $.fn.wpjam_show_if.selector = '[data-show_if]';
406
407 $.fn.wpjam_data_type = function(){
408 let $mu = this.closest('.mu-text');
409 let $hidden = !$mu[0] && this.data('filterable') && $('<input>',{type: 'hidden', name: this.attr('name'), value: this.val()}).insertAfter(this.removeAttr('name'));
410
411 if(!this.hasClass('mix-tag')){
412 this.data('label') && ($hidden ? this.val(this.data('label')) : this.wpjam_label());
413 }
414
415 return this.autocomplete({
416 minLength: 0,
417 delay: 400,
418 source: (request, response)=> {
419 let items = this.data('items');
420
421 if(items){
422 let term = request.term.toLowerCase();
423 let exclude = $mu.wpjam_schema('uniqueItems') ? $mu.wpjam_val() : [];
424
425 response(_.filter(items, item => {
426 if(exclude.includes(item.value)){
427 return false;
428 }
429
430 return !term || item.label.toLowerCase().includes(term) || item.value.toLowerCase().includes(term);
431 }));
432 }else{
433 this.wpjam_query(request.term).then(items => response(items));
434 }
435 },
436 search: (e, ui)=> {
437 if(!this.val() && _.isMatch(e.originalEvent, {type: 'keydown', key: 'Backspace'})){
438 return false;
439 }
440 },
441 select: (e, ui)=> {
442 if(this.hasClass('mix-tag')){
443 e.preventDefault();
444 this.wpjam_mix_tag('add', ui.item);
445
446 return false;
447 }else if($hidden){
448 this.val(ui.item.label);
449 $hidden.val(ui.item.value);
450 }else{
451 ui.item && this.val(ui.item.value).data('label', ui.item.label).wpjam_label();
452 }
453 },
454 change: (e, ui)=> {
455 this.trigger('change.wpjam');
456 }
457 }).on('click', (e)=> {
458 this.autocomplete('search');
459 }).on('keydown', (e)=> {
460 !this.val() && e.key === 'Backspace' && this.autocomplete('close');
461 }).on('input', (e)=>{
462 $hidden && $hidden.val(this.val());
463 });
464 };
465
466 $.fn.wpjam_data_type.selector = 'input[data-data_type][data-query_args], input[data-items]';
467
468 $.fn.wpjam_depend = function(){
469 let $el = this.wpjam_control();
470 let val = $el.wpjam_val();
471 let id = $el.data('dep-id');
472
473 id && $('.dep-on-'+id).wpjam_each($el => $el.wpjam_show_if(val));
474 };
475
476 $.fn.wpjam_depend.selector = '[data-dep-id]';
477 $.fn.wpjam_depend.events = [{name: 'change', selector: ':input[data-dep-id], [data-dep-id] :input'}];
478
479 $.fn.wpjam_action = function(e){
480 let type = this.is('#wpjam_option') ? 'option' : (this.is('#wpjam_form, .wpjam-button') ? 'page' : 'list-table');
481 let data = this.data();
482 let $form, $ae, title;
483
484 if(this.is('form')){
485 $ae = $(document.activeElement);
486 $ae = $ae.is(':submit') ? $ae : this.find(':submit').first().focus();
487 $form = this;
488 title = $ae.val();
489
490 if((type == 'option' && $ae.attr('name') === 'reset') ? !confirm('确定要'+title+'吗?') : !this.wpjam_validate()){
491 return false;
492 }
493
494 $ae.is('body') || $ae.after(wpjam.spinner);
495 }else{
496 $form = this.closest('form');
497 title = data.page_title || this.attr('title') || data.title;
498
499 if(data.confirm && (data.action == 'delete' ? !showNotice.warn() : !confirm('确定要'+title+'吗?'))){
500 return false;
501 }
502 }
503
504 let indeterminate = $form.find('input[type="checkbox"]:indeterminate').toArray().map(cb => `${encodeURIComponent(cb.name)}=${encodeURIComponent(cb.value)}`).join('&');
505
506 return wpjam.action(type, {
507 ...(type === 'page' && {page_action: data.action}),
508 ...(type === 'list-table' && {list_action: data.action, ..._.pick(data, ['bulk', 'id', 'ids'])}),
509 ...($ae ? {
510 action_type: 'submit',
511 submit: $ae.attr('name'),
512 data: $form.serialize(),
513 defaults: data.data || {},
514 $ae
515 } : {
516 action_type: data.direct ? 'direct' : 'form',
517 data: data.data || {},
518 form_data: $.param(wpjam.parse_params($form.serialize(), true))
519 }),
520 page_title: title,
521 _ajax_nonce: data.nonce,
522 indeterminate
523 }) && false;
524 }
525
526 $.fn.wpjam_action.events = [
527 {name: 'click', selector: '.wpjam-button, .list-table-action'},
528 {name: 'submit', selector: '#wpjam_form, #wpjam_option, #list_table_action_form'},
529 ];
530
531 $.fn.wpjam_query = function(term){
532 let {data_type, query_args} = this.data();
533
534 if(term){
535 query_args.search = term;
536 }
537
538 let $mu = this.closest('.mu-text');
539
540 if($mu.wpjam_schema('uniqueItems')){
541 query_args.exclude = $mu.wpjam_val();
542 }
543
544 return wpjam.post({
545 action: 'wpjam-query',
546 _ajax_nonce: (this.is('select') ? this.parent() : this).data('query_nonce'),
547 data_type,
548 query_args
549 }).then(data => data.errcode ? (data.errmsg && alert(data.errmsg), Promise.reject(data)) : data.items);
550 }
551
552 $.fn.wpjam_mix_tag = function(e, ...args){
553 let is_e = e ? _.isObject(e) : false;
554 let action = is_e ? (e.data.action || e.type) : e;
555
556 if(action){
557 if(action == 'keydown'){
558 if(e.key === 'Enter'){
559 e.preventDefault();
560 }
561 }
562
563 let $field, $editor, $hidden;
564
565 if(this.hasClass('mix-tag-editor')){
566 $editor = this;
567 $hidden = this.prev('input[type=hidden]');
568 $field = $hidden.prev('input');
569 }else{
570 $field = this;
571 $hidden = this.next('input[type=hidden]');
572 $editor = $hidden.next('.mix-tag-editor');
573 }
574
575 let sel = window.getSelection();
576 let range, node, word;
577
578 if(sel.rangeCount){
579 range = sel.getRangeAt(0);
580 node = range.startContainer;
581
582 if(node){
583 if($editor[0].contains(node)){
584 $editor.data('range', range);
585 }else{
586 range = $editor.data('range');
587 node = range ? range.startContainer : null;
588 }
589 }
590
591 if(node && node.nodeType === Node.TEXT_NODE){
592 let sep = [...($field.data('sep') || []), ' '];
593 let i = range.startOffset - 1;
594
595 while(i >= 0 && !sep.includes(node.textContent[i])){
596 i--;
597 }
598
599 word = node.textContent.substring(i + 1, range.startOffset).trim();
600 }
601 }
602
603 if(action == 'add'){
604 let $tag = $('<span class="query-label" contenteditable="false" data-value="'+args[0].value+'">'+args[0].label+'</span>');
605 let blank = document.createTextNode(' ');
606
607 if(word){
608 range.setStart(node, range.startOffset - word.length);
609 range.deleteContents();
610 }
611
612 range.insertNode($tag[0]);
613 range.setStartAfter($tag[0]);
614 $tag.after(blank);
615 range.setStartAfter(blank);
616 range.collapse(true);
617
618 $editor.trigger('focus');
619
620 sel.removeAllRanges();
621 sel.addRange(range);
622 }else{
623 $field.autocomplete('option', 'position', {my: 'left top', at: 'left bottom', of: e}).autocomplete('option', 'classes', {'ui-autocomplete': 'mix-tag-autocomplete'});
624 $field.val(word).autocomplete('search', word);
625
626 if(action == 'click'){
627 return false;
628 }
629 }
630
631 let parts = [];
632
633 $editor.contents().each(function(){
634 if(this.nodeType === Node.TEXT_NODE){
635 parts.push(this.textContent);
636 }else if(this.nodeType === Node.ELEMENT_NODE && $(this).hasClass('query-label')){
637 parts.push($(this).data('value'));
638 }
639 });
640
641 return $hidden.val(parts.join(' '));
642 }
643
644 this.css({position: 'absolute', left: '-9999px', width: '1px'});
645
646 let $hidden = $('<input>', {type: 'hidden', name: this.attr('name'), value: this.val()}).insertAfter(this.removeAttr('name'));
647 let $editor = $('<div>', {class: 'mix-tag-editor', contenteditable: 'true'}).insertAfter($hidden);
648 let value = this.data('value');
649
650 value && value.forEach(item => {
651 if(typeof item === 'object'){
652 $('<span class="query-label" contenteditable="false" data-value="'+item.value+'">'+item.label+'</span>').appendTo($editor);
653 }else{
654 $editor.append(document.createTextNode(item));
655 }
656 });
657
658 return this;
659 };
660
661 $.fn.wpjam_mix_tag.selector = 'input.mix-tag[data-items], input.mix-tag[data-data_type]';
662 $.fn.wpjam_mix_tag.events = [
663 {name: 'input', selector: '.mix-tag-editor'},
664 {name: 'click', selector: '.mix-tag-editor'},
665 {name: 'keydown', selector: '.mix-tag-editor'}
666 ];
667
668 $.fn.wpjam_mu = function(e, ...args){
669 let is_e = e ? _.isObject(e) : false;
670 let action = is_e ? (e.data.action || e.type) : e;
671 let $mu = this.closest('.mu');
672 let type = $mu.data('type').substring(3);
673
674 if(action == 'new_item'){
675 if($mu.wpjam_mu('rest', true) <= 0){
676 is_e && e.type === 'autocompleteselect' && (args[0].item = '');
677 return false;
678 }
679
680 if(['img', 'image', 'file'].includes(type)){
681 $mu.wpjam_media(value => $mu.wpjam_mu('add_item', value));
682 }else{
683 let $items = $mu.children();
684
685 if($items.length >= 2 && !$items.eq(-2).wpjam_mu('validate')){
686 return false;
687 }
688
689 $mu.wpjam_mu('add_item');
690 }
691
692 if($mu.wpjam_schema('uniqueItems')){
693 let value = $mu.wpjam_val();
694
695 if(value && _.uniq(value).length !== value.length){
696 alert('不�
697 �许重复');
698 }
699 }
700
701 return is_e ? false : true;
702 }else if(action == 'add_item'){
703 let $tmpl = $mu.children().last();
704 let $new = $tmpl.clone().find('.new-item, span.query-label').remove().end().insertBefore($tmpl);
705
706 let {value, label, url} = _.isObject(args[0]) ? args[0] : {value: args[0]};
707
708 if(['img', 'image', 'file'].includes(type)){
709 type == 'img' && url && $new.prepend($('<img>', {src: url+$new.find('input').data('thumb_args'), 'data-preview':url}));
710
711 $new.find('input').val(value);
712 }else if(type == 'text'){
713 if(value){
714 $new.find(':input').val(value).data(label ? {label} : {}).wpjam_label();
715 }else{
716 $tmpl.find(':input').is(':visible') && $new.insertAfter($tmpl).find(':input').val('').after($tmpl.find('.new-item'));
717 }
718 }else if(type == 'fields'){
719 $new.wpjam_mu('template').prevAll().wpjam_each($el => $el.wpjam_mu('tag_label'));
720 }
721
722 _.isUndefined(value) && $new.wpjam_mu('focus');
723
724 $mu.wpjam_mu('rest');
725
726 return $new.wpjam_init();
727 }else if(action == 'del_item'){
728 return this.closest('.mu-item').wpjam_remove(()=> $mu.wpjam_mu('rest')), false;
729 }else if(action == 'rest'){
730 let max = $mu.wpjam_schema('maxItems');
731 let rest = max ? (max - ($mu.children().length - (['img', 'fields', 'text'].includes(type) ? 1 : 0))) : 10000;
732
733 max && $mu.attr('data-rest', rest);
734 max && args[0] && rest <= 0 && alert('最多支持'+max+'');
735
736 return rest;
737 }else if(action == 'focus'){
738 return this.find(':input:visible').first().focus().select();
739 }else if(action == 'validate'){
740 return this.find(':input').toArray().every(el => el.checkValidity() || (el.reportValidity(), false));
741 }else if(action == 'keydown'){
742 let $item = this.closest('.mu-item');
743
744 if(type == 'text'){
745 if(this.hasClass('tag-input')){
746 let del = e.key === 'Backspace' && !this.val();
747 let timer = $mu.wpjam_timer(!del);
748
749 del && (timer ? $item.prev().wpjam_mu('del_item') : $item.prev().fadeOut(300).fadeIn(200));
750 }
751
752 if(e.key === 'Enter'){
753 if(this.val() && !this.data('data_type')){
754 if($mu.wpjam_mu('new_item')){
755 this.wpjam_label();
756
757 $(document.activeElement).closest('.mu-item').insertAfter($item).wpjam_mu('focus');
758 }else{
759 this.hasClass('tag-input') && this.val('');
760 }
761 }
762
763 return false;
764 }
765 }else{
766 if(e.key === 'Enter'){
767 let $inputs = $item.find(':input:visible');
768 let $next = $inputs.eq($inputs.index(this)+1);
769
770 if($next[0]){
771 $next.focus().select();
772 }else if($mu.data('tag_label')){
773 if($item.is($mu.children().eq(-2))){
774 $mu.wpjam_mu('new_item');
775 }else{
776 $item.wpjam_mu('validate') && $item.wpjam_mu('tag_label');
777 }
778 }
779
780 return false;
781 }
782 }
783 }else if(action == 'tag_label'){
784 let label = $mu.data('tag_label');
785
786 if(label && !this.has('template, span.tag-label')[0]){
787 let prefix = this.find(':input').first().attr('name');
788
789 prefix = prefix.endsWith('[]') ? prefix.slice(0, -2) : prefix;
790 prefix = prefix.substring(0, prefix.lastIndexOf('['));
791 label = label.replace(/\${(.*?)}/g, (match, name) => {
792 let $field = this.find('[name="'+prefix+'['+name+']"]');
793
794 return $field.is('select') ? $field.find('option:selected').text().trim() : $field.val();
795 });
796
797 $('<span class="tag-label">'+label+'</span>').append(this.find('.del-item').clone()).prependTo(this).on('dblclick', (e)=>$(e.target).remove());
798 }
799 }else if(action == 'template'){
800 return this.find('template').replaceWith((_, html) => html.replace(/\$\{i\}/g, $mu.data('i', ($mu.data('i') || 0)+ 1).data('i'))).end();
801 }
802
803 if(e){
804 return;
805 }
806
807 $mu.children().addClass('mu-item');
808
809 if(type == 'fields'){
810 $mu.children().not(':last-child').wpjam_each($el => $el.wpjam_mu('template').wpjam_init());
811 }else{
812 _.each($mu.data('value'), v => $mu.wpjam_mu('add_item', v));
813 }
814
815 let sortable = $mu.removeAttr('data-value').is('.sortable') && !$mu.closest('.disabled, .readonly')[0];
816
817 if(type == 'text' && $mu.find('input.tag-input')[0]){
818 $mu.attr('data-validation', true).on('validate.wpjam', ()=> $mu.find('input:visible').val(''));
819 }else{
820 let dir = $mu.data('direction') || (type == 'img' || $mu.data('tag_label') ? 'row' : 'column');
821 let row = dir == 'row';
822
823 $mu.addClass('direction-'+dir).find('> .mu-item').wpjam_each($el => $el.append([
824 $el.is(':last-child') && '<a class="new-item button">'+(type == 'img' ? '' : $mu.data('button_text'))+'</a>',
825 '<a class="del-item '+(row ? 'dashicons dashicons-no-alt' : 'button')+'"></a>',
826 sortable && type != 'img' && '<span class="move-item dashicons dashicons-menu"></span>',
827 ]));
828
829 ['text', 'fields'].includes(type) && row && $mu.wpjam_mu('rest') > 0 && $mu.wpjam_mu('add_item', '');
830 }
831
832 sortable && $mu.sortable({cursor: 'move', items: '.mu-item:not(:last-child)'});
833
834 return this;
835 };
836
837 $.fn.wpjam_mu.selector = '.mu';
838 $.fn.wpjam_mu.events = [
839 {name: 'autocompleteselect', selector: '.mu-text input', action: 'new_item'},
840 {name: 'click', selector: '.mu .new-item', action: 'new_item'},
841 {name: 'click', selector: '.mu .del-item', action: 'del_item'},
842 {name: 'keydown', selector: '.mu-text input, .mu-fields input, .mu-fields select'}
843 ];
844
845 $.fn.wpjam_validate = function(){
846 this[0].checkValidity() && this.find('[data-validation]').trigger('validate.wpjam');
847
848 if(!this[0].checkValidity()){
849 let $field = $(this.find('input:invalid')[0] || this.find(':invalid')[0]);
850 let custom = $field.data('custom_validity');
851
852 custom && $field.one('input', ()=> $field[0].setCustomValidity(''))[0].setCustomValidity(custom);
853
854 if(!$field.is(':visible')){
855 $field.closest('.tabs').wpjam_tabs('#'+$field.closest('.tab').attr('id'));
856 $field.closest('[popover]')[0]?.showPopover();
857 }
858
859 return this[0].reportValidity();
860 }
861
862 return true;
863 };
864
865 $.fn.wpjam_schema = function(key){
866 return (this.data('schema') || {})[key];
867 };
868
869 $.fn.wpjam_data = function(data){
870 _.each(data, (v, k)=> this.attr('data-'+k, _.isObject(v) ? JSON.stringify(v) : v));
871
872 return this;
873 };
874
875 $.fn.wpjam_val = function(){
876 if(this.prop('disabled')){
877 return null;
878 }else if(this.is('span')){
879 return this.data('value');
880 }else if(this.is('.mu-text')){
881 return this.find('input').toArray().map(el=> el.value).filter(v => v !== '');
882 }else if(this.is('.wpjam-choice')){
883 let val = this.find('input:checked').toArray().map(el => el.value);
884
885 return this.find('input').is(':radio') ? (val.length ? val[0] : null) : val;
886 }else if(this.is(':checkbox, :radio')){
887 let $field = this.wpjam_control();
888
889 return $field[0] !== this[0] ? $field.wpjam_val() : (this.is(':checked') ? this.val() : (this.is(':checkbox') ? 0 : null));
890 }
891
892 return this.val();
893 };
894
895 $.fn.wpjam_timer = function(cancel){
896 let timer = this.data('timer');
897
898 if(cancel){
899 timer && timer.cancel();
900
901 return this.removeData('timer');
902 }
903
904 if(timer){
905 return timer;
906 }
907
908 this.data('timer', _.debounce(()=> this.wpjam_timer(true), 2000)).data('timer')();
909 };
910
911 $.fn.wpjam_media = function(callback){
912 let {type, item_type, rest, button_text: btn} = this.data();
913
914 let mu = this.is('.mu');
915 type = type.substring(mu ? 3 : 0);
916
917 if(this.hasClass('readonly')){
918 return;
919 }
920
921 let args = {
922 ...(wp.media.view.settings.post.id && {frame: 'post'}),
923 id: 'uploader_'+this.prop('id'),
924 multiple: mu,
925 title: btn,
926 library : {type : ['img', 'image'].includes(type) ? 'image' : item_type},
927 // button : {text: title}
928 };
929
930 let frame = wp.media(args);
931
932 frame.on('open', function(){
933 frame.$el.addClass('hide-menu');
934
935 mu && rest && frame.state().get('selection').on('update', function(){
936 if(this.length > rest){
937 this.reset(this.first(rest));
938
939 alert('最多可以选择'+rest+'');
940 }
941 });
942 }).on('insert select', function(){
943 frame.state().get('selection').map((attachment)=> {
944 let data = attachment.toJSON();
945 let qs = $.param(_.pick(data, 'orientation', 'width', 'height'));
946 let value = data.url+(qs ? '?'+qs : '');
947
948 callback && callback(type == 'img' ? {...data, value : item_type === 'url' ? value : data.id} : value);
949 });
950 }).open();
951 };
952
953 $.fn.wpjam_lightbox = function(e){
954 $('dialog.wpjam-lightbox').remove();
955
956 let src = this.data('preview') || this.attr('href');
957 let rel = this.attr('rel');
958 let $btn = $('<button type="button" class="dashicons dashicons-no-alt del-icon"></button>');
959 let $modal = $('<dialog class="wpjam-lightbox"></dialog>').append([$btn.one('click', ()=> $modal.remove()), $('<img src="'+src+'">')]).appendTo($('body'));
960
961 $modal[0].showModal();
962
963 let images = rel ? $(`[rel="${rel}"]`).toArray().map(el => $(el).data('preview') || el.href) : [];
964 let length = images.length;
965
966 if(length > 1){
967 let index = images.indexOf(src);
968
969 $modal.wrapInner('<div>').prepend('<a rel="'+rel+'" data-preview="'+images.at(index - 1)+'" class="dashicons dashicons-arrow-left-alt2"></a>').append('<a rel="'+rel+'" data-preview="'+images.at((index + 1) % length)+'" class="dashicons dashicons-arrow-right-alt2"></a>')
970 }
971
972 return e ? false : this;
973 }
974
975 $.fn.wpjam_lightbox.events = [{name: 'click', selector: '[data-preview], a.lightbox'}];
976
977 $.fn.wpjam_tooltip = function(e){
978 let action = e?.type;
979 let $tip = $('div.wpjam-tooltip');
980
981 if(action === 'mouseenter'){
982 ($tip[0] ? $tip : $('<div popover="manual" class="wpjam-tooltip"></div>')).stop(true).fadeIn(100).html(this.is('.preview') ? '<img src="'+this.find('img:visible').attr('src')+'" />' : (this.data('description') || this.data('tooltip'))).appendTo(this)[0].showPopover();
983 }else if(action === 'mouseleave'){
984 $tip.fadeOut(300);
985 }else{
986 this.is('[data-description]') && this.addClass('dashicons dashicons-editor-help');
987 }
988
989 return this;
990 };
991
992 $.fn.wpjam_tooltip.selector = '[data-tooltip], [data-description], .image-radio.preview';
993 $.fn.wpjam_tooltip.events = [{name: 'mouseenter'}, {name: 'mouseleave'}];
994
995 $.fn.wpjam_modal = function(e){
996 if(this.hasClass('notice-dismiss')){
997 return this.prev('.delete-notice').trigger('click');
998 }
999
1000 let $modal = e ? $('#'+this.data('modal_id')) : this;
1001 let $dialog = wpjam.dialog($modal.html(), $modal.data('title'), $modal.data('width'));
1002
1003 e || $dialog.one('wpjam:dialog:closed', ()=> this.find('.delete-notice').trigger('click').end().remove());
1004
1005 return e ? false : this;
1006 }
1007
1008 $.fn.wpjam_modal.selector = '.notice-modal:first';
1009 $.fn.wpjam_modal.events = [{name: 'click', selector: '.show-modal, .is-dismissible .notice-dismiss'}];
1010
1011 $.fn.wpjam_chart = function(){
1012 let chart = this.data('chart');
1013 let {type, options} = _.isObject(chart) ? chart : {};
1014
1015 if(type && !_.isEmpty(options)){
1016 type == 'Donut' && this.height(Math.max(160, Math.min(240, this.next('table').height() || 240))).width(this.height());
1017
1018 ['Line', 'Bar', 'Donut'].includes(type) && Morris[type]({...options, element: this.prop('id')});
1019
1020 this.removeAttr('data-chart');
1021 }
1022 }
1023
1024 $.fn.wpjam_chart.selector = '[data-chart]';
1025
1026 $.fn.wpjam_tabs = function(hash){
1027 hash = window.location.hash = hash || window.location.hash;
1028
1029 this.find('.tab').hide().filter(hash || ':first').show();
1030 this.find('.nav-tab').removeClass('nav-tab-active').filter(hash ? '[href="'+hash+'"]' : ':first').addClass('nav-tab-active');
1031 };
1032
1033 $.fn.wpjam_place = function(content, replace, placement){
1034 let $content = $(content);
1035
1036 this[{before: 'prevAll', after: 'nextAll'}[placement] || 'find'](replace).remove();
1037 this[placement || 'append']($content);
1038
1039 return $content;
1040 };
1041
1042 $.fn.wpjam_scroll = function(){
1043 let $modal = this.closest('dialog .content');
1044
1045 if($modal[0]){
1046 $modal.animate({scrollTop: this[0].offsetTop - 80}, 300);
1047 }else if(this[0]){
1048 let top = this.offset().top;
1049 let dis = $(window).height() * 0.4;
1050
1051 (Math.abs(top - $(window).scrollTop()) > dis) && $('html, body').animate({scrollTop: top - dis}, 300);
1052 }
1053
1054 return this;
1055 };
1056
1057 window.wpjam = {
1058 ...wpjam_page_setting,
1059 spinner: '<span class="spinner is-active"></span>',
1060
1061 init: function(){
1062 $.ajax = this.enhance($.ajax, (options) => {
1063 let type = typeof options.data;
1064 let data = type == 'string' ? this.parse_params(options.data) : (type == 'object' ? options.data : {});
1065
1066 if(data.action){
1067 if(data.action.startsWith('wpjam-')){
1068 data = this.with_page(data);
1069 }else if(['fetch-list', 'inline-save-tax', 'get-comments', 'replyto-comment'].includes(data.action)){
1070 data.screen_id = this.screen_id;
1071 options.data = type == 'string' ? $.param(data) : data;
1072 }
1073 }
1074 }, 'before');
1075
1076 this.params = this.parse_params(window.location.search, true);
1077
1078 this.page_title_action && $('.wp-heading-inline:visible').last().wpjam_place(this.page_title_action, 'a.page-title-action', 'after');
1079
1080 $('a[href*="/wp-admin/page="]').attr('href', (_, v)=> v.replace('/wp-admin/page=', 'admin/admin.php?page='));
1081
1082 _.each(this.query_url, pair => $('a[href="'+pair[0]+'"]').attr('href', pair[1]));
1083
1084 $('body').on('click', 'input[type=submit]', e => $(document.activeElement).attr('id') || $(e.target).focus());
1085
1086 $(window).on('popstate', e => e.originalEvent.state?.params && this.load(e.originalEvent.state.params));
1087 $(window).on('hashchange load', ()=> $('.tabs').wpjam_each($el => $el.wpjam_tabs()));
1088
1089 $(document).on('heartbeat-send', (e, data)=> this.query_data && $.extend(data, this.query_data));
1090 $(document).on('widget-updated', (e, widget)=> widget.wpjam_init());
1091 $(document).on('mousemove', (e)=> $('html').css({
1092 '--wpjam-left': (e.clientX+(e.clientX + 300 > window.innerWidth ? -305 : 5))+'px',
1093 '--wpjam-top': (e.clientY+(e.clientY + 220 > window.innerHeight ? -225 : 5))+'px'
1094 }));
1095
1096 this.load();
1097
1098 $('body').wpjam_init();
1099 },
1100
1101 load: function(params){
1102 if(params){
1103 this.dialog('close');
1104 this.params = params;
1105 }
1106
1107 let args = {...this.params, action_type: 'form'};
1108
1109 if(list_table){
1110 if(!params){
1111 list_table.load();
1112 }
1113
1114 if(args.list_action){
1115 return list_table.action(args);
1116 }
1117
1118 if(params){
1119 return list_table.query(params);
1120 }
1121 }
1122
1123 if(args.page_action){
1124 return this.action('page', args);
1125 }
1126
1127 this.plugin_page && this.state('replace');
1128 },
1129
1130 state: function(action='push'){
1131 let url = new URL(this.admin_url);
1132
1133 if(!_.isEmpty(this.params) || this.query_data){
1134 url.search = '?'+$.param(_.extend(
1135 this.parse_params(url.search),
1136 this.query_data,
1137 _.omit(this.params, (v, k)=> v == null || (k == 'paged' && v <= 1))
1138 ));
1139 }
1140
1141 url = url.toString()+(window.location.hash || '');
1142
1143 $('input[name="_wp_http_referer"]').val(url);
1144
1145 if(action != 'push' || window.location.href != url){
1146 window.history[(action == 'push' ? 'pushState' : 'replaceState')]({params: this.params}, null, url);
1147 }
1148 },
1149
1150 notice: function(notice, type){
1151 if(_.isObject(notice)){
1152 type = notice.type;
1153 notice = notice.message;
1154 }
1155
1156 if(notice){
1157 let $dialog = this.dialog();
1158 let [$el, act] = $dialog[0] ? [$dialog.find('.content'), 'prepend'] : [$('.wp-header-end').last(), 'before'];
1159
1160 $el.wpjam_place('<div class="notice notice-'+(type || 'success')+' is-replaceable is-dismissible"><p><strong>'+notice+'</strong></p></div>', '.notice.is-replaceable', act).wpjam_scroll();
1161
1162 $(document).trigger('wp-notice-added');
1163 }
1164 },
1165
1166 dialog: function(...args){
1167 let id = 'wpjam_dialog';
1168
1169 if(!args.length){
1170 return $('#'+id+'[open]');
1171 }
1172
1173 let $dialog = $('#'+id);
1174
1175 if(args[0] === 'close'){
1176 return $dialog[0]?.close();
1177 }
1178
1179 if(args[0] === 'show'){
1180 if($dialog[0] && !$dialog[0].open){
1181 $dialog[0].returnValue = '';
1182 $dialog[0].showModal();
1183 }
1184
1185 return;
1186 }
1187
1188 let [data, ...rest] = args;
1189
1190 data = _.isObject(data) ? data : {..._.object(['page_title', 'width'], rest), data};
1191
1192 if(!$dialog[0]){
1193 $dialog = $('<dialog id="'+id+'" class="wpjam-dialog"><div class="title"><h2></h2><button type="button" commandfor="'+id+'" command="close"></button></div><div class="content"></div></dialog>').appendTo('body');
1194
1195 this.dialog.observer = new MutationObserver(()=> $('body').hasClass('modal-open') ? $dialog[0].close('temp') : this.dialog('show'));
1196
1197 this.dialog.observe = ()=> this.dialog.observer.observe(document.body, {attributes: true, attributeFilter: ['class']});
1198
1199 $dialog.on('close', ()=> {
1200 if($dialog[0].returnValue != 'temp'){
1201 this.dialog.observer.disconnect();
1202
1203 $dialog.trigger('wpjam:dialog:closed');
1204 }
1205 }).on('click', 'button[command="close"]', ()=> $dialog[0].close());
1206 }
1207
1208 $dialog.css('width', (data.width || 700)+'px').find('h2').text(data.page_title || '').end().find('.content').html(data.form || data.data || '');
1209
1210 $dialog[0].showModal();
1211 this.dialog.observe();
1212
1213 $dialog.trigger('wpjam:dialog:opened');
1214
1215 return $dialog;
1216 },
1217
1218 post: function(args){
1219 return $.ajax({
1220 url: ajaxurl,
1221 method: 'POST',
1222 data: args,
1223 dataType: 'json',
1224 headers: {'Accept': 'application/json'},
1225 error: function(xhr, status, error){}
1226 });
1227 },
1228
1229 action: Object.assign(function(type, args){
1230 let action = this.action[type];
1231
1232 if(action?.before?.(args) === false){
1233 return false;
1234 }
1235
1236 if(args.state){
1237 _.extend(this.params, _.pick(args, args.state));
1238
1239 $('body').one('wpjam:dialog:closed', ()=> {
1240 this.params = _.omit(this.params, args.state);
1241 this.state();
1242 });
1243 }
1244
1245 args.$ae && args.$ae.prop('disabled', true);
1246
1247 $('.spinner.is-active')[0] || $('<div class="wpjam-loading"><img src="'+this.loading+'" /></div>').appendTo('body').show();
1248
1249 return this.post({..._.omit(args, ['$ae', 'state']), action: 'wpjam-'+type+'-action'}).then(data => {
1250 args.$ae && args.$ae.prop('disabled', false);
1251
1252 $('.spinner.is-active, .wpjam-loading').remove();
1253
1254 if(data.errcode){
1255 this.notice((args.page_title ? args.page_title+'失败:' : '')+(data.errmsg || ''), 'error');
1256 }else{
1257 data.params && _.extend(this.params, data.params);
1258
1259 let $dialog = this.dialog();
1260 let dismiss = $dialog[0] && data.dismiss;
1261
1262 if(data.type == 'form'){
1263 !data.form && !data.data && alert('服务端未返回表单数据');
1264
1265 this.dialog(data);
1266 }else if(data.type == 'append'){
1267 if(!$dialog[0] && data.list_action){
1268 this.dialog(data);
1269 }else{
1270 ($dialog[0] ? $dialog.find('.content') : $('div.wrap')).wpjam_place($('<div class="card wrap-text">'+data.data+'</div>'), '.response.card').hide().fadeIn(400).wpjam_scroll();
1271 }
1272 }else if(data.type == 'redirect'){
1273 $('body').one(dismiss ? 'wpjam:dialog:closed' : type+'_action_success', ()=> {
1274 let url = data.url ? data.url.replace('admin/page=', 'admin/admin.php?page=') : (_.isObject(data.args) ? wpjam.admin_url+(wpjam.admin_url.includes('?') ? '&' : '?')+$.param(data.args) : null);
1275 url ? window.open(url, data.target) : window.location.reload();
1276 });
1277 }
1278
1279 action?.response?.(data, args);
1280
1281 dismiss && $dialog[0].close();
1282
1283 this.state();
1284
1285 $('body').wpjam_init().trigger(type+'_action_success', data);
1286 }
1287 });
1288 }, {
1289 page: {
1290 before: function(args){
1291 if(args.action_type == 'form'){
1292 args.state = ['page_action', 'data'];
1293 }
1294 },
1295
1296 response: function(data, args){
1297 if(!['form', 'append', 'redirect'].includes(data.type)){
1298 data.args && setTimeout(()=> wpjam.action('page', {...args, data: data.args}), 400);
1299
1300 args.action_type == 'submit' && data.form && $('#wpjam_form').html(data.form);
1301
1302 wpjam.notice(data.notice || args.page_title+'成功');
1303 }
1304
1305 data.page_action = args.page_action;
1306 data.action_type = data.page_action_type = args.action_type;
1307 }
1308 },
1309
1310 option: {
1311 response: function(data){
1312 data.type == 'save' && wpjam.notice(data.notice);
1313 }
1314 }
1315 }),
1316
1317 with_page: function(args){
1318 let left_key = args.action_type != 'query_items' && this.left_key;
1319
1320 if(this.query_data || left_key){
1321 let type = args.data ? typeof args.data : 'string';
1322 let data = type == 'object' ? args.data : (args.data ? this.parse_params(args.data) : {});
1323
1324 _.each(this.query_data, (v, k)=> {
1325 if(_.has(data, k)){
1326 this.query_data[k] = data[k];
1327 }else{
1328 data[k] = v;
1329 }
1330 });
1331
1332 if(left_key){
1333 data[left_key] = wpjam.params[left_key];
1334 }
1335
1336 if(type == 'string'){
1337 args.data = $.param(data);
1338 }
1339 }
1340
1341 return _.extend(args, _.pick(this, ['screen_id', 'plugin_page', 'current_tab', 'builtin_page', 'post_type', 'taxonomy']));
1342 },
1343
1344 parse_params: function(params, clean){
1345 if(_.isString(params)){
1346 let obj = {};
1347 params = params ? params.replace(/^\?|\+/g, ' ').trim() : '';
1348
1349 params && params.replace(/^\?|\+/g, ' ').trim().split('&').forEach(v => {
1350 let param = v.split('=');
1351 let key = decodeURIComponent(param[0]);
1352 let val = param.length === 2 ? decodeURIComponent(param[1]) : '';
1353 let keys = key.split('][');
1354
1355 if(keys[0].includes('[') && _.last(keys).endsWith(']')){
1356 keys = keys.shift().split('[').concat(keys);
1357 keys = [...keys.slice(0, -1), keys.pop().slice(0, -1)];
1358
1359 keys.reduce((cur, k, i)=> {
1360 k = (k === '') ? cur.length : k;
1361 cur[k] = keys.length - 1 > i ? (cur[k] || (isNaN(Number(keys[i + 1])) ? {} : [])) : val;
1362
1363 return cur[k];
1364 }, obj);
1365 }else{
1366 obj[key] = val;
1367 }
1368 });
1369
1370 params = obj;
1371 }
1372
1373 return clean ? _.omit(params, _.union(
1374 ['_wp_http_referer', '_wpnonce', 'action', 'action2'],
1375 this.query_data ? Object.keys(this.query_data) : [],
1376 this.builtin_page ? ['post_type', 'taxonomy'] : ['page', 'tab']
1377 )) : params;
1378 },
1379
1380 compare: function(a, compare, b){
1381 let cmp = compare;
1382
1383 if(_.isObject(compare)){
1384 b = compare.value;
1385 cmp = compare.compare;
1386 }
1387
1388 if(_.isArray(a) || (_.isObject(compare) && compare.swap)){
1389 [a, b] = [b, a];
1390 }
1391
1392 if(cmp){
1393 cmp = cmp.toUpperCase();
1394
1395 let antonym = {
1396 '!=': '=',
1397 '<=': '>',
1398 '>=': '<',
1399 'NOT IN': 'IN',
1400 'NOT BETWEEN': 'BETWEEN'
1401 }[cmp];
1402
1403 if(antonym){
1404 return !wpjam.compare(a, antonym, b);
1405 }
1406 }else{
1407 cmp = _.isArray(b) ? 'IN' : '=';
1408 }
1409
1410 if(cmp === 'IN' || cmp === 'BETWEEN'){
1411 b = _.isArray(b) ? b : b.split(/[\s,]+/);
1412
1413 if(!_.isArray(a) && b.length === 1) {
1414 return a == b[0];
1415 }
1416
1417 b = b.map(String);
1418 }else{
1419 b = _.isString(b) ? b.trim() : b;
1420 }
1421
1422 switch (cmp) {
1423 case '=': return a == b;
1424 case '>': return a > b;
1425 case '<': return a < b;
1426 case 'IN': return b.includes(a);
1427 case 'BETWEEN': return a >= b[0] && a <= b[1];
1428 default: return false;
1429 }
1430 },
1431
1432 enhance: function(func, callback, when){
1433 return function(...args){
1434 when == 'before' && callback.apply(this, args);
1435
1436 let result = func.call(this, ...args);
1437
1438 when != 'before' && callback.apply(this, args);
1439
1440 return result;
1441 };
1442 },
1443
1444 delegate: function(selector, sub){
1445 let $sel = $(selector);
1446
1447 _.each($._data($sel.get(0), 'events'), (list, type)=> {
1448 _.each(list, (event)=> {
1449 let sel = event?.selector;
1450
1451 if(event?.handler && (!sel || !sub || sel == sub)){
1452 $('body').on(type, sel ? selector+' '+sel : selector, event.handler);
1453 $sel.off(type, sel || event.handler, sel && event.handler);
1454 }
1455 });
1456 });
1457 }
1458 };
1459
1460 window.list_table = wpjam.list_table && {
1461 ...wpjam.list_table,
1462 $form: $('form:has(.wp-list-table)').attr('novalidate', 'novalidate'),
1463
1464 load: function(data){
1465 data && data.setting && _.extend(list_table, data.setting);
1466
1467 this.table(data);
1468 this.views(data);
1469 this.left(data);
1470
1471 $('input[name="post_status"]').val(wpjam.params.post_status || 'all');
1472
1473 let $end = $('.wp-header-end').last();
1474
1475 this.subtitle && $end.wpjam_place('<span class="subtitle">'+this.subtitle+'</span>', 'span.subtitle', 'before');
1476 this.summary && $end.wpjam_place('<div class="summary">'+this.summary+'</div>', 'div.summary', 'after');
1477
1478 if(this.search){
1479 if(this.search.box){
1480 $('#list_table_form').wpjam_place(this.search.box, 'p.search-box', 'prepend');
1481 }else{
1482 $('p.search-box input[type="search"]').val(this.search.term);
1483 }
1484
1485 this.search.columns && $('p.search-box').wpjam_place(this.search.columns, '#search_columns', 'prepend');
1486 }
1487
1488 if(wpjam.params.id && !wpjam.params.list_action && !wpjam.params.action){
1489 let id = wpjam.params.id;
1490
1491 delete wpjam.params.id;
1492
1493 this.get_row(id)[0] ? this.update_row(id) : this.query({id: id});
1494 }
1495
1496 data ? $('body').trigger('list_table_load', data) : $(window).on('load', ()=> $('body').trigger('list_table_load', data));
1497 },
1498
1499 table: function(data){
1500 let $form = this.$form.attr('data-layout', this.layout).addClass('layout-'+this.layout);
1501
1502 if(!data){
1503 _.each([
1504 ['submit'],
1505 ['keydown', '.tablenav :input, .search-box :input'],
1506 ['change', '.tablenav [type="date"]'],
1507 ['click', '.list-table-filter, td a, th a, .pagination-links a, .prev-day, .next-day']
1508 ], ([name, sel])=> $form.wpjam_on(name, sel, e => this.callback(e)));
1509
1510 wpjam.action['list-table'] = this;
1511 }
1512
1513 if(data && (data.table || data.tablenav)){
1514 $form.find('input[name="_wpnonce"], input[name="_wp_http_referer"]').remove();
1515
1516 if(data.table){
1517 $form.wpjam_place(data.table, 'table, div.tablenav');
1518 }else{
1519 _.each(['top', 'bottom'], key => $form.find('div.tablenav.'+key).replaceWith(data.tablenav[key]));
1520 }
1521 }
1522
1523 if(!data || data.table){
1524 let $table = $form.find('table.wp-list-table');
1525 let columns = {};
1526 this.$tbody = this.$form.find('#the-list');
1527 this.name = (this.$tbody.data('wp-lists') || ':post').split(':')[1];
1528
1529 $table.find('thead th i').wpjam_each($i => {
1530 let $th = $i.closest('th');
1531 let col = 'column-'+$th.attr('id');
1532 let data = $i.appendTo($th).data();
1533
1534 data.nowrap && $('.'+col).addClass('nowrap');
1535
1536 columns[col] = {...data, left: $th.prevAll().toArray().reduce((sum, el) => sum += $(el).outerWidth(), 0)};
1537 });
1538
1539 sticky = _.some(columns, data => data.sticky);
1540
1541 sticky && ($table.width() > $form.width()) && $table.addClass('sticky-columns');
1542
1543 this.columns = {...columns, 'check-column' : {check:true, sticky, left: 0}};
1544
1545 this.render($table);
1546 }
1547
1548 if(!data || data.table || data.tablenav){
1549 $form.removeData('initialized').wpjam_place($('<div class="actions overallactions"></div>').append(this.overall_actions), '.overallactions').insertBefore($('.tablenav.top').find('div.tablenav-pages, br.clear').first());
1550
1551 $form.find('.current-page').addClass('expandable').removeAttr('size').attr({type: 'number', min: 1, max: parseInt($form.find('span.total-pages').first().text())});
1552 }
1553 },
1554
1555 views: function(data){
1556 let $views = $('ul.subsubsub');
1557
1558 if(data){
1559 if(!data.views){
1560 return;
1561 }
1562
1563 $views.empty().append($(data.views).html());
1564
1565 data.type != 'list' && $views.find('a').removeClass('current').end().find('li.'+this.view+' a').addClass('current');
1566 }else{
1567 $views.wpjam_on('click', 'a', e => this.callback(e));
1568 }
1569
1570 this.view = $views.find('li:has(a.current)').attr('class');
1571 },
1572
1573 left: function(data){
1574 let $left = $('#col-left form').prop('novalidate', true);
1575 let $paged = $left.find('input.current-page');
1576
1577 if(!$left[0]){
1578 return;
1579 }
1580
1581 if(data && data.currentTarget){
1582 let $el = $(data.currentTarget);
1583
1584 if($el.is('[data-id]')){
1585 $left.find('.left-current').removeClass('left-current');
1586
1587 this.query({...wpjam.params, [wpjam.left_key]: $el.addClass('left-current').data('id')});
1588 }else{
1589 $paged.val($el.is('select.left-filter') ? 1 : parseInt($paged.val())+($el.is('.prev-page') ? -1 : ($el.is('.next-page') ? +1 : 0)));
1590
1591 if(!$left.wpjam_validate()){
1592 return false;
1593 }
1594
1595 this.query(wpjam.parse_params($left.serialize(), true));
1596 }
1597
1598 return false;
1599 }
1600
1601 if(data){
1602 if(!data.left){
1603 return;
1604 }
1605
1606 $left.removeData('initialized').html(data.left);
1607 }else{
1608 _.each([
1609 ['submit'],
1610 ['change', 'select'],
1611 ['click', '.prev-page, .next-page, [data-id]'],
1612 ], ([name, sel])=> $left.wpjam_on(name, sel, e => this.left(e)));
1613 }
1614
1615 let $items = $left.find('[data-id]');
1616 let paged = parseInt($paged.addClass('expandable').val());
1617 let key = wpjam.left_key = this.left_key;
1618
1619 $left.find('a.prev-page').addClass('button').addClass(paged <= 1 && 'disabled');
1620 $left.find('a.next-page').addClass('button').addClass(paged >= parseInt($paged.attr('max')) && 'disabled');
1621
1622 $items[0] && $left.find('[data-id='+(wpjam.params[key] = wpjam.params[key] || $items.first().data('id'))+']').addClass('left-current');
1623
1624 this.$form.find('.sticky-columns').css('--left-height', $('#col-left table').height()+'px');
1625
1626 $('a.page-title-action').clone().toggleClass('page-title-action button').prependTo($('div.overallactions'));
1627 },
1628
1629 render: function($el){
1630 $el.is('td, th') || _.each(this.columns, (column, sel)=> {
1631 let {sticky, left, nowrap, description, ...data} = column;
1632 let $col = $('.'+sel);
1633
1634 sticky && $col.addClass('sticky-column').css('left', left);
1635 nowrap && $col.addClass('nowrap');
1636
1637 if(_.isEmpty(data)){
1638 return;
1639 }
1640
1641 $col.wpjam_each($td => {
1642 if(data.check){
1643 let $input = $td.find('input');
1644
1645 return $input[0] ? $input.attr('title', '选择'+($td.nextAll('.column-primary')[0].childNodes[0].textContent.trim() || $input.val())) : ($td.find('span')[0] || $td.append('<span class="dashicons dashicons-minus"></span>'));
1646 }
1647
1648 let value = $td.text();
1649 let number = Number(value);
1650
1651 if(value === '' || isNaN(number)){
1652 return;
1653 }
1654
1655 _.some(data.conditional_styles, rule => wpjam.compare(number, rule) && $td.css(_.reduce({
1656 bold: {'font-weight': 'bold'},
1657 strikethrough: {'text-decoration': 'line-through'},
1658 color: '',
1659 'background-color': ''
1660 }, (acc, prop, key)=> rule[key] ? {...acc, ...(prop || _.pick(rule, key))} : acc, {})));
1661
1662 let {format, precision} = data;
1663
1664 if(format || precision){
1665 if(format == '%'){
1666 number = parseFloat((number*100).toFixed(precision || 2))+'%';
1667 }else{
1668 number = precision ? parseFloat(number.toFixed(precision)) : number;
1669 number = format == ',' ? number.toLocaleString() : number;
1670 }
1671
1672 $td.text(number).attr('value', value);
1673 }
1674 });
1675 });
1676
1677 $el.find('.items.sortable').add($el.is('table') && this.sortable && this.$tbody).wpjam_each($s => {
1678 let tbody = $s.is('tbody');
1679 let handle = '.list-table-move-'+(tbody ? '' : 'item-')+'action';
1680
1681 $s.sortable({
1682 ...(tbody ? {items: this.sortable.items, axis: 'y'} : {items: '> div.item'}),
1683 handle,
1684 cursor: 'move',
1685 start: (e, ui)=> {
1686 tbody && ui.placeholder.css({
1687 visibility: 'visible',
1688 height: ui.helper.outerHeight()+'px',
1689 width: ui.helper.outerWidth()+'px'
1690 });
1691 },
1692 update: (e, ui)=> {
1693 let $handle = ui.item.find(handle);
1694 let parts = [$handle.data('data'), 'pos='+ui.item.prevAll().length, $s.sortable('serialize')].filter(Boolean);
1695
1696 $handle.data('data', parts.join('&')).wpjam_action();
1697 }
1698 });
1699 });
1700
1701 return this;
1702 },
1703
1704 update_row: function(data, highlight=true){
1705 let $el = data;
1706
1707 if(!(data instanceof $)){
1708 if(this.layout == 'calendar'){
1709 _.each(data.data, (item, date)=> this.update_row($('td#date_'+date).html(item)));
1710
1711 return this;
1712 }
1713
1714 if(_.isObject(data) && data.bulk){
1715 _.each(data.data || data.ids, item => this.update_row(item));
1716
1717 return this;
1718 }
1719
1720 let id = data;
1721
1722 if(_.isObject(data)){
1723 id = data.id;
1724
1725 data.data && this.get_row(id).first().before(data.data).end().remove();
1726 }
1727
1728 $el = this.get_row(id);
1729 }
1730
1731 highlight && $el.wpjam_highlight('add');
1732
1733 return this.render($el);
1734 },
1735
1736 delete_row: function(id){
1737 this.get_row(id).wpjam_highlight('delete').wpjam_remove(()=> this.$tbody.find('> tr')[0] || this.$tbody.append('<tr class="no-items"><td colspan="'+this.$form.find('tr').children().length+'" class="colspanchange">'+_wpMediaViewsL10n.noItemsFound+'</td></tr>'));
1738 },
1739
1740 get_row: function(id){
1741 id = typeof id == "string" ? id.replace(/(:|\.|\[|\]|,|=|@)/g, "\\$1") : id;
1742
1743 return $('.tr-'+id)[0] ? $('.tr-'+id) : $('#'+this.name+'-'+id);
1744 },
1745
1746 action: function(args){
1747 return wpjam.action('list-table', args);
1748 },
1749
1750 query: function(params){
1751 $('.notice-dismiss').trigger('click.wp-dismiss-notice');
1752
1753 if(!params && !this.$form.wpjam_validate()){
1754 return false;
1755 }
1756
1757 wpjam.params = params ? _.omit(params, v => _.isNull(v)) : wpjam.parse_params(this.$form.serialize(), true);
1758
1759 return this.action({action_type: 'query_items', data: $.param(wpjam.params)});
1760 },
1761
1762 callback: function(e){
1763 let $el = $(e.currentTarget);
1764
1765 if(e.type == 'click'){
1766 if($el.hasClass('list-table-action')){
1767 return;
1768 }
1769
1770 if($el.is('.prev-day, .next-day')){
1771 let $date = $el.siblings('[name="date"]');
1772 let date = new Date($date.val());
1773
1774 date.setDate(date.getDate()+($el.hasClass('prev-day') ? -1 : 1));
1775 $date.val(date.toISOString().split('T')[0]);
1776
1777 return this.query(), false;
1778 }
1779
1780 if($el.hasClass('list-table-filter')){
1781 return this.query($el.data('filter')), false;
1782 }
1783
1784 if(this.ajax === false){
1785 return;
1786 }
1787
1788 if($el.closest('td, th')[0] && (wpjam.plugin_page || !$el.attr('href').startsWith($('#adminmenu a.current').attr('href')))){
1789 return;
1790 }
1791
1792 let params = wpjam.parse_params(new URL($el.prop('href')).search);
1793
1794 if(wpjam.builtin_page && (params.page || params.action)){
1795 return;
1796 }
1797
1798 return this.query($el.is('th a, .pagination-links a') ? {
1799 ...wpjam.params,
1800 ..._.omit(params, 'page'),
1801 paged: params.paged || 1
1802 } : params), false;
1803 }else if(e.type == 'submit'){
1804 let $ae = $(document.activeElement);
1805
1806 if($ae.is('#doaction, #doaction2')){
1807 let $select = $ae.prev('select');
1808 let name = $select.val();
1809 let $ids = this.$tbody.find('.check-column input[type="checkbox"]:checked');
1810 let ba = this.bulk_actions?.[name];
1811
1812 if(ba && $ids[0]){
1813 return $select.data({
1814 ...ba,
1815 ...(name == 'delete' && ba.bulk === true && {bulk: 2}),
1816 ids: $ids.toArray().map(cb => cb.value)
1817 }).wpjam_action(), false;
1818 }
1819 }else if($ae.is('[name=filter_action], #search-submit')){
1820 if(this.ajax !== false){
1821 return this.query(), false;
1822 }
1823 }
1824 }else if(e.type == 'keydown'){
1825 if(e.key === 'Enter' && this.ajax !== false){
1826 if($el.is('#current-page-selector')){
1827 return this.query(_.extend(wpjam.params, {paged: parseInt($el.val())})), false;
1828 }else if(!$el.closest('.mu-text, .mu-fields')[0]){
1829 let $submit = $el.closest(':has(:submit)').find(':submit');
1830
1831 if($submit[0]){
1832 return $submit.first().focus().trigger("click"), false;
1833 }
1834 }
1835 }
1836 }else if(e.type == 'change'){
1837 if($el.is('[name="date"]')){
1838 this.query();
1839 }else if($el.is('[name="end_date"]')){
1840 let dates = _.map(['start_date', 'end_date'], k => $('.tablenav [name="'+k+'"]').val());
1841
1842 dates[0] && dates[1] && dates[0] > dates[1] && wpjam.notice('开始日期不能大于结束日期', 'error');
1843 }
1844 }
1845 },
1846
1847 before: function(args){
1848 let state = ['list_action', 'id', 'data'];
1849
1850 if(args.action_type == 'form'){
1851 if(!args.bulk){
1852 args.state = state;
1853 }
1854 }else{
1855 if(args.bulk && args.bulk == 2 && !args.id){
1856 wpjam.dialog('close');
1857
1858 return this.action({...args, id: args.ids.shift()}).then(()=> args.ids.length && setTimeout(()=> this.action(args), 400)) && false;
1859 }
1860
1861 args.params = _.omit(wpjam.params, state);
1862 }
1863
1864 if(this.$tbody.find('.check-column')[0]){
1865 _.reduce(((args.bulk && args.bulk != 2) ? args.ids : (args.id ? [args.id] : [])), ($r, i)=> $r.add(this.get_row(i)), $()).find('.check-column input').before(wpjam.spinner);
1866 }
1867 },
1868
1869 response: function(data, args){
1870 if(args.bulk){
1871 this.$form.find('thead, tfoot').find('.check-column input').prop('checked', false);
1872 }else{
1873 this.$tbody.find('> tr').not(args.id ? this.get_row(args.id) : '').wpjam_highlight();
1874 }
1875
1876 let $item = args.id && this.get_row(args.id).wpjam_scroll();
1877 let type = data.type;
1878
1879 if(['up', 'down', 'move'].includes(type)){
1880 $item.wpjam_highlight('move');
1881
1882 if(type == 'up'){
1883 $item.insertBefore($item.prev());
1884 }else if(type == 'down'){
1885 $item.insertAfter($item.next());
1886 }
1887 }else if(!['form', 'append', 'redirect'].includes(type)){
1888 data.args && setTimeout(()=> this.action({...args, data: data.args}), 400);
1889
1890 type == 'list' && args.list_action == 'delete' && this.delete_row(args.id);
1891
1892 this.load(data);
1893
1894 if(type == 'items'){
1895 _.each(data.items, item => this.process(item, args));
1896 }else{
1897 this.process(data, args);
1898 }
1899 }
1900
1901 data.next && _.extend(wpjam.params, {list_action: data.next}, _.pick(args, ['id', 'data']));
1902
1903 data.list_action = args.list_action;
1904 data.action_type = data.list_action_type = args.action_type;
1905
1906 return data;
1907 },
1908
1909 process: function(data, args){
1910 let type = data.type;
1911 let $dialog = wpjam.dialog();
1912
1913 if($dialog[0] || args.action_type != 'submit'){
1914 $dialog[0] && data.form && wpjam.dialog(data);
1915
1916 wpjam.notice(data.notice);
1917 }
1918
1919 if(type == 'list'){
1920 $('html').scrollTop(0);
1921
1922 ((data.bulk && data.ids) || data.id) && this.update_row(data);
1923 }else if(['add', 'duplicate'].includes(type)){
1924 let pos = (data.after || data.before);
1925 let $pos = pos ? this.get_row(pos) : this.$tbody.find('> tr');
1926 let $row = $(data.data);
1927
1928 if(data.after || data.last){
1929 $pos.last().after($row);
1930 }else{
1931 $pos.first().before($row);
1932 }
1933
1934 this.update_row(data).$form.find('tr.no-items').remove();
1935 }else if(['add_item', 'edit_item', 'del_item', 'move_item'].includes(type)){
1936 let params = wpjam.parse_params(['add_item', 'edit_item'].includes(type) ? args.defaults : args.data);
1937 let $items = (type == 'del_item' ? this : this.update_row(data, false)).get_row(data.id).find('[data-field="'+params._field+'"]');
1938
1939 if(type == 'add_item'){
1940 $items.find('[data-i]:last').wpjam_highlight('add');
1941 }else if(type == 'edit_item'){
1942 $items.find('[data-i="'+params.i+'"]').wpjam_highlight('update');
1943 }else if(type == 'move_item'){
1944 $items.find('[data-i="'+params.pos+'"]').wpjam_highlight('move');
1945 }else if(type == 'del_item'){
1946 $items.find('[data-i="'+params.i+'"]').wpjam_highlight('delete').wpjam_remove();
1947 }
1948 }else if(type == 'delete'){
1949 _.each(data.bulk ? data.ids : [data.id], id => this.delete_row(id));
1950 }else{
1951 this.update_row(data);
1952 }
1953 }
1954 };
1955
1956 wpjam.init();
1957 });
1958
1959 jQuery.widget('wpjam.iris', jQuery.a8c.iris, {
1960 _create: function(){
1961 if(!Color.fn.fromHex6){
1962 Color.fn.fromHex6 = Color.fn.fromHex;
1963 Color.fn.fromHex = function(color){
1964 color = color.replace(/^#|^0x/, '');
1965
1966 if(color.length === 8 && /^[0-9A-F]{8}$/i.test(color)){
1967 this.a(parseInt(color.substring(6), 16)/255);
1968
1969 color = color.substring(0, 6);
1970 }
1971
1972 return this.fromHex6(color);
1973 };
1974
1975 Color.fn.toString = function(){
1976 return this.error ? '' : '#'+(parseInt(this._color, 10).toString(16).padStart(6, '0'))+(this._alpha < 1 ? parseInt(255*this._alpha, 10).toString(16).padStart(2, '0') : '');
1977 };
1978 }
1979
1980 this._super();
1981 },
1982 _change: function(){
1983 if(this.element.data('alpha-enabled')){
1984 this._inited || this.controls.strip.width(18).clone(false, false).find('> div').slider({
1985 orientation: 'vertical',
1986 value: parseInt(this._color.a()*100),
1987 slide: (e, ui)=> {
1988 this._color.a(parseFloat(ui.value/100));
1989 this.active = 'strip';
1990 this._change();
1991 }
1992 }).end().insertAfter(this.controls.strip);
1993
1994 this.element.closest('.wp-picker-container').css('--color', this._color.toString() || '#FFFFFF80');
1995 }
1996
1997 this._super();
1998 }
1999 });