- used bootstrap 5 CSS icon named copy, bootstrap 3 CSS glyphicon named duplicate

- keyboard-shortcuts made more accessible by wrapping the keys into kbd-tags
- translate messages may contain allowed HTML tags
- added the record to the CHANGELOG.md
This commit is contained in:
ribas160 2025-01-01 19:14:58 +02:00
parent a6a7df9a72
commit 0462da6e8e
45 changed files with 141 additions and 120 deletions

View file

@ -757,14 +757,14 @@ jQuery.PrivateBin = (function($, RawDeflate) {
args[0] = translations[messageId];
}
// messageID may contain links, but should be from a trusted source (code or translation JSON files)
let containsLinks = args[0].indexOf('<a') !== -1;
// messageID may contain HTML, but should be from a trusted source (code or translation JSON files)
let containsHtml = isStringContainsHtml(args[0]);
// prevent double encoding, when we insert into a text node
if (containsLinks || $element === null) {
if (containsHtml || $element === null) {
for (let i = 0; i < args.length; ++i) {
// parameters (i > 0) may never contain HTML as they may come from untrusted parties
if ((containsLinks ? i > 1 : i > 0) || !containsLinks) {
if ((containsHtml ? i > 1 : i > 0) || !containsHtml) {
args[i] = Helper.htmlEntities(args[i]);
}
}
@ -772,11 +772,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// format string
let output = Helper.sprintf.apply(this, args);
if (containsLinks) {
if (containsHtml) {
// only allow tags/attributes we actually use in translations
output = DOMPurify.sanitize(
output, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_TAGS: ['a', 'i', 'span', 'kbd'],
ALLOWED_ATTR: ['href', 'id']
}
);
@ -784,7 +784,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// if $element is given, insert translation
if ($element !== null) {
if (containsLinks) {
if (containsHtml) {
$element.html(output);
} else {
// text node takes care of entity encoding
@ -914,6 +914,25 @@ jQuery.PrivateBin = (function($, RawDeflate) {
translations = mockTranslations || {};
};
/**
* Check if string contains valid HTML code
*
* @name I18n.isStringContainsHtml
* @function
* @private
* @param {string} messageId
* @returns {boolean}
*/
function isStringContainsHtml(messageId) {
// An integer which specifies the type of the node. An Element node like <p> or <div>.
const elementNodeType = 1;
const div = document.createElement('div');
div.innerHTML = messageId;
return Array.from(div.childNodes).some(node => node.nodeType === elementNodeType);
}
return me;
})();
@ -3768,7 +3787,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
/**
* Clear the password input in the top navigation
*
*
* @name TopNav.clearPasswordInput
* @function
*/
@ -5371,21 +5390,21 @@ jQuery.PrivateBin = (function($, RawDeflate) {
})();
/**
*
*
* @name CopyToClipboard
* @class
*/
const CopyToClipboard = (function () {
const me = {};
let copyButton = $("#prettymessageCopyBtn"),
copyIcon = $("#copyIcon"),
successIcon = $("#copySuccessIcon"),
shortcutHint = $("#copyShortcutHintText");
let copyButton = $('#prettyMessageCopyBtn'),
copyIcon = $('#copyIcon'),
successIcon = $('#copySuccessIcon'),
shortcutHint = $('#copyShortcutHintText');
/**
* Handle copy to clipboard button click
*
*
* @name CopyToClipboard.handleCopyButtonClick
* @private
* @function
@ -5399,7 +5418,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
/**
* Handle CTRL+C/CMD+C keyboard shortcut
*
*
* @name CopyToClipboard.handleKeyboardShortcut
* @private
* @function
@ -5411,31 +5430,31 @@ jQuery.PrivateBin = (function($, RawDeflate) {
saveToClipboard(text);
}
});
}
};
/**
* Check if user selected some text on the page to copy it
*
*
* @name CopyToClipboard.isUserSelectedTextToCopy
* @private
* @function
* @returns {boolean}
*/
function isUserSelectedTextToCopy() {
let text = "";
let text = '';
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
} else if (document.selection && document.selection.type != 'Control') {
text = document.selection.createRange().text;
}
return text.length > 0;
}
};
/**
* Save text to the clipboard
*
*
* @name CopyToClipboard.saveToClipboard
* @private
* @param {string} text
@ -5449,55 +5468,65 @@ jQuery.PrivateBin = (function($, RawDeflate) {
/**
* Show alert message after text copy
*
*
* @name CopyToClipboard.showAlertMessage
* @private
* @function
*/
function showAlertMessage() {
Alert.showStatus("Paste copied to clipboard");
}
Alert.showStatus(I18n._('Paste copied to clipboard'));
};
/**
* Toogle success icon after copy
*
*
* @name CopyToClipboard.toggleSuccessIcon
* @private
* @function
*/
function toggleSuccessIcon() {
$(copyIcon).css("display", "none");
$(successIcon).css("display", "block");
$(copyIcon).css('display', 'none');
$(successIcon).css('display', 'block');
setTimeout(function() {
$(copyIcon).css("display", "block");
$(successIcon).css("display", "none");
$(copyIcon).css('display', 'block');
$(successIcon).css('display', 'none');
}, 1000);
};
/**
* Show keyboard shortcut hint
*
*
* @name CopyToClipboard.showKeyboardShortcutHint
* @function
*/
me.showKeyboardShortcutHint = function () {
I18n._(
shortcutHint,
'To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c'
'To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>'
);
}
};
/**
* Hide keyboard shortcut hint
*
* @name CopyToClipboard.showKeyboardShortcutHint
* @function
*/
me.hideKeyboardShortcutHint = function () {
$(shortcutHint).html('');
};
/**
* Initialize
*
*
* @name CopyToClipboard.init
* @function
*/
me.init = function() {
handleCopyButtonClick();
handleKeyboardShortcut();
}
};
return me;
})();
@ -5523,6 +5552,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
{
PasteStatus.hideMessages();
Alert.hideMessages();
CopyToClipboard.hideKeyboardShortcutHint();
};
/**