913 lines
28 KiB
JavaScript
913 lines
28 KiB
JavaScript
/* -*- js-indent-level: 8; fill-column: 100 -*- */
|
|
/*
|
|
* Toolbar handler
|
|
*/
|
|
|
|
/* global app $ window vex sanitizeUrl brandProductName brandProductURL _ Hammer */
|
|
L.Map.include({
|
|
|
|
// a mapping of uno commands to more readable toolbar items
|
|
unoToolbarCommands: [
|
|
'.uno:StyleApply',
|
|
'.uno:CharFontName'
|
|
],
|
|
|
|
_modalDialogOptions: {
|
|
overlayClose:true,
|
|
opacity: 80,
|
|
overlayCss: {
|
|
backgroundColor : '#000'
|
|
},
|
|
containerCss: {
|
|
overflow : 'hidden',
|
|
backgroundColor : '#fff',
|
|
padding : '20px',
|
|
border : '2px solid #000'
|
|
}
|
|
},
|
|
|
|
onFontSelect: function(e) {
|
|
var font = e.target.value;
|
|
this.applyFont(font);
|
|
this.focus();
|
|
},
|
|
|
|
_getCurrentFontName: function() {
|
|
return this['stateChangeHandler'].getItemValue('.uno:CharFontName');
|
|
},
|
|
|
|
createFontSelector: function(nodeSelector) {
|
|
var that = this;
|
|
|
|
var fontcombobox = $(nodeSelector);
|
|
if (!fontcombobox.hasClass('select2')) {
|
|
fontcombobox.select2({
|
|
placeholder: _('Font')
|
|
});
|
|
}
|
|
|
|
var createSelector = function() {
|
|
var commandValues = that.getToolbarCommandValues('.uno:CharFontName');
|
|
|
|
var data = []; // reset data in order to avoid that the font select box is populated with styles, too.
|
|
// Old browsers like IE11 et al don't like Object.keys with
|
|
// empty arguments
|
|
if (typeof commandValues === 'object') {
|
|
data = data.concat(Object.keys(commandValues));
|
|
}
|
|
fontcombobox.empty();
|
|
for (var i = 0; i < data.length; ++i) {
|
|
if (!data[i]) continue;
|
|
var option = document.createElement('option');
|
|
option.text = data[i];
|
|
option.value = data[i];
|
|
fontcombobox.append(option);
|
|
}
|
|
fontcombobox.on('select2:select', that.onFontSelect.bind(that));
|
|
|
|
fontcombobox.val(that._getCurrentFontName()).trigger('change');
|
|
};
|
|
|
|
createSelector();
|
|
|
|
var onCommandStateChanged = function(e) {
|
|
var commandName = e.commandName;
|
|
|
|
if (commandName !== '.uno:CharFontName')
|
|
return;
|
|
|
|
var state = e.state;
|
|
var found = false;
|
|
fontcombobox.children('option').each(function () {
|
|
var value = this.value;
|
|
if (value.toLowerCase() === state.toLowerCase()) {
|
|
found = true;
|
|
return;
|
|
}
|
|
});
|
|
|
|
if (!found && state) {
|
|
fontcombobox
|
|
.append($('<option></option>')
|
|
.text(state));
|
|
}
|
|
|
|
fontcombobox.val(state).trigger('change');
|
|
};
|
|
|
|
var onFontListChanged = function(e) {
|
|
if (e.commandName === '.uno:CharFontName')
|
|
createSelector();
|
|
};
|
|
|
|
this.off('commandstatechanged', onCommandStateChanged);
|
|
this.on('commandstatechanged', onCommandStateChanged);
|
|
this.off('updatetoolbarcommandvalues', onFontListChanged);
|
|
this.on('updatetoolbarcommandvalues', onFontListChanged);
|
|
},
|
|
|
|
onFontSizeSelect: function(e) {
|
|
this.applyFontSize(e.target.value);
|
|
this.focus();
|
|
},
|
|
|
|
createFontSizeSelector: function(nodeSelector) {
|
|
var data = [6, 7, 8, 9, 10, 10.5, 11, 12, 13, 14, 15, 16, 18, 20,
|
|
22, 24, 26, 28, 32, 36, 40, 44, 48, 54, 60, 66, 72, 80, 88, 96];
|
|
|
|
var fontsizecombobox = $(nodeSelector);
|
|
if (!fontsizecombobox.hasClass('select2')) {
|
|
fontsizecombobox.select2({
|
|
dropdownAutoWidth: true,
|
|
width: 'auto',
|
|
placeholder: _('Font Size'),
|
|
//Allow manually entered font size.
|
|
createTag: function(query) {
|
|
return {
|
|
id: query.term,
|
|
text: query.term,
|
|
tag: true
|
|
};
|
|
},
|
|
tags: true,
|
|
sorter: function(data) { return data.sort(function(a, b) {
|
|
return parseFloat(a.text) - parseFloat(b.text);
|
|
});}
|
|
});
|
|
}
|
|
|
|
fontsizecombobox.empty();
|
|
for (var i = 0; i < data.length; ++i) {
|
|
var option = document.createElement('option');
|
|
option.text = data[i];
|
|
option.value = data[i];
|
|
fontsizecombobox.append(option);
|
|
}
|
|
fontsizecombobox.off('select2:select', this.onFontSizeSelect.bind(this)).on('select2:select', this.onFontSizeSelect.bind(this));
|
|
|
|
var onCommandStateChanged = function(e) {
|
|
var commandName = e.commandName;
|
|
|
|
if (commandName !== '.uno:FontHeight')
|
|
return;
|
|
|
|
var state = e.state;
|
|
var found = false;
|
|
|
|
if (state === '0') {
|
|
state = '';
|
|
}
|
|
|
|
fontsizecombobox.children('option').each(function (i, e) {
|
|
if ($(e).text() === state) {
|
|
found = true;
|
|
}
|
|
});
|
|
|
|
if (!found) {
|
|
// we need to add the size
|
|
fontsizecombobox
|
|
.append($('<option>')
|
|
.text(state).val(state));
|
|
}
|
|
|
|
fontsizecombobox.val(state).trigger('change');
|
|
};
|
|
|
|
this.off('commandstatechanged', onCommandStateChanged);
|
|
this.on('commandstatechanged', onCommandStateChanged);
|
|
},
|
|
|
|
applyFont: function (fontName) {
|
|
if (!fontName)
|
|
return;
|
|
if (this.isPermissionEdit()) {
|
|
var msg = 'uno .uno:CharFontName {' +
|
|
'"CharFontName.FamilyName": ' +
|
|
'{"type": "string", "value": "' + fontName + '"}}';
|
|
app.socket.sendMessage(msg);
|
|
}
|
|
},
|
|
|
|
applyFontSize: function (fontSize) {
|
|
if (this.isPermissionEdit()) {
|
|
var msg = 'uno .uno:FontHeight {' +
|
|
'"FontHeight.Height": ' +
|
|
'{"type": "float", "value": "' + fontSize + '"}}';
|
|
app.socket.sendMessage(msg);
|
|
}
|
|
},
|
|
|
|
getToolbarCommandValues: function (command) {
|
|
if (this._docLayer) {
|
|
return this._docLayer._toolbarCommandValues[command];
|
|
}
|
|
|
|
return undefined;
|
|
},
|
|
|
|
downloadAs: function (name, format, options, id) {
|
|
if (this._fatal) {
|
|
return;
|
|
}
|
|
|
|
id = id || 'export'; // not any special download, simple export
|
|
|
|
if ((id === 'print' && this['wopi'].DisablePrint) ||
|
|
(id === 'export' && this['wopi'].DisableExport)) {
|
|
this.hideBusy();
|
|
return;
|
|
}
|
|
|
|
if (format === undefined || format === null) {
|
|
format = '';
|
|
}
|
|
if (options === undefined || options === null) {
|
|
options = '';
|
|
}
|
|
|
|
if (!window.ThisIsAMobileApp)
|
|
this.showBusy(_('Downloading...'), false);
|
|
app.socket.sendMessage('downloadas ' +
|
|
'name=' + encodeURIComponent(name) + ' ' +
|
|
'id=' + id + ' ' +
|
|
'format=' + format + ' ' +
|
|
'options=' + options);
|
|
},
|
|
|
|
print: function () {
|
|
if (window.ThisIsTheiOSApp || window.ThisIsTheAndroidApp) {
|
|
window.postMobileMessage('PRINT');
|
|
} else {
|
|
this.showBusy(_('Downloading...'), false);
|
|
this.downloadAs('print.pdf', 'pdf', null, 'print');
|
|
}
|
|
},
|
|
|
|
saveAs: function (url, format, options) {
|
|
if (url === undefined || url == null) {
|
|
return;
|
|
}
|
|
if (format === undefined || format === null) {
|
|
format = '';
|
|
}
|
|
if (options === undefined || options === null) {
|
|
options = '';
|
|
}
|
|
|
|
this.showBusy(_('Saving...'), false);
|
|
app.socket.sendMessage('saveas ' +
|
|
'url=wopi:' + encodeURIComponent(url) + ' ' +
|
|
'format=' + format + ' ' +
|
|
'options=' + options);
|
|
},
|
|
|
|
renameFile: function (filename) {
|
|
if (!filename) {
|
|
return;
|
|
}
|
|
this.showBusy(_('Renaming...'), false);
|
|
app.socket.sendMessage('renamefile filename=' + encodeURIComponent(filename));
|
|
},
|
|
|
|
applyStyle: function (style, familyName) {
|
|
if (!style || !familyName) {
|
|
this.fire('error', {cmd: 'setStyle', kind: 'incorrectparam'});
|
|
return;
|
|
}
|
|
if (this.isPermissionEdit()) {
|
|
var msg = 'uno .uno:StyleApply {' +
|
|
'"Style":{"type":"string", "value": "' + style + '"},' +
|
|
'"FamilyName":{"type":"string", "value":"' + familyName + '"}' +
|
|
'}';
|
|
app.socket.sendMessage(msg);
|
|
}
|
|
},
|
|
|
|
applyLayout: function (layout) {
|
|
if (!layout) {
|
|
this.fire('error', {cmd: 'setLayout', kind: 'incorrectparam'});
|
|
return;
|
|
}
|
|
if (this.isPermissionEdit()) {
|
|
var msg = 'uno .uno:AssignLayout {' +
|
|
'"WhatPage":{"type":"unsigned short", "value": "' + this.getCurrentPartNumber() + '"},' +
|
|
'"WhatLayout":{"type":"unsigned short", "value": "' + layout + '"}' +
|
|
'}';
|
|
app.socket.sendMessage(msg);
|
|
}
|
|
},
|
|
|
|
save: function(dontTerminateEdit, dontSaveIfUnmodified, extendedData) {
|
|
var msg = 'save' +
|
|
' dontTerminateEdit=' + (dontTerminateEdit ? 1 : 0) +
|
|
' dontSaveIfUnmodified=' + (dontSaveIfUnmodified ? 1 : 0);
|
|
|
|
if (extendedData !== undefined) {
|
|
msg += ' extendedData=' + extendedData;
|
|
}
|
|
|
|
app.socket.sendMessage(msg);
|
|
},
|
|
|
|
messageNeedsToBeRedirected: function(command) {
|
|
if (command === '.uno:EditHyperlink') {
|
|
var that = this;
|
|
setTimeout(function () { that.showHyperlinkDialog(); }, 500);
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
sendUnoCommand: function (command, json) {
|
|
// To exercise the Trace Event functionality, uncomment this
|
|
// app.socket.emitInstantTraceEvent('cool-unocommand:' + command);
|
|
|
|
var isAllowedInReadOnly = false;
|
|
var allowedCommands = ['.uno:Save', '.uno:WordCountDialog', '.uno:EditAnnotation',
|
|
'.uno:InsertAnnotation', '.uno:DeleteAnnotation', '.uno:Signature',
|
|
'.uno:ShowResolvedAnnotations'];
|
|
|
|
for (var i in allowedCommands) {
|
|
if (allowedCommands[i] === command) {
|
|
isAllowedInReadOnly = true;
|
|
break;
|
|
}
|
|
}
|
|
if (command.startsWith('.uno:SpellOnline')) {
|
|
var map = this;
|
|
var val = map['stateChangeHandler'].getItemValue('.uno:SpellOnline');
|
|
|
|
// proceed if the toggle button is pressed
|
|
if (val && (json === undefined || json === null)) {
|
|
// because it is toggle, state has to be the opposite
|
|
var state = !(val === 'true');
|
|
if (window.isLocalStorageAllowed)
|
|
window.localStorage.setItem('SpellOnline', state);
|
|
}
|
|
}
|
|
|
|
if (this.uiManager.isUIBlocked())
|
|
return;
|
|
if (this.dialog.hasOpenedDialog())
|
|
this.dialog.blinkOpenDialog();
|
|
else if (this.isPermissionEdit() || isAllowedInReadOnly) {
|
|
if (!this.messageNeedsToBeRedirected(command))
|
|
app.socket.sendMessage('uno ' + command + (json ? ' ' + JSON.stringify(json) : ''));
|
|
}
|
|
},
|
|
|
|
toggleCommandState: function (unoState) {
|
|
if (this.isPermissionEdit()) {
|
|
if (!unoState.startsWith('.uno:')) {
|
|
unoState = '.uno:' + unoState;
|
|
}
|
|
this.sendUnoCommand(unoState);
|
|
}
|
|
},
|
|
|
|
insertFile: function (file) {
|
|
this.fire('insertfile', {file: file});
|
|
},
|
|
|
|
insertURL: function (url) {
|
|
this.fire('inserturl', {url: url});
|
|
},
|
|
|
|
selectBackground: function (file) {
|
|
this.fire('selectbackground', {file: file});
|
|
},
|
|
|
|
_doVexOpenHelpFile: function(data, id, map) {
|
|
var productName;
|
|
if (window.ThisIsAMobileApp) {
|
|
productName = window.MobileAppName;
|
|
} else {
|
|
productName = (typeof brandProductName !== 'undefined') ? brandProductName : 'Collabora Online Development Edition';
|
|
}
|
|
var w;
|
|
var iw = window.innerWidth;
|
|
if (iw < 768) {
|
|
w = iw - 30;
|
|
}
|
|
else if (iw > 1920) {
|
|
w = 960;
|
|
}
|
|
else {
|
|
w = iw / 5 + 590;
|
|
}
|
|
vex.open({
|
|
unsafeContent: data,
|
|
showCloseButton: true,
|
|
escapeButtonCloses: true,
|
|
overlayClosesOnClick: false,
|
|
closeAllOnPopState: false,
|
|
contentClassName: 'vex-content vex-selectable',
|
|
buttons: {},
|
|
afterOpen: function() {
|
|
var $vexContent = $(this.contentEl);
|
|
this.contentEl.style.width = w + 'px';
|
|
var i;
|
|
// Display keyboard shortcut or online help
|
|
if (id === 'keyboard-shortcuts') {
|
|
document.getElementById('online-help').style.display='none';
|
|
// Display help according to document opened
|
|
if (map.getDocType() === 'text') {
|
|
document.getElementById('text-shortcuts').style.display='block';
|
|
}
|
|
else if (map.getDocType() === 'spreadsheet') {
|
|
document.getElementById('spreadsheet-shortcuts').style.display='block';
|
|
}
|
|
else if (map.getDocType() === 'presentation') {
|
|
document.getElementById('presentation-shortcuts').style.display='block';
|
|
}
|
|
else if (map.getDocType() === 'drawing') {
|
|
document.getElementById('drawing-shortcuts').style.display='block';
|
|
}
|
|
} else /* id === 'online-help' */ {
|
|
document.getElementById('keyboard-shortcuts').style.display='none';
|
|
if (window.socketProxy) {
|
|
var helpdiv = document.getElementById('online-help');
|
|
var imgList = helpdiv.querySelectorAll('img');
|
|
for (var p = 0; p < imgList.length; p++) {
|
|
var imgSrc = imgList[p].src;
|
|
imgSrc = imgSrc.substring(imgSrc.indexOf('/images'));
|
|
imgList[p].src = window.makeWsUrl('/cool/dist'+ imgSrc);
|
|
}
|
|
}
|
|
// Display help according to document opened
|
|
if (map.getDocType() === 'text') {
|
|
var x = document.getElementsByClassName('text');
|
|
for (i = 0; i < x.length; i++) {
|
|
x[i].style.display = 'block';
|
|
}
|
|
}
|
|
else if (map.getDocType() === 'spreadsheet') {
|
|
x = document.getElementsByClassName('spreadsheet');
|
|
for (i = 0; i < x.length; i++) {
|
|
x[i].style.display = 'block';
|
|
}
|
|
}
|
|
else if (map.getDocType() === 'presentation' || map.getDocType() === 'drawing') {
|
|
x = document.getElementsByClassName('presentation');
|
|
for (i = 0; i < x.length; i++) {
|
|
x[i].style.display = 'block';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Let's translate
|
|
var max;
|
|
var translatableContent = $vexContent.find('h1');
|
|
for (i = 0, max = translatableContent.length; i < max; i++) {
|
|
translatableContent[i].innerHTML = translatableContent[i].innerHTML.toLocaleString();
|
|
}
|
|
translatableContent = $vexContent.find('h2');
|
|
for (i = 0, max = translatableContent.length; i < max; i++) {
|
|
translatableContent[i].innerHTML = translatableContent[i].innerHTML.toLocaleString();
|
|
}
|
|
translatableContent = $vexContent.find('h3');
|
|
for (i = 0, max = translatableContent.length; i < max; i++) {
|
|
translatableContent[i].innerHTML = translatableContent[i].innerHTML.toLocaleString();
|
|
}
|
|
translatableContent = $vexContent.find('h4');
|
|
for (i = 0, max = translatableContent.length; i < max; i++) {
|
|
translatableContent[i].innerHTML = translatableContent[i].innerHTML.toLocaleString();
|
|
}
|
|
translatableContent = $vexContent.find('td');
|
|
for (i = 0, max = translatableContent.length; i < max; i++) {
|
|
translatableContent[i].innerHTML = translatableContent[i].innerHTML.toLocaleString();
|
|
}
|
|
translatableContent = $vexContent.find('p');
|
|
for (i = 0, max = translatableContent.length; i < max; i++) {
|
|
translatableContent[i].innerHTML = translatableContent[i].innerHTML.toLocaleString();
|
|
}
|
|
translatableContent = $vexContent.find('button'); // TOC
|
|
for (i = 0, max = translatableContent.length; i < max; i++) {
|
|
translatableContent[i].innerHTML = translatableContent[i].innerHTML.toLocaleString();
|
|
}
|
|
|
|
//translatable screenshots
|
|
var supportedLanguage = ['fr', 'it', 'de', 'es', 'pt-BR'];
|
|
var currentLanguage = String.locale;
|
|
if (supportedLanguage.indexOf(currentLanguage) >= 0) {
|
|
translatableContent = $($vexContent.find('.screenshot')).find('img');
|
|
for (i = 0, max = translatableContent.length; i < max; i++) {
|
|
translatableContent[i].src = translatableContent[i].src.replace('/en/', '/'+currentLanguage+'/');
|
|
}
|
|
}
|
|
|
|
// Substitute %productName in Online Help
|
|
if (id === 'online-help') {
|
|
var productNameContent = $vexContent.find('span.productname');
|
|
for (i = 0, max = productNameContent.length; i < max; i++) {
|
|
productNameContent[i].innerHTML = productNameContent[i].innerHTML.replace(/%productName/g, productName);
|
|
}
|
|
}
|
|
|
|
// Special Mac key names
|
|
if (navigator.appVersion.indexOf('Mac') != -1 || navigator.userAgent.indexOf('Mac') != -1) {
|
|
var ctrl = /Ctrl/g;
|
|
var alt = /Alt/g;
|
|
if (String.locale.startsWith('de') || String.locale.startsWith('dsb') || String.locale.startsWith('hsb')) {
|
|
ctrl = /Strg/g;
|
|
}
|
|
if (String.locale.startsWith('lt')) {
|
|
ctrl = /Vald/g;
|
|
}
|
|
if (String.locale.startsWith('sl')) {
|
|
ctrl = /Krmilka/gi;
|
|
alt = /Izmenjalka/gi;
|
|
}
|
|
if (id === 'keyboard-shortcuts') {
|
|
document.getElementById('keyboard-shortcuts').innerHTML = document.getElementById('keyboard-shortcuts').innerHTML.replace(ctrl, '⌘').replace(alt, '⌥');
|
|
}
|
|
if (id === 'online-help') {
|
|
document.getElementById('online-help').innerHTML = document.getElementById('online-help').innerHTML.replace(ctrl, '⌘').replace(alt, '⌥');
|
|
}
|
|
}
|
|
|
|
$vexContent.attr('tabindex', -1);
|
|
$vexContent.focus();
|
|
// workaround for https://github.com/HubSpot/vex/issues/43
|
|
$('.vex-overlay').css({ 'pointer-events': 'none'});
|
|
},
|
|
beforeClose: function () {
|
|
map.focus();
|
|
}
|
|
});
|
|
},
|
|
|
|
showHelp: function(id) {
|
|
var map = this;
|
|
if (window.ThisIsAMobileApp) {
|
|
map._doVexOpenHelpFile(window.HelpFile, id, map);
|
|
return;
|
|
}
|
|
var helpLocation = 'cool-help.html';
|
|
if (window.socketProxy)
|
|
helpLocation = window.makeWsUrl('/cool/dist/' + helpLocation);
|
|
$.get(helpLocation, function(data) {
|
|
map._doVexOpenHelpFile(data, id, map);
|
|
});
|
|
},
|
|
|
|
// show the actual welcome dialog with the given data
|
|
_showWelcomeDialogVex: function(data, calledFromMenu) {
|
|
var w;
|
|
var iw = window.innerWidth;
|
|
var hasDismissBtn = window.enableWelcomeMessageButton;
|
|
var btnText = _('I understand the risks');
|
|
|
|
if (iw < 768) {
|
|
w = iw - 30;
|
|
}
|
|
else if (iw > 1920) {
|
|
w = 960;
|
|
}
|
|
else {
|
|
w = iw / 5 + 590;
|
|
}
|
|
|
|
if (!hasDismissBtn && window.mode.isMobile()) {
|
|
var ih = window.innerHeight;
|
|
var h = ih / 2;
|
|
if (iw < 768) {
|
|
h = ih - 170; // Hopefully enough padding to avoid extra scroll-bar on mobile,
|
|
}
|
|
var containerDiv = '<div style="max-height:' + h + 'px;overflow-y:auto;">';
|
|
containerDiv += data;
|
|
containerDiv += '</div>';
|
|
data = containerDiv;
|
|
btnText = _('Dismiss');
|
|
hasDismissBtn = true;
|
|
}
|
|
|
|
// show the dialog
|
|
var map = this;
|
|
vex.dialog.open({
|
|
unsafeMessage: data,
|
|
showCloseButton: !hasDismissBtn,
|
|
escapeButtonCloses: false,
|
|
overlayClosesOnClick: false,
|
|
className: !window.mode.isMobile() ? 'vex-theme-plain' : 'vex-theme-plain vex-welcome-mobile',
|
|
closeAllOnPopState: false,
|
|
focusFirstInput: false, // Needed to avoid auto-scroll to the bottom
|
|
buttons: !hasDismissBtn ? {} : [
|
|
$.extend({}, vex.dialog.buttons.YES, { text: btnText }),
|
|
],
|
|
afterOpen: function() {
|
|
var $vexContent = $(this.contentEl);
|
|
this.contentEl.style.width = w + 'px';
|
|
|
|
$vexContent.attr('tabindex', -1);
|
|
// Work-around to avoid the ugly all-bold dialog message on mobile
|
|
if (window.mode.isMobile()) {
|
|
var dlgMsg = document.getElementsByClassName('vex-dialog-message')[0];
|
|
dlgMsg.setAttribute('class', 'vex-content');
|
|
}
|
|
$vexContent.focus();
|
|
// workaround for https://github.com/HubSpot/vex/issues/43
|
|
$('.vex-overlay').css({ 'pointer-events': 'none'});
|
|
},
|
|
beforeClose: function () {
|
|
if (!calledFromMenu) {
|
|
localStorage.setItem('WSDWelcomeVersion', app.socket.WSDServer.Version);
|
|
}
|
|
map.focus();
|
|
}
|
|
});
|
|
},
|
|
|
|
showWelcomeDialog: function(calledFromMenu) {
|
|
console.log('showWelcomeDialog, calledFromMenu: ' + calledFromMenu);
|
|
var welcomeLocation = 'welcome/welcome-' + String.locale + '.html';
|
|
if (window.socketProxy)
|
|
welcomeLocation = window.makeWsUrl('/cool/dist/' + welcomeLocation);
|
|
|
|
var map = this;
|
|
|
|
// if the user doesn't accept cookies, or we get several triggers,
|
|
// ensure we only ever do this once.
|
|
if (!calledFromMenu && map._alreadyShownWelcomeDialog)
|
|
return;
|
|
map._alreadyShownWelcomeDialog = true;
|
|
|
|
// try to load the welcome message
|
|
$.get(welcomeLocation)
|
|
.done(function(data) {
|
|
map._showWelcomeDialogVex(data, calledFromMenu);
|
|
})
|
|
.fail(function() {
|
|
var currentDate = new Date();
|
|
localStorage.setItem('WSDWelcomeDisabled', 'true');
|
|
localStorage.setItem('WSDWelcomeDisabledDate', currentDate.toDateString());
|
|
|
|
if (calledFromMenu)
|
|
map._showWelcomeDialogVex(_('We are sorry, the information about the latest updates is not available.'));
|
|
});
|
|
},
|
|
|
|
shouldWelcome: function() {
|
|
if (!window.isLocalStorageAllowed || !window.enableWelcomeMessage)
|
|
return false;
|
|
|
|
var storedVersion = localStorage.getItem('WSDWelcomeVersion');
|
|
var currentVersion = app.socket.WSDServer.Version;
|
|
var welcomeDisabledCookie = localStorage.getItem('WSDWelcomeDisabled');
|
|
var welcomeDisabledDate = localStorage.getItem('WSDWelcomeDisabledDate');
|
|
var isWelcomeDisabled = false;
|
|
|
|
if (welcomeDisabledCookie && welcomeDisabledDate) {
|
|
// Check if we are stil in the same day
|
|
var currentDate = new Date();
|
|
if (welcomeDisabledDate === currentDate.toDateString())
|
|
isWelcomeDisabled = true;
|
|
else {
|
|
//Values expired. Clear the local values
|
|
localStorage.removeItem('WSDWelcomeDisabled');
|
|
localStorage.removeItem('WSDWelcomeDisabledDate');
|
|
}
|
|
}
|
|
|
|
if ((!storedVersion || storedVersion !== currentVersion) && !isWelcomeDisabled) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
showLOAboutDialog: function() {
|
|
|
|
// Just as a test to exercise the Async Trace Event functionality, uncomment this
|
|
// line and the asyncTraceEvent.finish() below.
|
|
// var asyncTraceEvent = app.socket.createAsyncTraceEvent('cool-showLOAboutDialog');
|
|
|
|
// Move the div sitting in 'body' as vex-content and make it visible
|
|
var content = $('#about-dialog').clone().css({display: 'block'});
|
|
// fill product-name and product-string
|
|
var productName;
|
|
if (window.ThisIsAMobileApp) {
|
|
productName = window.MobileAppName;
|
|
} else {
|
|
productName = (typeof brandProductName !== 'undefined') ? brandProductName : 'Collabora Online Development Edition';
|
|
}
|
|
var productURL = (typeof brandProductURL !== 'undefined') ? brandProductURL : 'https://collaboraonline.github.io/';
|
|
content.find('#product-name').text(productName).addClass('product-' + productName.split(/[ ()]+/).join('-').toLowerCase());
|
|
var productString = _('This version of %productName is powered by');
|
|
var productNameWithURL;
|
|
if (!window.ThisIsAMobileApp)
|
|
productNameWithURL = '<a href="' + sanitizeUrl.sanitizeUrl(productURL) +
|
|
'" target="_blank">' + productName + '</a>';
|
|
else
|
|
productNameWithURL = productName;
|
|
content.find('#product-string').html(productString.replace('%productName', productNameWithURL));
|
|
|
|
if (window.socketProxy)
|
|
content.find('#slow-proxy').text(_('"Slow Proxy"'));
|
|
|
|
var w;
|
|
var iw = window.innerWidth;
|
|
if (iw < 768) {
|
|
w = iw - 30;
|
|
}
|
|
else if (iw > 1920) {
|
|
w = 960;
|
|
}
|
|
else {
|
|
w = iw / 5 + 590;
|
|
}
|
|
var map = this;
|
|
var handler = function(event) {
|
|
if (event.key === 'd') {
|
|
map._docLayer.toggleTileDebugMode();
|
|
} else if (event.key === 'l') {
|
|
// L toggges the Online logging level between the default (whatever
|
|
// is set in coolwsd.xml or on the coolwsd command line) and the
|
|
// most verbose a client is allowed to set (which also can be set in
|
|
// coolwsd.xml or on the coolwsd command line).
|
|
//
|
|
// In a typical developer "make run" setup, the default is "trace"
|
|
// so there is nothing more verbose. But presumably it is different
|
|
// in production setups.
|
|
|
|
app.socket.threadLocalLoggingLevelToggle = !app.socket.threadLocalLoggingLevelToggle;
|
|
|
|
var newLogLevel = (app.socket.threadLocalLoggingLevelToggle ? 'verbose' : 'default');
|
|
|
|
app.socket.sendMessage('loggingleveloverride ' + newLogLevel);
|
|
|
|
var logLevelInformation = newLogLevel;
|
|
if (newLogLevel === 'default')
|
|
logLevelInformation = 'default (from coolwsd.xml)';
|
|
else if (newLogLevel === 'verbose')
|
|
logLevelInformation = 'most verbose (from coolwsd.xml)';
|
|
else if (newLogLevel === 'terse')
|
|
logLevelInformation = 'least verbose (from coolwsd.xml)';
|
|
else
|
|
logLevelInformation = newLogLevel;
|
|
|
|
$(app.ExpertlyTrickForLOAbout.contentEl).find('#log-level-state').html('Log level: ' + logLevelInformation);
|
|
} else if (event.key === 't') {
|
|
// T turns Trace Event recording on in the Kit process
|
|
// for this document, as long as coolwsd is running with the
|
|
// trace_event[@enable] config option as true. T again
|
|
// turns it off.
|
|
|
|
if (app.socket.enableTraceEventLogging) {
|
|
app.socket.traceEventRecordingToggle = !app.socket.traceEventRecordingToggle;
|
|
|
|
app.socket.sendMessage('traceeventrecording '
|
|
+ (app.socket.traceEventRecordingToggle ? 'start' : 'stop'));
|
|
|
|
$(app.ExpertlyTrickForLOAbout.contentEl).find('#trace-event-state').html('Trace Event generation: ' + (app.socket.traceEventRecordingToggle ? 'ON' : 'OFF'));
|
|
// Just as a test, uncomment this to toggle SAL_WARN and
|
|
// SAL_INFO selection between two states: 1) the default
|
|
// as directed by the SAL_LOG environment variable, and
|
|
// 2) all warnings on plus SAL_INFO for sc.
|
|
//
|
|
// (Note that coolwsd sets the SAL_LOG environment variable
|
|
// to "-WARN-INFO", i.e. the default is that nothing is
|
|
// logged from core.)
|
|
|
|
// app.socket.sendMessage('sallogoverride ' + (app.socket.traceEventRecordingToggle ? '+WARN+INFO.sc' : 'default'));
|
|
}
|
|
}
|
|
};
|
|
vex.open({
|
|
unsafeContent: content[0].outerHTML,
|
|
showCloseButton: true,
|
|
escapeButtonCloses: true,
|
|
overlayClosesOnClick: true,
|
|
buttons: {},
|
|
afterOpen: function() {
|
|
|
|
var touchGesture = map['touchGesture'];
|
|
if (touchGesture && touchGesture._hammer) {
|
|
touchGesture._hammer.off('tripletap', L.bind(touchGesture._onTripleTap, touchGesture));
|
|
}
|
|
|
|
var $vexContent = $(this.contentEl);
|
|
var hammer = new Hammer.Manager($vexContent.get(0));
|
|
hammer.add(new Hammer.Tap({ taps: 3 }));
|
|
hammer.on('tap', function() {
|
|
map._docLayer.toggleTileDebugMode();
|
|
});
|
|
|
|
this.contentEl.style.width = w + 'px';
|
|
|
|
// FIXME: When we remove vex this needs to be cleaned up.
|
|
|
|
// It is hard to access the value of "this" in this afterOpen
|
|
// function in the handler function. Use a global variable until
|
|
// somebody figures out a better way.
|
|
app.ExpertlyTrickForLOAbout = this;
|
|
$(window).bind('keyup.vex', handler);
|
|
// workaround for https://github.com/HubSpot/vex/issues/43
|
|
$('.vex-overlay').css({ 'pointer-events': 'none'});
|
|
},
|
|
beforeClose: function () {
|
|
$(window).unbind('keyup.vex', handler);
|
|
var touchGesture = map['touchGesture'];
|
|
if (touchGesture && touchGesture._hammer) {
|
|
touchGesture._hammer.on('tripletap', L.bind(touchGesture._onTripleTap, touchGesture));
|
|
}
|
|
map.focus();
|
|
|
|
// Unset the global variable, see comment above.
|
|
app.ExpertlyTrickForLOAbout = undefined;
|
|
// asyncTraceEvent.finish();
|
|
}
|
|
});
|
|
},
|
|
|
|
extractContent: function(html) {
|
|
var parser = new DOMParser;
|
|
return parser.parseFromString(html, 'text/html').documentElement.getElementsByTagName('body')[0].textContent;
|
|
},
|
|
|
|
makeURLFromStr: function(str) {
|
|
if (!(str.toLowerCase().startsWith('http://') || str.toLowerCase().startsWith('https://'))) {
|
|
str = 'http://' + str;
|
|
}
|
|
return str;
|
|
},
|
|
|
|
showHyperlinkDialog: function() {
|
|
var map = this;
|
|
var text = '';
|
|
var link = '';
|
|
if (this.hyperlinkUnderCursor && this.hyperlinkUnderCursor.text && this.hyperlinkUnderCursor.link) {
|
|
text = this.hyperlinkUnderCursor.text;
|
|
link = this.hyperlinkUnderCursor.link;
|
|
} else if (this._clip && this._clip._selectionType == 'text') {
|
|
if (map['stateChangeHandler'].getItemValue('.uno:Copy') === 'enabled') {
|
|
text = this.extractContent(this._clip._selectionContent);
|
|
}
|
|
} else if (this._docLayer._selectedTextContent) {
|
|
text = this.extractContent(this._docLayer._selectedTextContent);
|
|
}
|
|
|
|
vex.dialog.open({
|
|
contentClassName: 'hyperlink-dialog',
|
|
message: _('Insert hyperlink'),
|
|
overlayClosesOnClick: false,
|
|
input: [
|
|
_('Text') + '<input name="text" id="hyperlink-text-box" type="text" value="' + text + '"/>',
|
|
_('Link') + '<input name="link" id="hyperlink-link-box" type="text" value="' + link + '"/>'
|
|
].join(''),
|
|
buttons: [
|
|
$.extend({}, vex.dialog.buttons.YES, { text: _('OK') }),
|
|
$.extend({}, vex.dialog.buttons.NO, { text: _('Cancel') })
|
|
],
|
|
callback: function(data) {
|
|
if (data && data.link != '') {
|
|
var command = {
|
|
'Hyperlink.Text': {
|
|
type: 'string',
|
|
value: data.text
|
|
},
|
|
'Hyperlink.URL': {
|
|
type: 'string',
|
|
value: map.makeURLFromStr(data.link)
|
|
}
|
|
};
|
|
map.sendUnoCommand('.uno:SetHyperlink', command);
|
|
map.focus();
|
|
}
|
|
else {
|
|
map.focus();
|
|
}
|
|
},
|
|
afterOpen: function() {
|
|
setTimeout(function() {
|
|
if (document.getElementById('hyperlink-text-box').value.trim() !== '') {
|
|
document.getElementById('hyperlink-link-box').focus();
|
|
}
|
|
else {
|
|
document.getElementById('hyperlink-text-box').focus();
|
|
}
|
|
}, 0);
|
|
}
|
|
});
|
|
},
|
|
|
|
openRevisionHistory: function () {
|
|
var map = this;
|
|
// if we are being loaded inside an iframe, ask
|
|
// our host to show revision history mode
|
|
map.fire('postMessage', {msgId: 'rev-history', args: {Deprecated: true}});
|
|
map.fire('postMessage', {msgId: 'UI_FileVersions'});
|
|
},
|
|
openShare: function () {
|
|
var map = this;
|
|
map.fire('postMessage', {msgId: 'UI_Share'});
|
|
},
|
|
openSaveAs: function () {
|
|
var map = this;
|
|
map.fire('postMessage', {msgId: 'UI_SaveAs'});
|
|
},
|
|
});
|