|
Lines 64-69
window.onbeforeunload = function () {
Link Here
|
| 64 |
} |
64 |
} |
| 65 |
}; |
65 |
}; |
| 66 |
|
66 |
|
|
|
67 |
// Add event handlers to any elements with .expand-textarea classes |
| 68 |
// this allows the CodeMirror widget to be displayed |
| 69 |
function addExpandHandler() { |
| 70 |
// Don't duplicate click event handlers |
| 71 |
const ev = $._data($('.expand-textarea'), 'events'); |
| 72 |
if (ev && ev.click) { |
| 73 |
return; |
| 74 |
} |
| 75 |
$(".expand-textarea").on("click", function (e) { |
| 76 |
e.preventDefault(); |
| 77 |
$(this).hide(); |
| 78 |
var target = $(this).data("target"); |
| 79 |
var syntax = $(this).data("syntax"); |
| 80 |
$("#collapse_" + target).show(); |
| 81 |
if (syntax) { |
| 82 |
var editor = CodeMirror.fromTextArea(document.getElementById("pref_" + target), { |
| 83 |
lineNumbers: true, |
| 84 |
mode: syntax, |
| 85 |
lineWrapping: true, |
| 86 |
viewportMargin: Infinity, |
| 87 |
gutters: ["CodeMirror-lint-markers"], |
| 88 |
lint: true |
| 89 |
}); |
| 90 |
editor.on("change", function () { |
| 91 |
mark_modified.call($("#pref_" + target)[0]); |
| 92 |
}); |
| 93 |
editor.on("blur", function () { |
| 94 |
editor.save(); |
| 95 |
}); |
| 96 |
} else { |
| 97 |
$("#pref_" + target).show(); |
| 98 |
} |
| 99 |
}); |
| 100 |
} |
| 101 |
|
| 102 |
// Add event handlers to any elements with .collapse-textarea classes |
| 103 |
// this allows the hiding of the CodeMirror widget |
| 104 |
function addCollapseHandler() { |
| 105 |
// Don't duplicate click event handlers |
| 106 |
const ev = $._data($('.collapse-textarea'), 'events'); |
| 107 |
if (ev && ev.click) { |
| 108 |
return; |
| 109 |
} |
| 110 |
$(".collapse-textarea").on("click", function (e) { |
| 111 |
e.preventDefault(); |
| 112 |
$(this).hide(); |
| 113 |
var target = $(this).data("target"); |
| 114 |
var syntax = $(this).data("syntax"); |
| 115 |
$("#expand_" + target).show(); |
| 116 |
if (syntax) { |
| 117 |
var editor = $("#pref_" + target).next(".CodeMirror")[0].CodeMirror; |
| 118 |
editor.toTextArea(); |
| 119 |
} |
| 120 |
$("#pref_" + target).hide(); |
| 121 |
}); |
| 122 |
} |
| 123 |
|
| 124 |
// Add a handler for any consent delete links |
| 125 |
function addConsentDeleteHandler() { |
| 126 |
// Don't duplicate click event handlers |
| 127 |
const ev = $._data($('.consentDelete'), 'events'); |
| 128 |
if (ev && ev.click) { |
| 129 |
return; |
| 130 |
} |
| 131 |
$('.consentDelete').on('click', function (e) { |
| 132 |
e.preventDefault(); |
| 133 |
const target = $(this).data('target'); |
| 134 |
const proceed = confirm(__('Are you sure you want to delete this consent item?')); |
| 135 |
if (proceed) { |
| 136 |
$('#' + target).remove(); |
| 137 |
} |
| 138 |
}); |
| 139 |
} |
| 140 |
|
| 67 |
$( document ).ready( function () { |
141 |
$( document ).ready( function () { |
| 68 |
|
142 |
|
| 69 |
$("table.preferences").dataTable($.extend(true, {}, dataTablesDefaults, { |
143 |
$("table.preferences").dataTable($.extend(true, {}, dataTablesDefaults, { |
|
Lines 107-150
$( document ).ready( function () {
Link Here
|
| 107 |
return false; |
181 |
return false; |
| 108 |
}); |
182 |
}); |
| 109 |
|
183 |
|
| 110 |
$( ".expand-textarea" ).on("click", function(e){ |
184 |
addExpandHandler(); |
| 111 |
e.preventDefault(); |
|
|
| 112 |
$(this).hide(); |
| 113 |
var target = $(this).data("target"); |
| 114 |
var syntax = $(this).data("syntax"); |
| 115 |
$("#collapse_" + target ).show(); |
| 116 |
if( syntax ){ |
| 117 |
var editor = CodeMirror.fromTextArea( document.getElementById( "pref_" + target ), { |
| 118 |
lineNumbers: true, |
| 119 |
mode: syntax, |
| 120 |
lineWrapping: true, |
| 121 |
viewportMargin: Infinity, |
| 122 |
gutters: ["CodeMirror-lint-markers"], |
| 123 |
lint: true |
| 124 |
}); |
| 125 |
editor.on("change", function(){ |
| 126 |
mark_modified.call( $("#pref_" + target )[0]); |
| 127 |
}); |
| 128 |
editor.on("blur", function(){ |
| 129 |
editor.save(); |
| 130 |
}); |
| 131 |
} else { |
| 132 |
$("#pref_" + target ).show(); |
| 133 |
} |
| 134 |
}); |
| 135 |
|
185 |
|
| 136 |
$( ".collapse-textarea" ).on("click", function(e){ |
186 |
addCollapseHandler(); |
| 137 |
e.preventDefault(); |
|
|
| 138 |
$(this).hide(); |
| 139 |
var target = $(this).data("target"); |
| 140 |
var syntax = $(this).data("syntax"); |
| 141 |
$("#expand_" + target ).show(); |
| 142 |
if( syntax ){ |
| 143 |
var editor = $("#pref_" + target ).next(".CodeMirror")[0].CodeMirror; |
| 144 |
editor.toTextArea(); |
| 145 |
} |
| 146 |
$("#pref_" + target ).hide(); |
| 147 |
}); |
| 148 |
|
187 |
|
| 149 |
$("h3").attr("class", "expanded").attr("title", __("Click to collapse this section")); |
188 |
$("h3").attr("class", "expanded").attr("title", __("Click to collapse this section")); |
| 150 |
var collapsible = $(".collapsed,.expanded"); |
189 |
var collapsible = $(".collapsed,.expanded"); |
|
Lines 262-285
$( document ).ready( function () {
Link Here
|
| 262 |
}).appendTo("#prefModalForm"); |
301 |
}).appendTo("#prefModalForm"); |
| 263 |
|
302 |
|
| 264 |
$("#saveModalPrefs").data("target", this.id ); |
303 |
$("#saveModalPrefs").data("target", this.id ); |
|
|
304 |
$("#saveModalPrefs").data("type", "modalselect" ); |
| 265 |
$("#prefModalLabel").text( pref_name ); |
305 |
$("#prefModalLabel").text( pref_name ); |
| 266 |
$("#prefModal").modal("show"); |
306 |
$("#prefModal").modal("show"); |
| 267 |
}); |
307 |
}); |
| 268 |
|
308 |
|
| 269 |
$("#saveModalPrefs").on("click", function(){ |
309 |
// Initialise the content of our modal, using the function |
| 270 |
var formfieldid = $("#" + $(this).data("target") ); |
310 |
// specified in the data-initiator attribute |
|
|
311 |
$('.modaljs').on('click', function () { |
| 312 |
const init = $(this).data('initiator'); |
| 313 |
if (init) { |
| 314 |
window[init](this); |
| 315 |
$("#prefModal").modal("show"); |
| 316 |
} |
| 317 |
}); |
| 318 |
|
| 319 |
// Initialise the content of our modal, if we are dealing |
| 320 |
// with a modalselect modal |
| 321 |
function prepareModalSelect(formfieldid) { |
| 271 |
var prefs = []; |
322 |
var prefs = []; |
| 272 |
$("#prefModal input[type='checkbox']").each(function(){ |
323 |
$("#prefModal input[type='checkbox']").each(function(){ |
| 273 |
if( $(this).prop("checked") ){ |
324 |
if( $(this).prop("checked") ){ |
| 274 |
prefs.push( this.value ); |
325 |
prefs.push( this.value ); |
| 275 |
} |
326 |
} |
| 276 |
}); |
327 |
}); |
|
|
328 |
return prefs.join("|"); |
| 329 |
} |
| 330 |
|
| 331 |
// Return a checkbox with an appropriate checked state |
| 332 |
function checkBox(id, className, state) { |
| 333 |
return state ? |
| 334 |
'<input id="' + id + '" type="checkbox" class="' + className + '" checked>' : |
| 335 |
'<input id="' + id + '" type="checkbox" class="' + className + '">'; |
| 336 |
} |
| 337 |
|
| 338 |
// Create a consentJS item, correctly populated |
| 339 |
function createConsentJSItem(item, idx) { |
| 340 |
const id = 'ConsentJS_' + idx; |
| 341 |
const code = item.code && item.code.length > 0 ? atob(item.code) : ''; |
| 342 |
const itemId = item.id && item.id.length > 0 ? item.id : ''; |
| 343 |
return '<div id="' + id + '" class="consentJSItem" data-id="' + itemId + '">' + |
| 344 |
' <div class="consentRow">' + |
| 345 |
' <div class="consentItem">' + |
| 346 |
' <label class="required" for="name_' + id + '">' + __('Name') + ':</label>' + |
| 347 |
' <input id="name_' + id + '" class="metaName" type="text" value="' + item.name + '"><span class="required">' + __('Required') + '</span>' + |
| 348 |
' </div >' + |
| 349 |
' <div class="consentItem">' + |
| 350 |
' <label class="required" for="description_' + id + '">' + __('Description') + ':</label>' + |
| 351 |
' <input id="description_' + id + '" class="metaDescription" type="text" value="' + item.description + '"><span class="required">' + __('Required') + '</span>' + |
| 352 |
' </div>' + |
| 353 |
' <div class="consentItem">' + |
| 354 |
' <label for="opacConsent_' + id + '">' + __('Requires consent in OPAC') + ':</label>' + |
| 355 |
checkBox('opacConsent_' + id, 'opacConsent', item.opacConsent) + |
| 356 |
' </div>' + |
| 357 |
' <div class="consentItem">' + |
| 358 |
' <label for="staffConsent_' + id + '">' + __('Requires consent in staff interface') + ':</label>' + |
| 359 |
checkBox('staffConsent_' + id, 'staffConsent', item.staffConsent) + |
| 360 |
' </div >' + |
| 361 |
' <div class="consentItem">' + |
| 362 |
' <label for="matchPattern_' + id + '">' + __('String used to identify cookie name') + ':</label>' + |
| 363 |
' <input id="matchPattern_' + id + '" class="metaMatchPattern" type="text" value="' + item.matchPattern + '"><span class="required">' + __('Required') + '</span>' + |
| 364 |
' </div >' + |
| 365 |
' <div class="consentItem">' + |
| 366 |
' <label for="cookieDomain' + id + '">' + __('Cookie domain') + ':</label>' + |
| 367 |
' <input id="cookieDomain' + id + '" class="metaCookieDomain" type="text" value="' + item.cookieDomain + '"><span class="required">' + __('Required') + '</span>' + |
| 368 |
' </div >' + |
| 369 |
' <div class="consentItem">' + |
| 370 |
' <label for="cookiePath' + id + '">' + __('Cookie path') + ':</label>' + |
| 371 |
' <input id="cookiePath' + id + '" class="metaCookiePath" type="text" value="' + item.cookiePath + '"><span class="required">' + __('Required') + '</span>' + |
| 372 |
' </div >' + |
| 373 |
' </div >' + |
| 374 |
' <div class="consentRow codeRow">' + |
| 375 |
' <textarea style="display:none;" id="pref_' + id + '" class="preference preference-code codemirror" rows="10" cols="40">' + code + '</textarea>' + |
| 376 |
' <div>' + |
| 377 |
' <a id="expand_' + id + '" class="expand-textarea" data-target="' + id + '" data-syntax="javascript" href="#">' + __('Click to expand') + '</a>' + |
| 378 |
' <a id="collapse_' + id + '" class="collapse-textarea" data-target="' + id + '" data-syntax="javascript" href="#" style="display:none">' + __('Click to collapse') + '</a>' + |
| 379 |
' </div >' + |
| 380 |
' </div>' + |
| 381 |
' <a class="consentDelete" data-target="' + id + '" href="#">Delete</a>' + |
| 382 |
'</div > '; |
| 383 |
} |
| 384 |
|
| 385 |
// Return the markup for all consentJS items concatenated |
| 386 |
function populateConsentMarkup(items) { |
| 387 |
return items.reduce(function (acc, current, idx) { |
| 388 |
return acc + createConsentJSItem(current, idx); |
| 389 |
}, ''); |
| 390 |
} |
| 391 |
|
| 392 |
// Return the markup for a validation warning |
| 393 |
function populateValidationWarning() { |
| 394 |
return '<div id="consentJSWarning" class="error" style="display:none;">' + __('You must complete all fields') + '</div>'; |
| 395 |
} |
| 396 |
|
| 397 |
// Return a new, empty consent item |
| 398 |
function emptyConsentItem() { |
| 399 |
return { |
| 400 |
name: '', |
| 401 |
description: '', |
| 402 |
matchPattern: '', |
| 403 |
cookieDomain: '', |
| 404 |
cookiePath: '', |
| 405 |
code: '', |
| 406 |
consentInOpac: false, |
| 407 |
consentInStaff: false |
| 408 |
}; |
| 409 |
} |
| 410 |
|
| 411 |
// Add the handler for a new empty consent item |
| 412 |
function addNewHandler() { |
| 413 |
$("#consentJSAddNew").on("click", function (e) { |
| 414 |
e.preventDefault(); |
| 415 |
const currentLen = $('.consentJSItem').length; |
| 416 |
const newItem = emptyConsentItem(); |
| 417 |
const markup = createConsentJSItem(newItem, currentLen); |
| 418 |
$('#prefModal .modal-body #consentJSItems').append($(markup)); |
| 419 |
addExpandHandler(); |
| 420 |
addCollapseHandler(); |
| 421 |
addConsentDeleteHandler(); |
| 422 |
}); |
| 423 |
} |
| 424 |
|
| 425 |
// Populate the consentJS modal, we also initialise any |
| 426 |
// event handlers that are required. This function is added |
| 427 |
// to the window object so we can call it if we are passed it's name |
| 428 |
// as a data-initiator attribute |
| 429 |
// (e.g.) |
| 430 |
// const f = 'populateConsentJS'; |
| 431 |
// window[f](); |
| 432 |
window.populateConsentJS = function(el) { |
| 433 |
let items = []; |
| 434 |
let decoded = ''; |
| 435 |
if (el.value && el.value.length > 0) { |
| 436 |
try { |
| 437 |
decoded = atob(el.value); |
| 438 |
} catch (err) { |
| 439 |
throw (__( |
| 440 |
'Unable to Base64 decode value stored in ConsentJS syspref: ' + |
| 441 |
err.message |
| 442 |
)); |
| 443 |
} |
| 444 |
try { |
| 445 |
items = JSON.parse(decoded); |
| 446 |
} catch (err) { |
| 447 |
throw (__( |
| 448 |
'Unable to JSON parse decoded value stored in ConsentJS syspref: ' + |
| 449 |
err.message |
| 450 |
)); |
| 451 |
} |
| 452 |
} |
| 453 |
const markup = populateConsentMarkup(items); |
| 454 |
const validationWarning = populateValidationWarning(); |
| 455 |
const pref_name = el.id.replace(/pref_/, ''); |
| 456 |
$('#saveModalPrefs').data('target', el.id); |
| 457 |
$('#prefModalLabel').text( pref_name ); |
| 458 |
$('#prefModal .modal-body').html($('<div id="consentJSItems">' + validationWarning + markup + '</div><div><a href="#" id="consentJSAddNew">' + __('Add new code') + '</a></div>')); |
| 459 |
addExpandHandler(); |
| 460 |
addCollapseHandler(); |
| 461 |
addNewHandler(); |
| 462 |
addConsentDeleteHandler(); |
| 463 |
} |
| 464 |
|
| 465 |
// Prepare the data in the UI for sending back as a syspref. |
| 466 |
// We validate that everything is what we expect. This function is added |
| 467 |
// to the window object so we can call it if we are passed it's name |
| 468 |
// as a data-initiator attribute |
| 469 |
// e.g. |
| 470 |
// const f = 'prepareConsentJS'; |
| 471 |
// window[f](); |
| 472 |
window.prepareConsentJS = function () { |
| 473 |
const items = $('.consentJSItem'); |
| 474 |
const invalid = []; |
| 475 |
const valid = []; |
| 476 |
items.each(function () { |
| 477 |
const id = $(this).data('id').length > 0 ? |
| 478 |
$(this).data('id') : |
| 479 |
'_' + Math.random().toString(36).substr(2, 9); |
| 480 |
const name = $(this).find('.metaName').val(); |
| 481 |
const desc = $(this).find('.metaDescription').val(); |
| 482 |
const matchPattern = $(this).find('.metaMatchPattern').val(); |
| 483 |
const cookieDomain = $(this).find('.metaCookieDomain').val(); |
| 484 |
const cookiePath = $(this).find('.metaCookiePath').val(); |
| 485 |
const opacConsent = $(this).find('.opacConsent').is(':checked') |
| 486 |
const staffConsent = $(this).find('.staffConsent').is(':checked'); |
| 487 |
const code = $(this).find('.preference-code').val(); |
| 488 |
// If the name, description, match pattern code are empty, then they've |
| 489 |
// added a new entry, but not filled it in, we can skip it |
| 490 |
if ( |
| 491 |
name.length === 0 && |
| 492 |
desc.length === 0 && |
| 493 |
matchPattern.length === 0 && |
| 494 |
cookieDomain.length === 0 && |
| 495 |
cookiePath.length === 0 && |
| 496 |
code.length === 0 |
| 497 |
) { |
| 498 |
return; |
| 499 |
} |
| 500 |
// They've filled in at least some info |
| 501 |
if ( |
| 502 |
(name.length === 0) || |
| 503 |
(desc.length === 0) || |
| 504 |
(matchPattern.length === 0) || |
| 505 |
(cookiePath.length === 0) || |
| 506 |
(code.length === 0) |
| 507 |
) { |
| 508 |
invalid.push(this); |
| 509 |
} else { |
| 510 |
const obj = { |
| 511 |
id: id, |
| 512 |
name: name, |
| 513 |
description: desc, |
| 514 |
matchPattern: matchPattern, |
| 515 |
cookieDomain: cookieDomain, |
| 516 |
cookiePath: cookiePath, |
| 517 |
opacConsent: opacConsent, |
| 518 |
staffConsent: staffConsent, |
| 519 |
code: btoa(code) |
| 520 |
} |
| 521 |
valid.push(obj); |
| 522 |
} |
| 523 |
}); |
| 524 |
// We failed validation |
| 525 |
if (invalid.length > 0) { |
| 526 |
$('#consentJSWarning').show(); |
| 527 |
return false; |
| 528 |
} |
| 529 |
$('#consentJSWarning').hide(); |
| 530 |
if (valid.length === 0) { |
| 531 |
return ''; |
| 532 |
} |
| 533 |
const json = JSON.stringify(valid); |
| 534 |
const base64 = btoa(json); |
| 535 |
return base64; |
| 536 |
} |
| 277 |
|
537 |
|
| 278 |
formfieldid.val( prefs.join("|") ) |
538 |
$("#saveModalPrefs").on("click", function(){ |
| 279 |
.addClass("modified"); |
539 |
var formfieldid = $("#" + $(this).data("target")); |
| 280 |
mark_modified.call( formfieldid ); |
540 |
let finalString = ""; |
| 281 |
KOHA.Preferences.Save( formfieldid.closest("form") ); |
541 |
if ($(this).data("type") == "modalselect") { |
| 282 |
$("#prefModal").modal("hide"); |
542 |
finalString = prepareModalSelect(formfieldid); |
|
|
543 |
} else { |
| 544 |
const processor = $(".modaljs").data("processor"); |
| 545 |
finalString = window[processor](); |
| 546 |
} |
| 547 |
// A processor can return false if any of the submitted |
| 548 |
// data has failed validation |
| 549 |
if (finalString !== false) { |
| 550 |
formfieldid.val(finalString).addClass("modified"); |
| 551 |
mark_modified.call( formfieldid ); |
| 552 |
KOHA.Preferences.Save( formfieldid.closest("form") ); |
| 553 |
$("#prefModal").modal("hide"); |
| 554 |
} |
| 283 |
}); |
555 |
}); |
| 284 |
|
556 |
|
| 285 |
$("#prefModal").on("hide.bs.modal", function(){ |
557 |
$("#prefModal").on("hide.bs.modal", function(){ |