Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to turn off external link warning #1236

Merged
merged 4 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions i18n/en.jsonp.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions i18n/es.jsonp.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions i18n/fr.jsonp.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 15 additions & 4 deletions www/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,15 @@ <h5 class="modal-title" id="modalLabel">Modal title goes here</h5>
<div class="modal-body">
<p id="modalText">Modal text goes here.</p>
</div>
<div class="modal-footer" id="modalFooter">
<button type="button" class="btn btn-primary" id="approveConfirm" data-dismiss="modal">Confirm</button>
<button type="button" class="btn btn-secondary" id="declineConfirm" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="closeMessage" data-dismiss="modal">Okay</button>
<div class="modal-footer justify-content-between" id="modalFooter">
<div>
<button type="button" class="btn btn-link" id="hideOption" data-dismiss="modal">Don't ask again</button>
</div>
<div>
<button type="button" class="btn btn-primary" id="approveConfirm" data-dismiss="modal">Confirm</button>
<button type="button" class="btn btn-secondary" id="declineConfirm" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="closeMessage" data-dismiss="modal">Okay</button>
</div>
</div>
</div>
</div>
Expand Down Expand Up @@ -685,6 +690,12 @@ <h3 data-i18n="configure-expert-settings-title">Expert settings</h3>
experienced users)</span>
</label>
</div>
<div class="checkbox">
<label data-i18n-tip="configure-expert-hideexternallinkwarning-tip" title="If this option is checked, links to external sites will open in a new tab without confirmation.">
<input type="checkbox" name="hideExternalLinkWarning" id="hideExternalLinkWarningCheck">
<span data-i18n="configure-expert-hideexternallinkwarning"><strong>Permanently hide "Opening external link" warning</strong></span>
</label>
</div>
<div class="checkbox">
<label data-i18n-tip="configure-expert-disabledragdrop-tip" title="In some browsers on some platforms, drag-and-drop may malfunction and make it difficult to select text, and other operations. Disable it here if it is causing issues." >
<input type="checkbox" name="disableDragAndDrop"
Expand Down
4 changes: 4 additions & 0 deletions www/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,10 @@ document.querySelectorAll('input[type="checkbox"][name=hideActiveContentWarning]
settingsStore.setItem('hideActiveContentWarning', params.hideActiveContentWarning, Infinity);
})
});
document.getElementById('hideExternalLinkWarningCheck').addEventListener('change', function () {
params.hideExternalLinkWarning = !!this.checked;
Jaifroid marked this conversation as resolved.
Show resolved Hide resolved
settingsStore.setItem('hideExternalLinkWarning', params.hideExternalLinkWarning, Infinity);
})
document.getElementById('slideAwayCheck').addEventListener('change', function (e) {
params.slideAway = e.target.checked;
if (typeof navigator.getDeviceStorages === 'function') {
Expand Down
3 changes: 3 additions & 0 deletions www/js/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
* @property {string} storeType - A parameter to determine the Settings Store API in use.
* @property {string} keyPrefix - The key prefix used by the settingsStore.js.
* @property {boolean} hideActiveContentWarning - A boolean indicating whether to hide the active content warning.
* @property {boolean} hideExternalLinkWarning - A boolean indicating whether to hide the external link warning.
* @property {boolean} slideAway - A boolean indicating whether to slide away the header and footer when scrolling.
* @property {boolean} showUIAnimations - A boolean indicating whether to show UI animations.
* @property {number} maxSearchResultsSize - The maximum number of article titles to return.
Expand Down Expand Up @@ -89,6 +90,7 @@ params['storeType'] = getBestAvailableStorageAPI();
// The key prefix used by the settingsStore.js (see comment there for explanation), but we also need it below
params['keyPrefix'] = 'kiwixjs-';
params['hideActiveContentWarning'] = getSetting('hideActiveContentWarning') === true;
params['hideExternalLinkWarning'] = getSetting('hideExternalLinkWarning') === true;
// A parameter to determine whether to slide away the header and footer when scrolling (defaults to true except on Firefox OS devices which may be buggy with this setting)
params['slideAway'] = getSetting('slideAway') === false ? false : typeof navigator.getDeviceStorages !== 'function';
params['showUIAnimations'] = getSetting('showUIAnimations') === true;
Expand Down Expand Up @@ -182,6 +184,7 @@ params.appCache = params.contentInjectionMode === 'jquery' ? true : params.appCa
* Set the State and UI settings associated with parameters defined above
*/
document.getElementById('hideActiveContentWarningCheck').checked = params.hideActiveContentWarning;
document.getElementById('hideExternalLinkWarningCheck').checked = params.hideExternalLinkWarning;
document.getElementById('disableDragAndDropCheck').checked = params.disableDragAndDrop;
document.getElementById('slideAwayCheck').checked = params.slideAway;
document.getElementById('showUIAnimationsCheck').checked = params.showUIAnimations;
Expand Down
27 changes: 22 additions & 5 deletions www/js/lib/uiUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,16 @@ function slideAway (e) {
* @param {String} declineConfirmLabel The text to display on the decline confirmation button (optional, Default = "Cancel")
* @param {String} approveConfirmLabel The text to display on the approve confirmation button (optional, Default = "Confirm")
* @param {String} closeMessageLabel The text to display on the close alert message button (optional, Default = "Okay")
* @param {String} hideOptionLabel The text to display on the hide option button (optional, Default = "Don't ask again")
* @param {Boolean} displayHideOption If true, option to permanently hide the modal will be shown (currently only implemented for hideExternalLinkWarning)
* @returns {Promise<Boolean>} A promise which resolves to true if the user clicked Confirm, false if the user clicked Cancel/Okay, backdrop or the cross(x) button
*/
function systemAlert (message, label, isConfirm, declineConfirmLabel, approveConfirmLabel, closeMessageLabel) {
function systemAlert (message, label, isConfirm, declineConfirmLabel, approveConfirmLabel, closeMessageLabel, hideOptionLabel, displayHideOption) {
declineConfirmLabel = declineConfirmLabel || (translateUI.t('dialog-cancel') || 'Cancel');
approveConfirmLabel = approveConfirmLabel || (translateUI.t('dialog-confirm') || 'Confirm');
closeMessageLabel = closeMessageLabel || (translateUI.t('dialog-ok') || 'Okay');
hideOptionLabel = hideOptionLabel || (translateUI.t('dialog-hide') || "Don't ask again");
displayHideOption = displayHideOption || false;
label = label || (isConfirm ? 'Confirmation' : 'Message');
return util.PromiseQueue.enqueue(function () {
return new Promise(function (resolve, reject) {
Expand All @@ -195,6 +199,7 @@ function systemAlert (message, label, isConfirm, declineConfirmLabel, approveCon
document.getElementById('approveConfirm').textContent = approveConfirmLabel;
document.getElementById('declineConfirm').textContent = declineConfirmLabel;
document.getElementById('closeMessage').textContent = closeMessageLabel;
document.getElementById('hideOption').textContent = hideOptionLabel;
// Some titles need &nbsp; or other HTML, so we have to use innerHTML
document.getElementById('modalLabel').innerHTML = label;
// Using innerHTML to set the message to allow HTML formatting
Expand All @@ -203,6 +208,7 @@ function systemAlert (message, label, isConfirm, declineConfirmLabel, approveCon
document.getElementById('approveConfirm').style.display = isConfirm ? 'inline' : 'none';
document.getElementById('declineConfirm').style.display = isConfirm ? 'inline' : 'none';
document.getElementById('closeMessage').style.display = isConfirm ? 'none' : 'inline';
document.getElementById('hideOption').style.display = displayHideOption ? 'inline' : 'none';
// Display the modal
const modal = document.querySelector('#alertModal');
const backdrop = document.createElement('div');
Expand Down Expand Up @@ -234,6 +240,7 @@ function systemAlert (message, label, isConfirm, declineConfirmLabel, approveCon
document.getElementById('declineConfirm').removeEventListener('click', close);
document.getElementById('closeMessage').removeEventListener('click', close);
document.getElementById('approveConfirm').removeEventListener('click', closeConfirm);
document.getElementById('hideOption').removeEventListener('click', hideConfirm);
modal.removeEventListener('click', close);
document.getElementsByClassName('modal-dialog')[0].removeEventListener('click', stopOutsideModalClick);
modal.removeEventListener('keyup', keyHandler);
Expand All @@ -248,6 +255,11 @@ function systemAlert (message, label, isConfirm, declineConfirmLabel, approveCon
closeModalHandler();
resolve(true);
};
var hideConfirm = function () {
document.getElementById('hideExternalLinkWarningCheck').click();
closeModalHandler();
resolve(true);
};
var stopOutsideModalClick = function (e) {
e.stopPropagation();
};
Expand All @@ -272,6 +284,7 @@ function systemAlert (message, label, isConfirm, declineConfirmLabel, approveCon
document.getElementById('declineConfirm').addEventListener('click', close);
document.getElementById('closeMessage').addEventListener('click', close);
document.getElementById('approveConfirm').addEventListener('click', closeConfirm);
document.getElementById('hideOption').addEventListener('click', hideConfirm);

modal.addEventListener('click', close);
document.getElementsByClassName('modal-dialog')[0].addEventListener('click', stopOutsideModalClick);
Expand Down Expand Up @@ -969,16 +982,20 @@ function warnAndOpenExternalLinkInNewTab (event, clickedAnchor, archive) {
clickedAnchor.href = clickedAnchor.href.replace(clickedAnchor.origin, archive.source.replace(/\/$/, ''));
}
var target = clickedAnchor.target;
if (!target) {
target = '_blank';
}
if (params.hideExternalLinkWarning) {
window.open(clickedAnchor.href, target);
return;
}
var message = translateUI.t('dialog-open-externalurl-message') || '<p>Do you want to open this external link?';
if (!target || target === '_blank') {
Jaifroid marked this conversation as resolved.
Show resolved Hide resolved
message += ' ' + (translateUI.t('dialog-open-externalurl-newtab') || '(in a new tab)');
}
message += '</p><p style="word-break:break-all;">' + clickedAnchor.href + '</p>';
systemAlert(message, translateUI.t('dialog-open-externalurl-title') || 'Opening external link', true).then(function (response) {
systemAlert(message, translateUI.t('dialog-open-externalurl-title') || 'Opening external link', true, null, null, null, null, true).then(function (response) {
if (response) {
if (!target) {
target = '_blank';
}
window.open(clickedAnchor.href, target);
}
});
Expand Down
Loading