Changes for page InplaceEditing

From version 4.1
edited by Nazzareno Pompei
on 28/10/2022 08:43
Change comment: Install extension [org.xwiki.platform:xwiki-platform-edit-ui/14.9]
To version 3.1
edited by Nazzareno Pompei
on 22/12/2021 09:31
Change comment: Install extension [org.xwiki.platform:xwiki-platform-edit-ui/13.10.1]

Summary

Details

XWiki.JavaScriptExtension[0]
Code
... ... @@ -87,24 +87,26 @@
87 87   timestamp: new Date().getTime()
88 88   };
89 89   if (!forView) {
90 - // We need the annotated HTML when editing in order to be able to protect the rendering transformations and to
90 + // We need the annotated XHTML when editing in order to be able to protect the rendering transformations and to
91 91   // be able to recreate the wiki syntax.
92 - queryString.outputSyntax = 'annotatedhtml';
93 - queryString.outputSyntaxVersion = '5.0'
92 + queryString.outputSyntax = 'annotatedxhtml';
94 94   // Currently, only the macro transformations are protected and thus can be edited.
95 95   // See XRENDERING-78: Add markers to modified XDOM by Transformations/Macros
96 96   queryString.transformations = 'macro';
97 97   }
98 - return Promise.resolve($.get(this.getURL('view'), queryString)).then(html => {
97 + var thisXWikiDocument = this;
98 + return $.get(this.getURL('view'), queryString).fail(function() {
99 + new XWiki.widgets.Notification(l10n['edit.inplace.page.renderFailed'], 'error');
100 + }).then(function(html) {
99 99   // Render succeeded.
100 100   var container = $('<div/>').html(html);
101 - return $.extend(this, {
103 + return $.extend(thisXWikiDocument, {
102 102   renderedTitle: container.find('#document-title h1').html(),
103 103   renderedContent: container.find('#xwikicontent').html()
104 104   });
105 - }).catch(() => {
106 - new XWiki.widgets.Notification(l10n['edit.inplace.page.renderFailed'], 'error');
107 - return Promise.reject(this);
107 + }, function() {
108 + // Render failed.
109 + return thisXWikiDocument;
108 108   });
109 109   },
110 110  
... ... @@ -114,19 +114,20 @@
114 114   * @return a promise that resolves to this document instance if the reload request succeeds
115 115   */
116 116   reload: function() {
117 - return Promise.resolve($.getJSON(this.getRestURL(), {
119 + var thisXWikiDocument = this;
120 + return $.getJSON(this.getRestURL(), {
118 118   // Make sure the response is not retrieved from cache (IE11 doesn't obey the caching HTTP headers).
119 119   timestamp: new Date().getTime()
120 - })).then(newXWikiDocument => {
123 + }).then(function(newXWikiDocument) {
121 121   // Reload succeeded.
122 122   // Resolve the document reference.
123 - this.documentReference = XWiki.Model.resolve(newXWikiDocument.id, XWiki.EntityType.DOCUMENT);
126 + thisXWikiDocument.documentReference = XWiki.Model.resolve(newXWikiDocument.id, XWiki.EntityType.DOCUMENT);
124 124   // We were able to load the document so it's not new.
125 - this.isNew = false;
126 - return $.extend(this, newXWikiDocument);
127 - }).catch(() => {
128 + thisXWikiDocument.isNew = false;
129 + return $.extend(thisXWikiDocument, newXWikiDocument);
130 + }, function() {
128 128   // Reload failed.
129 - return Promise.reject(this);
132 + return thisXWikiDocument;
130 130   });
131 131   },
132 132  
... ... @@ -137,8 +137,9 @@
137 137   * @return a promise that resolves to this document instance if the lock request succeeds
138 138   */
139 139   lock: function(action, force) {
143 + var thisXWikiDocument = this;
140 140   action = action || 'edit';
141 - return Promise.resolve($.getJSON(this.getURL('get'), {
145 + return $.getJSON(this.getURL('get'), {
142 142   sheet: 'XWiki.InplaceEditing',
143 143   action: 'lock',
144 144   lockAction: action,
... ... @@ -147,20 +147,20 @@
147 147   outputSyntax: 'plain',
148 148   // Make sure the response is not retrieved from cache (IE11 doesn't obey the caching HTTP headers).
149 149   timestamp: new Date().getTime()
150 - })).then(() => {
154 + }).then(function() {
151 151   // Lock succeeded.
152 - this.locked = action;
153 - return this;
154 - }).catch(response => {
156 + thisXWikiDocument.locked = action;
157 + return thisXWikiDocument;
158 + }, function(response) {
155 155   // Lock failed.
156 - delete this.locked;
160 + delete thisXWikiDocument.locked;
157 157   // Check if the user can force the lock.
158 158   var lockConfirmation = response.responseJSON;
159 159   if (response.status === 423 && lockConfirmation) {
160 160   // The user can force the lock, but needs confirmation.
161 - this.lockConfirmation = lockConfirmation;
165 + thisXWikiDocument.lockConfirmation = lockConfirmation;
162 162   }
163 - return Promise.reject(this);
167 + return thisXWikiDocument;
164 164   });
165 165   },
166 166  
... ... @@ -255,7 +255,7 @@
255 255   $('#xwikicontent').removeAttr('tabindex');
256 256   if (sectionId) {
257 257   // Select the heading of the specified section.
258 - $('#xwikicontent > #' + $.escapeSelector(sectionId)).each(function() {
262 + $('#xwikicontent > #' + escapeSelector(sectionId)).each(function() {
259 259   selectText(this);
260 260   });
261 261   }
... ... @@ -263,6 +263,22 @@
263 263   });
264 264   };
265 265  
270 + var escapeSelector = function(selector) {
271 + if (window.CSS && typeof CSS.escape === 'function') {
272 + // Not supported by Internet Explorer.
273 + return CSS.escape(selector);
274 + } else if (typeof $.escapeSelector === 'function') {
275 + // Added in jQuery 3.0
276 + return $.escapeSelector(selector);
277 + } else if (typeof selector === 'string') {
278 + // Simple implementation.
279 + // See https://learn.jquery.com/using-jquery-core/faq/how-do-i-select-an-element-by-an-id-that-has-characters-used-in-css-notation/
280 + return selector.replace(/(:|\.|\[|\]|,|=|@)/g, '\\$1');
281 + } else {
282 + return selector;
283 + }
284 + };
285 +
266 266   // We preserve the document data between edits in order to be able to know which document translation should be edited
267 267   // (e.g. when the document translation is missing and we create it, the next edit session should target the created
268 268   // translation).
... ... @@ -270,11 +270,6 @@
270 270   language: xcontext.locale
271 271   }, xwikiDocumentAPI);
272 272  
273 - var setCurrentXWikiDocument = function(xwikiDocument) {
274 - currentXWikiDocument = xwikiDocument;
275 - return Promise.resolve(xwikiDocument);
276 - };
277 -
278 278   var editInPlace = function(options) {
279 279   options = $.extend({
280 280   afterEdit: function() {},
... ... @@ -282,16 +282,11 @@
282 282   }, options);
283 283   $('#xwikicontent').addClass('loading');
284 284   // Lock the document first.
285 - return lock(currentXWikiDocument)
300 + return lock(currentXWikiDocument).fail(options.lockFailed)
286 286   // Then load the document only if we managed to lock it.
287 - .then(load, xwikiDocument => {
288 - options.lockFailed(xwikiDocument);
289 - return Promise.reject(xwikiDocument);
302 + .then(load)
290 290   // Then load the editors only if we managed to load the document.
291 - }).then(edit).then(xwikiDocument => {
292 - options.afterEdit(xwikiDocument);
293 - return xwikiDocument;
294 - }).finally(() => {
304 + .then(edit).done(options.afterEdit).always(function() {
295 295   $('#xwikicontent').removeClass('loading');
296 296   // Then wait for an action (save, cancel, reload) only if the editors were loaded successfuly.
297 297   }).then(maybeSave)
... ... @@ -299,39 +299,34 @@
299 299   .then(unlock, unlock)
300 300   // Finally view the document both when the edit ended with success and with a failure.
301 301   .then(view, view)
302 - // Update the current document for the next edit session.
303 - .then(setCurrentXWikiDocument, setCurrentXWikiDocument);
312 + .always(function(xwikiDocument) {
313 + // Update the current document for the next edit session.
314 + currentXWikiDocument = xwikiDocument;
315 + });
304 304   };
305 305  
306 306   var lock = function(xwikiDocument) {
307 - return xwikiDocument.lock().catch(function(xwikiDocument) {
319 + return xwikiDocument.lock().then(null, function(xwikiDocument) {
308 308   // If the document was already locked then we need to ask the user if they want to force the lock.
309 309   if (xwikiDocument.lockConfirmation) {
310 310   var confirmation = xwikiDocument.lockConfirmation;
311 311   delete xwikiDocument.lockConfirmation;
312 - return maybeForceLock(confirmation).then(xwikiDocument.lock.bind(xwikiDocument, 'edit', true), function() {
324 + return maybeForceLock(confirmation).then($.proxy(xwikiDocument, 'lock', 'edit', true), function() {
313 313   // Cancel the edit action.
314 - return Promise.reject(xwikiDocument);
326 + return xwikiDocument;
315 315   });
316 316   } else {
317 317   new XWiki.widgets.Notification(l10n['edit.inplace.page.lockFailed'], 'error');
318 - return Promise.reject(xwikiDocument);
330 + return xwikiDocument;
319 319   }
320 320   });
321 321   };
322 322  
323 323   var maybeForceLock = function(confirmation) {
324 - var deferred, promise = new Promise((resolve, reject) => {
325 - deferred = {resolve, reject};
326 - });
327 - // We need the catch() to prevent the "Uncaught (in promise)" error log in the console.
328 - promise.catch(() => {}).finally(() => {
329 - // This flag is used by the Force Lock modal to know whether the promise is settled when the modal is closing.
330 - deferred.settled = true;
331 - });
336 + var deferred = $.Deferred();
332 332   // Reuse the confirmation modal once it is created.
333 333   var modal = $('.force-edit-lock-modal');
334 - if (!modal.length) {
339 + if (modal.length === 0) {
335 335   modal = createForceLockModal();
336 336   }
337 337   // Update the deferred that needs to be resolved or rejected.
... ... @@ -347,7 +347,7 @@
347 347   }
348 348   // Show the confirmation modal.
349 349   modal.modal('show');
350 - return promise;
355 + return deferred.promise();
351 351   };
352 352  
353 353   var createForceLockModal = function() {
... ... @@ -371,16 +371,16 @@
371 371   '</div>'
372 372   ].join(''));
373 373   modal.find('.close').attr('aria-label', l10n['edit.inplace.close']);
374 - modal.find('.modal-footer .btn-warning').on('click', function() {
379 + modal.find('.modal-footer .btn-warning').click(function() {
375 375   // The user has confirmed they want to force the lock.
376 376   modal.data('deferred').resolve();
377 377   modal.modal('hide');
378 378   });
379 379   modal.on('hide.bs.modal', function() {
380 - // If the lock promise is not yet settled when the modal is closing then it means the modal was canceled,
385 + // If the lock promise is not yet resolved when the modal is closing then it means the modal was canceled,
381 381   // i.e. the user doesn't want to force the lock.
382 382   var deferred = modal.data('deferred');
383 - if (!deferred.settled) {
388 + if (deferred.state() === 'pending') {
384 384   deferred.reject();
385 385   }
386 386   });
... ... @@ -388,19 +388,17 @@
388 388   };
389 389  
390 390   var load = function(xwikiDocument) {
391 - return xwikiDocument.reload().then(xwikiDocument => {
396 + return xwikiDocument.reload().done(function(xwikiDocument) {
392 392   // Clone the current document version and keep a reference to it in order to be able to restore it on cancel.
393 393   xwikiDocument.originalDocument = $.extend(true, {
394 394   renderedTitle: $('#document-title h1').html(),
395 395   renderedContent: $('#xwikicontent').html()
396 396   }, xwikiDocument);
397 - return xwikiDocument;
398 - }).catch(xwikiDocument => {
402 + }).fail(function() {
399 399   new XWiki.widgets.Notification(l10n['edit.inplace.page.loadFailed'], 'error');
400 - return Promise.reject(xwikiDocument);
401 401   // Render the document for edit, in order to have the annotated content HTML. The annotations are used to protect
402 402   // the rendering transformations (e.g. macros) when editing the content.
403 - }).then(render.bind(null, false));
406 + }).then($.proxy(render, null, false));
404 404   };
405 405  
406 406   /**
... ... @@ -413,7 +413,7 @@
413 413   };
414 414  
415 415   var maybeSave = function(xwikiDocument) {
416 - return waitForAction(xwikiDocument).then(action => {
419 + return waitForAction(xwikiDocument).then(function(action) {
417 417   switch(action.name) {
418 418   case 'save': return save({
419 419   document: action.document,
... ... @@ -426,29 +426,29 @@
426 426   };
427 427  
428 428   var waitForAction = function(xwikiDocument) {
429 - return new Promise((resolve, reject) => {
430 - // We wait for the first save, reload or cancel event, whichever is triggered first. Note that the event listeners
431 - // that are not executed first will remain registered but that doesn't cause any problems because the state of a
432 - // deferred object (promise) cannot change once it was resolved. So the first event that fires will resolve the
433 - // promise and the remaining events won't be able to change that. The remaining event listeners could be called
434 - // later but they won't have any effect on the deferred object.
435 - $(document).one([
436 - 'xwiki:actions:save',
437 - 'xwiki:actions:reload',
438 - 'xwiki:actions:cancel',
439 - ].join(' '), '.xcontent.form', function(event, data) {
440 - resolve({
441 - name: event.type.substring('xwiki:actions:'.length),
442 - document: xwikiDocument,
443 - data: data
444 - });
432 + var deferred = $.Deferred();
433 + // We wait for the first save, reload or cancel event, whichever is triggered first. Note that the event listeners
434 + // that are not executed first will remain registered but that doesn't cause any problems because the state of a
435 + // deferred object (promise) cannot change once it was resolved. So the first event that fires will resolve the
436 + // promise and the remaining events won't be able to change that. The remaining event listeners could be called
437 + // later but they won't have any effect on the deferred object.
438 + $(document).one([
439 + 'xwiki:actions:save',
440 + 'xwiki:actions:reload',
441 + 'xwiki:actions:cancel',
442 + ].join(' '), '.xcontent.form', function(event, data) {
443 + deferred.resolve({
444 + name: event.type.substring('xwiki:actions:'.length),
445 + document: xwikiDocument,
446 + data: data
445 445   });
446 446   });
449 + return deferred.promise();
447 447   };
448 448  
449 449   var save = function(data) {
450 450   // Push the changes to the server.
451 - return push(data.document).then(xwikiDocument => {
454 + return push(data.document).then(function(xwikiDocument) {
452 452   // Save succeeded.
453 453   return shouldReload(xwikiDocument).then(
454 454   // The document was saved with merge and thus if we want to continue eding we need to reload the editor (because
... ... @@ -455,7 +455,7 @@
455 455   // its content doesn't match the saved content).
456 456   reload,
457 457   // No need to reload the editor because either the action was Save & View or there was no merge on save.
458 - maybeContinueEditing.bind(null, data['continue'])
461 + $.proxy(maybeContinueEditing, null, data['continue'])
459 459   );
460 460   // Save failed. Continue editing because we may have unsaved content.
461 461   }, maybeSave);
... ... @@ -463,15 +463,15 @@
463 463  
464 464   var push = function(xwikiDocument) {
465 465   // Let actionButtons.js do the push. We just catch the result.
466 - return new Promise((resolve, reject) => {
467 - // We wait for the save request to either succeed or fail. Note that one of the event listeners will remain
468 - // registered but that doesn't cause any problems because the state of a deferred object (promise) cannot change
469 - // once it was resolved or rejected. So the first event that fires will resolve/reject the promise and the
470 - // remaining event won't be able to change that. The remaining event listener could be called later but it won't
471 - // have any effect.
472 - $(document).one('xwiki:document:saved', '.xcontent.form', resolve.bind(null, xwikiDocument));
473 - $(document).one('xwiki:document:saveFailed', '.xcontent.form', reject.bind(null, xwikiDocument));
474 - });
469 + var deferred = $.Deferred();
470 + // We wait for the save request to either succeed or fail. Note that one of the event listeners will remain
471 + // registered but that doesn't cause any problems because the state of a deferred object (promise) cannot change
472 + // once it was resolved or rejected. So the first event that fires will resolve/reject the promise and the remaining
473 + // event won't be able to change that. The remaining event listener could be called later but it won't have any
474 + // effect.
475 + $(document).one('xwiki:document:saved', '.xcontent.form', $.proxy(deferred, 'resolve', xwikiDocument));
476 + $(document).one('xwiki:document:saveFailed', '.xcontent.form', $.proxy(deferred, 'reject', xwikiDocument));
477 + return deferred.promise();
475 475   };
476 476  
477 477   var maybeContinueEditing = function(continueEditing, xwikiDocument) {
... ... @@ -492,9 +492,9 @@
492 492  
493 493   // Reload the document JSON data (to have the new version) and render the document for view. We need the view HTML
494 494   // both if we stop editing now and if we continue but cancel the edit later.
495 - return xwikiDocument.reload().then(render.bind(null, true)).then(
496 - afterReloadAndRender.bind(null, /* success: */ true),
497 - afterReloadAndRender.bind(null, /* success: */ false)
498 + return xwikiDocument.reload().then($.proxy(render, null, true)).then(
499 + $.proxy(afterReloadAndRender, null, /* success: */ true),
500 + $.proxy(afterReloadAndRender, null, /* success: */ false)
498 498   );
499 499   };
500 500  
... ... @@ -513,7 +513,7 @@
513 513   };
514 514  
515 515   // Make sure we unlock the document when the user navigates to another page.
516 - $(window).on('unload pagehide', unlock.bind(null, currentXWikiDocument));
519 + $(window).on('unload pagehide', $.proxy(unlock, null, currentXWikiDocument));
517 517  
518 518   var shouldReload = function(xwikiDocument) {
519 519   var reloadEventFired = false;
... ... @@ -520,18 +520,18 @@
520 520   $(document).one('xwiki:actions:reload.maybe', '.xcontent.form', function() {
521 521   reloadEventFired = true;
522 522   });
523 - return new Promise((resolve, reject) => {
524 - // Wait a bit to see if the reload event is fired.
525 - setTimeout(function() {
526 - // Remove the listener in case the reload event wasn't fired.
527 - $(document).off('xwiki:actions:reload.maybe');
528 - if (reloadEventFired) {
529 - resolve(xwikiDocument);
530 - } else {
531 - reject(xwikiDocument);
532 - }
533 - }, 0);
534 - });
526 + var deferred = $.Deferred();
527 + // Wait a bit to see if the reload event is fired.
528 + setTimeout(function() {
529 + // Remove the listener in case the reload event wasn't fired.
530 + $(document).off('xwiki:actions:reload.maybe');
531 + if (reloadEventFired) {
532 + deferred.resolve(xwikiDocument);
533 + } else {
534 + deferred.reject(xwikiDocument);
535 + }
536 + }, 0);
537 + return deferred.promise();
535 535   };
536 536  
537 537   var reload = function(xwikiDocument) {
... ... @@ -558,7 +558,7 @@
558 558   if (window.location.hash === '#edit' || window.location.hash === '#translate') {
559 559   history.replaceState(null, null, '#');
560 560   }
561 - return Promise.resolve(xwikiDocument);
564 + return $.Deferred().resolve(xwikiDocument).promise();
562 562   };
563 563  
564 564   var edit = function(xwikiDocument) {
... ... @@ -603,7 +603,7 @@
603 603   // action buttons so we need to re-enable them each time we enter the edit mode.
604 604   fakeForm.enable();
605 605   }
606 - return Promise.resolve(xwikiDocument);
609 + return $.Deferred().resolve(xwikiDocument).promise();
607 607   }
608 608   };
609 609  
... ... @@ -664,9 +664,9 @@
664 664   .parent().removeClass('hidden');
665 665   }
666 666   });
667 - return Promise.resolve($.get(XWiki.currentDocument.getURL('get'), {
670 + return $.get(XWiki.currentDocument.getURL('get'), {
668 668   xpage: 'editactions'
669 - })).then(html => {
672 + }).then(function(html) {
670 670   actionButtons.html(html);
671 671   // Fix the name of the Save & View action.
672 672   actionButtons.find('.btn-primary').first().attr('name', 'action_save');
... ... @@ -676,21 +676,21 @@
676 676   actionButtons.append('<div class="hidden extra"/>');
677 677   // Let the others know that the DOM has been updated, in order to enhance it.
678 678   $(document).trigger('xwiki:dom:updated', {'elements': actionButtons.toArray()});
679 - return new Promise((resolve, reject) => {
680 - require(['xwiki-actionButtons', 'xwiki-diff', 'xwiki-autoSave'], function() {
681 - overrideEditActions();
682 - overrideAjaxSaveAndContinue();
683 - // Activate the auto-save feature passing our fake edit form. Note that autosave.js also creates an instance of
684 - // AutoSave but it doesn't do anything because it doesn't find a real edit form in the page. This is why we have
685 - // to create our own instance of AutoSave passing the right (fake) form.
686 - new XWiki.editors.AutoSave({form: fakeForm});
687 - var xwikiDocument = actionButtons.data('xwikiDocument');
688 - // Enable the action buttons (and their shortcut keys) only if we're editing a document.
689 - actionButtons.find(':input').prop('disabled', !xwikiDocument);
690 - resolve(xwikiDocument);
691 - });
682 + var deferred = $.Deferred();
683 + require(['xwiki-actionButtons', 'xwiki-diff', 'xwiki-autoSave'], function() {
684 + overrideEditActions();
685 + overrideAjaxSaveAndContinue();
686 + // Activate the auto-save feature passing our fake edit form. Note that autosave.js also creates an instance of
687 + // AutoSave but it doesn't do anything because it doesn't find a real edit form in the page. This is why we have
688 + // to create our own instance of AutoSave passing the right (fake) form.
689 + new XWiki.editors.AutoSave({form: fakeForm});
690 + var xwikiDocument = actionButtons.data('xwikiDocument');
691 + // Enable the action buttons (and their shortcut keys) only if we're editing a document.
692 + actionButtons.find(':input').prop('disabled', !xwikiDocument);
693 + deferred.resolve(xwikiDocument);
692 692   });
693 - }).catch(() => {
695 + return deferred.promise();
696 + }, function() {
694 694   new XWiki.widgets.Notification(l10n['edit.inplace.actionButtons.loadFailed'], 'error');
695 695   });
696 696   };
... ... @@ -731,13 +731,6 @@
731 731   extra[entry.name] = value;
732 732   return extra;
733 733   }, {});
734 - // retrieve all input fields listing the temporary uploaded files.
735 - var uploadedFiles = $('#xwikicontent').nextAll('input[name="uploadedFiles"]').serializeArray().reduce(function(extra, entry) {
736 - var value = extra[entry.name] || [];
737 - value.push(entry.value);
738 - extra[entry.name] = value;
739 - return extra;
740 - }, {});
741 741   var xwikiDocument = this._getActionButtons().data('xwikiDocument');
742 742   var formData = {
743 743   title: xwikiDocument.rawTitle,
... ... @@ -755,8 +755,6 @@
755 755   content_syntax: xwikiDocument.syntax
756 756   });
757 757   }
758 - // Add the temporary uploaded files to the form.
759 - $.extend(formData, uploadedFiles);
760 760   // Check for merge conflicts only if the document is not new and we know the current version.
761 761   if (!xwikiDocument.isNew && xwikiDocument.version) {
762 762   formData.previousVersion = xwikiDocument.version;
... ... @@ -845,7 +845,7 @@
845 845   deferred: $.Deferred()
846 846   });
847 847   editContent.trigger('xwiki:actions:edit', data);
848 - return data.deferred.promise().then(() => {
842 + return data.deferred.done(function() {
849 849   editContent.show();
850 850   viewContent.remove();
851 851   if (withFocus) {
... ... @@ -856,8 +856,7 @@
856 856   editContent[0].focus({preventScroll: true});
857 857   }, 0);
858 858   }
859 - return xwikiDocument;
860 - });
853 + }).promise();
861 861   };
862 862  
863 863   var startRealTimeEditingSession = function(xwikiDocument) {
... ... @@ -922,7 +922,7 @@
922 922   require(['editInPlace', wysiwygEditorModule], function(editInPlace) {
923 923   // Re-enable the translate button because it can be used while editing to create the missing translation.
924 924   translateButton.removeClass('disabled');
925 - handler.edit(editInPlace, data).finally(function() {
918 + handler.edit(editInPlace, data).always(function() {
926 926   // Restore only the edit button at the end because:
927 927   // * the translate button is restored (if needed) by the editInPlace module
928 928   // * the section edit links are restored when the document is rendered for view
... ... @@ -929,7 +929,7 @@
929 929   editButton.removeClass('disabled');
930 930   });
931 931   // Fallback on the standalone edit mode if we fail to load the required modules.
932 - }, disableInPlaceEditing.bind(event.target));
925 + }, $.proxy(disableInPlaceEditing, event.target));
933 933   };
934 934  
935 935   var disableInPlaceEditing = function() {
XWiki.UIExtensionClass[0]
Executed Content
... ... @@ -48,6 +48,7 @@
48 48   'editButtonSelector': '#tmEdit > a',
49 49   'translateButtonSelector': '#tmTranslate > a',
50 50   'enableSourceMode': true,
51 + 'enableOfficeImport': $services.officemanager.isConnected(),
51 51   'paths': {
52 52   'js': {
53 53   'xwiki-actionButtons': "#getSkinFileWithParams('js/xwiki/actionbuttons/actionButtons.js' $jsParams)",