From 9e7109c05c8a24271f5f55c653c6400b5620e808 Mon Sep 17 00:00:00 2001 From: Jesse Weaver Date: Thu, 6 Aug 2015 15:56:36 -0600 Subject: [PATCH] Bug 11559: (followup) Fix import bugs, display/parsing issues This fixes the following issues: * ISO2709 import fails for Unicode * Import only works with .mrc/.xml extensions * MARC21 widgets not translatable * Macro UI broken * Uppercase subfield codes forbidden * Tag with no valid subfields shows as error but tries to save Signed-off-by: Nick Clemens Signed-off-by: Katrin Fischer --- .../lib/koha/cateditor/marc-mode.js | 2 +- .../lib/koha/cateditor/marc-record.js | 21 +++++-- .../lib/koha/cateditor/text-marc.js | 7 ++- .../intranet-tmpl/prog/en/css/cateditor.css | 19 +++++-- .../prog/en/includes/cateditor-ui.inc | 56 +++++++++++-------- .../en/includes/cateditor-widgets-marc21.inc | 6 +- 6 files changed, 72 insertions(+), 39 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-mode.js b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-mode.js index f9bf862f07..c42c993d46 100644 --- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-mode.js +++ b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-mode.js @@ -137,7 +137,7 @@ CodeMirror.defineMode( 'marc', function( config, modeConfig ) { if ( stream.eat( /[$|ǂ‡]/ ) ) { var subfieldCode; - if ( ( subfieldCode = stream.eat( /[a-z0-9%]/ ) ) && stream.eat( ' ' ) ) { + if ( ( subfieldCode = stream.eat( /[a-zA-Z0-9%]/ ) ) && stream.eat( ' ' ) ) { state.subfieldCode = subfieldCode; if ( state.seenSubfields[state.subfieldCode] && ( modeConfig.nonRepeatableSubfields[state.tagNumber] || {} )[state.subfieldCode] ) { return 'bad-subfieldcode'; diff --git a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-record.js b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-record.js index f745533f61..1e57904d9c 100644 --- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-record.js +++ b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-record.js @@ -23,6 +23,8 @@ * * ISO2709 import/export is cribbed from marcjs, which is under the MIT license. * Source: https://github.com/fredericd/marcjs/blob/master/lib/marcjs.js + * + * UTF8 encode/decode cribbed from: http://ecmanaut.blogspot.com/2006/07/encoding-decoding-utf8-in-javascript.html */ define( function() { @@ -46,6 +48,14 @@ define( function() { return i; } + function _encode_utf8(s) { + return unescape(encodeURIComponent(s)); + } + + function _decode_utf8(s) { + return decodeURIComponent(escape(s)); + } + MARC.Record = function (fieldlist) { this._fieldlist = fieldlist || []; } @@ -200,7 +210,7 @@ define( function() { } else { chunk = element.indicators().join(''); $.each( element.subfields(), function( undef, subfield ) { - chunk += DE + subfield[0] + subfield[1]; + chunk += DE + subfield[0] + _encode_utf8(subfield[1]); } ); } chunk += FT; @@ -218,10 +228,13 @@ define( function() { leader.substr(17); chunks[0] = leader; chunks[1] = directory; - return chunks.join(''); + return _decode_utf8( chunks.join('') ); }, loadISO2709: function(data) { + // The underlying offsets work on bytes, not characters + data = _encode_utf8(data); + this._fieldlist.length = 0; this.leader(data.substr(0, 24)); var directory_len = parseInt(data.substring(12, 17), 0) - 25, @@ -235,13 +248,13 @@ define( function() { if ( parseInt(tag) < 10 ) { this.addField( new MARC.Field( tag, '', '', [ [ '@', value ] ] ) ); } else { - if ( value.indexOf('\x1F') ) { // There are some letters + if ( value.indexOf('\x1F') ) { // There are some subfields var ind1 = value.substr(0, 1), ind2 = value.substr(1, 1); var subfields = []; $.each( value.substr(3).split('\x1f'), function( undef, v ) { if (v.length < 2) return; - subfields.push([v.substr(0, 1), v.substr(1)]); + subfields.push([v.substr(0, 1), _decode_utf8( v.substr(1) )]); } ); this.addField( new MARC.Field( tag, ind1, ind2, subfields ) ); diff --git a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/text-marc.js b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/text-marc.js index ba471e657c..778b4ccb2b 100644 --- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/text-marc.js +++ b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/text-marc.js @@ -80,7 +80,7 @@ define( [ 'marc-record' ], function( MARC ) { var field = new MARC.Field( tagNumber, ( indicators[1] == '_' ? ' ' : indicators[1] ), ( indicators[2] == '_' ? ' ' : indicators[2] ), [] ); - var matcher = /[$|ǂ‡]([a-z0-9%]) /g; + var matcher = /[$|ǂ‡]([a-zA-Z0-9%]) /g; var match; var subfields = []; @@ -89,6 +89,11 @@ define( [ 'marc-record' ], function( MARC ) { subfields.push( { code: match[1], ch: match.index } ); } + if ( !subfields.length ) { + errors.push( { type: 'noSubfields', line: i } ); + return; + } + $.each( subfields, function( i, subfield ) { var next = subfields[ i + 1 ]; diff --git a/koha-tmpl/intranet-tmpl/prog/en/css/cateditor.css b/koha-tmpl/intranet-tmpl/prog/en/css/cateditor.css index 04258a5686..6e0ee75745 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/css/cateditor.css +++ b/koha-tmpl/intranet-tmpl/prog/en/css/cateditor.css @@ -355,11 +355,6 @@ body { } /*> Macros */ - -#macro-ui .CodeMirror { - width: 100%; -} - #macro-save-message { color: #666; font-size: 13px; @@ -429,6 +424,18 @@ body { padding: 2px; } -#macro-editor .CodeMirror { +#macro-editor { + display: flex; + flex-direction: column; height: 100%; } + +#macro-editor .CodeMirror { + flex: 1; + font-size: 13px; +} + +/* Hotpatch from latest CodeMirror: Fix gutter positioning */ +.CodeMirror-gutter-wrapper { + position: absolute; +} diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc index 9a579affbc..3b71d6a397 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc @@ -569,7 +569,7 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr editor.refresh(); break; case 'macros': - showSavedMacros(); + // Macros loaded on first show of modal break; case 'selected_search_targets': $.each( z3950Servers, function( server_id, server ) { @@ -735,14 +735,6 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr position: function (elt) { $(elt).insertAfter('#toolbar') }, } ); - macroEditor = CodeMirror( - $('#macro-editor')[0], - { - mode: 'null', - lineNumbers: true, - } - ); - // Automatically detect resizes and change the height of the editor and position of modals. var resizeTimer = null; $( window ).resize( function() { @@ -765,6 +757,32 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr } ).resize(); + $( '#macro-ui' ).on( 'shown', function() { + if ( macroEditor ) return; + + macroEditor = CodeMirror( + $('#macro-editor')[0], + { + mode: 'null', + lineNumbers: true, + } + ); + var saveTimeout; + macroEditor.on( 'change', function( cm, change ) { + $('#macro-save-message').empty(); + if ( change.origin == 'setValue' ) return; + + if ( saveTimeout ) clearTimeout( saveTimeout ); + saveTimeout = setTimeout( function() { + saveMacro(); + + saveTimeout = null; + }, 500 ); + } ); + + showSavedMacros(); + } ); + var saveableBackends = []; $.each( backends, function( id, backend ) { if ( backend.save ) saveableBackends.push( [ backend.saveLabel, id ] ); @@ -805,6 +823,9 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr case 'noIndicators': editor.addError( error.line, _("Invalid indicators") ); break; + case 'noSubfields': + editor.addError( error.line, _("Tag has no subfields") ); + break; case 'missingTag': editor.addError( null, _("Missing mandatory tag: ") + error.tag ); break; @@ -854,9 +875,9 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr reader.onload = function() { var record = new MARC.Record(); - if ( /\.mrc$/.test( file.name ) ) { + if ( /\.(mrc|marc|iso|iso2709|marcstd)$/.test( file.name ) ) { record.loadISO2709( reader.result ); - } else if ( /\.xml$/.test( file.name ) ) { + } else if ( /\.(xml|marcxml)$/.test( file.name ) ) { record.loadMARCXML( reader.result ); } else { humanMsg.displayAlert( _("Unknown record type, cannot import"), { className: 'humanError' } ); @@ -914,19 +935,6 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr return false; } ); - var saveTimeout; - macroEditor.on( 'change', function( cm, change ) { - $('#macro-save-message').empty(); - if ( change.origin == 'setValue' ) return; - - if ( saveTimeout ) clearTimeout( saveTimeout ); - saveTimeout = setTimeout( function() { - saveMacro(); - - saveTimeout = null; - }, 500 ); - } ); - $( '#switch-editor' ).click( function() { if ( !confirm( _("Any changes will not be saved. Continue?") ) ) return; diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-widgets-marc21.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-widgets-marc21.inc index bfba1baede..1761c03913 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-widgets-marc21.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-widgets-marc21.inc @@ -114,7 +114,7 @@ require( [ 'widget' ], function( Widget ) { Widget.Register( '005@', { init: function() { - var $result = $( 'Updated: ' ); + var $result = $( '' + _("Updated: ") + '' ); return $result[0]; }, @@ -134,7 +134,7 @@ require( [ 'widget' ], function( Widget ) { $( this.node ).append( dateVal.toLocaleString() ); } else { - $( this.node ).append( 'unset' ); + $( this.node ).append( '' + _("unset") + '' ); } } } ); @@ -145,7 +145,7 @@ require( [ 'widget' ], function( Widget ) { return Widget.PadNum( now.getYear() % 100, 2 ) + Widget.PadNum( now.getMonth() + 1, 2 ) + Widget.PadNum( now.getDate(), 2 ) + "b xxu||||| |||| 00| 0 [% DefaultLanguageField008 %] d"; }, init: function() { - var $result = $( 'Fixed data:Loading...' ); + var $result = $( '' + _("Fixed data:") + '' + _("Loading...") + '' ); return $result[0]; }, -- 2.39.5