@@ -, +, @@
* 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
---
.../intranet-tmpl/lib/koha/cateditor/marc-mode.js | 2 +-
.../lib/koha/cateditor/marc-record.js | 21 ++++++--
.../intranet-tmpl/lib/koha/cateditor/text-marc.js | 7 ++-
koha-tmpl/intranet-tmpl/prog/en/css/cateditor.css | 19 +++++---
.../prog/en/includes/cateditor-ui.inc | 56 ++++++++++++----------
.../prog/en/includes/cateditor-widgets-marc21.inc | 6 +--
6 files changed, 72 insertions(+), 39 deletions(-)
--- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-mode.js
+++ a/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';
--- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-record.js
+++ a/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 ) );
--- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/text-marc.js
+++ a/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 ];
--- a/koha-tmpl/intranet-tmpl/prog/en/css/cateditor.css
+++ a/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;
+}
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc
+++ a/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;
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-widgets-marc21.inc
+++ a/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];
},
--