Implement Email button
This commit is contained in:
parent
63fdd2eba3
commit
e079f6c830
@ -180,3 +180,28 @@ li.L0, li.L1, li.L2, li.L3, li.L5, li.L6, li.L7, li.L8 {
|
|||||||
padding-right: 4ch;
|
padding-right: 4ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-dialog {
|
||||||
|
margin: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* makeup for the original margin on modal-dialog */
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.modal-content {
|
||||||
|
margin: 30px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .modal-content button {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
BIN
img/icon_email.png
Normal file
BIN
img/icon_email.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 332 B |
257
js/privatebin.js
257
js/privatebin.js
@ -403,6 +403,45 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
baseUri = null;
|
baseUri = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculate expiration date given initial date and expiration period
|
||||||
|
*
|
||||||
|
* @name Helper.calculateExpirationDate
|
||||||
|
* @function
|
||||||
|
* @param {Date} initialDate - may not be empty
|
||||||
|
* @param {string|number} expirationDisplayStringOrSecondsToExpire - may not be empty
|
||||||
|
* @return {Date}
|
||||||
|
*/
|
||||||
|
me.calculateExpirationDate = function(initialDate, expirationDisplayStringOrSecondsToExpire) {
|
||||||
|
let expirationDate = new Date(initialDate);
|
||||||
|
|
||||||
|
const expirationDisplayStringToSecondsDict = {
|
||||||
|
'5min': 300,
|
||||||
|
'10min': 600,
|
||||||
|
'1hour': 3500,
|
||||||
|
'1day': 86400,
|
||||||
|
'1week': 604800,
|
||||||
|
'1month': 2592000,
|
||||||
|
'1year': 31536000,
|
||||||
|
'never': 0
|
||||||
|
};
|
||||||
|
|
||||||
|
let secondsToExpiration = expirationDisplayStringOrSecondsToExpire;
|
||||||
|
if (typeof expirationDisplayStringOrSecondsToExpire === 'string') {
|
||||||
|
secondsToExpiration = expirationDisplayStringToSecondsDict[expirationDisplayStringOrSecondsToExpire];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof secondsToExpiration !== 'number') {
|
||||||
|
throw new Error('Cannot calculate expiration date.');
|
||||||
|
}
|
||||||
|
if (secondsToExpiration === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
expirationDate = expirationDate.setUTCSeconds(expirationDate.getUTCSeconds() + secondsToExpiration);
|
||||||
|
return expirationDate;
|
||||||
|
}
|
||||||
|
|
||||||
return me;
|
return me;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@ -3332,9 +3371,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$passwordInput,
|
$passwordInput,
|
||||||
$rawTextButton,
|
$rawTextButton,
|
||||||
$qrCodeLink,
|
$qrCodeLink,
|
||||||
|
$emailLink,
|
||||||
$sendButton,
|
$sendButton,
|
||||||
$retryButton,
|
$retryButton,
|
||||||
pasteExpiration = '1week',
|
pasteExpiration = null,
|
||||||
retryButtonCallback;
|
retryButtonCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3542,6 +3582,133 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$('#qrcode-display').html(qrCanvas);
|
$('#qrcode-display').html(qrCanvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template Email body.
|
||||||
|
*
|
||||||
|
* @name TopNav.templateEmailBody
|
||||||
|
* @private
|
||||||
|
* @param {string} expirationDateString
|
||||||
|
* @param {bool} isBurnafterreading
|
||||||
|
*/
|
||||||
|
function templateEmailBody(expirationDateString, isBurnafterreading)
|
||||||
|
{
|
||||||
|
const EOL = '\n';
|
||||||
|
const BULLET = ' - ';
|
||||||
|
let emailBody = '';
|
||||||
|
if (expirationDateString !== null || isBurnafterreading) {
|
||||||
|
emailBody += I18n._('Notice:');
|
||||||
|
emailBody += EOL;
|
||||||
|
|
||||||
|
if (expirationDateString !== null) {
|
||||||
|
emailBody += EOL;
|
||||||
|
emailBody += BULLET;
|
||||||
|
emailBody += I18n._(
|
||||||
|
'This link will expire after %s.',
|
||||||
|
expirationDateString
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isBurnafterreading) {
|
||||||
|
emailBody += EOL;
|
||||||
|
emailBody += BULLET;
|
||||||
|
emailBody += I18n._(
|
||||||
|
'This link can only be accessed once, do not use back or refresh button in your browser.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
emailBody += EOL;
|
||||||
|
emailBody += EOL;
|
||||||
|
}
|
||||||
|
emailBody += I18n._('Link:');
|
||||||
|
emailBody += EOL;
|
||||||
|
emailBody += `${window.location.href}`;
|
||||||
|
return emailBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger Email send.
|
||||||
|
*
|
||||||
|
* @name TopNav.triggerEmailSend
|
||||||
|
* @private
|
||||||
|
* @param {string} emailBody
|
||||||
|
*/
|
||||||
|
function triggerEmailSend(emailBody)
|
||||||
|
{
|
||||||
|
window.open(
|
||||||
|
`mailto:?body=${encodeURIComponent(emailBody)}`,
|
||||||
|
'_self',
|
||||||
|
'noopener, noreferrer'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send Email with current paste (URL).
|
||||||
|
*
|
||||||
|
* @name TopNav.sendEmail
|
||||||
|
* @private
|
||||||
|
* @function
|
||||||
|
* @param {Date|null} expirationDate date of expiration
|
||||||
|
* @param {bool} isBurnafterreading whether it is burn after reading
|
||||||
|
*/
|
||||||
|
function sendEmail(expirationDate, isBurnafterreading)
|
||||||
|
{
|
||||||
|
const expirationDateRoundedToSecond = new Date(expirationDate);
|
||||||
|
|
||||||
|
// round down at least 30 seconds to make up for the delay of request
|
||||||
|
expirationDateRoundedToSecond.setUTCSeconds(
|
||||||
|
expirationDateRoundedToSecond.getUTCSeconds() - 30
|
||||||
|
);
|
||||||
|
expirationDateRoundedToSecond.setUTCSeconds(0);
|
||||||
|
|
||||||
|
const $emailconfirmmodal = $('#emailconfirmmodal');
|
||||||
|
if ($emailconfirmmodal.length > 0) {
|
||||||
|
if (expirationDate !== null) {
|
||||||
|
$emailconfirmmodal.find('#emailconfirm-display').text(
|
||||||
|
I18n._('Recipient may become aware of your timezone, convert time to UTC?')
|
||||||
|
);
|
||||||
|
const $emailconfirmTimezoneCurrent = $emailconfirmmodal.find('#emailconfirm-timezone-current');
|
||||||
|
const $emailconfirmTimezoneUtc = $emailconfirmmodal.find('#emailconfirm-timezone-utc');
|
||||||
|
$emailconfirmTimezoneCurrent.off('click.sendEmailCurrentTimezone');
|
||||||
|
$emailconfirmTimezoneCurrent.on('click.sendEmailCurrentTimezone', function(expirationDateRoundedToSecond, isBurnafterreading) {
|
||||||
|
return function() {
|
||||||
|
const emailBody = templateEmailBody(expirationDateRoundedToSecond.toLocaleString(), isBurnafterreading);
|
||||||
|
$emailconfirmmodal.modal('hide');
|
||||||
|
triggerEmailSend(emailBody);
|
||||||
|
};
|
||||||
|
} (expirationDateRoundedToSecond, isBurnafterreading));
|
||||||
|
$emailconfirmTimezoneUtc.off('click.sendEmailUtcTimezone');
|
||||||
|
$emailconfirmTimezoneUtc.on('click.sendEmailUtcTimezone', function(expirationDateRoundedToSecond, isBurnafterreading) {
|
||||||
|
return function() {
|
||||||
|
const emailBody = templateEmailBody(expirationDateRoundedToSecond.toLocaleString(
|
||||||
|
undefined,
|
||||||
|
// we don't use Date.prototype.toUTCString() because we would like to avoid GMT
|
||||||
|
{ timeZone: 'UTC', dateStyle: 'long', timeStyle: 'long' }
|
||||||
|
), isBurnafterreading);
|
||||||
|
$emailconfirmmodal.modal('hide');
|
||||||
|
triggerEmailSend(emailBody);
|
||||||
|
};
|
||||||
|
} (expirationDateRoundedToSecond, isBurnafterreading));
|
||||||
|
$emailconfirmmodal.modal('show');
|
||||||
|
} else {
|
||||||
|
triggerEmailSend(templateEmailBody(null, isBurnafterreading));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let emailBody = '';
|
||||||
|
if (expirationDate !== null) {
|
||||||
|
const expirationDateString = window.confirm(
|
||||||
|
I18n._('Recipient may become aware of your timezone, convert time to UTC?')
|
||||||
|
) ? expirationDateRoundedToSecond.toLocaleString(
|
||||||
|
undefined,
|
||||||
|
// we don't use Date.prototype.toUTCString() because we would like to avoid GMT
|
||||||
|
{ timeZone: 'UTC', dateStyle: 'long', timeStyle: 'long' }
|
||||||
|
) : expirationDateRoundedToSecond.toLocaleString();
|
||||||
|
emailBody = templateEmailBody(expirationDateString, isBurnafterreading);
|
||||||
|
} else {
|
||||||
|
emailBody = templateEmailBody(null, isBurnafterreading);
|
||||||
|
}
|
||||||
|
triggerEmailSend(emailBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows all navigation elements for viewing an existing paste
|
* Shows all navigation elements for viewing an existing paste
|
||||||
*
|
*
|
||||||
@ -3578,6 +3745,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$newButton.addClass('hidden');
|
$newButton.addClass('hidden');
|
||||||
$rawTextButton.addClass('hidden');
|
$rawTextButton.addClass('hidden');
|
||||||
$qrCodeLink.addClass('hidden');
|
$qrCodeLink.addClass('hidden');
|
||||||
|
me.hideEmailButton();
|
||||||
|
|
||||||
viewButtonsDisplayed = false;
|
viewButtonsDisplayed = false;
|
||||||
};
|
};
|
||||||
@ -3675,6 +3843,50 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$retryButton.addClass('hidden');
|
$retryButton.addClass('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show the "email" button
|
||||||
|
*
|
||||||
|
* @name TopNav.showEmailbutton
|
||||||
|
* @function
|
||||||
|
* @param {int|undefined} optionalRemainingTimeInSeconds
|
||||||
|
*/
|
||||||
|
me.showEmailButton = function(optionalRemainingTimeInSeconds)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// we cache expiration date in closure to avoid inaccurate expiration datetime
|
||||||
|
const expirationDate = Helper.calculateExpirationDate(
|
||||||
|
new Date(),
|
||||||
|
typeof optionalRemainingTimeInSeconds === 'number' ? optionalRemainingTimeInSeconds : TopNav.getExpiration()
|
||||||
|
);
|
||||||
|
const isBurnafterreading = TopNav.getBurnAfterReading();
|
||||||
|
|
||||||
|
$emailLink.removeClass('hidden');
|
||||||
|
$emailLink.off('click.sendEmail');
|
||||||
|
$emailLink.on('click.sendEmail', function(expirationDate, isBurnafterreading) {
|
||||||
|
return function() {
|
||||||
|
sendEmail(expirationDate, isBurnafterreading);
|
||||||
|
};
|
||||||
|
} (expirationDate, isBurnafterreading));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
Alert.showError(
|
||||||
|
I18n._('Cannot calculate expiration date.')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hide the "email" button
|
||||||
|
*
|
||||||
|
* @name TopNav.hideEmailButton
|
||||||
|
* @function
|
||||||
|
*/
|
||||||
|
me.hideEmailButton = function()
|
||||||
|
{
|
||||||
|
$emailLink.addClass('hidden');
|
||||||
|
$emailLink.off('click.sendEmail');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* only hides the clone button
|
* only hides the clone button
|
||||||
*
|
*
|
||||||
@ -3697,6 +3909,30 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$rawTextButton.addClass('hidden');
|
$rawTextButton.addClass('hidden');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* only hides the qr code button
|
||||||
|
*
|
||||||
|
* @name TopNav.hideQrCodeButton
|
||||||
|
* @function
|
||||||
|
*/
|
||||||
|
me.hideQrCodeButton = function()
|
||||||
|
{
|
||||||
|
$qrCodeLink.addClass('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hide all irrelevant buttons when viewing burn after reading paste
|
||||||
|
*
|
||||||
|
* @name TopNav.hideBurnAfterReadingButtons
|
||||||
|
* @function
|
||||||
|
*/
|
||||||
|
me.hideBurnAfterReadingButtons = function()
|
||||||
|
{
|
||||||
|
me.hideCloneButton();
|
||||||
|
me.hideQrCodeButton();
|
||||||
|
me.hideEmailButton();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hides the file selector in attachment
|
* hides the file selector in attachment
|
||||||
*
|
*
|
||||||
@ -3784,7 +4020,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
/**
|
/**
|
||||||
* returns the state of the burn after reading checkbox
|
* returns the state of the burn after reading checkbox
|
||||||
*
|
*
|
||||||
* @name TopNav.getExpiration
|
* @name TopNav.getBurnAfterReading
|
||||||
* @function
|
* @function
|
||||||
* @return {bool}
|
* @return {bool}
|
||||||
*/
|
*/
|
||||||
@ -3914,6 +4150,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$retryButton = $('#retrybutton');
|
$retryButton = $('#retrybutton');
|
||||||
$sendButton = $('#sendbutton');
|
$sendButton = $('#sendbutton');
|
||||||
$qrCodeLink = $('#qrcodelink');
|
$qrCodeLink = $('#qrcodelink');
|
||||||
|
$emailLink = $('#emaillink');
|
||||||
|
|
||||||
// bootstrap template drop down
|
// bootstrap template drop down
|
||||||
$('#language ul.dropdown-menu li a').click(setLanguage);
|
$('#language ul.dropdown-menu li a').click(setLanguage);
|
||||||
@ -4258,6 +4495,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
history.pushState({type: 'newpaste'}, document.title, url);
|
history.pushState({type: 'newpaste'}, document.title, url);
|
||||||
|
|
||||||
TopNav.showViewButtons();
|
TopNav.showViewButtons();
|
||||||
|
|
||||||
|
// this cannot be grouped with showViewButtons due to remaining time calculation
|
||||||
|
TopNav.showEmailButton();
|
||||||
|
|
||||||
TopNav.hideRawButton();
|
TopNav.hideRawButton();
|
||||||
Editor.hide();
|
Editor.hide();
|
||||||
|
|
||||||
@ -4698,7 +4939,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
|
|
||||||
// discourage cloning (it cannot really be prevented)
|
// discourage cloning (it cannot really be prevented)
|
||||||
if (paste.isBurnAfterReadingEnabled()) {
|
if (paste.isBurnAfterReadingEnabled()) {
|
||||||
TopNav.hideCloneButton();
|
TopNav.hideBurnAfterReadingButtons();
|
||||||
|
} else {
|
||||||
|
// we have to pass in remaining_time here
|
||||||
|
TopNav.showEmailButton(paste.getTimeToLive());
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@ -4914,6 +5158,13 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
|
|
||||||
DOMPurify.setConfig({SAFE_FOR_JQUERY: true});
|
DOMPurify.setConfig({SAFE_FOR_JQUERY: true});
|
||||||
|
|
||||||
|
// center all modals
|
||||||
|
$('.modal').on('show.bs.modal', function(e) {
|
||||||
|
$(e.target).css({
|
||||||
|
display: 'flex'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// initialize other modules/"classes"
|
// initialize other modules/"classes"
|
||||||
Alert.init();
|
Alert.init();
|
||||||
Model.init();
|
Model.init();
|
||||||
|
@ -326,7 +326,7 @@ describe('TopNav', function () {
|
|||||||
'returns the currently selected expiration date',
|
'returns the currently selected expiration date',
|
||||||
function () {
|
function () {
|
||||||
$.PrivateBin.TopNav.init();
|
$.PrivateBin.TopNav.init();
|
||||||
assert.ok($.PrivateBin.TopNav.getExpiration() === '1week');
|
assert.ok($.PrivateBin.TopNav.getExpiration() === null);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -118,13 +118,41 @@ if ($QRCODE):
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="mx-auto" id="qrcode-display"></div>
|
<div class="mx-auto" id="qrcode-display"></div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-primary btn-block" data-dismiss="modal"><?php echo I18n::_('Close') ?></button>
|
<div class="row">
|
||||||
|
<div class="btn-group col-xs-12">
|
||||||
|
<span class="col-xs-12">
|
||||||
|
<button type="button" class="btn btn-primary btn-block" data-dismiss="modal"><?php echo I18n::_('Close') ?></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
endif;
|
endif;
|
||||||
?>
|
?>
|
||||||
|
<div id="emailconfirmmodal" tabindex="-1" class="modal fade" aria-labelledby="emailconfirmmodalTitle" role="dialog" aria-hidden="true">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div id="emailconfirm-display"></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="btn-group col-xs-12" data-toggle="buttons">
|
||||||
|
<span class="col-xs-12 col-md-4">
|
||||||
|
<button id="emailconfirm-timezone-current" type="button" class="btn btn-danger btn-block" data-dismiss="modal"><?php echo I18n::_('Use Current Timezone') ?></button>
|
||||||
|
</span>
|
||||||
|
<span class="col-xs-12 col-md-4">
|
||||||
|
<button id="emailconfirm-timezone-utc" type="button" class="btn btn-default btn-block" data-dismiss="modal"><?php echo I18n::_('Convert To UTC') ?></button>
|
||||||
|
</span>
|
||||||
|
<span class="col-xs-12 col-md-4">
|
||||||
|
<button type="button" class="btn btn-primary btn-block" data-dismiss="modal"><?php echo I18n::_('Close') ?></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<nav class="navbar navbar-<?php echo $isDark ? 'inverse' : 'default'; ?> navbar-<?php echo $isCpct ? 'fixed' : 'static'; ?>-top"><?php
|
<nav class="navbar navbar-<?php echo $isDark ? 'inverse' : 'default'; ?> navbar-<?php echo $isCpct ? 'fixed' : 'static'; ?>-top"><?php
|
||||||
if ($isCpct):
|
if ($isCpct):
|
||||||
?><div class="container"><?php
|
?><div class="container"><?php
|
||||||
@ -171,6 +199,9 @@ endif;
|
|||||||
<button id="rawtextbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
|
<button id="rawtextbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
|
||||||
<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'), PHP_EOL; ?>
|
<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'), PHP_EOL; ?>
|
||||||
</button>
|
</button>
|
||||||
|
<button id="emaillink" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
|
||||||
|
<span class="glyphicon glyphicon-envelope" aria-hidden="true"></span> <?php echo I18n::_('Email'), PHP_EOL; ?>
|
||||||
|
</button>
|
||||||
<?php
|
<?php
|
||||||
if ($QRCODE):
|
if ($QRCODE):
|
||||||
?>
|
?>
|
||||||
|
@ -105,6 +105,7 @@ endif;
|
|||||||
<button id="sendbutton" class="hidden"><img src="img/icon_send.png" width="18" height="15" alt="" /><?php echo I18n::_('Send'); ?></button>
|
<button id="sendbutton" class="hidden"><img src="img/icon_send.png" width="18" height="15" alt="" /><?php echo I18n::_('Send'); ?></button>
|
||||||
<button id="clonebutton" class="hidden"><img src="img/icon_clone.png" width="15" height="17" alt="" /><?php echo I18n::_('Clone'); ?></button>
|
<button id="clonebutton" class="hidden"><img src="img/icon_clone.png" width="15" height="17" alt="" /><?php echo I18n::_('Clone'); ?></button>
|
||||||
<button id="rawtextbutton" class="hidden"><img src="img/icon_raw.png" width="15" height="15" alt="" /><?php echo I18n::_('Raw text'); ?></button>
|
<button id="rawtextbutton" class="hidden"><img src="img/icon_raw.png" width="15" height="15" alt="" /><?php echo I18n::_('Raw text'); ?></button>
|
||||||
|
<button id="emaillink" class="hidden"><img src="img/icon_email.png" width="15" height="15" alt="" /><?php echo I18n::_('Email'); ?></button>
|
||||||
<?php
|
<?php
|
||||||
if ($QRCODE):
|
if ($QRCODE):
|
||||||
?>
|
?>
|
||||||
|
Loading…
Reference in New Issue
Block a user