Changes for page InplaceEditing

From version 2.1
edited by N Pompei
on 16/09/2020 12:29
Change comment: Install extension [org.xwiki.platform:xwiki-platform-edit-ui/12.7.1]
To version 1.1
edited by N Pompei
on 08/06/2020 17:32
Change comment: Install extension [org.xwiki.platform:xwiki-platform-edit-ui/12.4]

Summary

Details

XWiki.JavaScriptExtension[0]
Code
... ... @@ -1,9 +1,8 @@
1 1  require.config({
2 2   paths: {
3 3   'actionButtons': $jsontool.serialize($xwiki.getSkinFile('js/xwiki/actionbuttons/actionButtons.js', true)),
4 - 'autoSave': $jsontool.serialize($xwiki.getSkinFile('js/xwiki/editors/autosave.js', true)),
5 5   // Required in case the user needs to resolve merge conflicts on save.
6 - 'xwiki-diff': $jsontool.serialize($xwiki.getSkinFile('uicomponents/viewers/diff.js'))
5 + 'diff': $jsontool.serialize($xwiki.getSkinFile('uicomponents/viewers/diff.js'))
7 7   }
8 8  });
9 9  
... ... @@ -18,17 +18,7 @@
18 18   * @return this document's real locale
19 19   */
20 20   getRealLocale: function() {
21 - var realLocale = this.language;
22 - if (typeof realLocale === 'string' && realLocale !== '') {
23 - // This document is a translation.
24 - } else if (this.translations && typeof this.translations['default'] === 'string') {
25 - // This is the original document.
26 - realLocale = this.translations['default'];
27 - } else {
28 - // The document locale is not specified. Use the UI locale.
29 - realLocale = $('html').attr('lang');
30 - }
31 - return realLocale;
20 + return this.language || (this.translations && this.translations['default']) || $('html').attr('lang');
32 32   },
33 33  
34 34   /**
... ... @@ -66,7 +66,7 @@
66 66   */
67 67   render: function(forView) {
68 68   var queryString = {
69 - xpage: 'get',
58 + xpage: 'rendercontent',
70 70   outputTitle: true,
71 71   outputSyntax: forView ? null : 'annotatedxhtml',
72 72   language: this.getRealLocale(),
... ... @@ -80,15 +80,11 @@
80 80   'error'
81 81   );
82 82   }).then(function(html) {
83 - // Render succeeded.
84 84   var container = $('<div/>').html(html);
85 85   return $.extend(thisXWikiDocument, {
86 86   renderedTitle: container.find('#document-title h1').html(),
87 87   renderedContent: container.find('#xwikicontent').html()
88 88   });
89 - }, function() {
90 - // Render failed.
91 - return thisXWikiDocument;
92 92   });
93 93   },
94 94  
... ... @@ -103,15 +103,11 @@
103 103   // Make sure the response is not retrieved from cache (IE11 doesn't obey the caching HTTP headers).
104 104   timestamp: new Date().getTime()
105 105   }).then(function(newXWikiDocument) {
106 - // Reload succeeded.
107 107   // Resolve the document reference.
108 108   thisXWikiDocument.documentReference = XWiki.Model.resolve(newXWikiDocument.id, XWiki.EntityType.DOCUMENT);
109 109   // We were able to load the document so it's not new.
110 110   thisXWikiDocument.isNew = false;
111 111   return $.extend(thisXWikiDocument, newXWikiDocument);
112 - }, function() {
113 - // Reload failed.
114 - return thisXWikiDocument;
115 115   });
116 116   },
117 117  
... ... @@ -134,19 +134,8 @@
134 134   // Make sure the response is not retrieved from cache (IE11 doesn't obey the caching HTTP headers).
135 135   timestamp: new Date().getTime()
136 136   }).then(function() {
137 - // Lock succeeded.
138 138   thisXWikiDocument.locked = action;
139 139   return thisXWikiDocument;
140 - }, function(response) {
141 - // Lock failed.
142 - delete thisXWikiDocument.locked;
143 - // Check if the user can force the lock.
144 - var lockConfirmation = response.responseJSON;
145 - if (response.status === 423 && lockConfirmation) {
146 - // The user can force the lock, but needs confirmation.
147 - thisXWikiDocument.lockConfirmation = lockConfirmation;
148 - }
149 - return thisXWikiDocument;
150 150   });
151 151   },
152 152  
... ... @@ -186,7 +186,6 @@
186 186  ], function($, xcontext, xwikiDocumentAPI) {
187 187   var preload = function() {
188 188   loadCSS($jsontool.serialize($xwiki.getSkinFile('js/xwiki/actionbuttons/actionButtons.css', true)));
189 - loadCSS($jsontool.serialize($xwiki.getSkinFile('js/xwiki/editors/autosave.css', true)));
190 190   // Required in case the user needs to resolve merge conflicts on save.
191 191   loadCSS($jsontool.serialize($xwiki.getSkinFile('uicomponents/viewers/diff.css', true)));
192 192   return initActionButtons();
... ... @@ -256,27 +256,20 @@
256 256   lockFailed: function() {}
257 257   }, options);
258 258   $('#xwikicontent').addClass('loading');
259 - // Lock the document first.
260 260   return lock(currentXWikiDocument).fail(options.lockFailed)
261 - // Then load the document only if we managed to lock it.
262 262   .then(load)
263 - // Then load the editors only if we managed to load the document.
264 264   .then(edit).done(options.afterEdit).always(function() {
265 265   $('#xwikicontent').removeClass('loading');
266 - // Then wait for an action (save, cancel, reload) only if the editors were loaded successfuly.
267 267   }).then(maybeSave)
268 - // Then unlock the document both when the edit ended with success and with a failure.
269 - .then(unlock, unlock)
270 - // Finally view the document both when the edit ended with success and with a failure.
271 - .then(view, view);
233 + .then(unlock)
234 + .then(view);
272 272   };
273 273  
274 274   var lock = function(xwikiDocument) {
275 - return xwikiDocument.lock().then(null, function(xwikiDocument) {
238 + return xwikiDocument.lock().then(null, function(response) {
239 + var confirmation = response.responseJSON;
276 276   // If the document was already locked then we need to ask the user if they want to force the lock.
277 - if (xwikiDocument.lockConfirmation) {
278 - var confirmation = xwikiDocument.lockConfirmation;
279 - delete xwikiDocument.lockConfirmation;
241 + if (response.status === 423 && confirmation) {
280 280   return maybeForceLock(confirmation).then($.proxy(xwikiDocument, 'lock', 'edit', true));
281 281   } else {
282 282   new XWiki.widgets.Notification(
... ... @@ -283,7 +283,6 @@
283 283   $jsontool.serialize($services.localization.render('edit.inplace.page.lockFailed')),
284 284   'error'
285 285   );
286 - return xwikiDocument;
287 287   }
288 288   });
289 289   };
... ... @@ -407,18 +407,24 @@
407 407   };
408 408  
409 409   var save = function(data) {
410 - // Push the changes to the server.
411 - return push(data.document).then(function(xwikiDocument) {
371 + // Push the changes to the server then render the document for view. We need the view HTML both if we stop editing
372 + // now and if we continue but cancel the edit later.
373 + return push(data.document).then($.proxy(render, null, true)).then(function(xwikiDocument) {
412 412   // Save succeeded.
413 - return shouldReload(xwikiDocument).then(
414 - // The document was saved with merge and thus if we want to continue eding we need to reload the editor (because
415 - // its content doesn't match the saved content).
416 - reload,
417 - // No need to reload the editor because either the action was Save & View or there was no merge on save.
418 - $.proxy(maybeContinueEditing, null, data['continue'])
419 - );
420 - // Save failed. Continue editing because we may have unsaved content.
421 - }, maybeSave);
375 + if (data['continue']) {
376 + // Update the original version in order to be able to restore it on cancel.
377 + delete xwikiDocument.originalDocument;
378 + xwikiDocument.originalDocument = $.extend(true, {}, xwikiDocument);
379 + // Continue editing.
380 + return maybeSave(xwikiDocument);
381 + } else {
382 + // This is the final version.
383 + return xwikiDocument;
384 + }
385 + }, function(xwikiDocument) {
386 + // Save failed. Continue editing.
387 + return maybeSave(xwikiDocument);
388 + });
422 422   };
423 423  
424 424   var push = function(xwikiDocument) {
... ... @@ -431,33 +431,9 @@
431 431   // effect.
432 432   $(document).one('xwiki:document:saved', $.proxy(deferred, 'resolve', xwikiDocument));
433 433   $(document).one('xwiki:document:saveFailed', $.proxy(deferred, 'reject', xwikiDocument));
434 - return deferred.promise();
401 + return deferred.promise().then($.proxy(xwikiDocument, 'reload'));
435 435   };
436 436  
437 - var maybeContinueEditing = function(continueEditing, xwikiDocument) {
438 - var afterReloadAndRender = function(success, xwikiDocument) {
439 - if (continueEditing) {
440 - if (success) {
441 - // Update the original version in order to be able to restore it on cancel.
442 - delete xwikiDocument.originalDocument;
443 - xwikiDocument.originalDocument = $.extend(true, {}, xwikiDocument);
444 - }
445 - // Continue editing.
446 - return maybeSave(xwikiDocument);
447 - } else {
448 - // This is the final version. We stop editing even if the reload / render failed.
449 - return xwikiDocument;
450 - }
451 - };
452 -
453 - // Reload the document JSON data (to have the new version) and render the document for view. We need the view HTML
454 - // both if we stop editing now and if we continue but cancel the edit later.
455 - return xwikiDocument.reload().then($.proxy(render, null, true)).then(
456 - $.proxy(afterReloadAndRender, null, /* success: */ true),
457 - $.proxy(afterReloadAndRender, null, /* success: */ false)
458 - );
459 - };
460 -
461 461   var cancel = function(xwikiDocument) {
462 462   // Simply return the original version to be restored.
463 463   return xwikiDocument.originalDocument;
... ... @@ -475,25 +475,6 @@
475 475   // Make sure we unlock the document when the user navigates to another page.
476 476   $(window).on('unload pagehide', $.proxy(unlock, null, currentXWikiDocument));
477 477  
478 - var shouldReload = function(xwikiDocument) {
479 - var reloadEventFired = false;
480 - $(document).one('xwiki:actions:reload.maybe', function() {
481 - reloadEventFired = true;
482 - });
483 - var deferred = $.Deferred();
484 - // Wait a bit to see if the reload event is fired.
485 - setTimeout(function() {
486 - // Remove the listener in case the reload event wasn't fired.
487 - $(document).off('xwiki:actions:reload.maybe');
488 - if (reloadEventFired) {
489 - deferred.resolve(xwikiDocument);
490 - } else {
491 - deferred.reject(xwikiDocument);
492 - }
493 - }, 0);
494 - return deferred.promise();
495 - };
496 -
497 497   var reload = function(xwikiDocument) {
498 498   // Leave the edit mode and then re-enter.
499 499   return view(xwikiDocument, true).then(editInPlace);
... ... @@ -580,12 +580,8 @@
580 580  
581 581   var loadActionButtons = function(actionButtons) {
582 582   $(document).on('xwiki:actions:view', function() {
583 - // Blur the action buttons first to re-enable the "disabled in inputs" shortcut keys (e.g. the page edit
584 - // shortcut), then disable the action buttons in order to disable their shortcut keys while we're not editing
585 - // in-place (e.g. prevent the Save shortcut while the user is only viewing the page). Finally hide the action
586 - // buttons to have them ready for the next editing session (the user can save or cancel and then edit again
587 - // without reloading the page).
588 - actionButtons.find(':input').blur().prop('disabled', true).end().hide();
507 + // Hide the action buttons and disable the shortcut keys (by disabling the buttons).
508 + actionButtons.hide().find(':input').prop('disabled', true);
589 589   // Hide the translate button because it can be used only in edit mode for the moment.
590 590   $('#tmTranslate').addClass('hidden');
591 591   });
... ... @@ -600,13 +600,9 @@
600 600   // We need a place where actionButtons.js can add more hidden inputs.
601 601   actionButtons.append('<div class="hidden extra"/>');
602 602   var deferred = $.Deferred();
603 - require(['actionButtons', 'xwiki-diff', 'autoSave'], function() {
523 + require(['actionButtons'], function() {
604 604   overrideEditActions();
605 605   overrideAjaxSaveAndContinue();
606 - // Activate the auto-save feature passing our fake edit form. Note that autosave.js also creates an instance of
607 - // AutoSave but it doesn't do anything because it doesn't find a real edit form in the page. This is why we have
608 - // to create our own instance of AutoSave passing the right (fake) form.
609 - new XWiki.editors.AutoSave({form: fakeForm});
610 610   var xwikiDocument = actionButtons.data('xwikiDocument');
611 611   // Enable the action buttons (and their shortcut keys) only if we're editing a document.
612 612   actionButtons.find(':input').prop('disabled', !xwikiDocument);
... ... @@ -643,9 +643,6 @@
643 643   insert: function(element) {
644 644   this._getActionButtons().find('.hidden.extra').append(element);
645 645   },
646 - down: function(selector) {
647 - return this._getActionButtons().find(selector)[0];
648 - },
649 649   serialize: function() {
650 650   var extra = this._getActionButtons().find(':input').serializeArray().reduce(function(extra, entry) {
651 651   var value = extra[entry.name] || [];
... ... @@ -655,21 +655,13 @@
655 655   }, {});
656 656   var xwikiDocument = this._getActionButtons().data('xwikiDocument');
657 657   var formData = {
658 - title: xwikiDocument.rawTitle,
571 + title: xwikiDocument.title,
572 + content: xwikiDocument.renderedContent,
573 + RequiresHTMLConversion: 'content',
574 + content_syntax: xwikiDocument.syntax,
659 659   language: xwikiDocument.getRealLocale(),
660 660   isNew: xwikiDocument.isNew
661 661   };
662 - if (xwikiDocument.content != xwikiDocument.originalDocument.content) {
663 - // Submit the raw (source) content. No syntax conversion is needed in this case.
664 - formData.content = xwikiDocument.content;
665 - } else {
666 - // Submit the rendered content (HTML), but make sure it is converted to the document syntax on the server.
667 - $.extend(formData, {
668 - content: xwikiDocument.renderedContent,
669 - RequiresHTMLConversion: 'content',
670 - content_syntax: xwikiDocument.syntax
671 - });
672 - }
673 673   // Check for merge conflicts only if the document is not new and we know the current version.
674 674   if (!xwikiDocument.isNew && xwikiDocument.version) {
675 675   formData.previousVersion = xwikiDocument.version;
... ... @@ -704,14 +704,11 @@
704 704   return originalAjaxSaveAndContinue.reloadEditor.apply(this, arguments);
705 705   }
706 706   },
707 - maybeRedirect: function(continueEditing) {
612 + maybeRedirect: function() {
708 708   if ($('.inplace-editing-buttons').is(':visible')) {
709 - // Overwrite the default behavior so that we don't redirect when leaving the edit mode because we're already
710 - // in view mode. We still need to report a redirect (return true) if we don't continue editing, so that
711 - // actionButtons.js behaves as if a redirect was done.
712 - return !continueEditing;
614 + // Never redirect when leaving the edit mode because we're already in view mode.
615 + return false;
713 713   } else {
714 - // Fallback on the default behavior if the in-place editing buttons are hidden.
715 715   return originalAjaxSaveAndContinue.maybeRedirect.apply(this, arguments);
716 716   }
717 717   }
... ... @@ -721,7 +721,7 @@
721 721   var initTitleEditor = function(xwikiDocument) {
722 722   var label = $('<label for="document-title-input" class="sr-only"/>')
723 723   .text($jsontool.serialize($services.localization.render('core.editors.content.titleField.label')));
724 - var input = $('<input type="text" id="document-title-input"/>').val(xwikiDocument.rawTitle);
626 + var input = $('<input type="text" id="document-title-input"/>').val(xwikiDocument.title);
725 725   var placeholder = xwikiDocument.documentReference.name;
726 726   if (placeholder === 'WebHome') {
727 727   placeholder = xwikiDocument.documentReference.parent.name;
... ... @@ -729,12 +729,12 @@
729 729   input.attr('placeholder', placeholder);
730 730   $('#document-title h1').addClass('editable').empty().append([label, input]);
731 731   $(document).on('xwiki:actions:beforeSave.titleEditor', function(event) {
732 - xwikiDocument.rawTitle = input.val();
634 + xwikiDocument.title = input.val();
733 733   });
734 734   $(document).one('xwiki:actions:view', function(event, data) {
735 735   // Destroy the title editor.
736 736   $(document).off('xwiki:actions:beforeSave.titleEditor');
737 - $('#document-title h1').removeClass('editable').text(xwikiDocument.rawTitle);
639 + $('#document-title h1').removeClass('editable').text(xwikiDocument.title);
738 738   });
739 739   return xwikiDocument;
740 740   };
... ... @@ -756,11 +756,7 @@
756 756   editMode: 'wysiwyg',
757 757   document: xwikiDocument,
758 758   // The content editor is loaded on demand, asynchronously.
759 - deferred: $.Deferred(),
760 - // We have to explicitly enable the source mode for in-line edit because the latest version of the content editor
761 - // could be installed on an older version of XWiki where the in-place editor didn't support the source mode (so
762 - // the content editor cannot enable the source mode by default).
763 - enableSourceMode: true
661 + deferred: $.Deferred()
764 764   };
765 765   var editContentPromise = data.deferred.promise();
766 766   editContentPromise.done(function() {
... ... @@ -798,11 +798,6 @@
798 798  });
799 799  
800 800  require(['jquery'], function($) {
801 - // We can edit in-place only if the #xwikicontent element is present.
802 - if (!$('#xwikicontent').length) {
803 - return;
804 - }
805 -
806 806   var inplaceEditingConfig = $('div[data-inplace-editing-config]').data('inplaceEditingConfig') || {};
807 807   var wysiwygEditorModule = 'xwiki-' + inplaceEditingConfig.wysiwygEditor + '-inline';
808 808  
XWiki.StyleSheetExtension[0]
Code
... ... @@ -6,7 +6,6 @@
6 6   margin-bottom: @line-height-computed / 4;
7 7  }
8 8  
9 -@document-title-input-padding-vertical: @line-height-computed / 4 - 1;
10 10  input#document-title-input {
11 11   /* Preserve the heading styles. */
12 12   border: 1px solid transparent;
... ... @@ -13,10 +13,9 @@
13 13   box-shadow: none;
14 14   color: inherit;
15 15   font-size: inherit;
16 - /* It seems it's not enough to set the line height for the text input. We also need to set its height. */
17 - height: @font-size-document-title * @headings-line-height + 2 * (1 + @document-title-input-padding-vertical);
15 + height: auto;
18 18   line-height: @headings-line-height;
19 - padding: @document-title-input-padding-vertical (ceil(@grid-gutter-width / 2) - 1);
17 + padding: (@line-height-computed / 4 - 1) (ceil(@grid-gutter-width / 2) - 1);
20 20   width: 100%;
21 21  }
22 22  
... ... @@ -49,8 +49,3 @@
49 49  #xwikicontent {
50 50   padding-top: @line-height-computed * 0.75;
51 51  }
52 -
53 -.sticky-buttons-wrapper {
54 - /* Leave some space for the bottom box shadow of the editing area. */
55 - margin-top: 7px;
56 -}
XWiki.UIExtensionClass[0]
Executed Content
... ... @@ -1,6 +1,6 @@
1 1  {{velocity}}
2 2  {{html clean="false"}}
3 -#if ($services.edit.document.inPlaceEditingEnabled() && $hasEdit && $xcontext.action == 'view' && !$doc.isNew())
3 +#if ($xcontext.action == 'view' && !$doc.isNew())
4 4   ## We support in-place editing only for the WYSIWYG edit mode ATM.
5 5   #getDefaultDocumentEditor($defaultEditMode)
6 6   #if ($defaultEditMode == 'wysiwyg')
XWiki.UIExtensionClass[1]
Executed Content
... ... @@ -5,8 +5,8 @@
5 5  ## * we're loading the original document version
6 6  ## * the original document version has a locale specified (it doesn't make sense to translate technical documents)
7 7  ## * the current UI locale doesn't match the original document locale
8 -#if ($services.edit.document.inPlaceEditingEnabled() && $hasEdit && $xwiki.isMultiLingual()
9 - && $tdoc.realLocale == $doc.realLocale && "$!doc.realLocale" != '' && $doc.realLocale != $xcontext.locale)
8 +#if ($xwiki.isMultiLingual() && $tdoc.realLocale == $doc.realLocale && "$!doc.realLocale" != ''
9 + && $doc.realLocale != $xcontext.locale)
10 10   #set ($url = $doc.getURL('edit', $escapetool.url({'language': $xcontext.locale})))
11 11   #set ($hint = $services.localization.render('edit.inplace.page.translate.hint',
12 12   [$xcontext.locale.getDisplayName($xcontext.locale)]))