Nikerabbit has uploaded a new change for review.
https://gerrit.wikimedia.org/r/258170
Change subject: Do not drop id-less draft sections
......................................................................
Do not drop id-less draft sections
These happen when people use enter in content editable. Dropping
them results in data loss. Now we will generate a random id for
them and treat them as orphan sections.
Slightly changed how orphans are added: before they would be added
right before next matching section, but I changed that to be right
after last matching section, because I think it makes more sense
if an user splits one section into multiple paragraphs.
This should prevent data loss as reported by some users. There are
multiple easy to reproduce alignment issues, because it is easy
to create inline tags (span) with the content editable as sections.
Added dropping of empty (void of text) sections that are created
when adding empty line between paragraphs.
Bug: T121092
Change-Id: Ie1e0ed0821733a68eff6557fa60372cdfebb1246
---
M modules/translation/ext.cx.translation.draft.js
1 file changed, 88 insertions(+), 64 deletions(-)
git pull
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/ContentTranslation
refs/changes/70/258170/1
diff --git a/modules/translation/ext.cx.translation.draft.js
b/modules/translation/ext.cx.translation.draft.js
index 73354bd..86bd77f 100644
--- a/modules/translation/ext.cx.translation.draft.js
+++ b/modules/translation/ext.cx.translation.draft.js
@@ -16,8 +16,6 @@
function ContentTranslationDraft() {
this.$draft = null;
this.disabled = false;
- this.$source = null;
- this.$translation = null;
this.listen();
}
@@ -57,12 +55,10 @@
* @return {string} HTML to save
*/
ContentTranslationDraft.prototype.getContent = function () {
- var $content;
+ var $content, $translationColumn;
- if ( !this.$translation || !this.$translation.length ) {
- this.$translation = $( '.cx-column--translation
.cx-column__content' );
- }
- $content = this.$translation.clone();
+ $translationColumn = $( '.cx-column--translation
.cx-column__content' );
+ $content = $translationColumn.clone();
// Remove placeholder sections
$content.find( '.placeholder' ).remove();
// Remove empty sections.
@@ -192,8 +188,8 @@
ContentTranslationDraft.prototype.addOrphanTranslation = function (
$translation, $section, afterOrBefore ) {
// Add a dummy source section
var $dummySourceSection = $( '<' + $translation.prop( 'tagName'
) + '>' )
- .css( 'height', 1 ) // Non-zero height to avoid it
ignored by keepAlignment plugin.
- .attr( 'id', $translation.data( 'source' ) );
+ .css( 'height', 1 ) // Non-zero height to avoid it
being ignored by keepAlignment plugin.
+ .prop( 'id', $translation.data( 'source' ) );
if ( afterOrBefore === 'after' ) {
$( '#' + $section.data( 'source' ) ).after(
$dummySourceSection );
@@ -202,6 +198,7 @@
$( '#' + $section.data( 'source' ) ).before(
$dummySourceSection );
$section.before( $translation );
}
+
// Annotate the section to indicate it was restored from draft
// so that certain adaptations can be skipped.
$translation.attr( {
@@ -209,6 +206,7 @@
'data-cx-draft': true,
'data-source': $dummySourceSection.prop( 'id' )
} ).keepAlignment();
+
mw.hook( 'mw.cx.translation.postMT' ).fire( $translation );
};
@@ -216,31 +214,48 @@
* Restore this draft to the appropriate placeholders
*/
ContentTranslationDraft.prototype.restore = function () {
- var i, j, $draftSection, sectionId, $section, $sourceSection,
- $placeholderSection, orphans = [],
- $lastPlaceholder;
+ var i, j, $sourceColumn, $translationColumn, $draftSection,
+ sectionId, sourceId, $section = [], $sourceSection,
+ $placeholderSection = [], orphans = [],
+ $lastPlaceholder, randomId;
- // We cannot populate this early because this
ext.cx.translation.draft modules may be loaded before
- // source and target is ready.
- if ( !this.$source || !this.$source.length ) {
- this.$source = $( '.cx-column--source
.cx-column__content' );
- }
- if ( !this.$translation || !this.$translation.length ) {
- this.$translation = $( '.cx-column--translation
.cx-column__content' );
- }
+ $sourceColumn = $( '.cx-column--source .cx-column__content' );
+ $translationColumn = $( '.cx-column--translation
.cx-column__content' );
+
for ( i = 0; i < this.$draft.length; i++ ) {
$draftSection = $( this.$draft[ i ] );
sectionId = $draftSection.prop( 'id' );
- if ( !sectionId ) {
- // Is this possible?
+ sourceId = $draftSection.data( 'source' );
+
+ // Skip "empty" sections. If there is no text, nothing
to translate, nothing to lose.s
+ if ( $draftSection.text() === '' ) {
continue;
}
- $placeholderSection = this.$translation.find( '#' +
sectionId );
- $sourceSection = this.$source.find( '#' +
$placeholderSection.data( 'source' ) );
+
+ if ( !sectionId || !sourceId ) {
+ // If people add new paragraphs, those do not
have ids. We set the
+ // source attribute here; addOrphanTranslation
will take care of the id.
+ randomId = mw.user.generateRandomSessionId();
+ $draftSection.data( 'source', randomId );
+
+ mw.log( 'Found novel section. Named it as cx' +
randomId );
+
+ // Insert right after last matched section if
possible
+ if ( $section.length ) {
+ this.addOrphanTranslation(
$draftSection, $section, 'after' );
+ } else {
+ orphans.push( $draftSection );
+ }
+
+ continue;
+ }
+
+ $placeholderSection = $translationColumn.find( '#' +
sectionId );
+ $sourceSection = $sourceColumn.find( '#' +
$placeholderSection.data( 'source' ) );
if ( !$placeholderSection.length ) {
// Support old sections with sequential
idendifiers
- $sourceSection = this.$source.find(
'[data-seqid="' + $draftSection.data( 'source' ) + '"]' );
- $placeholderSection = this.$translation.find(
'#cx' +
+ $sourceSection = $sourceColumn.find(
'[data-seqid="' + sourceId + '"]' );
+ $placeholderSection = $translationColumn.find(
'#cx' +
$sourceSection.prop( 'id' )
);
sectionId = $placeholderSection.prop( 'id' );
@@ -249,61 +264,70 @@
$draftSection.prop( 'id', sectionId );
}
}
- // If we still don't see the source section for this
draft section, it means the
- // source article changed.
+
+ // If we still don't see the source section for this
draft section,
+ // it means that the source article has changed.
if ( !$placeholderSection.length ) {
mw.log( 'Source section not found for ' +
$draftSection.prop( 'id' ) );
- orphans.push( $draftSection );
+
+ // Insert right after last matched section if
possible
+ if ( $section.length ) {
+ this.addOrphanTranslation(
$draftSection, $section, 'after' );
+ } else {
+ orphans.push( $draftSection );
+ }
+
continue;
}
$placeholderSection.replaceWith( $draftSection );
- // Get new section
- $section = this.$translation.find( '#' + sectionId );
- // Annotate the section to indicate it was restored
from draft
- // so that certain adaptations can be skipped.
+
+ // Get new section so that we can annotate the section
to indicate it
+ // was restored from draft, so that certain adaptations
can be skipped.
+ $section = $translationColumn.find( '#' + sectionId );
$section.attr( {
'data-cx-draft': true,
'data-source': $sourceSection.prop( 'id' )
} ).keepAlignment();
+
mw.hook( 'mw.cx.translation.postMT' ).fire( $section );
- // We have a matching source and target section. Get
all orphan backlog added.
- // We add them before this section.
+
+ // As a last resort, if we did not add orphans
immediately, add them
+ // now before this section.
for ( j = 0; j < orphans.length; j++ ) {
this.addOrphanTranslation( orphans[ j ],
$section );
}
- // Clear the orphans array
orphans = [];
}
- // Do we have any more orphans left out?
- if ( orphans.length === this.$draft.length ) {
- // Source article changed completely!
- for ( j = 0; j < orphans.length; j++ ) {
- // Add it after the first placeholder
- $placeholderSection = this.$translation.find(
'.placeholder:first' );
- if ( $placeholderSection &&
$placeholderSection.length ) {
- sectionId = orphans[ j ].prop( 'id' );
- $sourceSection = this.$source.find( '#'
+ $placeholderSection.data( 'source' ) );
- $placeholderSection.replaceWith(
orphans[ j ] );
- $section = this.$translation.find( '#'
+ sectionId );
- $section.attr( {
- id: 'cx' + $sourceSection.prop(
'id' ),
- 'data-cx-draft': true,
- 'data-source':
$sourceSection.prop( 'id' )
- } ).keepAlignment();
- mw.hook( 'mw.cx.translation.postMT'
).fire( $section );
- } else {
- // We ran out of placeholders. Add
orphan sections to end.
- this.addOrphanTranslation( orphans[ j
], $section, 'after' );
- }
- }
- } else {
- // Add it after the last placeholder
- $lastPlaceholder = this.$translation.find(
'.placeholder:last' );
- for ( j = 0; j < orphans.length; j++ ) {
- // Add it after the last placeholder
- this.addOrphanTranslation( orphans[ j ],
$lastPlaceholder, 'after' );
+ // We should not have anything more to do here, except if were
not able
+ // to match nothing at all. This could be due to a bug or if
source article
+ // changed completely. Let's just add what we have to the
translation column.
+
+ if ( orphans.length ) {
+ mw.log( 'Draft restoration failed. Dumping draft
unaligned' );
+ }
+
+ // TODO: tell the user or log this event somehow?
+ for ( j = 0; j < orphans.length; j++ ) {
+ $placeholderSection = $translationColumn.find(
'.placeholder:first' );
+ if ( $placeholderSection.length ) {
+ sectionId = orphans[ j ].prop( 'id' );
+ $sourceSection = $sourceColumn.find( '#' +
$placeholderSection.data( 'source' ) );
+ $placeholderSection.replaceWith( orphans[ j ] );
+
+ $section = $translationColumn.find( '#' +
sectionId );
+ $section.attr( {
+ id: 'cx' + $sourceSection.prop( 'id' ),
+ 'data-cx-draft': true,
+ 'data-source': $sourceSection.prop(
'id' )
+ } ).keepAlignment();
+
+ mw.hook( 'mw.cx.translation.postMT' ).fire(
$section );
+ } else {
+ // We ran out of placeholders. Add orphan
sections to end.
+ // TODO: $section might be empty if source
article is empty.
+ this.addOrphanTranslation( orphans[ j ],
$section, 'after' );
}
}
--
To view, visit https://gerrit.wikimedia.org/r/258170
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie1e0ed0821733a68eff6557fa60372cdfebb1246
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Nikerabbit <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits