From 5c287a8931103ae23df529267f0cb876c90f2f89 Mon Sep 17 00:00:00 2001 From: Jesse Weaver Date: Tue, 6 Oct 2015 16:00:49 -0600 Subject: [PATCH] Bug 11559: (QA followup) switch to new delimiter, fix minor issues MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This followup introduces a major change; instead of subfields starting with '$', they now start with '‡'. The double-cross character can be typed with Ctrl-D. It also fixes the following: * Add UUID.pm dependency * Remove debugging call * Fix toLocaleFormat error reported by Nick Clemens * Ignore subfields that are marked as unrepeatable/mandatory AND ignored (tab is -1) * Mention lack of support for UNIMARC/NORMARC fixed fields in system preferences screen * Confirm when user creates new record and current record is modified * Perform better when importing gigantic record dump * Show "Edit" instead of "Import" and allow direct editing for local catalog records in search screen * Add "Keyboard shortcuts" help button to toolbar Signed-off-by: Nick Clemens Signed-off-by: Katrin Fischer --- C4/Installer/PerlDependencies.pm | 5 ++ .../lib/koha/cateditor/koha-backend.js | 4 +- .../lib/koha/cateditor/marc-editor.js | 22 ++++---- .../lib/koha/cateditor/marc-mode.js | 8 +-- .../lib/koha/cateditor/marc-record.js | 9 +++- .../lib/koha/cateditor/text-marc.js | 19 ++----- .../lib/koha/cateditor/widget.js | 2 +- .../intranet-tmpl/prog/en/css/cateditor.css | 8 ++- .../prog/en/includes/cateditor-ui.inc | 38 +++++++++++--- .../en/modules/admin/preferences/labs.pref | 2 +- .../prog/en/modules/cataloguing/editor.tt | 52 ++++++++++++++++++- 11 files changed, 127 insertions(+), 42 deletions(-) diff --git a/C4/Installer/PerlDependencies.pm b/C4/Installer/PerlDependencies.pm index f93e26624f..0e5057b96f 100644 --- a/C4/Installer/PerlDependencies.pm +++ b/C4/Installer/PerlDependencies.pm @@ -757,6 +757,11 @@ our $PERL_DEPS = { 'required' => '0', 'min_ver' => '0.614', }, + 'UUID' => { + 'usage' => 'Professional cataloging interface', + 'required' => '1', + 'min_ver' => '0.05', + }, }; 1; diff --git a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/koha-backend.js b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/koha-backend.js index 330cfbd59e..f02ab97520 100644 --- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/koha-backend.js +++ b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/koha-backend.js @@ -56,8 +56,6 @@ define( [ '/cgi-bin/koha/svc/cataloguing/framework?frameworkcode=&callback=defin _framework_mappings[frameworkcode][tagnum] = $.extend( {}, taginfo, { subfields: subfields } ); } ); - - console.dir( _framework_kohafields ); } _importFramework( '', defaultFramework.framework ); @@ -138,7 +136,7 @@ define( [ '/cgi-bin/koha/svc/cataloguing/framework?frameworkcode=&callback=defin $.each( _frameworks[frameworkcode], function( undef, tag ) { var tagnum = tag[0], taginfo = tag[1]; - if ( taginfo[field] == value ) result[tagnum] = true; + if ( taginfo[field] == value && taginfo.tab != '-1' ) result[tagnum] = true; } ); return result; diff --git a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-editor.js b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-editor.js index beb73797e3..3ccb284a9f 100644 --- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-editor.js +++ b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-editor.js @@ -47,7 +47,7 @@ define( [ 'marc-record', 'koha-backend', 'preferences', 'text-marc', 'widget' ], if ( change.from.ch == change.to.ch - 1 && cm.findMarksAt( { line: change.from.line, ch: change.from.ch + 1 } ).length ) { change.cancel(); - } else if ( change.from.ch == change.to.ch && cm.findMarksAt(change.from).length && !change.text[0].match(/^[$|ǂ‡]$/) ) { + } else if ( change.from.ch == change.to.ch && cm.findMarksAt(change.from).length && !change.text[0] == '‡' ) { change.cancel(); } } @@ -68,7 +68,10 @@ define( [ 'marc-record', 'koha-backend', 'preferences', 'text-marc', 'widget' ], for (var line = origin; line <= newTo.line; line++) { if ( Preferences.user.fieldWidgets ) Widget.UpdateLine( cm.marceditor, line ); - if ( change.origin != 'setValue' && change.origin != 'marcWidgetPrefill' && change.origin != 'widget.clearToText' ) cm.addLineClass( line, 'wrapper', 'modified-line' ); + if ( change.origin != 'setValue' && change.origin != 'marcWidgetPrefill' && change.origin != 'widget.clearToText' ) { + cm.addLineClass( line, 'wrapper', 'modified-line' ); + editor.modified = true; + } } } @@ -206,7 +209,7 @@ define( [ 'marc-record', 'koha-backend', 'preferences', 'text-marc', 'widget' ], // make it be the double cross. var cur = cm.getCursor(); - cm.replaceRange( "$", cur, null ); + cm.replaceRange( "‡", cur, null ); }, }; @@ -244,7 +247,7 @@ define( [ 'marc-record', 'koha-backend', 'preferences', 'text-marc', 'widget' ], this.contentsStart = start; this.code = '@'; } else { - this.contentsStart = start + 3; + this.contentsStart = start + 2; this.code = this.field.contents.substr( this.start + 1, 1 ); } @@ -350,7 +353,7 @@ define( [ 'marc-record', 'koha-backend', 'preferences', 'text-marc', 'widget' ], var result = ''; $.each( this.getSubfields(), function() { - if ( this.code != '@' ) result += '$' + this.code + ' '; + if ( this.code != '@' ) result += '‡' + this.code; result += this.getText(); } ); @@ -358,7 +361,7 @@ define( [ 'marc-record', 'koha-backend', 'preferences', 'text-marc', 'widget' ], return result; }, setText: function( text ) { - var indicator_match = /^([_ 0-9])([_ 0-9])\$/.exec( text ); + var indicator_match = /^([_ 0-9])([_ 0-9])\‡/.exec( text ); if ( indicator_match ) { text = text.substr(2); this.setIndicator1( indicator_match[1] ); @@ -398,7 +401,7 @@ define( [ 'marc-record', 'koha-backend', 'preferences', 'text-marc', 'widget' ], if ( this.isControlField ) throw new FieldError('Cannot add subfields to control field'); this._invalidateSubfields(); - this.cm.replaceRange( '$' + code + ' ', { line: this.line }, null, 'marcAware' ); + this.cm.replaceRange( '‡' + code, { line: this.line }, null, 'marcAware' ); var subfields = this.getSubfields(); return subfields[ subfields.length - 1 ]; @@ -410,7 +413,7 @@ define( [ 'marc-record', 'koha-backend', 'preferences', 'text-marc', 'widget' ], var subfields = this.getSubfields(); this._invalidateSubfields(); - this.cm.replaceRange( '$' + code + ' ', { line: this.line, ch: subfields[position] ? subfields[position].start : null }, null, 'marcAware' ); + this.cm.replaceRange( '‡' + code, { line: this.line, ch: subfields[position] ? subfields[position].start : null }, null, 'marcAware' ); subfields = this.getSubfields(); return subfields[ position ]; @@ -501,6 +504,7 @@ define( [ 'marc-record', 'koha-backend', 'preferences', 'text-marc', 'widget' ], displayRecord: function( record ) { this.cm.setValue( TextMARC.RecordToText(record) ); + this.modified = false; }, getRecord: function() { @@ -530,7 +534,7 @@ define( [ 'marc-record', 'koha-backend', 'preferences', 'text-marc', 'widget' ], if ( tagNumber < '010' ) return { tagNumber: tagNumber, contents: contents }; // No current subfield - var matcher = /[$|ǂ‡]([a-z0-9%]) /g; + var matcher = /‡([a-z0-9%])/g; var match; var subfields = []; 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 c42c993d46..511a2bad84 100644 --- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-mode.js +++ b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-mode.js @@ -17,7 +17,7 @@ * along with Koha; if not, see . */ -// Expected format: 245 _ 1 $a Pizza |c 34ars +// Expected format: 245 _ 1 ‡aPizza ‡c34ars CodeMirror.defineMode( 'marc', function( config, modeConfig ) { modeConfig.nonRepeatableTags = modeConfig.nonRepeatableTags || {}; @@ -130,14 +130,14 @@ CodeMirror.defineMode( 'marc', function( config, modeConfig ) { // matching. if ( stream.match( /[ \t]+$/ ) ) { return 'end-space'; - } else if ( stream.match( /[^ \t$|ǂ‡]+/ ) || stream.match( /[ \t]+/ ) ) { + } else if ( stream.match( /[^ \t‡]+/ ) || stream.match( /[ \t]+/ ) ) { return; } } - if ( stream.eat( /[$|ǂ‡]/ ) ) { + if ( stream.eat( '‡' ) ) { var subfieldCode; - if ( ( subfieldCode = stream.eat( /[a-zA-Z0-9%]/ ) ) && stream.eat( ' ' ) ) { + if ( ( subfieldCode = stream.eat( /[a-zA-Z0-9%]/ ) ) ) { 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 d09f894a8a..f626eb39a9 100644 --- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-record.js +++ b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/marc-record.js @@ -236,8 +236,13 @@ define( function() { }, loadISO2709: function(data) { - // The underlying offsets work on bytes, not characters - data = _encode_utf8(data); + // The underlying offsets work on bytes, not characters, so we have to encode back into + // UTF-8 before we try to use the directory. + // + // The substr is a performance optimization; we can only load the first record, so we + // extract only the first record. We may get some of the next record, because the substr + // happens before UTF-8 encoding, but that won't cause any issues. + data = _encode_utf8(data.substr(0, parseInt(data.substr(0, 5)))); this._fieldlist.length = 0; this.leader(data.substr(0, 24)); 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 2110652d31..b8226ec56d 100644 --- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/text-marc.js +++ b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/text-marc.js @@ -18,15 +18,6 @@ */ define( [ 'marc-record' ], function( MARC ) { - // Convert any characters for display - function _sanitize( text ) { - return text.replace( '$', '{dollar}' ); - } - - // Undo conversion - function _desanitize( text ) { - return text.replace( '{dollar}', '$' ); - } return { RecordToText: function( record ) { var lines = []; @@ -36,7 +27,7 @@ define( [ 'marc-record' ], function( MARC ) { var field = fields[i]; if ( field.isControlField() ) { - lines.push( field.tagnumber() + ' ' + _sanitize( field.subfield( '@' ) ) ); + lines.push( field.tagnumber() + ' ' + field.subfield('@') ); } else { var result = [ field.tagnumber() + ' ' ]; @@ -44,7 +35,7 @@ define( [ 'marc-record' ], function( MARC ) { result.push( field.indicator(1) == ' ' ? '_' : field.indicator(1), ' ' ); $.each( field.subfields(), function( i, subfield ) { - result.push( '$' + subfield[0] + ' ' + _sanitize( subfield[1] ) ); + result.push( '‡' + subfield[0] + subfield[1] ); } ); lines.push( result.join('') ); @@ -68,7 +59,7 @@ define( [ 'marc-record' ], function( MARC ) { tagNumber = tagNumber[1]; if ( tagNumber < '010' ) { - var field = new MARC.Field( tagNumber, ' ', ' ', [ [ '@', _desanitize( line.substring( 4 ) ) ] ] ); + var field = new MARC.Field( tagNumber, ' ', ' ', [ [ '@', line.substring( 4 ) ] ] ); field.sourceLine = i; record.addField( field ); } else { @@ -80,7 +71,7 @@ define( [ 'marc-record' ], function( MARC ) { var field = new MARC.Field( tagNumber, ( indicators[1] == '_' ? ' ' : indicators[1] ), ( indicators[2] == '_' ? ' ' : indicators[2] ), [] ); - var matcher = /[$|ǂ‡]([a-zA-Z0-9%]) /g; + var matcher = /‡([a-zA-Z0-9%])/g; var match; var subfields = []; @@ -97,7 +88,7 @@ define( [ 'marc-record' ], function( MARC ) { $.each( subfields, function( i, subfield ) { var next = subfields[ i + 1 ]; - field.addSubfield( [ subfield.code, _desanitize( line.substring( subfield.ch + 3, next ? next.ch : line.length ) ) ] ); + field.addSubfield( [ subfield.code, line.substring( subfield.ch + 3, next ? next.ch : line.length ) ] ); } ); field.sourceLine = i; diff --git a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/widget.js b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/widget.js index 35d47270a5..ec03ecfe42 100644 --- a/koha-tmpl/intranet-tmpl/lib/koha/cateditor/widget.js +++ b/koha-tmpl/intranet-tmpl/lib/koha/cateditor/widget.js @@ -250,7 +250,7 @@ define( [ 'resources' ], function( Resources ) { } else { for ( var i = 0; i < info.subfields.length; i++ ) { var next = ( i < info.subfields.length - 1 ) ? info.subfields[i + 1].ch : end; - subfields.push( { code: info.subfields[i].code, from: info.subfields[i].ch + 3, to: next } ); + subfields.push( { code: info.subfields[i].code, from: info.subfields[i].ch + 2, to: next } ); } // If not a fixed field, and we didn't find any subfields, we need to throw in the // '@' subfield so we can properly remove it diff --git a/koha-tmpl/intranet-tmpl/prog/en/css/cateditor.css b/koha-tmpl/intranet-tmpl/prog/en/css/cateditor.css index 6e0ee75745..882ddf2aac 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/css/cateditor.css +++ b/koha-tmpl/intranet-tmpl/prog/en/css/cateditor.css @@ -55,6 +55,10 @@ body { padding-bottom: 0; } +#shortcuts-container { + font-size: 12px; +} + /*> MARC editor */ #editor .CodeMirror { line-height: 1.2; @@ -77,9 +81,11 @@ body { .cm-subfieldcode { background-color: #F4F4F4; color: #187848; - border-radius: 3px 8px 8px 3px; + border-radius: 3px; border-right: 2px solid white; font-weight: bold; + padding-left: 3px; + padding-right: 3px; margin-right: -2px; } 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 0bfeb0a407..310ca4545e 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc @@ -437,9 +437,24 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr $('#searchresults thead tr').append('' + _("Tools") + ''); + var bibnumMap = KohaBackend.GetSubfieldForKohaField('biblio.biblionumber'); $.each( data.hits, function( undef, hit ) { backends.search.records[ hit.server + ':' + hit.index ] = hit.record; - hit.id = 'search/' + hit.server + ':' + hit.index; + + switch ( hit.server ) { + case 'koha:biblioserver': + var bibnumField = hit.record.field( bibnumMap[0] ); + + if ( bibnumField && bibnumField.hasSubfield( bibnumMap[1] ) ) { + hit.id = 'catalog/' + bibnumField.subfield( bibnumMap[1] ); + break; + } + + // Otherwise, fallthrough + + default: + hit.id = 'search/' + hit.server + ':' + hit.index; + } var result = ''; result += '' + z3950Servers[ hit.server ].name + ''; @@ -455,7 +470,7 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr } ); result += ''; @@ -670,7 +685,7 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr var modified = macro.modified && new Date(macro.modified); $li.find( '.macro-info' ).append( '
  • ' + _("Last changed:") + '' + - ( modified ? modified.toLocaleFormat() : _("never") ) + '
  • ' + ( modified ? ( modified.toLocaleDateString() + ', ' + modified.toLocaleTimeString() ) : _("never") ) + '' ); $('#macro-list').append($li); } ); @@ -721,7 +736,7 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr if ( !subfield ) return; var subfieldinfo = taginfo.subfields[ subfield.code ]; - $('#status-subfield-info').html( '$' + subfield.code + ': ' ); + $('#status-subfield-info').html( '‡' + subfield.code + ': ' ); if ( subfieldinfo ) { $('#status-subfield-info').append( subfieldinfo.lib ); @@ -833,14 +848,14 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr if ( error.subfield == '@' ) { editor.addError( error.line, _("Missing control field contents") ); } else { - editor.addError( error.line, _("Missing mandatory subfield: $") + error.subfield ); + editor.addError( error.line, _("Missing mandatory subfield: ‡") + error.subfield ); } break; case 'unrepeatableTag': editor.addError( error.line, _("Tag ") + error.tag + _(" cannot be repeated") ); break; case 'unrepeatableSubfield': - editor.addError( error.line, _("Subfield $") + error.subfield + _(" cannot be repeated") ); + editor.addError( error.line, _("Subfield ‡") + error.subfield + _(" cannot be repeated") ); break; case 'itemTagUnsupported': editor.addError( error.line, _("Item tags cannot currently be saved") ); @@ -1030,7 +1045,18 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr return '
      ' + prevAlerts.join('') + '
    '; }, }); + + $('#show-shortcuts').popover({ + html: true, + placement: 'bottom', + content: function() { + return '
    ' + $('#shortcuts-contents').html() + '
    '; + }, + }); + $('#new-record' ).click( function() { + if ( editor.modified && !confirm( _("Are you sure you want to erase your changes?") ) ) return; + openRecord( 'new/', editor ); return false; } ); diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/labs.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/labs.pref index c6dc285de1..34fb6cd5c4 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/labs.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/labs.pref @@ -8,4 +8,4 @@ Labs: no: "Don't enable" - the advanced cataloging editor. - "
    NOTE:" - - This feature is currently experimental, and may have bugs that cause corruption of records. Please help us test it and report any bugs, but do so at your own risk. + - This feature is currently experimental, and may have bugs that cause corruption of records. It also does not include any support for UNIMARC or NORMARC fixed fields. Please help us test it and report any bugs, but do so at your own risk. diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/editor.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/editor.tt index 4e2bbdf7fa..aa69ca0d46 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/editor.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/editor.tt @@ -57,7 +57,8 @@
  • peep
  • - + + [%# CodeMirror instance will be inserted here %]
    @@ -228,6 +229,55 @@
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ShortcutBehavior
    Ctrl-DInsert delimiter (‡)
    Ctrl-HGet help on current subfield
    Ctrl-SSave record
    Ctrl-XDelete current field
    Ctrl-Shift-XDelete current field
    EnterNew field on next line
    Shift-EnterInsert line break
    TabMove to next position
    Shift-TabMove to previous position
    +
    + [% PROCESS 'cateditor-ui.inc' %] -- 2.39.5