| 1 |
/* global jQuery, ajaxurl, mainwp_secure_data, mainwp_confirm */ |
| 2 |
|
| 3 |
/** |
| 4 |
* Each panel owns its list; a single editor owns the active record request. |
| 5 |
*/ |
| 6 |
jQuery(function ($) { |
| 7 |
const modal = $('#mainwp-knowledge-modal'); |
| 8 |
if (!modal.length) { |
| 9 |
return; |
| 10 |
} |
| 11 |
const modalHeader = modal.find('.header'); |
| 12 |
const modalTitle = $('#mainwp-knowledge-modal-title'); |
| 13 |
const modalLevel = $('#mainwp-knowledge-modal-level'); |
| 14 |
const modalUnverified = $('#mainwp-knowledge-modal-unverified'); |
| 15 |
const modalMessage = $('#mainwp-knowledge-modal-message'); |
| 16 |
const typeField = $('#mainwp-knowledge-type'); |
| 17 |
const typeViewField = $('#mainwp-knowledge-type-view'); |
| 18 |
const titleField = $('#mainwp-knowledge-title'); |
| 19 |
const descriptionField = $('#mainwp-knowledge-description'); |
| 20 |
const bodyField = $('#mainwp-knowledge-body'); |
| 21 |
const requiredField = $('#mainwp-knowledge-required'); |
| 22 |
const requiredHelp = $('#mainwp-knowledge-required-help'); |
| 23 |
const idField = $('#mainwp-knowledge-id'); |
| 24 |
const revisionField = $('#mainwp-knowledge-revision'); |
| 25 |
const saveButton = $('#mainwp-knowledge-save'); |
| 26 |
const deleteButton = $('#mainwp-knowledge-remove'); |
| 27 |
const cancelButton = modal.find('.actions .cancel.button'); |
| 28 |
const strings = window.mainwpKnowledgeStrings || {}; |
| 29 |
let readOnly = true; |
| 30 |
let canWrite = false; |
| 31 |
let scope = null; |
| 32 |
let owner = null; |
| 33 |
let session = 0; |
| 34 |
|
| 35 |
const showMessage = (target, text, color) => { |
| 36 |
target.removeClass('hidden red green yellow').addClass(color).empty().append($('<p></p>').text(text)); |
| 37 |
}; |
| 38 |
const hideMessage = (target) => target.addClass('hidden').removeClass('red green yellow').empty(); |
| 39 |
const post = (action, data) => $.post(ajaxurl, mainwp_secure_data($.extend({ action: action }, data)), null, 'json'); |
| 40 |
const errorText = (response) => (response && response.data && response.data.message) ? response.data.message : strings.failed; |
| 41 |
const recordScope = (record) => { |
| 42 |
const result = { scope_type: record.scope_type }; |
| 43 |
// Agency inputs must omit scope_id even though stored records carry zero. |
| 44 |
if ('agency' !== record.scope_type) { |
| 45 |
result.scope_id = parseInt(record.scope_id, 10); |
| 46 |
} |
| 47 |
return result; |
| 48 |
}; |
| 49 |
const updateFields = () => { |
| 50 |
const isSkill = 'skill' === typeField.val(); |
| 51 |
descriptionField.closest('.field').toggle(isSkill).toggleClass('required', isSkill && !readOnly); |
| 52 |
descriptionField.prop('required', isSkill && !readOnly).prop('readonly', readOnly); |
| 53 |
$('#mainwp-knowledge-description-help').toggle(!readOnly); |
| 54 |
const eligible = scope && ['agency', 'client'].includes(scope.scope_type) && ['context', 'skill'].includes(typeField.val()); |
| 55 |
$('#mainwp-knowledge-required-field').toggle(!!eligible && canWrite && !readOnly); |
| 56 |
requiredHelp.toggle(!!eligible && canWrite && !readOnly); |
| 57 |
requiredField.prop('disabled', !eligible || !canWrite || readOnly); |
| 58 |
}; |
| 59 |
const fill = (record) => { |
| 60 |
idField.val(record.id); |
| 61 |
revisionField.val(record.revision); |
| 62 |
typeField.val(record.type); |
| 63 |
typeField.closest('.dropdown').dropdown('set selected', record.type); |
| 64 |
typeViewField.val(record.type_label || ''); |
| 65 |
titleField.val(record.title); |
| 66 |
descriptionField.val(record.description || ''); |
| 67 |
bodyField.val(record.body); |
| 68 |
requiredField.prop('checked', !!record.required); |
| 69 |
modalLevel.text(record.level_label || '').toggle(!!record.level_label); |
| 70 |
modalUnverified.toggle(record.verified === 0); |
| 71 |
updateFields(); |
| 72 |
}; |
| 73 |
const openModal = (mode) => { |
| 74 |
readOnly = 'view' === mode; |
| 75 |
hideMessage(modalMessage); |
| 76 |
titleField.prop('readonly', readOnly); |
| 77 |
bodyField.prop('readonly', readOnly); |
| 78 |
typeField.closest('.field').toggle(!readOnly); |
| 79 |
typeViewField.closest('.field').toggle(readOnly); |
| 80 |
updateFields(); |
| 81 |
saveButton.toggle(!readOnly).prop('disabled', readOnly).toggleClass('disabled', readOnly).removeClass('loading'); |
| 82 |
deleteButton.toggle(!readOnly && parseInt(idField.val(), 10) > 0).prop('disabled', readOnly).removeClass('loading disabled'); |
| 83 |
cancelButton.text(cancelButton.data(readOnly ? 'close' : 'cancel')); |
| 84 |
modalTitle.text(modalHeader.data(mode)); |
| 85 |
modal.modal('show'); |
| 86 |
}; |
| 87 |
const begin = (nextOwner) => { |
| 88 |
++session; |
| 89 |
owner = nextOwner; |
| 90 |
scope = null; |
| 91 |
canWrite = false; |
| 92 |
readOnly = true; |
| 93 |
fill({ id: 0, revision: 0, type: 'context', title: '', body: '' }); |
| 94 |
titleField.prop('readonly', true); |
| 95 |
bodyField.prop('readonly', true); |
| 96 |
saveButton.prop('disabled', true).addClass('disabled'); |
| 97 |
deleteButton.hide(); |
| 98 |
hideMessage(modalMessage); |
| 99 |
return session; |
| 100 |
}; |
| 101 |
const applyRecord = (response, mode) => { |
| 102 |
const record = response.data.record; |
| 103 |
scope = recordScope(record); |
| 104 |
canWrite = !!response.data.can_write; |
| 105 |
fill(record); |
| 106 |
openModal('view' === mode || !canWrite ? 'view' : 'edit'); |
| 107 |
}; |
| 108 |
const openRecord = (id, mode, nextOwner) => { |
| 109 |
const current = begin(nextOwner); |
| 110 |
post('mainwp_knowledge_get', { id: id }).done((response) => { |
| 111 |
if (current !== session) { |
| 112 |
return; |
| 113 |
} |
| 114 |
if (!response.success) { |
| 115 |
showMessage(owner.message, errorText(response), 'yellow'); |
| 116 |
owner.refresh(true); |
| 117 |
return; |
| 118 |
} |
| 119 |
applyRecord(response, mode); |
| 120 |
}).fail(() => { |
| 121 |
if (current === session) { |
| 122 |
showMessage(owner.message, strings.failed, 'red'); |
| 123 |
} |
| 124 |
}); |
| 125 |
}; |
| 126 |
const reloadIntoEditor = () => { |
| 127 |
const current = session; |
| 128 |
const button = modalMessage.find('button'); |
| 129 |
if (button.hasClass('disabled')) { |
| 130 |
return; |
| 131 |
} |
| 132 |
button.addClass('loading disabled'); |
| 133 |
post('mainwp_knowledge_get', { id: idField.val() }).done((response) => { |
| 134 |
if (current !== session) { |
| 135 |
return; |
| 136 |
} |
| 137 |
if (!response.success) { |
| 138 |
if (response.data && response.data.code === 'mainwp_knowledge_not_found') { |
| 139 |
const previousOwner = owner; |
| 140 |
modal.modal('hide'); |
| 141 |
showMessage(previousOwner.message, errorText(response), 'yellow'); |
| 142 |
previousOwner.refresh(true); |
| 143 |
return; |
| 144 |
} |
| 145 |
showConflict(errorText(response)); |
| 146 |
return; |
| 147 |
} |
| 148 |
applyRecord(response, 'edit'); |
| 149 |
showMessage(modalMessage, strings.reloaded, 'yellow'); |
| 150 |
}).fail(() => { |
| 151 |
if (current === session) { |
| 152 |
showConflict(strings.failed); |
| 153 |
} |
| 154 |
}); |
| 155 |
}; |
| 156 |
const showConflict = (message) => { |
| 157 |
showMessage(modalMessage, message || strings.conflict, 'yellow'); |
| 158 |
modalMessage.append($('<p></p>').append( |
| 159 |
$('<button type="button" class="ui mini basic button"></button>').text(strings.reload).on('click', reloadIntoEditor) |
| 160 |
)); |
| 161 |
}; |
| 162 |
const save = () => { |
| 163 |
if (readOnly || !canWrite || !scope || saveButton.hasClass('disabled')) { |
| 164 |
return; |
| 165 |
} |
| 166 |
if ('skill' === typeField.val() && !descriptionField[0].reportValidity()) { |
| 167 |
return; |
| 168 |
} |
| 169 |
const current = session; |
| 170 |
const previousOwner = owner; |
| 171 |
hideMessage(modalMessage); |
| 172 |
saveButton.prop('disabled', true).addClass('loading disabled'); |
| 173 |
deleteButton.prop('disabled', true).addClass('disabled'); |
| 174 |
const data = $.extend({}, scope, { |
| 175 |
type: typeField.val(), |
| 176 |
title: titleField.val(), |
| 177 |
description: 'skill' === typeField.val() ? descriptionField.val() : '', |
| 178 |
body: bodyField.val(), |
| 179 |
}); |
| 180 |
if (['agency', 'client'].includes(scope.scope_type)) { |
| 181 |
data.required = ['context', 'skill'].includes(data.type) && requiredField.prop('checked') ? 1 : 0; |
| 182 |
} |
| 183 |
const id = parseInt(idField.val(), 10); |
| 184 |
if (id > 0) { |
| 185 |
data.id = id; |
| 186 |
data.revision = revisionField.val(); |
| 187 |
} |
| 188 |
post('mainwp_knowledge_save', data).done((response) => { |
| 189 |
if (response.success) { |
| 190 |
if (current === session) { |
| 191 |
modal.modal('hide'); |
| 192 |
} |
| 193 |
previousOwner.refresh(); |
| 194 |
return; |
| 195 |
} |
| 196 |
if (current !== session) { |
| 197 |
return; |
| 198 |
} |
| 199 |
if (response.data && response.data.code === 'mainwp_knowledge_conflict') { |
| 200 |
saveButton.removeClass('loading'); |
| 201 |
showConflict(response.data.message); |
| 202 |
return; |
| 203 |
} |
| 204 |
showMessage(modalMessage, errorText(response), 'red'); |
| 205 |
saveButton.prop('disabled', false).removeClass('loading disabled'); |
| 206 |
deleteButton.prop('disabled', false).removeClass('disabled'); |
| 207 |
if (response.data && response.data.code === 'mainwp_knowledge_not_found') { |
| 208 |
previousOwner.refresh(); |
| 209 |
} |
| 210 |
}).fail(() => { |
| 211 |
if (current === session) { |
| 212 |
showMessage(modalMessage, strings.failed, 'red'); |
| 213 |
saveButton.prop('disabled', false).removeClass('loading disabled'); |
| 214 |
deleteButton.prop('disabled', false).removeClass('disabled'); |
| 215 |
} |
| 216 |
}); |
| 217 |
}; |
| 218 |
|
| 219 |
const reviewLevel = (record, classes) => { |
| 220 |
const level = record.level_url ? $('<a></a>').attr('href', record.level_url) : $('<span></span>'); |
| 221 |
if (record.level_url) { |
| 222 |
level.on('click keydown', (event) => event.stopPropagation()); |
| 223 |
} |
| 224 |
return level.addClass(classes).text(record.level_label || ''); |
| 225 |
}; |
| 226 |
const recordPair = (record, canEdit = false, siteUrl = '', options = {}) => { |
| 227 |
const recordCanEdit = options.review ? !!record.can_write : canEdit; |
| 228 |
const title = $('<div class="title mainwp-knowledge-record-title"></div>') |
| 229 |
.attr('data-id', record.id) |
| 230 |
.attr('data-revision', record.revision) |
| 231 |
.data('can-edit', recordCanEdit) |
| 232 |
.attr({ role: 'button', tabindex: '0', 'aria-expanded': 'false' }); |
| 233 |
const requiredEligible = ['agency', 'client'].includes(record.scope_type) && ['context', 'skill'].includes(record.type); |
| 234 |
if (requiredEligible) { |
| 235 |
const checkboxId = `mainwp-knowledge-required-record-${record.id}`; |
| 236 |
const required = $('<span class="mainwp-knowledge-required-indicator"></span>').on('click keydown', (event) => event.stopPropagation()); |
| 237 |
const checkbox = $('<span class="ui checkbox"></span>').toggleClass('disabled', !recordCanEdit); |
| 238 |
checkbox.append($('<input type="checkbox" class="mainwp-knowledge-required-toggle">').attr('id', checkboxId).prop('checked', !!record.required).prop('disabled', !recordCanEdit)); |
| 239 |
checkbox.append($('<label></label>').attr('for', checkboxId).text(strings.required)); |
| 240 |
title.append(required.append(checkbox)); |
| 241 |
} |
| 242 |
if (!record.verified) { |
| 243 |
title.append($('<span class="ui mini yellow label"></span>').attr('data-tooltip', strings.unverifiedHint).attr('data-inverted', '').text(strings.unverified)); |
| 244 |
} else if (options.review) { |
| 245 |
title.append($('<span class="ui mini green label"></span>').text(strings.verified)); |
| 246 |
} |
| 247 |
title.append($('<span class="mainwp-knowledge-record-name"></span>').text(record.title)); |
| 248 |
if (options.review && record.level_label) { |
| 249 |
title.append(reviewLevel(record, 'ui mini basic label mainwp-knowledge-record-level')); |
| 250 |
} |
| 251 |
title.append($('<i class="chevron right grey icon mainwp-knowledge-record-chevron"></i>').attr('aria-hidden', 'true')); |
| 252 |
|
| 253 |
const content = $('<div class="content mainwp-knowledge-record-content"></div>') |
| 254 |
.attr('data-id', record.id) |
| 255 |
.attr('data-revision', record.revision) |
| 256 |
.attr('aria-hidden', 'true') |
| 257 |
.data('can-edit', !!recordCanEdit) |
| 258 |
.data('review', !!options.review) |
| 259 |
.attr('data-site-url', siteUrl || ''); |
| 260 |
content.append($('<div class="ui active centered inline loader"></div>')); |
| 261 |
return [title, content]; |
| 262 |
}; |
| 263 |
const loadRecordDetails = (content) => { |
| 264 |
if (content.data('loaded') || content.data('loading')) { |
| 265 |
return; |
| 266 |
} |
| 267 |
content.data('loading', true); |
| 268 |
post('mainwp_knowledge_get', { id: content.data('id') }).done((response) => { |
| 269 |
if (!response.success) { |
| 270 |
content.empty().append($('<div class="ui yellow message"></div>').text(errorText(response))); |
| 271 |
return; |
| 272 |
} |
| 273 |
const record = response.data.record; |
| 274 |
const details = $('<div class="mainwp-knowledge-record-details"></div>'); |
| 275 |
const recordCards = $('<div class="ui one cards mainwp-knowledge-record-card"></div>'); |
| 276 |
const recordCard = $('<div class="card"></div>'); |
| 277 |
if (content.data('review') && record.level_label) { |
| 278 |
recordCard.append($('<div class="content mainwp-knowledge-record-heading"></div>') |
| 279 |
.append($('<div class="ui small header"></div>').append(reviewLevel(record, 'mainwp-knowledge-record-level-link')))); |
| 280 |
} |
| 281 |
const bodyContent = $('<div class="content mainwp-knowledge-record-body"></div>') |
| 282 |
.attr({ role: 'region', tabindex: '0', 'aria-label': strings.body }); |
| 283 |
bodyContent.append($('<div class="description mainwp-knowledge-record-value"></div>').text(record.body || '')); |
| 284 |
const descriptionContent = $('<div class="extra content mainwp-knowledge-record-description"></div>'); |
| 285 |
if ('skill' === record.type) { |
| 286 |
descriptionContent |
| 287 |
.append($('<div class="ui tiny header"></div>').text(strings.description)) |
| 288 |
.append($('<div class="mainwp-knowledge-record-value"></div>').text(record.description || '')); |
| 289 |
} |
| 290 |
const footerContent = $('<div class="extra content mainwp-knowledge-record-footer"></div>'); |
| 291 |
const actions = $('<div class="ui two column middle aligned grid mainwp-knowledge-record-actions"></div>'); |
| 292 |
const leftActions = $('<div class="eight wide left aligned column"></div>'); |
| 293 |
const rightActions = $('<div class="eight wide right aligned column"></div>'); |
| 294 |
leftActions.append($('<span class="ui small text mainwp-knowledge-record-meta"></span>').text(`${strings.editedBy} ${record.updated_by_name} ${record.updated_ago}`)); |
| 295 |
const inReadOnlyWidget = !!content.closest('.mainwp-knowledge-read-only-widget').length; |
| 296 |
const canEdit = !inReadOnlyWidget && !!content.data('can-edit') && !!response.data.can_write; |
| 297 |
if (canEdit) { |
| 298 |
if (content.data('review') && !record.verified) { |
| 299 |
rightActions.append($('<button type="button" class="ui mini green button mainwp-knowledge-verify"></button>').text(strings.verify)); |
| 300 |
} |
| 301 |
rightActions.append($('<button type="button" class="ui mini basic button mainwp-knowledge-edit"></button>').text(strings.edit)); |
| 302 |
rightActions.append($('<button type="button" class="ui mini basic red button mainwp-knowledge-delete"></button>').text(strings.remove)); |
| 303 |
} else if (!inReadOnlyWidget) { |
| 304 |
rightActions.append($('<button type="button" class="ui mini basic button mainwp-knowledge-view"></button>').text(strings.view)); |
| 305 |
} |
| 306 |
const siteUrl = content.attr('data-site-url'); |
| 307 |
if (siteUrl) { |
| 308 |
rightActions.append($('<a class="ui mini basic button"></a>').attr('href', siteUrl).text(strings.viewOnSite)); |
| 309 |
} |
| 310 |
footerContent.append(actions.append(leftActions, rightActions)); |
| 311 |
if ('skill' === record.type) { |
| 312 |
recordCard.append(descriptionContent); |
| 313 |
} |
| 314 |
recordCard.append(bodyContent); |
| 315 |
recordCard.append(footerContent); |
| 316 |
recordCards.append(recordCard); |
| 317 |
details.append(recordCards); |
| 318 |
content.empty().append(details).data('loaded', true); |
| 319 |
}).fail(() => { |
| 320 |
content.empty().append($('<div class="ui red message"></div>').text(strings.failed)); |
| 321 |
}).always(() => content.data('loading', false)); |
| 322 |
}; |
| 323 |
const initializeRecordAccordions = (container) => { |
| 324 |
container.find('.mainwp-knowledge-records').each(function () { |
| 325 |
const accordion = $(this); |
| 326 |
accordion.accordion({ |
| 327 |
exclusive: false, |
| 328 |
onOpening: function () { |
| 329 |
$(this).attr('aria-hidden', 'false').prev('.mainwp-knowledge-record-title').attr('aria-expanded', 'true'); |
| 330 |
loadRecordDetails($(this)); |
| 331 |
}, |
| 332 |
onClosing: function () { |
| 333 |
$(this).attr('aria-hidden', 'true').prev('.mainwp-knowledge-record-title').attr('aria-expanded', 'false'); |
| 334 |
}, |
| 335 |
}); |
| 336 |
// Do not let the surrounding Client Edit accordion process this nested accordion click too. |
| 337 |
accordion.off('click.mainwpKnowledge').on('click.mainwpKnowledge', '.mainwp-knowledge-record-title', (event) => event.stopPropagation()); |
| 338 |
accordion.off('keydown.mainwpKnowledge').on('keydown.mainwpKnowledge', '.mainwp-knowledge-record-title', function (event) { |
| 339 |
if ($(event.target).is('input, label, button, a')) { |
| 340 |
return; |
| 341 |
} |
| 342 |
if (['Enter', ' '].includes(event.key)) { |
| 343 |
event.preventDefault(); |
| 344 |
$(this).trigger('click'); |
| 345 |
} |
| 346 |
}); |
| 347 |
}); |
| 348 |
}; |
| 349 |
const renderRecordSet = (target, records, emptyText, canEdit = false, siteUrl = '', options = {}) => { |
| 350 |
const placeholder = target.siblings('.mainwp-knowledge-empty'); |
| 351 |
const sectionBox = target.closest('.mainwp-knowledge-section-box'); |
| 352 |
const footer = sectionBox.children('.mainwp-widget-footer'); |
| 353 |
const addButton = sectionBox.find('.mainwp-knowledge-add').first(); |
| 354 |
target.empty(); |
| 355 |
placeholder.hide().attr('aria-hidden', 'true'); |
| 356 |
if (!records.length) { |
| 357 |
if (placeholder.length && (emptyText === strings.empty || options.usePlaceholder)) { |
| 358 |
target.hide().attr('aria-hidden', 'true'); |
| 359 |
placeholder.show().attr('aria-hidden', 'false'); |
| 360 |
addButton.appendTo(placeholder.find('.mainwp-empty-widget-placeholder')); |
| 361 |
footer.hide(); |
| 362 |
} else { |
| 363 |
target.show().attr('aria-hidden', 'false').append($('<div class="mainwp-knowledge-empty"></div>').append($('<em></em>').text(emptyText))); |
| 364 |
footer.hide(); |
| 365 |
} |
| 366 |
} else { |
| 367 |
target.show().attr('aria-hidden', 'false'); |
| 368 |
addButton.appendTo(footer); |
| 369 |
footer.toggle(canEdit); |
| 370 |
records.forEach((record) => { |
| 371 |
const pair = recordPair(record, canEdit, siteUrl, options); |
| 372 |
target.append(pair[0], pair[1]); |
| 373 |
}); |
| 374 |
} |
| 375 |
initializeRecordAccordions(target.parent()); |
| 376 |
}; |
| 377 |
const recordContainer = (element) => element.closest('[data-id]'); |
| 378 |
const updateRequired = (checkbox, message, refresh) => { |
| 379 |
const checkboxUi = checkbox.closest('.ui.checkbox'); |
| 380 |
const record = checkbox.closest('.mainwp-knowledge-record-title'); |
| 381 |
const next = checkbox.prop('checked'); |
| 382 |
const restore = () => { |
| 383 |
checkbox.prop('checked', !next).prop('disabled', false); |
| 384 |
checkboxUi.removeClass('disabled').removeAttr('aria-busy'); |
| 385 |
}; |
| 386 |
if (!record.data('can-edit') || checkbox.prop('disabled')) { |
| 387 |
restore(); |
| 388 |
return; |
| 389 |
} |
| 390 |
checkbox.prop('disabled', true); |
| 391 |
checkboxUi.addClass('disabled').attr('aria-busy', 'true'); |
| 392 |
post('mainwp_knowledge_required', { id: record.data('id'), revision: record.data('revision'), required: next ? 1 : 0 }).done((response) => { |
| 393 |
if (response.success) { |
| 394 |
checkbox.prop('disabled', false); |
| 395 |
checkboxUi.removeClass('disabled').removeAttr('aria-busy'); |
| 396 |
refresh(); |
| 397 |
return; |
| 398 |
} |
| 399 |
restore(); |
| 400 |
showMessage(message, errorText(response), 'yellow'); |
| 401 |
if (response.data && ['mainwp_knowledge_conflict', 'mainwp_knowledge_not_found'].includes(response.data.code)) { |
| 402 |
refresh(true); |
| 403 |
} |
| 404 |
}).fail(() => { |
| 405 |
restore(); |
| 406 |
showMessage(message, strings.failed, 'red'); |
| 407 |
}); |
| 408 |
}; |
| 409 |
|
| 410 |
$('.mainwp-knowledge-panel').each(function () { |
| 411 |
const panel = $(this); |
| 412 |
const panelScope = recordScope({ scope_type: panel.data('scope-type'), scope_id: panel.data('scope-id') }); |
| 413 |
const panelReadOnly = '1' === panel.attr('data-read-only') || !!panel.closest('.mainwp-knowledge-read-only-widget').length; |
| 414 |
if (panelReadOnly) { |
| 415 |
panelScope.read_only = 1; |
| 416 |
} |
| 417 |
const message = panel.find('.mainwp-knowledge-message'); |
| 418 |
const loader = panel.children('.mainwp-knowledge-loader'); |
| 419 |
const inheritedBlock = panel.find('.mainwp-knowledge-inherited'); |
| 420 |
let panelCanWrite = false; |
| 421 |
const renderInherited = (inherited) => { |
| 422 |
if (!inherited) { |
| 423 |
inheritedBlock.hide().find('.mainwp-knowledge-records').empty(); |
| 424 |
return; |
| 425 |
} |
| 426 |
inheritedBlock.find('.mainwp-knowledge-inherited-title').text(strings.inheritedFrom.replace('%s', () => inherited.client_name)); |
| 427 |
inheritedBlock.find('.mainwp-knowledge-inherited-link').attr('href', inherited.client_url); |
| 428 |
inheritedBlock.find('.mainwp-knowledge-inherited-empty').toggle(!inherited.records.length).text(inherited.records.length ? '' : strings.inheritedEmpty); |
| 429 |
inheritedBlock.find('.mainwp-knowledge-inherited-sections').toggle(!!inherited.records.length); |
| 430 |
inheritedBlock.find('.mainwp-knowledge-inherited-section').each(function () { |
| 431 |
const section = $(this); |
| 432 |
const records = inherited.records.filter((record) => record.type === section.data('type')); |
| 433 |
renderRecordSet(section.find('.mainwp-knowledge-records'), records, strings.empty); |
| 434 |
}); |
| 435 |
inheritedBlock.show(); |
| 436 |
}; |
| 437 |
const render = (records, denied) => { |
| 438 |
panel.find('.mainwp-knowledge-section').each(function () { |
| 439 |
const section = $(this); |
| 440 |
const own = records.filter((record) => record.type === section.data('type')); |
| 441 |
renderRecordSet(section.find('.mainwp-knowledge-records'), own, denied ? strings.noAccess : strings.empty, panelCanWrite); |
| 442 |
section.find('.mainwp-knowledge-add').toggle(panelCanWrite); |
| 443 |
}); |
| 444 |
}; |
| 445 |
const load = (preserveMessage = false) => { |
| 446 |
loader.addClass('active').attr('aria-hidden', 'false'); |
| 447 |
post('mainwp_knowledge_list', panelScope).done((response) => { |
| 448 |
if (response.success) { |
| 449 |
panelCanWrite = !panelReadOnly && !!response.data.can_write; |
| 450 |
if (!preserveMessage) { |
| 451 |
hideMessage(message); |
| 452 |
} |
| 453 |
render(response.data.records, false); |
| 454 |
renderInherited(response.data.inherited); |
| 455 |
} else { |
| 456 |
const code = response.data ? response.data.code : ''; |
| 457 |
if ('mainwp_knowledge_insecure' !== code && response.data && [403, 404].includes(response.data.status)) { |
| 458 |
panelCanWrite = false; |
| 459 |
render([], true); |
| 460 |
renderInherited(null); |
| 461 |
} |
| 462 |
showMessage(message, errorText(response), 'yellow'); |
| 463 |
} |
| 464 |
}).fail(() => showMessage(message, strings.failed, 'red')).always(() => { |
| 465 |
loader.removeClass('active').attr('aria-hidden', 'true'); |
| 466 |
}); |
| 467 |
}; |
| 468 |
const panelOwner = { message: message, refresh: load }; |
| 469 |
panel.on('change', '.mainwp-knowledge-required-toggle', function () { |
| 470 |
if (panelReadOnly) { |
| 471 |
return; |
| 472 |
} |
| 473 |
updateRequired($(this), message, load); |
| 474 |
}); |
| 475 |
panel.on('click', '.mainwp-knowledge-add', function () { |
| 476 |
if (panelReadOnly || !panelCanWrite) { |
| 477 |
return; |
| 478 |
} |
| 479 |
begin(panelOwner); |
| 480 |
scope = $.extend({}, panelScope); |
| 481 |
canWrite = panelCanWrite; |
| 482 |
fill({ id: 0, revision: 0, type: $(this).data('type'), title: '', description: '', body: '' }); |
| 483 |
openModal('add'); |
| 484 |
}); |
| 485 |
panel.on('click', '.mainwp-knowledge-edit, .mainwp-knowledge-view', function (event) { |
| 486 |
event.preventDefault(); |
| 487 |
openRecord(recordContainer($(this)).data('id'), panelReadOnly || $(this).hasClass('mainwp-knowledge-view') ? 'view' : 'edit', panelOwner); |
| 488 |
}); |
| 489 |
panel.on('click', '.mainwp-knowledge-delete', function () { |
| 490 |
if (panelReadOnly) { |
| 491 |
return; |
| 492 |
} |
| 493 |
const record = recordContainer($(this)); |
| 494 |
mainwp_confirm(strings.confirmDelete, () => { |
| 495 |
post('mainwp_knowledge_delete', { id: record.data('id'), revision: record.data('revision') }).done((response) => { |
| 496 |
if (response.success) { |
| 497 |
load(); |
| 498 |
} else { |
| 499 |
showMessage(message, errorText(response), 'yellow'); |
| 500 |
load(true); |
| 501 |
} |
| 502 |
}).fail(() => showMessage(message, strings.failed, 'red')); |
| 503 |
}); |
| 504 |
}); |
| 505 |
load(); |
| 506 |
}); |
| 507 |
|
| 508 |
$('.mainwp-knowledge-site-list').each(function () { |
| 509 |
const list = $(this); |
| 510 |
const siteScope = recordScope({ scope_type: 'site', scope_id: list.data('scope-id') }); |
| 511 |
const message = list.children('.mainwp-knowledge-message'); |
| 512 |
const loader = list.children('.mainwp-knowledge-loader'); |
| 513 |
const sections = list.find('.mainwp-knowledge-site-sections'); |
| 514 |
const empty = list.find('.mainwp-knowledge-site-empty'); |
| 515 |
let request = 0; |
| 516 |
const load = (preserveMessage = false) => { |
| 517 |
const current = ++request; |
| 518 |
list.find('.mainwp-knowledge-records').empty(); |
| 519 |
loader.addClass('active').attr('aria-hidden', 'false'); |
| 520 |
post('mainwp_knowledge_list', $.extend({}, siteScope, { read_only: 1 })).done((response) => { |
| 521 |
if (current !== request) { |
| 522 |
return; |
| 523 |
} |
| 524 |
if (!response.success) { |
| 525 |
showMessage(message, errorText(response), 'yellow'); |
| 526 |
return; |
| 527 |
} |
| 528 |
if (!preserveMessage) { |
| 529 |
hideMessage(message); |
| 530 |
} |
| 531 |
const hasRecords = !!response.data.records.length; |
| 532 |
empty.toggle(!hasRecords).text(hasRecords ? '' : strings.noRecords); |
| 533 |
sections.toggle(hasRecords); |
| 534 |
list.find('.mainwp-knowledge-site-section').each(function () { |
| 535 |
const section = $(this); |
| 536 |
const records = response.data.records.filter((record) => record.type === section.data('type')); |
| 537 |
renderRecordSet(section.find('.mainwp-knowledge-records'), records, strings.empty, false, list.data('site-url')); |
| 538 |
}); |
| 539 |
}).fail(() => { |
| 540 |
if (current === request) { |
| 541 |
showMessage(message, strings.failed, 'red'); |
| 542 |
} |
| 543 |
}).always(() => { |
| 544 |
if (current === request) { |
| 545 |
loader.removeClass('active').attr('aria-hidden', 'true'); |
| 546 |
} |
| 547 |
}); |
| 548 |
}; |
| 549 |
const siteOwner = { message: message, refresh: load }; |
| 550 |
list.data('knowledge-owner', siteOwner); |
| 551 |
list.on('click', '.mainwp-knowledge-view', function (event) { |
| 552 |
event.preventDefault(); |
| 553 |
openRecord(recordContainer($(this)).data('id'), 'view', siteOwner); |
| 554 |
}); |
| 555 |
}); |
| 556 |
$('.mainwp-knowledge-site-accordion').each(function () { |
| 557 |
const accordion = $(this); |
| 558 |
accordion.find('tr.title a').on('click', (event) => event.stopPropagation()); |
| 559 |
accordion.accordion({ |
| 560 |
exclusive: false, |
| 561 |
onOpen: function () { |
| 562 |
const siteOwner = $(this).find('.mainwp-knowledge-site-list').data('knowledge-owner'); |
| 563 |
if (siteOwner) { |
| 564 |
siteOwner.refresh(); |
| 565 |
} |
| 566 |
}, |
| 567 |
}); |
| 568 |
}); |
| 569 |
|
| 570 |
const review = $('#mainwp-knowledge-review'); |
| 571 |
if (review.length) { |
| 572 |
const message = $('#mainwp-knowledge-review-message'); |
| 573 |
const emptyState = $('#mainwp-knowledge-review-empty'); |
| 574 |
const filteredEmpty = $('#mainwp-knowledge-review-filtered-empty'); |
| 575 |
const sections = review.find('.mainwp-knowledge-review-sections'); |
| 576 |
const loader = review.children('.mainwp-knowledge-loader'); |
| 577 |
const filters = $('#mainwp-knowledge-review-filters'); |
| 578 |
let request = 0; |
| 579 |
const clearRecords = () => review.find('.mainwp-knowledge-records').empty(); |
| 580 |
const renderRecords = (records) => { |
| 581 |
review.find('.mainwp-knowledge-review-section').each(function () { |
| 582 |
const section = $(this); |
| 583 |
const typeRecords = records.filter((record) => record.type === section.data('type')); |
| 584 |
renderRecordSet(section.find('.mainwp-knowledge-records'), typeRecords, strings.noRecords, true, '', { review: true, usePlaceholder: true }); |
| 585 |
}); |
| 586 |
}; |
| 587 |
const load = (preserveMessage = false) => { |
| 588 |
const current = ++request; |
| 589 |
const data = { |
| 590 |
draw: current, |
| 591 |
status: $('#mainwp-knowledge-filter-status').val(), |
| 592 |
level: $('#mainwp-knowledge-filter-level').val(), |
| 593 |
}; |
| 594 |
loader.addClass('active').attr('aria-hidden', 'false'); |
| 595 |
post('mainwp_knowledge_review', data).done((response) => { |
| 596 |
if (current !== request) { |
| 597 |
return; |
| 598 |
} |
| 599 |
if (response.success === false) { |
| 600 |
showMessage(message, errorText(response), 'yellow'); |
| 601 |
clearRecords(); |
| 602 |
return; |
| 603 |
} |
| 604 |
if (!preserveMessage) { |
| 605 |
hideMessage(message); |
| 606 |
} |
| 607 |
const total = Number(response.recordsTotal); |
| 608 |
const filtered = Number(response.recordsFiltered); |
| 609 |
const hasRecords = total > 0; |
| 610 |
const hasFilteredRecords = filtered > 0; |
| 611 |
filters.toggleClass('hidden', !hasRecords).attr('aria-hidden', hasRecords ? 'false' : 'true'); |
| 612 |
review.toggleClass('hidden', !hasRecords).attr('aria-hidden', hasRecords ? 'false' : 'true'); |
| 613 |
emptyState.toggleClass('hidden', hasRecords).attr('aria-hidden', hasRecords ? 'true' : 'false'); |
| 614 |
sections.toggleClass('hidden', !hasFilteredRecords).attr('aria-hidden', hasFilteredRecords ? 'false' : 'true'); |
| 615 |
filteredEmpty.toggleClass('hidden', !hasRecords || hasFilteredRecords).attr('aria-hidden', hasRecords && !hasFilteredRecords ? 'false' : 'true'); |
| 616 |
clearRecords(); |
| 617 |
if (hasFilteredRecords) { |
| 618 |
renderRecords(response.data); |
| 619 |
} |
| 620 |
}).fail(() => { |
| 621 |
if (current === request) { |
| 622 |
showMessage(message, strings.failed, 'red'); |
| 623 |
clearRecords(); |
| 624 |
} |
| 625 |
}).always(() => { |
| 626 |
if (current === request) { |
| 627 |
loader.removeClass('active').attr('aria-hidden', 'true'); |
| 628 |
} |
| 629 |
}); |
| 630 |
}; |
| 631 |
const reviewOwner = { message: message, refresh: load }; |
| 632 |
filters.find('select').dropdown().on('change', () => load()); |
| 633 |
review.on('change', '.mainwp-knowledge-required-toggle', function () { |
| 634 |
updateRequired($(this), message, load); |
| 635 |
}); |
| 636 |
review.on('click', '.mainwp-knowledge-edit, .mainwp-knowledge-view', function (event) { |
| 637 |
event.preventDefault(); |
| 638 |
openRecord(recordContainer($(this)).data('id'), $(this).hasClass('mainwp-knowledge-view') ? 'view' : 'edit', reviewOwner); |
| 639 |
}); |
| 640 |
review.on('click', '.mainwp-knowledge-verify', function () { |
| 641 |
const button = $(this); |
| 642 |
const record = recordContainer(button); |
| 643 |
button.prop('disabled', true).addClass('loading disabled'); |
| 644 |
post('mainwp_knowledge_verify', { id: record.data('id'), revision: record.data('revision') }).done((response) => { |
| 645 |
if (response.success) { |
| 646 |
load(); |
| 647 |
} else { |
| 648 |
showMessage(message, errorText(response), 'yellow'); |
| 649 |
load(true); |
| 650 |
} |
| 651 |
}).fail(() => { |
| 652 |
button.prop('disabled', false).removeClass('loading disabled'); |
| 653 |
showMessage(message, strings.failed, 'red'); |
| 654 |
}); |
| 655 |
}); |
| 656 |
review.on('click', '.mainwp-knowledge-delete', function () { |
| 657 |
const record = recordContainer($(this)); |
| 658 |
mainwp_confirm(strings.confirmDelete, () => { |
| 659 |
post('mainwp_knowledge_delete', { id: record.data('id'), revision: record.data('revision') }).done((response) => { |
| 660 |
if (response.success) { |
| 661 |
load(); |
| 662 |
} else { |
| 663 |
showMessage(message, errorText(response), 'yellow'); |
| 664 |
load(true); |
| 665 |
} |
| 666 |
}).fail(() => showMessage(message, strings.failed, 'red')); |
| 667 |
}); |
| 668 |
}); |
| 669 |
load(); |
| 670 |
} |
| 671 |
|
| 672 |
modal.modal({ closable: false, onHide: () => { |
| 673 |
++session; |
| 674 |
owner = null; |
| 675 |
scope = null; |
| 676 |
canWrite = false; |
| 677 |
readOnly = true; |
| 678 |
} }); |
| 679 |
saveButton.on('click', save); |
| 680 |
deleteButton.on('click', () => { |
| 681 |
if (readOnly || !canWrite || deleteButton.hasClass('disabled')) { |
| 682 |
return; |
| 683 |
} |
| 684 |
const current = session; |
| 685 |
const previousOwner = owner; |
| 686 |
const data = { id: idField.val(), revision: revisionField.val() }; |
| 687 |
mainwp_confirm(strings.confirmDelete, () => { |
| 688 |
if (current !== session) { |
| 689 |
return; |
| 690 |
} |
| 691 |
deleteButton.prop('disabled', true).addClass('loading disabled'); |
| 692 |
saveButton.prop('disabled', true).addClass('disabled'); |
| 693 |
post('mainwp_knowledge_delete', data).done((response) => { |
| 694 |
if (response.success) { |
| 695 |
if (current === session) { |
| 696 |
modal.modal('hide'); |
| 697 |
} |
| 698 |
previousOwner.refresh(); |
| 699 |
return; |
| 700 |
} |
| 701 |
if (current !== session) { |
| 702 |
return; |
| 703 |
} |
| 704 |
if (response.data && response.data.code === 'mainwp_knowledge_conflict') { |
| 705 |
deleteButton.removeClass('loading'); |
| 706 |
showConflict(response.data.message); |
| 707 |
} else { |
| 708 |
showMessage(modalMessage, errorText(response), 'red'); |
| 709 |
deleteButton.prop('disabled', false).removeClass('loading disabled'); |
| 710 |
saveButton.prop('disabled', false).removeClass('disabled'); |
| 711 |
} |
| 712 |
}).fail(() => { |
| 713 |
if (current === session) { |
| 714 |
showMessage(modalMessage, strings.failed, 'red'); |
| 715 |
deleteButton.prop('disabled', false).removeClass('loading disabled'); |
| 716 |
saveButton.prop('disabled', false).removeClass('disabled'); |
| 717 |
} |
| 718 |
}); |
| 719 |
}, false, false, true); |
| 720 |
}); |
| 721 |
typeField.on('change', updateFields); |
| 722 |
typeField.closest('.dropdown').dropdown(); |
| 723 |
requiredField.closest('.checkbox').checkbox(); |
| 724 |
}); |
| 725 |
|