Bug 11559: (followup) Fix import bugs, display/parsing issues
authorJesse Weaver <pianohacker@gmail.com>
Thu, 6 Aug 2015 21:56:36 +0000 (15:56 -0600)
committerTomas Cohen Arazi <tomascohen@theke.io>
Tue, 27 Oct 2015 15:18:00 +0000 (12:18 -0300)
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 <nick@quecheelibrary.org>
Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-mode.js
koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-record.js
koha-tmpl/intranet-tmpl/lib/koha/cateditor/text-marc.js
koha-tmpl/intranet-tmpl/prog/en/css/cateditor.css
koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc
koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-widgets-marc21.inc

index f9bf862..c42c993 100644 (file)
@@ -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';
index f745533..1e57904 100644 (file)
@@ -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 ) );
index ba471e6..778b4cc 100644 (file)
@@ -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 ];
 
index 04258a5..6e0ee75 100644 (file)
@@ -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;
+}
index 9a579af..3b71d6a 100644 (file)
@@ -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;
 
index bfba1ba..1761c03 100644 (file)
@@ -114,7 +114,7 @@ require( [ 'widget' ], function( Widget ) {
 
     Widget.Register( '005@', {
         init: function() {
-            var $result = $( '<span class="subfield-widget fixed-widget">Updated: </span>' );
+            var $result = $( '<span class="subfield-widget fixed-widget">' + _("Updated: ") + '</span>' );
 
             return $result[0];
         },
@@ -134,7 +134,7 @@ require( [ 'widget' ], function( Widget ) {
 
                 $( this.node ).append( dateVal.toLocaleString() );
             } else {
-                $( this.node ).append( '<span class="hint">unset</span>' );
+                $( this.node ).append( '<span class="hint">' + _("unset") + '</span>' );
             }
         }
     } );
@@ -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 = $( '<span class="subfield-widget fixed-widget">Fixed data:<span class="hint widget-loading">Loading...</span></span>' );
+            var $result = $( '<span class="subfield-widget fixed-widget">' + _("Fixed data:") + '<span class="hint widget-loading">' + _("Loading...") + '</span></span>' );
 
             return $result[0];
         },