From da8f825d42daa7b71835492f1362c7984c1ee0e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Ho=CC=88=C3=9Fl?= Date: Sat, 16 Sep 2017 14:03:45 +0200 Subject: [PATCH] Sort attributes before applying the diff - fixes #3402 --- openslides/motions/static/js/motions/diff.js | 25 +++++++++++++------- tests/karma/motions/diff.service.test.js | 16 +++++++++---- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/openslides/motions/static/js/motions/diff.js b/openslides/motions/static/js/motions/diff.js index 920ec857a..815ca0bfb 100644 --- a/openslides/motions/static/js/motions/diff.js +++ b/openslides/motions/static/js/motions/diff.js @@ -625,21 +625,30 @@ angular.module('OpenSlidesApp.motions.diff', ['OpenSlidesApp.motions.lineNumberi */ this._normalizeHtmlForDiff = function (html) { // Convert all HTML tags to uppercase, but leave the values of attributes unchanged + // All attributes and CSS class names are sorted alphabetically html = html.replace(/<(\/?[a-z]*)( [^>]*)?>/ig, function (html, tag, attributes) { var tagNormalized = tag.toUpperCase(); if (attributes === undefined) { attributes = ""; } - attributes = attributes.replace(/( [^"'=]*)(= *((["'])(.*?)\4))?/gi, function (attr, attrName, attrRest, attrRest2, quot, attrValue) { - var attrNormalized = attrName.toUpperCase(); - if (attrRest !== undefined) { - if (attrNormalized === ' CLASS') { - attrValue = attrValue.split(' ').sort().join(' '); + var attributesList = [], + attributesMatcher = /( [^"'=]*)(= *((["'])(.*?)\4))?/gi, + match; + do { + match = attributesMatcher.exec(attributes); + if (match) { + var attrNormalized = match[1].toUpperCase(), + attrValue = match[5]; + if (match[2] !== undefined) { + if (attrNormalized === ' CLASS') { + attrValue = attrValue.split(' ').sort().join(' '); + } + attrNormalized += "=" + match[4] + attrValue + match[4]; } - attrNormalized += "=" + quot + attrValue + quot; + attributesList.push(attrNormalized); } - return attrNormalized; - }); + } while (match); + attributes = attributesList.sort().join(''); return "<" + tagNormalized + attributes + ">"; }); diff --git a/tests/karma/motions/diff.service.test.js b/tests/karma/motions/diff.service.test.js index de5e65999..548f1fca8 100644 --- a/tests/karma/motions/diff.service.test.js +++ b/tests/karma/motions/diff.service.test.js @@ -5,10 +5,10 @@ describe('linenumbering', function () { var diffService, baseHtml1, baseHtmlDom1, baseHtml2, baseHtmlDom2, baseHtml3, baseHtmlDom3, brMarkup = function (no) { return '
' + - ' '; + ' '; }, noMarkup = function (no) { - return ' '; + return ' '; }; beforeEach(inject(function (_diffService_, _lineNumberingService_) { @@ -374,12 +374,12 @@ describe('linenumbering', function () { expect(normalized).toBe('The brown fox') }); - it('uppercases the names of html attributes, but not the values', function () { + it('uppercases the names of html attributes, but not the values, and sort the attributes', function () { var unnormalized = 'This is our cool home page - have a look! ' + '', normalized = diffService._normalizeHtmlForDiff(unnormalized); expect(normalized).toBe('This is our cool home page - have a look! ' + - '') + '') }); it('strips unnecessary spaces', function () { @@ -569,6 +569,14 @@ describe('linenumbering', function () { expect(diff).toBe('

tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren bla, no sea takimata sanctus est Lorem ipsum dolor gubergren sit amet.

'); }); + + it('works with style-tags in spans', function () { + var before = '

 sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing

', + after = '

sanctus est Lorem ipsum dolor sit amet. Test Lorem ipsum dolor sit amet, consetetur sadipscing

'; + var diff = diffService.diff(before, after); + + expect(diff).toBe('

 sanctus est Lorem ipsum dolor sit amet. Test Lorem ipsum dolor sit amet, consetetur sadipscing

'); + }); }); describe('ignoring line numbers', function () {