diff --git a/modules/bibedit/lib/bibedit_engine.js b/modules/bibedit/lib/bibedit_engine.js
index 28defd5d8..537d15241 100644
--- a/modules/bibedit/lib/bibedit_engine.js
+++ b/modules/bibedit/lib/bibedit_engine.js
@@ -1,4590 +1,4631 @@
 /*
  * This file is part of Invenio.
  * Copyright (C) 2009, 2010, 2011 CERN.
  *
  * Invenio is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * Invenio is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with Invenio; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*
  * This is the main BibEdit Javascript.
  */
 
 /* ************************* Table of contents ********************************
  *
  * 1. Global variables
  *
  * 2. Initialization
  *   - $()
  *   - initJeditable
  *   - initMisc
  *
  * 3. Ajax
  *   - initAjax
  *   - createReq
  *   - onAjaxError
  *   - onAjaxSuccess
  *
  * 4. Hash management
  *   - initStateFromHash
  *   - deserializeHash
  *   - changeAndSerializeHash
  *
  * 5. Data logic
  *   - getTagsSorted
  *   - getFieldPositionInTag
  *   - getPreviousTag
  *   - deleteFieldFromTag
  *   - cmpFields
  *   - fieldIsProtected
  *   - containsProtected
  *   - getMARC
  *   - getFieldTag
  *   - getSubfieldTag
  *   - validMARC
  *
  * 6. Record UI
  *   - onNewRecordClick
  *   - getRecord
  *   - onGetRecordSuccess
  *   - onSubmitClick
  *   - onPreviewClick
  *   - onCancelClick
  *   - onCloneRecordClick
  *   - onDeleteRecordClick
  *   - onMergeClick
  *   - bindNewRecordHandlers
  *   - cleanUp
  *
  * 7. Editor UI
  *   - colorFields
  *   - reColorFields
  *   - onMARCTagsClick
  *   - onHumanTagsClick
  *   - updateTags
  *   - onFieldBoxClick
  *   - onSubfieldBoxClick
  *   - onAddFieldClick
  *   - onAddFieldControlfieldClick
  *   - onAddFieldChange
  *   - onAddFieldSave
  *   - onAddSubfieldsClick
  *   - onAddSubfieldsChange
  *   - onAddSubfieldsSave
  *   - onDoubleClick
  *   - onContentChange
  *   - onMoveSubfieldClick
  *   - onDeleteClick
  */
 
 
 
 /*
  * **************************** 1. Global variables ****************************
  */
 
 // Record data
 var gRecID = null;
 var gRecIDLoading = null;
 var gRecRev = null;
 var gRecRevAuthor = null;
 var gRecLatestRev = null;
 var gRecord = null;
 // Search results (record IDs)
 var gResultSet = null;
 // Current index in the result set
 var gResultSetIndex = null;
 // Tag format.
 var gTagFormat = null;
 // Has the record been modified?
 var gRecordDirty = false;
 // Last recorded cache modification time
 var gCacheMTime = null;
 
 // Are we navigating a set of records?
 var gNavigatingRecordSet = false;
 
 // The current hash (fragment part of the URL).
 var gHash;
 // The current hash deserialized to an object.
 var gHashParsed;
 // Hash check timer ID.
 var gHashCheckTimerID;
 // The previous and current state (this is not exactly the same as the state
 // parameter, but an internal state control mechanism).
 var gPrevState;
 var gState;
 // A current status
 var gCurrentStatus;
 
 // a global array of visible changes associated with a currently viewed record
 // This array is cleared always when a new changes set is applied... then it is used
 // for redrawing the change fields
 // The index in this array is used when referring to a particular change [ like finding an appropriate box]
 
 var gHoldingPenChanges = [];
 
 // A global variable used to avoid multiple retrieving of the same changes stored in the Holding Pen
 // this is the dictionary indexed by the HoldingPen entry identifiers and containing the javascript objects
 // representing the records
 // due to this mechanism, applying previously previewed changes, as well as previewing the change for the
 // second time, can be made much faster
 var gHoldingPenLoadedChanges = {};
 
 // The changes that have been somehow processed and should not be displayed as already processed
 
 var gDisabledHpEntries = {};
 
 // is the read-only mode enabled ?
 var gReadOnlyMode = false;
 
 // revisions history
 var gRecRevisionHistory = [];
 
 var gUndoList = []; // list of possible undo operations
 var gRedoList = []; // list of possible redo operations
 
 // number of bibcirculation copies from the retrieval time
 var gPhysCopiesNum = 0;
 var gBibCircUrl = null;
 
 var gDisplayBibCircPanel = false;
 
 /*
  * **************************** 2. Initialization ******************************
  */
 
 window.onload = function(){
   if (typeof(jQuery) == 'undefined'){
     alert('ERROR: jQuery not found!\n\n' +
     'The Record Editor requires jQuery, which does not appear to be ' +
     'installed on this server. Please alert your system ' +
     'administrator.\n\nInstructions on how to install jQuery and other ' +
     "required plug-ins can be found in Invenio's INSTALL file.");
     var imgError = document.createElement('img');
     imgError.setAttribute('src', '/img/circle_red.png');
     var txtError = document.createTextNode('jQuery missing');
     var cellIndicator = document.getElementById('cellIndicator');
     cellIndicator.replaceChild(imgError, cellIndicator.firstChild);
     var cellStatus = document.getElementById('cellStatus');
     cellStatus.replaceChild(txtError, cellStatus.firstChild);
   }
 };
 
 $(function(){
   /*
    * Initialize all components.
    */
   initMenu();
   initJeditable();
   initAjax();
   initMisc();
   createTopToolbar();
   initStateFromHash();
   gHashCheckTimerID = setInterval(initStateFromHash, gHASH_CHECK_INTERVAL);
   initHotkeys();
   initClipboardLibrary();
   initClipboard()
 });
 
 
 function failInReadOnly(){
   /** Function checking if the current BibEdit mode is read-only. In sucha a case, a warning
     dialog is displayed and true returned.
     If bibEdit is in read/write mode, false is returned
    */
   if (gReadOnlyMode === true){
     alert("It is impossible to perform this operation in the Read/Only mode. Please switch to Read-write mode before trying again");
     return true;
   }
   else{
     return false;
   }
 }
 
 function initJeditable(){
   /* Initialize Jeditable with the Autogrow extension. Used for in-place
    * content editing.
    */
   $.editable.addInputType('autogrow', {
     element: function(settings, original){
       var textarea = $('<textarea>');
       if (settings.rows){
         textarea.attr('rows', settings.rows);
       } else {
         textarea.height(settings.height);
       }if (settings.cols) {
         textarea.attr('cols', settings.cols);
       } else {
         textarea.width(settings.width);
       }
       $(this).append(textarea);
       return(textarea);
     },
     plugin: function(settings, original){
       $('textarea', this).autogrow(settings.autogrow);
     }
   });
 }
 
 function initClipboard(){
   // attaching the events -> handlers are stored in bibedit_engine.js file
   $(document).bind("copy", onPerformCopy);
   $(document).bind("paste", onPerformPaste);
 }
 
 function initMisc(){
   /*
    * Miscellaneous initialization operations.
    */
   // CERN allows for capital MARC indicators.
   if (gCERN_SITE){
     validMARC.reIndicator1 = /[\dA-Za-z]{1}/;
     validMARC.reIndicator2 = /[\dA-Za-z]{1}/;
   }
 
   // Warn user if BibEdit is being closed while a record is open.
   window.onbeforeunload = function(){
     if (gRecID && gRecordDirty){
       return '******************** WARNING ********************\n' +
              '                  You have unsubmitted changes.\n\n' +
              'You should go back to the page and click either:\n' +
              ' * Submit (to save your changes permanently)\n      or\n' +
              ' * Cancel (to discard your changes)';
     }
   };
 
   //Initialising the BibCircualtion integration plugin
   $("#bibEditBibCirculationBtn").bind("click", onBibCirculationBtnClicked);
 }
 
 
 /*
  * **************************** 3. Ajax ****************************************
  */
 
 function initAjax(){
   /*
    * Initialize Ajax.
    */
   $.ajaxSetup(
     {cache: false,
       dataType: 'json',
       error: onAjaxError,
       type: 'POST',
       url: '/record/edit/'
     }
   );
 }
 
 function createReq(data, onSuccess, asynchronous){
   /*
    * Create Ajax request.
    */
   if (asynchronous == undefined){
     asynchronous = true;
   }
   // Include and increment transaction ID.
   var tID = createReq.transactionID++;
   createReq.transactions[tID] = data['requestType'];
   data.ID = tID;
   // Include cache modification time if we have it.
   if (gCacheMTime){
     data.cacheMTime = gCacheMTime;
   }
   // Send the request.
   $.ajax({data: {jsondata: JSON.stringify(data)},
            success: function(json){
                       onAjaxSuccess(json, onSuccess);
                     },
            async: asynchronous
   });
 }
 // Transactions data.
 createReq.transactionID = 0;
 createReq.transactions = [];
 
 function createBulkReq(reqsData, onSuccess, optArgs){
   /* optArgs is a disctionary containning the optional arguments
      possible keys include:
        asynchronous : if the request should be asynchronous
        undoRedo : handler for the undo operation
   */
     // creating a bulk request ... the cache timestamp is not saved
 
     var data = {'requestType' : 'applyBulkUpdates',
                  'requestsData' : reqsData,
                  'recID' : gRecID};
     if (optArgs.undoRedo != undefined){
         data.undoRedo = optArgs.undoRedo;
     }
 
     createReq(data, onSuccess, optArgs.asynchronous);
 }
 
 function onAjaxError(XHR, textStatus, errorThrown){
   /*
    * Handle Ajax request errors.
    */
   alert('Request completed with status ' + textStatus +
     '\nResult: ' + XHR.responseText +
     '\nError: ' + errorThrown);
 }
 
 function onAjaxSuccess(json, onSuccess){
   /*
    * Handle server response to Ajax requests, in particular error situations.
    * See BibEdit config for result codes.
    * If a function onSuccess is specified this will be called in the end,
    * if no error was encountered.
    */
   var resCode = json['resultCode'];
   var recID = json['recID'];
   if (resCode == 100){
     // User's session has timed out.
     gRecID = null;
     gRecIDLoading = null;
     window.location = recID ? gSITE_URL + '/record/' + recID + '/edit/'
       : gSITE_URL + '/record/edit/';
     return;
   }
   else if ($.inArray(resCode, [101, 102, 103, 104, 105, 106, 107, 108, 109])
      != -1){
     cleanUp(!gNavigatingRecordSet, null, null, true, true);
     if ($.inArray(resCode, [108, 109]) == -1)
       $('.headline').text('Record Editor: Record #' + recID);
     displayMessage(resCode);
     if (resCode == 107)
       return;
       $('#lnkGetRecord').bind('click', function(event){
         getRecord(recID);
         event.preventDefault();
       });
     updateStatus('error', gRESULT_CODES[resCode]);
   }
   else if (resCode == 110){
     displayMessage(resCode, true, [json['errors'].toString()]);
-    $(document).scrollTop(0);
     updateStatus('error', gRESULT_CODES[resCode]);
   }
   else{
     var cacheOutdated = json['cacheOutdated'];
     var requestType = createReq.transactions[json['ID']];
     if (cacheOutdated && requestType == 'submit'){
       // User wants to submit, but cache is outdated. Outdated means that the
       // DB version of the record has changed after the cache was created.
       displayCacheOutdatedScreen(requestType);
       $('#lnkMergeCache').bind('click', onMergeClick);
       $('#lnkForceSubmit').bind('click', function(event){
   onSubmitClick.force = true;
   onSubmitClick();
   event.preventDefault();
       });
       $('#lnkDiscardChanges').bind('click', function(event){
   onCancelClick();
   event.preventDefault();
       });
       updateStatus('error', 'Error: Record cache is outdated');
     }
     else{
       if (requestType != 'getRecord'){
   // On getRecord requests the below actions will be performed in
   // onGetRecordSuccess (after cleanup).
   var cacheMTime = json['cacheMTime'];
   if (cacheMTime)
     // Store new cache modification time.
     gCacheMTime = cacheMTime;
   var cacheDirty = json['cacheDirty'];
   if (cacheDirty){
     // Cache is dirty. Enable submit button.
     gRecordDirty = cacheDirty;
     $('#btnSubmit').removeAttr('disabled');
     $('#btnSubmit').css('background-color', 'lightgreen');
   }
       }
       if (onSuccess)
   // No critical errors; call onSuccess function.
   onSuccess(json);
     }
   }
 }
 
 function resetBibeditState(){
   /** A function clearing the state of the bibEdit (all the panels content)
   */
   gHoldingPenLoadedChanges = {};
   gHoldingPenChanges = [];
   gDisabledHpEntries = {};
   gReadOnlyMode = false;
   gRecRevisionHistory = [];
   gUndoList = [];
   gRedoList = [];
   gPhysCopiesNum = 0;
   gBibCircUrl = null;
 
   updateRevisionsHistory();
   updateInterfaceAccordingToMode();
   updateRevisionsHistory();
   updateUrView();
   updateBibCirculationPanel();
   holdingPenPanelRemoveEntries();
 }
 
 /*
  * **************************** 4. Hash management *****************************
  */
 
 function initStateFromHash(){
   /*
    * Initialize or update page state from hash.
    * Any program functions changing the hash should use changeAndSerializeHash()
    * which circumvents this function, meaning this function should only run on
    * page load and when browser navigation buttons (ie. Back and Forward) are
    * clicked. Any invalid hashes entered by the user will be ignored.
    */
   if (window.location.hash == gHash)
     // Hash is the same as last time we checked, do nothing.
     return;
 
   gHash = window.location.hash;
   gHashParsed = deserializeHash(gHash);
   gPrevState = gState;
   var tmpState = gHashParsed.state;
   var tmpRecID = gHashParsed.recid;
   var tmpRecRev = gHashParsed.recrev;
   var tmpReadOnlyMode = gHashParsed.romode;
 
   // Find out which internal state the new hash leaves us with
   if (tmpState && tmpRecID){
     // We have both state and record ID.
     if ($.inArray(tmpState, ['edit', 'submit', 'cancel', 'deleteRecord']) != -1)
   gState = tmpState;
     else
       // Invalid state, fail...
       return;
   }
   else if (tmpState){
     // We only have state.
     if (tmpState == 'edit')
       gState = 'startPage';
     else if (tmpState == 'newRecord')
       gState = 'newRecord';
     else
       // Invalid state, fail... (all states but 'edit' and 'newRecord' are
       // illegal without record ID).
       return;
   }
   else
     // Invalid hash, fail...
     return;
 
   if (gState != gPrevState
     || (gState == 'edit' && parseInt(tmpRecID) != gRecID) || // different record number
     (tmpRecRev != undefined && tmpRecRev != gRecRev) // different revision
     || (tmpRecRev == undefined && gRecRev != gRecLatestRev) // latest revision requested but another open
     || (tmpReadOnlyMode != gReadOnlyMode)){ // switched between read-only and read-write modes
 
     // We have an actual and legal change of state. Clean up and update the
     // page.
     updateStatus('updating');
     if (gRecID && !gRecordDirty && !tmpReadOnlyMode)
       // If the record is unchanged, delete the cache.
       createReq({recID: gRecID, requestType: 'deleteRecordCache'});
     switch (gState){
       case 'startPage':
         cleanUp(true, '', 'recID', true, true);
         updateStatus('ready');
         break;
       case 'edit':
         var recID = parseInt(tmpRecID);
         if (isNaN(recID)){
           // Invalid record ID.
           cleanUp(true, tmpRecID, 'recID', true);
           $('.headline').text('Record Editor: Record #' + tmpRecID);
           displayMessage(102);
           updateStatus('error', gRESULT_CODES[102]);
         }
         else{
           cleanUp(true, recID, 'recID');
           gReadOnlyMode = tmpReadOnlyMode;
             if (tmpRecRev != undefined && tmpRecRev != 0){
               getRecord(recID, tmpRecRev);
             } else {
               getRecord(recID);
             }
         }
       break;
     case 'newRecord':
       cleanUp(true, '', null, null, true);
       $('.headline').text('Record Editor: Create new record');
       displayNewRecordScreen();
       bindNewRecordHandlers();
       updateStatus('ready');
       break;
     case 'submit':
       cleanUp(true, '', null, true);
       $('.headline').text('Record Editor: Record #' + tmpRecID);
       displayMessage(4);
       updateStatus('ready');
       break;
     case 'cancel':
       cleanUp(true, '', null, true, true);
       updateStatus('ready');
       break;
     case 'deleteRecord':
       cleanUp(true, '', null, true);
       $('.headline').text('Record Editor: Record #' + tmpRecID);
       displayMessage(6);
       updateStatus('ready');
         break;
     }
   }
   else
   // What changed was not of interest, continue as if nothing happened.
     return;
 }
 
 function deserializeHash(aHash){
   /*
    * Deserializes a string (given as parameter or taken from the window object)
    * into the hash object.
    */
   if (aHash == undefined){
     aHash = window.location.hash;
   }
   var hash = {};
   var args = aHash.slice(1).split('&');
   var tmpArray;
   for (var i=0, n=args.length; i<n; i++){
     tmpArray = args[i].split('=');
     if (tmpArray.length == 2)
       hash[tmpArray[0]] = tmpArray[1];
   }
   return hash;
 }
 
 function changeAndSerializeHash(updateData){
   /*
    * Change the hash object to use the data from the object given as parameter.
    * Then update the hash accordingly, WITHOUT invoking initStateFromHash().
    */
   clearTimeout(gHashCheckTimerID);
   gHashParsed = {};
   for (var key in updateData){
     gHashParsed[key.toString()] = updateData[key].toString();
   }
   gHash = '#';
   for (key in gHashParsed){
     gHash += key + '=' + gHashParsed[key] + '&';
   }
   gHash = gHash.slice(0, -1);
   gState = gHashParsed.state;
   window.location.hash = gHash;
   gHashCheckTimerID = setInterval(initStateFromHash, gHASH_CHECK_INTERVAL);
 }
 
 
 /*
  * **************************** 5. Data logic **********************************
 */
 
 function getTagsSorted(){
   /*
    * Return field tags in sorted order.
    */
   var tags = [];
   for (var tag in gRecord){
     tags.push(tag);
   }
   return tags.sort();
 }
 
 function getFieldPositionInTag(tag, field){
   /*
    * Determine the local (in tag) position of a new field.
    */
   var fields = gRecord[tag];
   if (fields){
     var fieldLength = fields.length, i = 0;
     while (i < fieldLength && cmpFields(field, fields[i]) != -1)
       i++;
     return i;
   }
   else
     return 0;
 }
 
 function getPreviousTag(tag){
   /*
    * Determine the previous tag in the record (if the given tag is the first
    * tag, 0 will be returned).
    */
   var tags = getTagsSorted();
   var tagPos = $.inArray(tag, tags);
   if (tagPos == -1){
     tags.push(tag);
     tags.sort();
     tagPos = $.inArray(tag, tags);
   }
   if (tagPos > 0)
     return tags[tagPos-1];
   return 0;
 }
 
 function deleteFieldFromTag(tag, fieldPosition){
   /*
    * Delete a specified field.
    */
   var field = gRecord[tag][fieldPosition];
   var fields = gRecord[tag];
   fields.splice($.inArray(field, fields), 1);
   // If last field, delete tag.
   if (fields.length == 0){
     delete gRecord[tag];
   }
 }
 
 function cmpFields(field1, field2){
   /*
    * Compare fields by indicators (tag assumed equal).
    */
   if (field1[1].toLowerCase() > field2[1].toLowerCase())
     return 1;
   else if (field1[1].toLowerCase() < field2[1].toLowerCase())
     return -1;
   else if (field1[2].toLowerCase() > field2[2].toLowerCase())
     return 1;
   else if (field1[2].toLowerCase() < field2[2].toLowerCase())
     return -1;
   return 0;
 }
 
 function insertFieldToRecord(record, fieldId, ind1, ind2, subFields){
   /**Inserting a new field on the client side and returning the position of the newly created field*/
   newField = [subFields, ind1, ind2, '', 0];
   if (record[fieldId] == undefined){
     record[fieldId] = [newField]
     return 0;
   } else {
     record[fieldId].push(newField);
     return (record[fieldId].length-1);
   }
 }
 
 function transformRecord(record){
   /**Transforming a bibrecord to a form that is easier to compare that is a dictionary
    * field identifier -> field indices -> fields list -> [subfields list, position in the record]
    *
    * The data is enriched with the positions inside the record in a following manner:
    * each field consists of:
    * */
   result = {};
   for (fieldId in record){
     result[fieldId] = {}
     indicesList = []; // a list of all the indices ... utilised later when determining the positions
     for (fieldIndex in record[fieldId]){
 
       indices =  "";
       if (record[fieldId][fieldIndex][1] == ' '){
         indices += "_";
       }else{
         indices += record[fieldId][fieldIndex][1]
       }
 
       if (record[fieldId][fieldIndex][2] == ' '){
         indices += "_";
       }else{
         indices += record[fieldId][fieldIndex][2]
       }
 
       if (result[fieldId][indices] == undefined){
         result[fieldId][indices] = []; // a future list of fields sharing the same indice
         indicesList.push(indices);
       }
       result[fieldId][indices].push([record[fieldId][fieldIndex][0], 0]);
     }
 
     // now calculating the positions within a field identifier ( utilised on the website )
 
     position = 0;
 
     indices = indicesList.sort();
     for (i in indices){
       for (fieldInd in result[fieldId][indices[i]]){
         result[fieldId][indices[i]][fieldInd][1] = position;
         position ++;
       }
     }
   }
 
     return result;
 }
 
 function filterChanges(changeset){
   /*Filtering the changes list -> removing the changes related to the fields
    * that should never be changed */
   unchangableTags = {"001" : true}; // a dictionary of the fields that should not be modified
   result = [];
   for (changeInd in changeset){
     change = changeset[changeInd];
     if ((change.tag == undefined) || (!(change.tag in unchangableTags))){
       result.push(change);
     }
   }
   return result;
 }
 
 ///// Functions generating easy to display changes list
 
 function compareFields(fieldId, indicators, fieldPos, field1, field2){
   result = [];
   for (sfPos in field2){
     if (field1[sfPos] == undefined){
       //  adding the subfield at the end of the record can be treated in a more graceful manner
       result.push(
           {"change_type" : "subfield_added",
            "tag" : fieldId,
            "indicators" : indicators,
            "field_position" : fieldPos,
            "subfield_code" : field2[sfPos][0],
            "subfield_content" : field2[sfPos][1]});
     }
     else
     {
       // the subfield exists in both the records
       if (field1[sfPos][0] != field2[sfPos][0]){
       //  a structural change ... we replace the entire field
         return [{"change_type" : "field_changed",
            "tag" : fieldId,
            "indicators" : indicators,
            "field_position" : fieldPos,
            "field_content" : field2}];
       } else
       {
         if (field1[sfPos][1] != field2[sfPos][1]){
           result.push({"change_type" : "subfield_changed",
             "tag" : fieldId,
             "indicators" : indicators,
             "field_position" : fieldPos,
             "subfield_position" : sfPos,
             "subfield_code" : field2[sfPos][0],
             "subfield_content" : field2[sfPos][1]});
 
         }
       }
     }
   }
 
   for (sfPos in field1){
     if (field2[sfPos] == undefined){
       result.push({"change_type" : "subfield_removed",
                 "tag" : fieldId,
                 "indicators" : indicators,
                 "field_position" : fieldPos,
                 "subfield_position" : sfPos});
     }
   }
 
   return result;
 }
 
 function compareIndicators(fieldId, indicators, fields1, fields2){
    /*a helper function allowing to compare inside one indicator
     * excluded from compareRecords for the code clarity reason*/
   result = []
   for (fieldPos in fields2){
     if (fields1[fieldPos] == undefined){
       result.push({"change_type" : "field_added",
                   "tag" : fieldId,
                   "indicators" : indicators,
                   "field_content" : fields2[fieldPos][0]});
     } else { // comparing the content of the subfields
       result = result.concat(compareFields(fieldId, indicators, fields1[fieldPos][1], fields1[fieldPos][0], fields2[fieldPos][0]));
     }
   }
 
   for (fieldPos in fields1){
     if (fields2[fieldPos] == undefined){
       fieldPosition = fields1[fieldPos][1];
       result.push({"change_type" : "field_removed",
              "tag" : fieldId,
              "indicators" : indicators,
              "field_position" : fieldPosition});
     }
   }
   return result;
 }
 
 function compareRecords(record1, record2){
   /*Compares two bibrecords, producing a list of atom changes that can be displayed
    * to the user if for example applying the Holding Pen change*/
    // 1) This is more convenient to have a different structure of the storage
   r1 = transformRecord(record1);
   r2 = transformRecord(record2);
   result = [];
 
   for (fieldId in r2){
     if (r1[fieldId] == undefined){
       for (indicators in r2[fieldId]){
         for (field in r2[fieldId][indicators]){
           result.push({"change_type" : "field_added",
                         "tag" : fieldId,
                         "indicators" : indicators,
                         "field_content" : r2[fieldId][indicators][field][0]});
 
 
         }
       }
     }
     else
     {
       for (indicators in r2[fieldId]){
         if (r1[fieldId][indicators] == undefined){
           for (field in r2[fieldId][indicators]){
             result.push({"change_type" : "field_added",
                          "tag" : fieldId,
                          "indicators" : indicators,
                          "field_content" : r2[fieldId][indicators][field][0]});
 
 
           }
         }
         else{
           result = result.concat(compareIndicators(fieldId, indicators,
               r1[fieldId][indicators], r2[fieldId][indicators]));
         }
       }
 
       for (indicators in r1[fieldId]){
         if (r2[fieldId][indicators] == undefined){
           for (fieldInd in r1[fieldId][indicators]){
             fieldPosition = r1[fieldId][indicators][fieldInd][1];
             result.push({"change_type" : "field_removed",
                  "tag" : fieldId,
                  "field_position" : fieldPosition});
           }
 
         }
       }
 
     }
   }
 
   for (fieldId in r1){
     if (r2[fieldId] == undefined){
       for (indicators in r1[fieldId]){
         for (field in r1[fieldId][indicators])
         {
           // field position has to be calculated here !!!
           fieldPosition = r1[fieldId][indicators][field][1]; // field position inside the mark
           result.push({"change_type" : "field_removed",
                        "tag" : fieldId,
                        "field_position" : fieldPosition});
 
         }
       }
     }
   }
   return result;
 }
 
 function fieldIsProtected(MARC){
   /*
    * Determine if a MARC field is protected or part of a protected group of
    * fields.
    */
   do{
     var i = MARC.length - 1;
     if ($.inArray(MARC, gPROTECTED_FIELDS) != -1)
       return true;
     MARC = MARC.substr(0, i);
     i--;
   }
   while (i >= 1)
   return false;
 }
 
 function containsProtectedField(fieldData){
   /*
    * Determine if a field data structure contains protected elements (useful
    * when checking if a deletion command is valid).
    * The data structure must be an object with the following levels
    * - Tag
    *   - Field position
    *     - Subfield index
    */
   var fieldPositions, subfieldIndexes, MARC;
   for (var tag in fieldData){
     fieldPositions = fieldData[tag];
     for (var fieldPosition in fieldPositions){
       subfieldIndexes = fieldPositions[fieldPosition];
       if (subfieldIndexes.length == 0){
   MARC = getMARC(tag, fieldPosition);
   if (fieldIsProtected(MARC))
     return MARC;
   }
       else{
   for (var i=0, n=subfieldIndexes.length; i<n; i++){
     MARC = getMARC(tag, fieldPosition, subfieldIndexes[i]);
     if (fieldIsProtected(MARC))
       return MARC;
   }
       }
     }
   }
   return false;
 }
 
 function getMARC(tag, fieldPosition, subfieldIndex){
   /*
    * Return the MARC representation of a field or a subfield.
    */
   var field = gRecord[tag][fieldPosition];
   var ind1, ind2;
   if (validMARC.reControlTag.test(tag))
     ind1 = '', ind2 = '';
   else{
     ind1 = (field[1] == ' ' || !field[1]) ? '_' : field[1];
     ind2 = (field[2] == ' ' || !field[2]) ? '_' : field[2];
   }
   if (subfieldIndex == undefined)
     return tag + ind1 + ind2;
   else
     return tag + ind1 + ind2 + field[0][subfieldIndex][0];
 }
 
 function getFieldTag(MARC){
   /*
    * Get the tag name of a field in format as specified by gTagFormat.
    */
   MARC = MARC.substr(0, 5);
   if (gTagFormat == 'human'){
     var tagName = gTAG_NAMES[MARC];
     if (tagName != undefined)
       // Direct hit. Return it.
       return tagName;
     else{
       // Start looking for wildcard hits.
       if (MARC.length == 3){
   // Controlfield
   tagName = gTAG_NAMES[MARC.substr(0, 2) + '%'];
   if (tagName != undefined && tagName != MARC + 'x')
     return tagName;
       }
       else{
   // Regular field, try finding wildcard hit by shortening expression
   // gradually. Ignores wildcards which gives values like '27x'.
   var term = MARC + '%', i = 5;
   do{
     tagName = gTAG_NAMES[term];
     if (tagName != undefined){
       if (tagName != MARC.substr(0, i) + 'x')
         return tagName;
       break;
     }
     i--;
     term = MARC.substr(0, i) + '%';
   }
   while (i >= 3)
       }
     }
   }
   return MARC;
 }
 
 function getSubfieldTag(MARC){
   /*
    * Get the tag name of a subfield in format as specified by gTagFormat.
    */
   if (gTagFormat == 'human'){
     var subfieldName = gTAG_NAMES[MARC];
       if (subfieldName != undefined)
   return subfieldName;
   }
   return MARC.charAt(5);
 }
 
 function validMARC(datatype, value){
   /*
    * Validate a value of given datatype according to the MARC standard. The
    * value should be restricted/extended to it's expected size before being
    * passed to this function.
    * Datatype can be 'ControlTag', 'Tag', 'Indicator' or 'SubfieldCode'.
    * Returns a boolean.
    */
   return eval('validMARC.re' + datatype + '.test(value)');
 }
 // MARC validation REs
 validMARC.reControlTag = /00[1-9A-Za-z]{1}/;
 validMARC.reTag = /(0([1-9A-Z][0-9A-Z])|0([1-9a-z][0-9a-z]))|(([1-9A-Z][0-9A-Z]{2})|([1-9a-z][0-9a-z]{2}))/;
 validMARC.reIndicator1 = /[\da-z]{1}/;
 validMARC.reIndicator2 = /[\da-z]{1}/;
 //validMARC.reSubfieldCode = /[\da-z!&quot;#$%&amp;'()*+,-./:;&lt;=&gt;?{}_^`~\[\]\\]{1}/;
 validMARC.reSubfieldCode = /[\da-z!&quot;#$%&amp;'()*+,-.\/:;&lt;=&gt;?{}_^`~\[\]\\]{1}/;
 
 /*
  * **************************** 6. Record UI ***********************************
  */
 
 function onNewRecordClick(event){
   /*
    * Handle 'New' button (new record).
    */
   updateStatus('updating');
   if (gRecordDirty){
     if (!displayAlert('confirmLeavingChangedRecord')){
       updateStatus('ready');
       event.preventDefault();
       return;
     }
   }
   else
     // If the record is unchanged, erase the cache.
     if (gReadOnlyMode == false){
       createReq({recID: gRecID, requestType: 'deleteRecordCache'});
   }
   changeAndSerializeHash({state: 'newRecord'});
   cleanUp(true, '');
   $('.headline').text('Record Editor: Create new record');
   displayNewRecordScreen();
   bindNewRecordHandlers();
   updateStatus('ready');
   event.preventDefault();
 }
 
 function getRecord(recID, recRev, onSuccess){
   /* A function retrieving the bibliographic record, using an AJAX request.
    *
    * recID : the identifier of a record to be retrieved from the server
    * recRev : the revision of the record to be retrieved (0 or undefined
    *          means retrieving the newest version )
    * onSuccess : The callback to be executed upon retrieval. The default
    *             callback loads the retrieved record into the bibEdit user
    *             interface
    */
 
   // Temporary store the record ID by attaching it to the onGetRecordSuccess
   // function.
   if (onSuccess == undefined)
     onSuccess = onGetRecordSuccess;
   if (recRev != undefined && recRev != 0){
     changeAndSerializeHash({state: 'edit', recid: recID, recrev: recRev});
   }
   else{
     changeAndSerializeHash({state: 'edit', recid: recID});
   }
 
   gRecIDLoading = recID;
 
   reqData = {recID: recID,
              requestType: 'getRecord',
              deleteRecordCache:
              getRecord.deleteRecordCache,
              clonedRecord: getRecord.clonedRecord,
              inReadOnlyMode: gReadOnlyMode};
 
   if (recRev != undefined && recRev != 0){
     reqData.recordRevision = recRev;
     reqData.inReadOnlyMode = true;
   }
 
   resetBibeditState();
   createReq(reqData, onSuccess);
 
   onHoldingPenPanelRecordIdChanged(recID); // reloading the Holding Pen toolbar
   getRecord.deleteRecordCache = false;
   getRecord.clonedRecord = false;
 }
 // Enable this flag to delete any existing cache before fetching next record.
 getRecord.deleteRecordCache = false;
 // Enable this flag to tell that we are fetching a record that has just been
 // cloned (enables proper feedback, highlighting).
 getRecord.clonedRecord = false;
 
 
 function onGetRecordSuccess(json){
   /*
    * Handle successfull 'getRecord' requests.
    */
   cleanUp(!gNavigatingRecordSet);
   // Store record data.
   gRecID = json['recID'];
   gRecIDLoading = null;
   gRecRev = json['recordRevision'];
   gRecRevAuthor = json['revisionAuthor'];
   gPhysCopiesNum = json['numberOfCopies'];
   gBibCircUrl = json['bibCirculationUrl'];
   gDisplayBibCircPanel = json['canRecordHavePhysicalCopies'];
 
   var revDt = formatDateTime(getRevisionDate(gRecRev));
   var recordRevInfo = "record revision: " + revDt;
   var revAuthorString = gRecRevAuthor;
 
   /*$('.headline').html(
     'Record Editor: Record #<span id="spnRecID">' + gRecID + '</span>' +
     '<div style="margin-left: 5px; font-size: 0.5em; color: #36c;">' +
     recordRevInfo + ' ' + revAuthorString + '</div>').css('white-space', 'nowrap');*/
   $('.revisionLine').html(recordRevInfo + ' ' + revAuthorString)
   gRecord = json['record'];
   gTagFormat = json['tagFormat'];
   gRecordDirty = json['cacheDirty'];
   gCacheMTime = json['cacheMTime'];
 
   if (json['cacheOutdated']){
     // User had an existing outdated cache.
     displayCacheOutdatedScreen('getRecord');
     $('#lnkMergeCache').bind('click', onMergeClick);
     $('#lnkDiscardChanges').bind('click', function(event){
       getRecord.deleteRecordCache = true;
       getRecord(gRecID);
       event.preventDefault();
     });
     $('#lnkRemoveMsg').bind('click', function(event){
       $('#bibEditMessage').remove();
       event.preventDefault();
     });
   }
 
   gHoldingPenChanges = json['pendingHpChanges'];
   gDisabledHpEntries = json['disabledHpChanges'];
   gHoldingPenLoadedChanges = {};
 
   adjustHPChangesetsActivity();
   updateBibCirculationPanel();
 
   // updating the undo/redo lists
   gUndoList = json['undoList'];
   gRedoList = json['redoList'];
   updateUrView();
 
   // Display record.
   displayRecord();
   // Activate menu record controls.
   activateRecordMenu();
   // the current mode should is indicated by the result from the server
   gReadOnlyMode = (json['inReadOnlyMode'] != undefined) ? json['inReadOnlyMode'] : false;
   gRecLatestRev = (json['latestRevision'] != undefined) ? json['latestRevision'] : null;
   gRecRevisionHistory = (json['revisionsHistory'] != undefined) ? json['revisionsHistory'] : null;
 
   updateInterfaceAccordingToMode();
 
   if (gRecordDirty){
     $('#btnSubmit').removeAttr('disabled');
     $('#btnSubmit').css('background-color', 'lightgreen');
   }
   if (gTagFormat == 'MARC')
     $('#btnHumanTags').bind('click', onHumanTagsClick).removeAttr('disabled');
   else
     $('#btnMARCTags').bind('click', onMARCTagsClick).removeAttr('disabled');
   // Unfocus record selection field (to facilitate hotkeys).
   $('#txtSearchPattern').blur();
   if (json['resultCode'] == 9)
     $('#spnRecID').effect('highlight', {color: gCLONED_RECORD_COLOR},
       gCLONED_RECORD_COLOR_FADE_DURATION);
   updateStatus('report', gRESULT_CODES[json['resultCode']]);
   updateRevisionsHistory();
   adjustGeneralHPControlsVisibility();
 
   createReq({recID: gRecID, requestType: 'getTickets'}, onGetTicketsSuccess);
 
   updateToolbar(true);
 }
 
 function onGetTemplateSuccess(json) {
   onGetRecordSuccess(json);
 }
 
 function onSubmitClick(){
   /*
    * Handle 'Submit' button (submit record).
    */
   updateStatus('updating');
   if (displayAlert('confirmSubmit')){
     createReq({recID: gRecID, requestType: 'submit',
          force: onSubmitClick.force}, function(json){
        // Submission was successful.
       changeAndSerializeHash({state: 'submit', recid: gRecID});
       var resCode = json['resultCode'];
       cleanUp(!gNavigatingRecordSet, '', null, true);
       updateStatus('report', gRESULT_CODES[resCode]);
       displayMessage(resCode);
       resetBibeditState()
     });
     onSubmitClick.force = false;
     resetBibeditState();
   }
   else
     updateStatus('ready');
 }
 
 // Enable this flag to force the next submission even if cache is outdated.
 onSubmitClick.force = false;
 
 function onPreviewClick(){
   /*
    * Handle 'Preview' button (preview record).
    */
     createReq({recID: gRecID, requestType: 'preview'
        }, function(json){
        // Preview was successful.
         var html_preview = json['html_preview'];
         var preview_window = window.open('', '', 'width=768,height=768,resizeable,scrollbars');
         preview_window.document.write(html_preview);
         preview_window.document.close(); // needed for chrome and safari
        });
 }
 
 function onCancelClick(){
   /*
    * Handle 'Cancel' button (cancel editing).
    */
   updateStatus('updating');
   if (!gRecordDirty || displayAlert('confirmCancel')) {
   createReq({
     recID: gRecID,
     requestType: 'cancel'
   }, function(json){
     // Cancellation was successful.
       changeAndSerializeHash({
           state: 'cancel',
           recid: gRecID
         });
         cleanUp(!gNavigatingRecordSet, '', null, true, true);
         updateStatus('report', gRESULT_CODES[json['resultCode']]);
       });
       holdingPenPanelRemoveEntries();
       gUndoList = [];
       gRedoList = [];
       gReadOnlyMode = false;
       gRecRevisionHistory = [];
       gHoldingPenLoadedChanges = [];
       gHoldingPenChanges = [];
       gPhysCopiesNum = 0;
       gBibCircUrl = null;
       // making the changes visible
       updateBibCirculationPanel();
       updateInterfaceAccordingToMode();
       updateRevisionsHistory();
       updateUrView();
       updateToolbar(false);
 
     }
     else {
       updateStatus('ready');
     }
 }
 
 function onCloneRecordClick(){
   /*
    * Handle 'Clone' button (clone record).
    */
   updateStatus('updating');
   if (!displayAlert('confirmClone')){
     updateStatus('ready');
     return;
   }
   else if (!gRecordDirty)
     // If the record is unchanged, erase the cache.
     createReq({recID: gRecID, requestType: 'deleteRecordCache'});
   createReq({requestType: 'newRecord', newType: 'clone', recID: gRecID},
     function(json){
       var newRecID = json['newRecID'];
       $('#txtSearchPattern').val(newRecID);
       getRecord.clonedRecord = true;
       getRecord(newRecID);
   });
 }
 
 function onDeleteRecordClick(){
   /*
    * Handle 'Delete record' button.
    */
   if (gPhysCopiesNum > 0){
     displayAlert('errorPhysicalCopiesExist');
     return;
   }
   if (displayAlert('confirmDeleteRecord')){
     updateStatus('updating');
     createReq({recID: gRecID, requestType: 'deleteRecord'}, function(json){
       // Record deletion was successful.
       changeAndSerializeHash({state: 'deleteRecord', recid: gRecID});
       cleanUp(!gNavigatingRecordSet, '', null, true);
       var resCode = json['resultCode'];
       // now cleaning the interface - removing holding pen entries and record history
       resetBibeditState();
       updateStatus('report', gRESULT_CODES[resCode]);
       displayMessage(resCode);
       updateToolbar(false);
     });
   }
 }
 
 function onMergeClick(event){
   /*
    * Handle click on 'Merge' link (to merge outdated cache with current DB
    * version of record).
    */
   notImplemented(event);
 
   updateStatus('updating');
   createReq({recID: gRecID, requestType: 'prepareRecordMerge'}, function(json){
     // Null gRecID to avoid warning when leaving page.
     gRecID = null;
     var recID = json['recID'];
     window.location = gSITE_URL + '/record/merge/#recid1=' + recID + '&recid2=' +
       'tmp';
   });
   event.preventDefault();
 }
 
 function bindNewRecordHandlers(){
   /*
    * Bind event handlers to links on 'Create new record' page.
    */
   $('#lnkNewEmptyRecord').bind('click', function(event){
     updateStatus('updating');
     createReq({requestType: 'newRecord', newType: 'empty'}, function(json){
       getRecord(json['newRecID']);
     });
     event.preventDefault();
   });
   for (var i=0, n=gRECORD_TEMPLATES.length; i<n; i++)
     $('#lnkNewTemplateRecord_' + i).bind('click', function(event){
       updateStatus('updating');
       var templateNo = this.id.split('_')[1];
       createReq({requestType: 'newRecord', newType: 'template',
 	templateFilename: gRECORD_TEMPLATES[templateNo][0]}, function(json){
 	  getRecord(json['newRecID'], 0, onGetTemplateSuccess); // recRev = 0 -> current revision
       });
       event.preventDefault();
     });
 }
 
 function cleanUp(disableRecBrowser, searchPattern, searchType,
      focusOnSearchBox, resetHeadline){
   /*
    * Clean up display and data.
    */
   // Deactivate controls.
   deactivateRecordMenu();
   if (disableRecBrowser){
     disableRecordBrowser();
     gResultSet = null;
     gResultSetIndex = null;
     gNavigatingRecordSet = false;
   }
   // Clear main content area.
   /*if (resetHeadline)
     $('.headline').text('Record Editor');*/
   $('#bibEditContent').empty();
   // Clear search area.
   if (typeof(searchPattern) == 'string' || typeof(searchPattern) == 'number')
     $('#txtSearchPattern').val(searchPattern);
   if ($.inArray(searchType, ['recID', 'reportnumber', 'anywhere']) != -1)
     $('#sctSearchType').val(searchPattern);
   if (focusOnSearchBox)
     $('#txtSearchPattern').focus();
   // Clear tickets.
   $('#tickets').empty();
   // Clear data.
   gRecID = null;
   gRecord = null;
   gTagFormat = null;
   gRecordDirty = false;
   gCacheMTime = null;
   gSelectionMode = false;
   gReadOnlyMode = false;
   gHoldingPenLoadedChanges = null;
   gHoldingPenChanges = null;
   gUndoList = [];
   gRedoList = [];
   gBibCircUrl = null;
   gPhysCopiesNum = 0;
 }
 
 /*
  * **************************** 7. Editor UI ***********************************
  */
 
 function colorFields(){
   /*
    * Color every other field (rowgroup) gray to increase readability.
    */
   $('#bibEditTable tbody:even').each(function(){
     $(this).addClass('bibEditFieldColored');
   });
 }
 
 function reColorFields(){
   /*
    * Update coloring by removing existing, then recolor.
    */
   $('#bibEditTable tbody').each(function(){
     $(this).removeClass('bibEditFieldColored');
   });
   colorFields();
 }
 
 function onMARCTagsClick(event){
   /*
    * Handle 'MARC' link (MARC tags).
    */
   $(this).unbind('click').attr('disabled', 'disabled');
   createReq({recID: gRecID, requestType: 'changeTagFormat', tagFormat: 'MARC'});
   gTagFormat = 'MARC';
   updateTags();
   $('#btnHumanTags').bind('click', onHumanTagsClick).removeAttr('disabled');
   event.preventDefault();
 }
 
 function onHumanTagsClick(event){
   /*
    * Handle 'Human' link (Human tags).
    */
   $(this).unbind('click').attr('disabled', 'disabled');
   createReq({recID: gRecID, requestType: 'changeTagFormat',
        tagFormat: 'human'});
   gTagFormat = 'human';
   updateTags();
   $('#btnMARCTags').bind('click', onMARCTagsClick).removeAttr('disabled');
   event.preventDefault();
 }
 
 function onLnkSpecialSymbolsClick(){
     var special_char_list = ['&#192;','&#193;','&#194;','&#195;','&#196;','&#197;',
                             '&#198;','&#199;','&#200;','&#201;','&#202;','&#203;',
                             '&#204;','&#205;','&#206;','&#207;','&#208;','&#209;',
                             '&#210;','&#211;','&#212;','&#213;','&#214;','&#215;',
                             '&#216;','&#217;','&#218;','&#219;','&#220;','&#221;',
                             '&#222;','&#223;','&#224;','&#225;','&#226;','&#227;',
                             '&#228;','&#229;','&#230;','&#231;','&#232;','&#233;',
                             '&#234;','&#235;','&#236;','&#237;','&#238;','&#239;',
                             '&#240;','&#241;','&#242;','&#243;','&#244;','&#245;',
                             '&#246;','&#247;','&#248;','&#249;','&#250;','&#251;',
                             '&#252;','&#253;','&#254;','&#255;'];
     var html_content;
     html_content = '<html><head><title>Special Symbols</title>';
     html_content += '<style type="text/css">';
     html_content += '#char_table_div { padding: 20px 0px 0px 20px; }';
     html_content += '#symbol_table { border: 1px solid black; border-collapse:collapse;}';
     html_content += 'td { border: 1px solid black; padding: 5px 5px 5px 5px;}';
     html_content += '</style>';
     html_content += '</head><body>';
     html_content += '<div id="char_table_div"><table id="symbol_table"><tr>';
     var char_list_length = special_char_list.length;
     for (var i=0; i<char_list_length; i++) {
         html_content += '<td>' + special_char_list[i] + '</td>';
         if ((i+1)%10 == 0) {
             html_content += '</tr><tr>';
         }
     }
     html_content += '</tr></table></div></body></html>';
     var special_char_window = window.open('', '', 'width=310,height=310,resizeable,scrollbars');
     special_char_window.document.write(html_content);
     special_char_window.document.close(); // needed for chrome and safari
 }
 
 function updateTags(){
   /*
    * Check and update all tags (also subfield codes) against the currently
    * selected tag format.
    */
   $('.bibEditCellFieldTag').each(function(){
     var currentTag = $(this).text();
     var tmpArray = this.id.split('_');
     var tag = tmpArray[1], fieldPosition = tmpArray[2];
     var newTag = getFieldTag(getMARC(tag, fieldPosition));
     if (newTag != currentTag)
       $(this).text(newTag);
   });
   $('.bibEditCellSubfieldTag').each(function(){
     var currentTag = $(this).text();
     var tmpArray = this.id.split('_');
     var tag = tmpArray[1], fieldPosition = tmpArray[2],
       subfieldIndex = tmpArray[3];
     var newTag = getSubfieldTag(getMARC(tag, fieldPosition, subfieldIndex));
     if (newTag != currentTag)
       $(this).text(newTag);
   });
 }
 
 function onFieldBoxClick(box){
   /*
    * Handle field select boxes.
    */
   // Check/uncheck all subfield boxes, add/remove selected class.
   var rowGroup = $('#rowGroup_' + box.id.slice(box.id.indexOf('_')+1));
   if (box.checked){
     $(rowGroup).find('td[id^=content]').andSelf().addClass('bibEditSelected');
     if (gReadOnlyMode == false){
       $('#btnDeleteSelected').removeAttr('disabled');
     }
   }
   else{
     $(rowGroup).find('td[id^=content]').andSelf().removeClass(
       'bibEditSelected');
     if (!$('.bibEditSelected').length)
       // Nothing is selected, disable "Delete selected"-button.
       $('#btnDeleteSelected').attr('disabled', 'disabled');
   }
   $(rowGroup).find('input[type="checkbox"]').attr('checked', box.checked);
 }
 
 function onSubfieldBoxClick(box){
   /*
    * Handle subfield select boxes.
    */
   var tmpArray = box.id.split('_');
   var tag = tmpArray[1], fieldPosition = tmpArray[2],
     subfieldIndex = tmpArray[3];
   var fieldID = tag + '_' + fieldPosition;
   var subfieldID = fieldID + '_' + subfieldIndex;
   // If uncheck, uncheck field box and remove selected class.
   if (!box.checked){
     $('#content_' + subfieldID).removeClass('bibEditSelected');
     $('#boxField_' + fieldID).attr('checked', false);
     $('#rowGroup_' + fieldID).removeClass('bibEditSelected');
     if (!$('.bibEditSelected').length)
       // Nothing is selected, disable "Delete selected"-button.
       $('#btnDeleteSelected').attr('disabled', 'disabled');
   }
   // If check and all other subfield boxes checked, check field box, add
   // selected class.
   else{
     $('#content_' + subfieldID).addClass('bibEditSelected');
     var field = gRecord[tag][fieldPosition];
     if (field[0].length == $(
       '#rowGroup_' + fieldID + ' input[type=checkbox]' +
       '[class=bibEditBoxSubfield]:checked').length){
       $('#boxField_' + fieldID).attr('checked', true);
       $('#rowGroup_' + fieldID).addClass('bibEditSelected');
     }
     $('#btnDeleteSelected').removeAttr('disabled');
   }
 }
 
 function addFieldGatherInformations(fieldTmpNo){
   /** Gathering the information about a current form
       returns [template_num, data]
       This funcion saves the state of a form -> saving the template name and values only would
       not be enough. we want to know what has been modified in last-chosen template !
       data is in the same format as teh templates data.
   */
   var templateNum = $('#selectAddFieldTemplate_' + fieldTmpNo).attr("value");
   var tag = $("#txtAddFieldTag_" + fieldTmpNo).attr("value");
 
   // now checking if this is a controlfield ... controlfield if ind1 box is invisible
   if ($("#txtAddFieldInd1_" + fieldTmpNo + ":visible").length == 1){
     var ind1 = $("#txtAddFieldInd1_" + fieldTmpNo).attr("value");
     var ind2 = $("#txtAddFieldInd2_" + fieldTmpNo).attr("value");
     var subfieldTmpNo = $('#rowGroupAddField_' + fieldTmpNo).data('freeSubfieldTmpNo');
     var subfields = [];
     for (i=0;i<subfieldTmpNo;i++){
       var subfieldCode = $('#txtAddFieldSubfieldCode_' + fieldTmpNo + '_' + i).attr("value");
       var subfieldValue = $('#txtAddFieldValue_' + fieldTmpNo + '_' + i).attr("value");
       subfields.push([subfieldCode, subfieldValue]);
     }
 
     data = {
       "name": "nonexisting template - values taken from the field",
       "description": "The description of a template",
       "tag" : tag,
       "ind1" : ind1,
       "ind2" : ind2,
       "subfields" : subfields,
       "isControlfield" : false
     };
   } else {
     cfValue = $("#txtAddFieldValue_" + fieldTmpNo + "_0").attr("value");
     data = {
       "name": "nonexisting template - values taken from the field",
       "description": "The description of a template",
       "tag" : tag,
       "value" : cfValue,
       "isControlfield" : true
     }
   }
 
   return [templateNum, data];
 }
 
 function addFieldAddSubfieldEditor(jQRowGroupID, fieldTmpNo, defaultCode, defaultValue){
   /**
      Adding a subfield input control into the editor
      optional parameters:
 
      defaultCode - the subfield code that will be displayed
      defaultValue - the value that will be displayed by default in the editor
   */
   var subfieldTmpNo = $(jQRowGroupID).data('freeSubfieldTmpNo');
   $(jQRowGroupID).data('freeSubfieldTmpNo', subfieldTmpNo+1);
 
   var addFieldRows = $(jQRowGroupID + ' tr');
 
   $(addFieldRows).eq(addFieldRows.length-1).before(createAddFieldRow(
     fieldTmpNo, subfieldTmpNo, defaultCode, defaultValue));
   $('#txtAddFieldSubfieldCode_' + fieldTmpNo + '_' + subfieldTmpNo).bind(
     'keyup', onAddFieldChange);
   $('#btnAddFieldRemove_' + fieldTmpNo + '_' + subfieldTmpNo).bind('click', function(){
     $('#rowAddField_' + this.id.slice(this.id.indexOf('_')+1)).remove();
   });
   $('#txtAddFieldValue_' + fieldTmpNo + '_' + subfieldTmpNo).bind(
     'focus', function(){
       if ($(this).hasClass('bibEditVolatileSubfield')){
         $(this).select();
         $(this).removeClass("bibEditVolatileSubfield");
       }
     });
   var contentEditorId = '#txtAddFieldValue_' + fieldTmpNo + '_' + subfieldTmpNo;
   $(contentEditorId).bind('keyup', function(e){
     onAddFieldValueKeyPressed(e, jQRowGroupID, fieldTmpNo, subfieldTmpNo);
   });
 
 }
 
 function onAddFieldJumpToNextSubfield(jQRowGroupID, fieldTmpNo, subfieldTmpNo){
   // checking, how many subfields are there and if last, submitting the form
   var numberOfSubfields = $(jQRowGroupID).data('freeSubfieldTmpNo');
   if (subfieldTmpNo < (numberOfSubfields - 1)){
     var elementCode = "#txtAddFieldSubfieldCode_" + fieldTmpNo + "_" + (subfieldTmpNo + 1);
     $(elementCode)[0].focus();
   }
   else{
     addFieldSave(fieldTmpNo);
   }
 }
 
 function applyFieldTemplate(jQRowGroupID, formData, fieldTmpNo){
   /** A function that applies a template
       formNo is the number of addfield form that is treated at teh moment
       formData is the data of the field template
   */
 
   // first cleaning the existing fields
 
   $(jQRowGroupID).data('isControlfield', formData.isControlfield);
   if (formData.isControlfield){
     changeFieldToControlfield(fieldTmpNo);
     $("#txtAddFieldTag_" + fieldTmpNo).attr("value", formData.tag);
     $("#txtAddFieldInd1_" + fieldTmpNo).attr("value", '');
     $("#txtAddFieldInd2_" + fieldTmpNo).attr("value", '');
     $("#txtAddFieldValue_" + fieldTmpNo + "_0").attr("value", formData.value);
   }
   else
   {
     changeFieldToDatafield(fieldTmpNo);
     var subfieldTmpNo = $(jQRowGroupID).data('freeSubfieldTmpNo');
     $(jQRowGroupID).data('freeSubfieldTmpNo', 0);
 
     for (i=subfieldTmpNo-1; i>=0; i--){
       $('#rowAddField_' + fieldTmpNo + '_' + i).remove();
     }
 
     for (subfieldInd in formData.subfields){
       subfield = formData.subfields[subfieldInd];
       addFieldAddSubfieldEditor(jQRowGroupID, fieldTmpNo, subfield[0], subfield[1]);
     }
 
     // now changing the main field properties
     $("#txtAddFieldTag_" + fieldTmpNo).attr("value", formData.tag);
     $("#txtAddFieldInd1_" + fieldTmpNo).attr("value", formData.ind1);
     $("#txtAddFieldInd2_" + fieldTmpNo).attr("value", formData.ind2);
   }
 }
 
 function createAddFieldInterface(initialContent, initialTemplateNo){
-  // Create form and scroll close to the top of the table.
-  $(document).scrollTop(0);
+  /* Create form to add a new field. If only one field is selected, the
+   * new field will be inserted below it. Otherwise, the new field will
+   * be inserted in the 3rd position
+   */
+
+  // Check if we are in the use case of adding in a specific position
+  var selected_fields = getSelectedFields();
+  var insert_below_selected = false;
+  if (selected_fields != undefined) {
+      var count_fields = 0;
+      var selected_local_field_pos;
+      var selected_tag;
+      for (var tag in selected_fields.fields) {
+          for (var localFieldPos in selected_fields.fields[tag]) {
+              count_fields++;
+              selected_local_field_pos = localFieldPos;
+          }
+          selected_tag = tag;
+      }
+      if (count_fields === 1)
+          insert_below_selected = true;
+  }
+
   var fieldTmpNo = onAddFieldClick.addFieldFreeTmpNo++;
   var jQRowGroupID = '#rowGroupAddField_' + fieldTmpNo;
   $('#bibEditColFieldTag').css('width', '90px');
   var tbodyElements = $('#bibEditTable tbody');
-  var insertionPoint = (tbodyElements.length >= 4) ? 3 : tbodyElements.length-1;
-  $('#bibEditTable tbody').eq(insertionPoint).after(
-    createAddFieldForm(fieldTmpNo, initialTemplateNo));
+
+  // If only one field selected, add below the selected field
+  if (insert_below_selected === true) {
+      $('#rowGroup' + '_' + selected_tag + '_' + selected_local_field_pos).after(
+      createAddFieldForm(fieldTmpNo, initialTemplateNo));
+      $(jQRowGroupID).data('insertionPoint', parseInt(selected_local_field_pos) + 1);
+      $(jQRowGroupID).data('selected_tag', selected_tag);
+  }
+  else {
+      var insertionPoint = (tbodyElements.length >= 4) ? 3 : tbodyElements.length-1;
+      $('#bibEditTable tbody').eq(insertionPoint).after(
+      createAddFieldForm(fieldTmpNo, initialTemplateNo));
+  }
+  
   $(jQRowGroupID).data('freeSubfieldTmpNo', 1);
 
   // Bind event handlers.
   $('#btnAddFieldAddSubfield_' + fieldTmpNo).bind('click', function(){
     addFieldAddSubfieldEditor(jQRowGroupID, fieldTmpNo, "", "");
   });
   $('#txtAddFieldTag_' + fieldTmpNo).bind('keyup', onAddFieldChange);
   $('#txtAddFieldInd1_' + fieldTmpNo).bind('keyup', onAddFieldChange);
   $('#txtAddFieldInd2_' + fieldTmpNo).bind('keyup', onAddFieldChange);
   $('#txtAddFieldSubfieldCode_' + fieldTmpNo + '_0').bind('keyup',
 							  onAddFieldChange);
   $('#txtAddFieldValue_' + fieldTmpNo + '_0').bind('keyup', function (e){
     onAddFieldValueKeyPressed(e, jQRowGroupID, fieldTmpNo, 0);
   });
 
   $('#selectAddFieldTemplate_' + fieldTmpNo).bind('change', function(e){
       value = $('#selectAddFieldTemplate_' + fieldTmpNo).attr("value");
       applyFieldTemplate(jQRowGroupID, fieldTemplates[value], fieldTmpNo);
   });
   $('#selectAddSimilarFields_' + fieldTmpNo).bind('click', function(e){
     var data = addFieldGatherInformations(fieldTmpNo);
     var numRepetitions = parseInt($('#selectAddFieldTemplateTimes_' + fieldTmpNo).attr('value'));
     for (var i=0; i< numRepetitions; i++){
       createAddFieldInterface(data[1], data[0]);
     }
   });
 
   if (initialContent != undefined){
     applyFieldTemplate(jQRowGroupID, initialContent , fieldTmpNo);
   }else{
     $(jQRowGroupID).data('isControlfield', false);
   }
-
   reColorFields();
   $('#txtAddFieldTag_' + fieldTmpNo).focus();
   // Color the new form for a short period.
   $(jQRowGroupID).effect('highlight', {color: gNEW_ADD_FIELD_FORM_COLOR},
     gNEW_ADD_FIELD_FORM_COLOR_FADE_DURATION);
 
 }
 
 function onAddSubfieldValueKeyPressed(e, tag, fieldPosition, subfieldPosition){
   if (e.which == 13){
     // enter key pressed.
     var subfieldsNum = $('#rowGroup_' + tag + '_' + fieldPosition + ' .bibEditTxtSubfieldCode').length;
     if (subfieldPosition < (subfieldsNum - 1)){
       //jump to the next field
       $('#txtAddSubfieldsCode_' + tag + '_' + fieldPosition + '_' + (subfieldPosition + 1))[0].focus();
     } else {
       onAddSubfieldsSave(e, tag, fieldPosition);
     }
   }
   if (e.which == 27){
     // escape key pressed
     $('#rowAddSubfields_' + tag + '_' + fieldPosition + '_' + 0).nextAll().andSelf().remove();
   }
 }
 
 function onAddFieldValueKeyPressed(e, jQRowGroupID, fieldTmpNo, subfieldInd){
   if (e.which == 13){
     // enter key pressed
     onAddFieldJumpToNextSubfield(jQRowGroupID, fieldTmpNo, subfieldInd);
   }
   if (e.which == 27){
     // escape key pressed
     $(jQRowGroupID).remove();
     if (!$('#bibEditTable > [id^=rowGroupAddField]').length)
       $('#bibEditColFieldTag').css('width', '48px');
     reColorFields();
   }
 }
 function onAddFieldClick(){
   /*
    * Handle 'Add field' button.
    */
   if (failInReadOnly())
     return;
   createAddFieldInterface();
 }
 
 // Incrementing temporary field numbers.
 onAddFieldClick.addFieldFreeTmpNo = 100000;
 
 function changeFieldToControlfield(fieldTmpNo){
   /**
      Switching the field to be a control field
    */
 
   // removing additional entries
   var addFieldRows = $('#rowGroupAddField_' + fieldTmpNo + ' tr');
   $(addFieldRows).slice(2, addFieldRows.length-1).remove();
 
   // Clear all fields.
   var addFieldTextInput = $('#rowGroupAddField_' + fieldTmpNo +
           ' input[type=text]');
   $(addFieldTextInput).val('').removeClass('bibEditInputError');
 
   // Toggle hidden fields.
   var elems = $('#txtAddFieldInd1_' + fieldTmpNo + ', #txtAddFieldInd2_' +
     fieldTmpNo + ', #txtAddFieldSubfieldCode_' + fieldTmpNo + '_0,' +
     '#btnAddFieldAddSubfield_' + fieldTmpNo).hide();
 
   $('#txtAddFieldTag_' + fieldTmpNo).focus();
 }
 
 function changeFieldToDatafield(fieldTmpNo){
   /**
      Switching the field to be a datafield
    */
   // making the elements visible
   var elems = $('#txtAddFieldInd1_' + fieldTmpNo + ', #txtAddFieldInd2_' +
     fieldTmpNo + ', #txtAddFieldSubfieldCode_' + fieldTmpNo + '_0,' +
     '#btnAddFieldAddSubfield_' + fieldTmpNo).show();
 
   $('#txtAddFieldTag_' + fieldTmpNo).focus();
 }
 
 function onAddFieldChange(event){
   /*
    * Validate MARC and add or remove error class.
    */
 
   // first handling the case of escape key, which is a little different that others
   var fieldTmpNo = this.id.split('_')[1];
 
   if (event.which == 27){
     // escape key pressed
     var jQRowGroupID = "#rowGroupAddField_" + fieldTmpNo;
     $(jQRowGroupID).remove();
     if (!$('#bibEditTable > [id^=rowGroupAddField]').length)
       $('#bibEditColFieldTag').css('width', '48px');
     reColorFields();
   }
   else if (this.value.length == this.maxLength){
     var fieldType;
     if (this.id.indexOf('Tag') != -1){
       var jQRowGroupID = "#rowGroupAddField_" + fieldTmpNo;
       fieldType = ($(jQRowGroupID).data('isControlfield')) ? 'ControlTag' : 'Tag';
     }
     else if (this.id.indexOf('Ind1') != -1)
       fieldType = 'Indicator1';
     else if (this.id.indexOf('Ind2') != -1)
       fieldType = 'Indicator2';
     else
       fieldType = 'SubfieldCode';
 
     var valid = (((fieldType == 'Indicator1' || fieldType == 'Indicator2')
       && (this.value == '_' || this.value == ' '))
      || validMARC(fieldType, this.value));
     if (!valid && !$(this).hasClass('bibEditInputError'))
       $(this).addClass('bibEditInputError');
     else if (valid){
       if ($(this).hasClass('bibEditInputError'))
   $(this).removeClass('bibEditInputError');
       if (event.keyCode != 9 && event.keyCode != 16){
 	switch(fieldType){
 	  case 'ControlTag':
 	    $(this).parent().nextAll().eq(3).children('input').focus();
 	    break;
 	  case 'Tag':
 	  case 'Indicator1':
 	    $(this).next().focus();
 	    break;
 	  case 'Indicator2':
           // in case the indicator is present, we can be sure this is not a control field... so we can safely jump to the subfield code input
           $('#txtAddFieldSubfieldCode_' + fieldTmpNo + '_0')[0].focus();
 	    break;
 	  case 'SubfieldCode':
 	    $(this).parent().next().children('input').focus();
 	    break;
 	  default:
 	    ;
 	}
       }
     }
   }
   else if ($(this).hasClass('bibEditInputError'))
     $(this).removeClass('bibEditInputError');
 }
 
 function onAddFieldSave(event){
   var fieldTmpNo = this.id.split('_')[1];
   addFieldSave(fieldTmpNo);
 }
 
 function addFieldSave(fieldTmpNo)
 {
   /*
    * Handle 'Save' button in add field form.
    */
   updateStatus('updating');
 
   var jQRowGroupID = "#rowGroupAddField_" + fieldTmpNo;
   var controlfield = $(jQRowGroupID).data('isControlfield');
   var tag = $('#txtAddFieldTag_' + fieldTmpNo).val();
   var value = $('#txtAddFieldValue_' + fieldTmpNo + '_0').val();
   var subfields = [], ind1 = ' ', ind2 = ' ';
 
+  // variables used when we are adding a field in a specific position
+  var insertPosition = $(jQRowGroupID).data('insertionPoint');
+  var selected_tag = $(jQRowGroupID).data('selected_tag');
+
   if (controlfield){
     // Controlfield. Validate and prepare to update.
     if (fieldIsProtected(tag)){
       displayAlert('alertAddProtectedField', [tag]);
       updateStatus('ready');
       return;
     }
     if (!validMARC('ControlTag', tag) || value == ''){
       displayAlert('alertCriticalInput');
       updateStatus('ready');
       return;
     }
     var field = [[], ' ', ' ', value, 0];
     var fieldPosition = getFieldPositionInTag(tag, field);
   }
   else{
     // Regular field. Validate and prepare to update.
     ind1 = $('#txtAddFieldInd1_' + fieldTmpNo).val();
     ind1 = (ind1 == '' || ind1 == '_') ? ' ' : ind1;
     ind2 = $('#txtAddFieldInd2_' + fieldTmpNo).val();
     ind2 = (ind2 == '' || ind2 == '_') ? ' ' : ind2;
     var MARC = tag + ind1 + ind2;
     if (fieldIsProtected(MARC)){
       displayAlert('alertAddProtectedField', [MARC]);
       updateStatus('ready');
       return;
     }
     var validInd1 = (ind1 == ' ' || validMARC('Indicator1', ind1));
     var validInd2 = (ind2 == ' ' || validMARC('Indicator2', ind2));
     if (!validMARC('Tag', tag)
   || !validInd1
   || !validInd2){
       displayAlert('alertCriticalInput');
       updateStatus('ready');
       return;
     }
     // Collect valid subfields in an array.
     var invalidOrEmptySubfields = false;
      $('#rowGroupAddField_' + fieldTmpNo + ' .bibEditTxtSubfieldCode'
       ).each(function(){
         var subfieldTmpNo = this.id.slice(this.id.lastIndexOf('_')+1);
         var txtValue = $('#txtAddFieldValue_' + fieldTmpNo + '_' +
     subfieldTmpNo);
         var value = $(txtValue).val();
         var isStillVolatile = txtValue.hasClass('bibEditVolatileSubfield');
 
         if (!$(this).hasClass('bibEditInputError')
           && this.value != ''
 	  && !$(txtValue).hasClass('bibEditInputError')
           && value != ''){
             if (!isStillVolatile){
               subfields.push([this.value, value]);
             }
         }
         else
           invalidOrEmptySubfields = true;
       });
 
     if (invalidOrEmptySubfields){
       if (!subfields.length){
   // No valid subfields.
   displayAlert('alertCriticalInput');
   updateStatus('ready');
   return;
       }
       else if (!displayAlert('confirmInvalidOrEmptyInput')){
   updateStatus('ready');
   return;
       }
     }
 
     if (subfields[0] == undefined){
       displayAlert('alertEmptySubfieldsList');
       return;
     }
     var field = [subfields, ind1, ind2, '', 0];
-    var fieldPosition = getFieldPositionInTag(tag, field);
+    var fieldPosition;
+    if ((insertPosition != undefined) && (tag == selected_tag)) {
+        fieldPosition = $(jQRowGroupID).data('insertionPoint');
+    }
+    else {
+        fieldPosition = getFieldPositionInTag(tag, field);
+    }
   }
 
   // adding an undo handler
   var undoHandler = prepareUndoHandlerAddField(tag,
                                                ind1,
                                                ind2,
                                                fieldPosition,
                                                subfields,
                                                controlfield,
                                                value);
   addUndoOperation(undoHandler);
 
   // Create Ajax request.
   var data = {
     recID: gRecID,
     requestType: 'addField',
     controlfield: controlfield,
     fieldPosition: fieldPosition,
     tag: tag,
     ind1: ind1,
     ind2: ind2,
     subfields: subfields,
     value: value,
     undoRedo: undoHandler
   };
   createReq(data, function(json){
     updateStatus('report', gRESULT_CODES[json['resultCode']]);
   });
 
   // Continue local updating.
   var fields = gRecord[tag];
   // New field?
-  if (!fields)
+  if (!fields) {
     gRecord[tag] = [field];
+  }
   else{
     fields.splice(fieldPosition, 0, field);
   }
   // Remove form.
   $('#rowGroupAddField_' + fieldTmpNo).remove();
   if (!$('#bibEditTable > [id^=rowGroupAddField]').length)
       $('#bibEditColFieldTag').css('width', '48px');
   // Redraw all fields with the same tag and recolor the full table.
   redrawFields(tag);
   reColorFields();
-  // Scroll to and color the new field for a short period.
+  // Scroll and color the new field for a short period.
   var rowGroup = $('#rowGroup_' + tag + '_' + fieldPosition);
-  $(document).scrollTop($(rowGroup).position().top - $(window).height()*0.5);
+  $('#bibEditContent').scrollTop($(rowGroup).position().top);
   $(rowGroup).effect('highlight', {color: gNEW_CONTENT_COLOR},
          gNEW_CONTENT_COLOR_FADE_DURATION);
 }
 
 
 function onAddSubfieldsClick(img){
   /*
    * Handle 'Add subfield' buttons.
    */
   var fieldID = img.id.slice(img.id.indexOf('_')+1);
   addSubfield(fieldID);
 }
 
 function addSubfield(fieldID, defSubCode, defValue) {
   /* add a subfield based on fieldID, where the first 3 digits are
    * the main tag, followed by _ and the position of the field.
    * defSubCode = the default value for subfield code
   */
   var jQRowGroupID = '#rowGroup_' + fieldID;
   var tmpArray = fieldID.split('_');
   var tag = tmpArray[0];var fieldPosition = tmpArray[1];
   if ($('#rowAddSubfieldsControls_' + fieldID).length == 0){
     // The 'Add subfields' form does not exist for this field.
     $(jQRowGroupID).append(createAddSubfieldsForm(fieldID, defSubCode, defValue));
     $(jQRowGroupID).data('freeSubfieldTmpNo', 1);
     $('#txtAddSubfieldsCode_' + fieldID + '_' + 0).bind('keyup',
       onAddSubfieldsChange);
     $('#txtAddSubfieldsValue_' + fieldID + '_0').bind('keyup', function (e){
       onAddSubfieldValueKeyPressed(e, tag, fieldPosition, 0);
     });
     $('#txtAddSubfieldsCode_' + fieldID + '_' + 0).focus();
   }
   else{
     // The 'Add subfields' form exist for this field. Just add another row.
     var subfieldTmpNo = $(jQRowGroupID).data('freeSubfieldTmpNo');
     $(jQRowGroupID).data('freeSubfieldTmpNo', subfieldTmpNo+1);
     var subfieldTmpID = fieldID + '_' + subfieldTmpNo;
     $('#rowAddSubfieldsControls_' + fieldID).before(
       createAddSubfieldsRow(fieldID, subfieldTmpNo));
     $('#txtAddSubfieldsCode_' + subfieldTmpID).bind('keyup',
       onAddSubfieldsChange);
     $('#btnAddSubfieldsRemove_' + subfieldTmpID).bind('click', function(){
       $('#rowAddSubfields_' + subfieldTmpID).remove();
     });
     $('#txtAddSubfieldsValue_' + subfieldTmpID).bind('keyup', function (e){
       onAddSubfieldValueKeyPressed(e, tag, fieldPosition, subfieldTmpNo);
     });
   }
 }
 
 function onAddSubfieldsChange(event){
   /*
    * Validate subfield code and add or remove error class.
    */
   if (this.value.length == 1){
     var valid = validMARC('SubfieldCode', this.value);
     if (!valid && !$(this).hasClass('bibEditInputError'))
       $(this).addClass('bibEditInputError');
     else if (valid){
       if ($(this).hasClass('bibEditInputError'))
   $(this).removeClass('bibEditInputError');
       if (event.keyCode != 9 && event.keyCode != 16){
   $(this).parent().next().children('input').focus();
       }
     }
   }
   else if ($(this).hasClass('bibEditInputError'))
     $(this).removeClass('bibEditInputError');
 }
 
 function onAddSubfieldsSave(event, tag, fieldPosition){
   /*
    * Handle 'Save' button in add subfields form.
    */
   updateStatus('updating');
 
 //  var tmpArray = this.id.split('_');
 //  var tag = tmpArray[1], fieldPosition = tmpArray[2];
   var fieldID = tag + '_' + fieldPosition;
   var subfields = [];
   var protectedSubfield = false, invalidOrEmptySubfields = false;
   // Collect valid fields in an array.
   $('#rowGroup_' + fieldID + ' .bibEditTxtSubfieldCode'
    ).each(function(){
      var MARC = getMARC(tag, fieldPosition) + this.value;
      if ($.inArray(MARC, gPROTECTED_FIELDS) != -1){
        protectedSubfield = MARC;
        return false;
      }
      var subfieldTmpNo = this.id.slice(this.id.lastIndexOf('_')+1);
      var txtValue = $('#txtAddSubfieldsValue_' + fieldID + '_' +
        subfieldTmpNo);
      var value = $(txtValue).val();
      if (!$(this).hasClass('bibEditInputError')
    && this.value != ''
    && !$(txtValue).hasClass('bibEditInputError')
    && value != '')
        subfields.push([this.value, value]);
      else
        invalidOrEmptySubfields = true;
   });
 
   // Report problems, like protected, empty or invalid fields.
   if (protectedSubfield){
     displayAlert('alertAddProtectedSubfield');
     updateStatus('ready');
     return;
   }
   if (invalidOrEmptySubfields && !displayAlert('confirmInvalidOrEmptyInput')){
     updateStatus('ready');
     return;
   }
 
   if (!subfields.length == 0){
      // creating the undo/redo handler
     var urHandler = prepareUndoHandlerAddSubfields(tag, fieldPosition, subfields);
     addUndoOperation(urHandler);
     // Create Ajax request
     var data = {
       recID: gRecID,
       requestType: 'addSubfields',
       tag: tag,
       fieldPosition: fieldPosition,
       subfields: subfields,
       undoRedo: urHandler
     };
     createReq(data, function(json){
       updateStatus('report', gRESULT_CODES[json['resultCode']]);
     });
 
     // Continue local updating
     var field = gRecord[tag][fieldPosition];
     field[0] = field[0].concat(subfields);
     var rowGroup  = $('#rowGroup_' + fieldID);
     var coloredRowGroup = $(rowGroup).hasClass('bibEditFieldColored');
     $(rowGroup).replaceWith(createField(tag, field, fieldPosition));
     if (coloredRowGroup)
       $('#rowGroup_' + fieldID).addClass('bibEditFieldColored');
 
     // Color the new fields for a short period.
     var rows = $('#rowGroup_' + fieldID + ' tr');
     $(rows).slice(rows.length - subfields.length).effect('highlight', {
       color: gNEW_CONTENT_COLOR}, gNEW_CONTENT_COLOR_FADE_DURATION);
   }
   else{
     // No valid fields were submitted.
     $('#rowAddSubfields_' + fieldID + '_' + 0).nextAll().andSelf().remove();
     updateStatus('ready');
   }
 }
 
 function convertFieldIntoEditable(cell, shouldSelect){
   // chacking if the clicked field is still present int the DOM structure ... if not, we have just removed the element
   if ($(cell).parent().parent().parent()[0] == undefined){
     return;
   }
   // first we have to detach all exisiting editables ... which means detaching the event
   editEvent = 'click';
   $(cell).unbind(editEvent);
 
   $(cell).editable(
     function(value){
       newVal = onContentChange(value, this);
       if (newVal.substring(0,9) == "VOLATILE:"){
         $(cell).addClass("bibEditVolatileSubfield");
         newVal = newVal.substring(9);
         $(cell).addClass("bibEditVolatileSubfield");
         if (!shouldSelect){
           // the field should start selecting all the content upon the click
           convertFieldIntoEditable(cell, true);
         }
       }
       else{
         $(cell).removeClass("bibEditVolatileSubfield");
         if (shouldSelect){
           // this is a volatile field any more - clicking should not
           // select all the content inside.
           convertFieldIntoEditable(cell, false);
         }
       }
 
       return newVal;
     }, {
       type: 'autogrow',
       callback: function(data, settings){
         var tmpArray = this.id.split('_');
         var tag = tmpArray[1], fieldPosition = tmpArray[2],
         subfieldIndex = tmpArray[3];
 
         for (changeNum in gHoldingPenChanges){
           change =  gHoldingPenChanges[changeNum];
           if (change.tag == tag &&
               change.field_position == fieldPosition &&
               change.subfield_position != undefined &&
               change.subfield_position == subfieldIndex){
               addChangeControl(changeNum, true);
           }
         }
       },
       event: editEvent,
       data: function(){
         // Get the real content from the record structure (instead of
         // from the view, where HTML entities are escaped).
         var tmpArray = this.id.split('_');
         var tag = tmpArray[1], fieldPosition = tmpArray[2],
         subfieldIndex = tmpArray[3];
         var field = gRecord[tag][fieldPosition];
         var tmpResult = "";
         if (tmpArray[0] == 'fieldTag'){
             var ind1 = (field[1] == " ") ? "_" : field[1];
             var ind2 = (field[2] == " ") ? "_" : field[2];
             tmpResult = tag + ind1 + ind2;
         }
         else if (subfieldIndex == undefined){
           // Controlfield
           tmpResult = field[3];
         }
         else if (tmpArray[0] == 'subfieldTag'){
             tmpResult = field[0][subfieldIndex][0];
         }
         else {
             tmpResult = field[0][subfieldIndex][1];
         }
         if (tmpResult.substring(0,9) == "VOLATILE:"){
           tmpResult = tmpResult.substring(9);
         }
         return tmpResult;
       },
       placeholder: '',
       width: '100%',
       onblur: 'submit',
       select: shouldSelect,
       autogrow: {
         lineHeight: 16,
         minHeight: 36
       }
     });
 }
 
 function onContentClick(cell){
   /*
    * Handle click on editable content fields.
    */
   // Check if subfield is volatile subfield from a template
   var shouldSelect = false;
   if ( $(cell).hasClass('bibEditVolatileSubfield') ){
     shouldSelect = true;
   }
   if (!$(cell).hasClass('edit_area')){
     $(cell).addClass('edit_area').removeAttr('onclick');
     convertFieldIntoEditable(cell, shouldSelect);
     $(cell).trigger('click');
   }
 }
 
 function getUpdateSubfieldValueRequestData(tag, fieldPosition, subfieldIndex, 
         subfieldCode, value, changeNo, undoDescriptor, modifySubfieldCode){
   var requestType;
   if (modifySubfieldCode == true) {
       requestType = 'modifySubfieldTag';
   }
   else {
       requestType = 'modifyContent';
   }
   var data = {
     recID: gRecID,
     requestType: requestType,
     tag: tag,
     fieldPosition: fieldPosition,
     subfieldIndex: subfieldIndex,
     subfieldCode: subfieldCode,
     value: value
   };
   if (changeNo != undefined && changeNo != -1){
     data.hpChanges = {toDisable: [changeNo]};
   }
   if (undoDescriptor != undefined && undoDescriptor != null){
     data.undoRedo = undoDescriptor;
   }
   return data;
 }
 
 function updateSubfieldValue(tag, fieldPosition, subfieldIndex, subfieldCode, 
                             value, consumedChange, undoDescriptor,
                             modifySubfieldCode){
   updateStatus('updating');
   // Create Ajax request for simple updating the subfield value
   if (consumedChange == undefined || consumedChange == null){
     consumedChange = -1;
   }
   
   var data = getUpdateSubfieldValueRequestData(tag,
                                                fieldPosition,
                                                subfieldIndex,
                                                subfieldCode,
                                                value,
                                                consumedChange,
                                                undoDescriptor,
                                                modifySubfieldCode);
 
   createReq(data, function(json){
     updateStatus('report', gRESULT_CODES[json['resultCode']]);
   });
 }
 
 function updateFieldTag(oldTag, newTag, oldInd1, oldInd2, ind1, ind2, fieldPosition,
                         consumedChange, undoDescriptor){
   updateStatus('updating');
   // Create Ajax request for simple updating the subfield value
   if (consumedChange == undefined || consumedChange == null){
       consumedChange = -1;
   }
   var data = getUpdateFieldTagRequestData(oldTag,
                                           oldInd1,
                                           oldInd2,
                                           newTag,
                                           ind1,
                                           ind2,
                                           fieldPosition,
                                           consumedChange,
                                           undoDescriptor);
 
   createReq(data, function(json){
     updateStatus('report', gRESULT_CODES[json['resultCode']]);
   });
 }
 
 function getUpdateFieldTagRequestData(oldTag, oldInd1, oldInd2, newTag, ind1, ind2,
                                       fieldPosition, changeNo, undoDescriptor){
   var data = {
     recID: gRecID,
     requestType: "modifyFieldTag",
     fieldPosition: fieldPosition,
     oldTag: oldTag,
     newTag: newTag,
     ind1: ind1,
     ind2: ind2,
     oldInd1: oldInd1,
     oldInd2: oldInd2
   };
   if (changeNo != undefined && changeNo != -1){
     data.hpChanges = {toDisable: [changeNo]};
   }
   if (undoDescriptor != undefined && undoDescriptor != null){
     data.undoRedo = undoDescriptor;
   }
 
   // updating the local model
   var currentField = gRecord[oldTag][fieldPosition];
   currentField[1] = ind1;
   currentField[2] = ind2;
   gRecord[oldTag].splice(fieldPosition,1);
   if (gRecord[oldTag].length == 0){
       delete gRecord[oldTag];
   }
   var fieldNewPos;
   if (gRecord[newTag] == undefined) {
       fieldNewPos = 0;
       gRecord[newTag] = [];
       gRecord[newTag][fieldNewPos] = currentField;
   }
   else {
       fieldNewPos = gRecord[newTag].length;
       gRecord[newTag].splice(fieldNewPos, 0, currentField);
   }
   // changing the display .... what if being edited right now ?
   redrawFields(oldTag);
   redrawFields(newTag);
   reColorFields();
 
   return data;
 }
 
 /*call autosuggest, get the values, suggest them to the user*/
 /*this is typically called when autosuggest key is pressed*/
 function onAutosuggest(event) {
   var mytarget = event.target;
   if (event.srcElement) mytarget = event.srcElement;/*fix for IE*/
   var myparent = mytarget.parentNode;
   var mygrandparent = myparent.parentNode;
   var parentid = myparent.id;
   var value = mytarget.value;
   var mylen = value.length;
   var replacement = ""; //used by autocomplete
   var tmpArray = mygrandparent.id.split('_');
   /*ids for autosuggest/autocomplete html elements*/
   var content_id = 'content_'+tmpArray[1]+'_'+tmpArray[2]+'_'+tmpArray[3];
   var autosuggest_id = 'autosuggest_'+tmpArray[1]+'_'+tmpArray[2]+'_'+tmpArray[3];
   var select_id = 'select_'+tmpArray[1]+'_'+tmpArray[2]+'_'+tmpArray[3];
   var maintag = tmpArray[1], fieldPosition = tmpArray[2],
 	  subfieldIndex = tmpArray[3];
   var field = gRecord[maintag][fieldPosition];
   var subfieldcode = field[0][subfieldIndex][0];
   var subtag1 = field[1];
   var subtag2 = field[2];
   //check if this an autosuggest or autocomplete field.
   var fullcode = getMARC(maintag, fieldPosition, subfieldIndex);
   var reqtype = ""; //autosuggest or autocomplete, according to tag..
   for (var i=0;i<gAUTOSUGGEST_TAGS.length;i++) {if (fullcode == gAUTOSUGGEST_TAGS[i]) {reqtype = "autosuggest"}}
   for (var i=0;i<gAUTOCOMPLETE_TAGS.length;i++) {if (fullcode == gAUTOCOMPLETE_TAGS[i]) {reqtype = "autocomplete"}}
   if (fullcode == gKEYWORD_TAG) {reqtype = "autokeyword"}
   if (reqtype == "") {
     return;
   }
 
   // Create Ajax request.
   var data = {
     recID: gRecID,
     maintag: maintag,
     subtag1: subtag1,
     subtag2: subtag2,
     subfieldcode: subfieldcode,
     requestType: reqtype,
     value: value
   }; //reqtype is autosuggest, autocomplete or autokeyword
   createReq(data, function(json){
     updateStatus('report', gRESULT_CODES[json['resultCode']]);
     suggestions = json[reqtype];
     if (reqtype == 'autocomplete') {
         if ((suggestions != null) && (suggestions.length > 0)) {
             //put the first one "here"
             replacement = suggestions[0];
             var myelement = document.getElementById(mygrandparent.id);
             if (myelement != null) {
                //put in the the gRecord
                gRecord[maintag][fieldPosition][0][subfieldIndex][1] = replacement;
                mytarget.value = replacement;
             }
             //for the rest, create new subfields
             for (var i=1;i<suggestions.length;i++) {
                 var valuein = suggestions[i];
                 var addhereID = maintag+"_"+fieldPosition; //an id to indicate where the new subfield goes
                 addSubfield(addhereID, subfieldcode, valuein);
             }
         } else { //autocomplete, nothing found
             alert("No suggestions for your search term "+value);
         }
     } //autocomplete
     if ((reqtype == 'autosuggest') || (reqtype == 'autokeyword')) {
         if ((suggestions != null) && (suggestions.length > 0)) {
             /*put the suggestions in the div autosuggest_xxxx*/
             //make a nice box..
             mysel = '<table width="400" border="0"><tr><td><span class="bibeditscrollArea"><ul>';
             //create the select items..
             for (var i=0;i<suggestions.length;i++) {
                tmpid = select_id+"-"+suggestions[i];
                mysel = mysel +'<li onClick="onAutosuggestSelect(\''+tmpid+'\');">'+suggestions[i]+"</li>";
             }
             mysel = mysel+"</ul></td>"
             //add a stylish close link in case the user does not find
             //the value among the suggestions
             mysel = mysel + "<td><form><input type='button' value='close' onClick='onAutosuggestSelect(\""+select_id+"-"+'\");></form></td>';
             mysel = mysel+"</tr></table>";
             //for (var i=0;i<suggestions.length;i++) { mysel = mysel + +suggestions[i]+ " "; }
             autosugg_in = document.getElementById(autosuggest_id);
             if (autosugg_in != null) {autosugg_in.innerHTML = mysel;}
          } else { //there were no suggestions
              alert("No suggestions for your search term "+value);
          }
     } //autosuggest
   }, false); /*NB! This function is called synchronously.*/
 } //onAutoSuggest
 
 
 /*put the content of the autosuggest select into the field where autoselect was lauched*/
 function onAutosuggestSelect(selectidandselval){
   /*first take the selectid. It is the string before the first hyphen*/
   var tmpArray = selectidandselval.split('-');
   var selectid = tmpArray[0];
   var selval =  tmpArray[1];
   /*generate the content element id and autosuggest element id from the selectid*/
   var tmpArray = selectid.split('_');
   var content_id = 'content_'+tmpArray[1]+'_'+tmpArray[2]+'_'+tmpArray[3];
   var autosuggest_id = 'autosuggest_'+tmpArray[1]+'_'+tmpArray[2]+'_'+tmpArray[3];
   var content_t = document.getElementById(content_id); //table
   var content = null; //the actual text
   //this is interesting, since if the user is browsing the list of selections by mouse,
   //the autogrown form has disapperaed and there is only the table left.. so check..
   if (content_t.innerHTML.indexOf("<form>") ==0) {
      var content_f = null; //form
      var content_ta = null; //textarea
      if (content_t) {
          content_f = content_t.firstChild; //form is the sub-elem of table
      }
      if (content_f) {
          content_ta = content_f.firstChild; //textarea is the sub-elem of form
      }
      if (!(content_ta)) {return;}
      content = content_ta;
   } else {
      content = content_t;
   }
   /*put value in place*/
   if (selval) {
       content.innerHTML = selval;
       content.value = selval;
   }
   /*remove autosuggest box*/
   var autosugg_in = document.getElementById(autosuggest_id);
   autosugg_in.innerHTML = "";
 }
 
 function onContentChange(value, th){
   /*
    * Handle 'Save' button in editable content fields.
    */
   if (failInReadOnly()){
     return;
   }
   var tmpArray = th.id.split('_');
   var tag = tmpArray[1], fieldPosition = tmpArray[2], subfieldIndex = tmpArray[3];
   var field = gRecord[tag][fieldPosition];
   var tag_ind = tag + field[1] + field[2];
   var oldValue = "";
   value = value.replace(/\n/g, ' '); // Replace newlines with spaces.
   if (subfieldIndex == undefined){
     // Controlfield or modifying a field tag
     if (tmpArray[0] == 'fieldTag') {
         if (tag_ind == value.replace(/_/g, " "))
             return escapeHTML(value);
         else {
             oldValue = tag_ind;
         }
     }
     else if (field[3] == value)
       return escapeHTML(value);
     else{
         oldValue = field[3];
         field[3] = value;
         subfieldIndex = null;
         var subfieldCode = null;
     }
   }
   else{
     if (tmpArray[0] == 'subfieldTag') {
         if (field[0][subfieldIndex][0] == value)
             return escapeHTML(value);
         else {
             // Regular subfield
             oldValue = field[0][subfieldIndex][0];
             field[0][subfieldIndex][0] = value;
         }
     }
     else {
         if (field[0][subfieldIndex][1] == value)
             return escapeHTML(value);
         // Regular field
         else {
             oldValue = field[0][subfieldIndex][1];
             field[0][subfieldIndex][1] = value;
         }
     }
     var subfieldCode = field[0][subfieldIndex][0];
   }
 
   // setting the undo/redo handlers
   var newValue = escapeHTML(value);
   var code;
 
   var urHandler;
   var operation_type;
   if (tmpArray[0] == 'subfieldTag') {
       code = gRecord[tag][fieldPosition][0][subfieldIndex][0];
       value = field[0][subfieldIndex][1];
       operation_type = "change_subfield_code";
       urHandler = prepareUndoHandlerChangeSubfield(tag,
                                                fieldPosition,
                                                subfieldIndex,
                                                value,
                                                value,
                                                oldValue, code,
                                                operation_type);
   }
   else if (tmpArray[0] == 'fieldTag') {
       var oldTag = oldValue.substring(0,3);
       var oldInd1 = oldValue.substring(3,4);
       var oldInd2 = oldValue.substring(4,5);
       var newTag = value.substring(0,3);
       var newInd1 = value.substring(3,4);
       var newInd2 = value.substring(4,5);
       operation_type = "change_field_code";
       urHandler = prepareUndoHandlerChangeFieldCode(oldTag,
                                                     oldInd1,
                                                     oldInd2,
                                                     newTag,
                                                     newInd1,
                                                     newInd2,
                                                     fieldPosition,
                                                     operation_type);
   }
   else {
       code = gRecord[tag][fieldPosition][0][subfieldIndex][0];
       operation_type = "change_content";
       urHandler = prepareUndoHandlerChangeSubfield(tag,
                                                fieldPosition,
                                                subfieldIndex,
                                                oldValue,
                                                newValue,
                                                code, code,
                                                operation_type);
   }
   addUndoOperation(urHandler);
 
   // generating the Ajax request
   if (tmpArray[0] == 'subfieldTag') {
       value = field[0][subfieldIndex][1];
       updateSubfieldValue(tag, fieldPosition, subfieldIndex, subfieldCode, value,
                           null, urHandler, modifySubfieldCode=true);
   }
   else if (tmpArray[0] == 'fieldTag'){
       updateFieldTag(oldTag, newTag, oldInd1, oldInd2, newInd1, newInd2, fieldPosition, null, urHandler);
   }
   else{
       updateSubfieldValue(tag, fieldPosition, subfieldIndex, subfieldCode, value, null, urHandler);
   }
 
   var idPrefix;
   if (tmpArray[0] == 'subfieldTag') {
       idPrefix = '"#subfieldTag_';
   }
   else{
       idPrefix = '"#content_';
   }
   setTimeout('$(' + idPrefix + tag + '_' + fieldPosition + '_' + subfieldIndex +
       '").effect("highlight", {color: gNEW_CONTENT_COLOR}, ' +
       'gNEW_CONTENT_COLOR_FADE_DURATION)', gNEW_CONTENT_HIGHLIGHT_DELAY);
   // Return escaped value to display.
   return newValue;
 }
 
 function onMoveSubfieldClick(type, tag, fieldPosition, subfieldIndex){
   /*
    * Handle subfield moving arrows.
    */
   if (failInReadOnly()){
     return;
   }
   updateStatus('updating');
 
   // Check if moving is possible
   if (type == 'up') {
     if ( (parseInt(subfieldIndex) - 1 )< 0) {
       updateStatus('ready', '');
       return;
     }
   }
   else {
     if ((parseInt(subfieldIndex) + 1) >= gRecord[tag][fieldPosition][0].length) {
       updateStatus('ready', '');
       return;
     }
   }
   // creating the undoRedo Hanglers
   var undoHandler = prepareUndoHandlerMoveSubfields(tag, parseInt(fieldPosition), parseInt(subfieldIndex), type);
   addUndoOperation(undoHandler);
 
   var ajaxData = performMoveSubfield(tag, fieldPosition, subfieldIndex, type, undoHandler);
   createReq(ajaxData, function(json){
     updateStatus('report', gRESULT_CODES[json['resultCode']]);
   }, false);
 
 }
 
 function onDeleteClick(event){
   /*
    * Handle 'Delete selected' button or delete hotkeys.
    */
   if (failInReadOnly()){
     return;
   }
   updateStatus('updating');
 
   var toDelete = getSelectedFields();
   // Assert that no protected fields are scheduled for deletion.
   var protectedField = containsProtectedField(toDelete);
   if (protectedField){
     displayAlert('alertDeleteProtectedField', [protectedField]);
     updateStatus('ready');
     return;
   }
     // register the undo Handler
   var urHandler = prepareUndoHandlerDeleteFields(toDelete);
   addUndoOperation(urHandler);
   var ajaxData = deleteFields(toDelete, urHandler);
 
   createReq(ajaxData, function(json){
     updateStatus('report', gRESULT_CODES[json['resultCode']]);
   });
 }
 
 function onMoveFieldUp(tag, fieldPosition) {
   if (failInReadOnly()){
     return;
   }
   fieldPosition = parseInt(fieldPosition);
   var thisField = gRecord[tag][fieldPosition];
   if (fieldPosition > 0) {
     var prevField = gRecord[tag][fieldPosition-1];
     // check if the previous field has the same indicators
     if ( cmpFields(thisField, prevField) == 0 ) {
       var undoHandler = prepareUndoHandlerMoveField(tag, fieldPosition, "up");
       addUndoOperation(undoHandler);
       var ajaxData = performMoveField(tag, fieldPosition, "up", undoHandler);
       createReq(ajaxData, function(json){
         updateStatus('report', gRESULT_CODES[json['resultCode']]);
       }, false);
     }
   }
 }
 
 function onMoveFieldDown(tag, fieldPosition) {
   if (failInReadOnly()){
     return;
   }
   fieldPosition = parseInt(fieldPosition);
   var thisField = gRecord[tag][fieldPosition];
   if (fieldPosition < gRecord[tag].length-1) {
     var nextField = gRecord[tag][fieldPosition+1];
     // check if the next field has the same indicators
     if ( cmpFields(thisField, nextField) == 0 ) {
       var undoHandler = prepareUndoHandlerMoveField(tag, fieldPosition, "down");
       addUndoOperation(undoHandler);
       var ajaxData = performMoveField(tag, fieldPosition, "down", undoHandler);
       createReq(ajaxData, function(json){
         updateStatus('report', gRESULT_CODES[json['resultCode']]);
       }, false);
     }
   }
 }
 
 
 
 function updateInterfaceAccordingToMode(){
   /* updates the user interface (in particular the activity of menu buttons)
      accordingly to the surrent operation mode of BibEdit.
    */
   // updating the switch button caption
   if (gReadOnlyMode){
     deactivateRecordMenu();
     $('#btnSwitchReadOnly').attr("innerHTML", "R/W");
   } else {
     activateRecordMenu();
     $('#btnSwitchReadOnly').attr("innerHTML", "Read-only");
   }
 }
 
 function switchToReadOnlyMode(){
   // Moving to the read only mode with BibEdit
 
   if (gRecordDirty == true){
     alert("Please submit the record or cancel your changes before going to the read-only mode ");
     return false;
   }
   gReadOnlyMode = true;
   createReq({recID: gRecID, requestType: 'deleteRecordCache'});
   gCacheMTime = 0;
 
   updateInterfaceAccordingToMode();
 }
 
 function canSwitchToReadWriteMode(){
   /*A function determining if at current moment, it is possible to switch to the read/write mode*/
   // If the revision is not the newest -> return false
   return true;
 }
 
 function switchToReadWriteMode(){
   // swtching to a normal editing mode of BibEdit
   if (!canSwitchToReadWriteMode()){
     alert("It is not possible to switch to the editing mode at the moment");
     return false;
   }
 
   gReadOnlyMode = false;
   // reading the record as if it was just opened
   getRecord(gRecID);
   updateInterfaceAccordingToMode();
 }
 
 
 function onSwitchReadOnlyMode(){
   // an event habdler being executed when user clicks on the switch to read only mode button
   if (gReadOnlyMode){
     switchToReadWriteMode();
   } else {
     switchToReadOnlyMode();
   }
 }
 
 
 // functions handling the revisions history
 
 function getCompareClickedHandler(revisionId){
   return function(e){
     //document.location = "/record/merge/#recid1=" + gRecID + "&recid2=" + gRecID + "." + revisionId;
     var comparisonUrl = "/record/edit/compare_revisions?recid=" +
       gRecID + "&rev1=" + gRecRev + "&rev2=" + revisionId;
     var newWindow = window.open(comparisonUrl);
     newWindow.focus();
     return false;
   };
 }
 
 function onRevertClick(revisionId){
   /*
    * Handle 'Revert' button (submit record).
    */
   updateStatus('updating');
   if (displayAlert('confirmRevert')){
     createReq({recID: gRecID, revId: revisionId, requestType: 'revert',
          force: onSubmitClick.force}, function(json){
     // Submission was successful.
       changeAndSerializeHash({state: 'submit', recid: gRecID});
       var resCode = json['resultCode'];
       cleanUp(!gNavigatingRecordSet, '', null, true);
       updateStatus('report', gRESULT_CODES[resCode]);
       displayMessage(resCode);
       // clear the list of record revisions
       resetBibeditState()
     });
     onSubmitClick.force = false;
   }
   else
     updateStatus('ready');
   holdingPenPanelRemoveEntries(); // clearing the holding pen entries list
 }
 
 function getRevertClickedHandler(revisionId){
   return function(e){
       onRevertClick(revisionId);
       return false;
   };
 }
 
 function updateRevisionsHistory(){
   if (gRecRevisionHistory == null){
       return;
   }
 
   var result = "";
   var results = [];
   for (revInd in  gRecRevisionHistory){
     tmpResult = displayRevisionHistoryEntry(gRecID, gRecRevisionHistory[revInd]);
     tmpResult["revisionID"] = gRecRevisionHistory[revInd];
     results.push(tmpResult);
     result += tmpResult["HTML"];
   }
 
   $("#bibEditRevisionsHistory").attr("innerHTML", result);
   $(".bibEditRevHistoryEntryContent").bind("click", function(evt){
     var revision = $(this)[0].id.split("_")[1];
     updateStatus('updating');
     getRecord(gRecID, revision);
   });
 
   /*Attaching the actions on user interface*/
   for (resultInd in results){
     result = results[resultInd];
     $('#' + result['compareImgId']).bind("click", getCompareClickedHandler(result["revisionID"]));
     $('#' + result['revertImgId']).bind("click", getRevertClickedHandler(result["revisionID"]));
   }
 }
 
 function encodeXml(str){
     var resultString = "";
     for (var i=0;i<str.length;i++){
         var c = str.charAt(i);
         switch (c){
         case '<':
             resultString += "&lt;";
             break;
         case '>':
             resultString += "&gt;";
             break;
         case '&':
             resultString += "&amp;";
             break;
         case '"':
             resultString += "&quot;";
             break;
         case "'":
             resultString += "&apos;";
             break;
         default:
             resultString += c;
         }
     }
     return resultString;
 }
 
 function getSelectionMarcXml(){
   /*Gets the MARC XML of the current editor selection*/
 
   var checkedFieldBoxes = $('input[class="bibEditBoxField"]:checked'); // interesting only for the controlfields
                                                                        //  where no subfields are
   var checkedSubfieldBoxes = $('input[class="bibEditBoxSubfield"]:checked');
 
   // now constructing the interesting data
 
   var selectionNormal = {}; // a dictionary of identifiers taht have appeared already
 
   var selectionControlFields = [];
 
   var selectedFields = []; // a list of fields already selected
   var currentField = null; // a curently edited field
 
   // Collect subfields to be deleted in toDelete.
   var normalFieldsXml = "";
   var controlFieldsXml = "";
 
   $(checkedSubfieldBoxes).each(function(){
     var tmpArray = this.id.split('_');
     var tag = tmpArray[1], fieldPosition = tmpArray[2], subfieldIndex = tmpArray[3];
     if (currentField == null || currentField.tag != tag || currentField.position != fieldPosition){
       if (currentField != null){
         var newPos = selectedFields.length;
         selectedFields[newPos] = currentField;
         normalFieldsXml += "</datafield>"
       }
       // creating an empty field
       currentField={};
       currentField.subfields = [];
       currentField.tag = tag;
       currentField.position = fieldPosition;
       currentField.ind1 = gRecord[tag][fieldPosition][1];
       currentField.ind2 = gRecord[tag][fieldPosition][2];
       currentField.isControlField = false;
       selectionNormal[tag] = true;
       normalFieldsXml += "<datafield tag=\"" + currentField.tag + "\" ind1=\"" +
           currentField.ind1 + "\" ind2=\"" + currentField.ind2 + "\">";
     }
 
     // appending a current subfield
     var newPos = currentField.subfields.length;
     subfield = gRecord[tag][fieldPosition][0][subfieldIndex];
     currentField.subfields[newPos] = subfield;
       normalFieldsXml += "<subfield code=\"" + subfield[0] + "\">" + encodeXml(subfield[1]) + "</subfield>";
   });
 
   if (currentField != null){
     var newPos = selectedFields.length;
     selectedFields[newPos] = currentField;
     normalFieldsXml += "</datafield>";
   }
 
   // now extending by the control fields (they did not appear earlier)
   $(checkedFieldBoxes).each(function(){
     var tmpArray = this.id.split('_');
     var tag = tmpArray[1], fieldPosition = tmpArray[2];
     if (selectionNormal[tag] == undefined){
        // we have a control field ! otherwise, the field has been already utilised
       currentField = {};
       currentField.tag = tag;
       currentField.value = gRecord[tag][fieldPosition][3]
       var newPos = selectionControlFields.length;
       selectionControlFields[newPos] = currentField;
       controlFieldsXml += "<controlfield tag=\"" + currentField.tag + "\">" + currentField.value+ "</controlfield>";
     }
   });
 
   return "<record>" + controlFieldsXml + normalFieldsXml + "</record>";
 
 }
 
 function onPerformCopy(){
   /** The handler performing the copy operation
    */
   if (document.activeElement.type == "textarea" || document.activeElement.type == "text"){
     /*we do not want to perform this in case we are in an ordinary text area*/
     return;
   }
   var valueToCopy = getSelectionMarcXml();
   clipboardCopyValue(valueToCopy);
 }
 
 function onPerformPaste(){
   /* Performing the paste operation -> retriexing the MARC XML from the clipboard,
      decoding and applying the code to the
 
      According to the default behaviour, the fields are appended as last of the same kind
    */
 
   if (document.activeElement.type == "textarea" || document.activeElement.type == "text"){
     /*we do not want to perform this in case we are in an ordinary text area*/
     return;
   }
 
   var clipboardContent = clipboardPasteValue();
 
   var record = null;
   try{
     record = decodeMarcXMLRecord(clipboardContent);
   } catch (err){
     alert("Error when parsing XML occured ... " + err.mesage);
   }
 
   var changesAdd = []; // the ajax requests for all the fields
   var undoHandlers = [];
 
   for (tag in record){
     if (gRecord[tag] == undefined){
       gRecord[tag] = [];
     }
     // now appending the fields
     for (fieldInd in record[tag]){
       newPos = gRecord[tag].length;
       gRecord[tag][newPos] = record[tag][fieldInd];
       // enqueue ajax add field request
 
       isControlfield = record[tag][fieldInd][0].length == 0;
       ind1 = record[tag][fieldInd][1];
       ind2 = record[tag][fieldInd][2];
       subfields = record[tag][fieldInd][0];
       value: record[tag][fieldInd][3]; // in case of a control field
 
       changesAdd.push({
         recID: gRecID,
         requestType: "addField",
         controlfield : isControlfield,
         fieldPosition : newPos,
         tag: tag,
         ind1: record[tag][fieldInd][1],
         ind2: record[tag][fieldInd][2],
         subfields: record[tag][fieldInd][0],
         value: record[tag][fieldInd][3]
       });
 
       undoHandler = prepareUndoHandlerAddField(
           tag, ind1, ind2, newPos, subfields, isControlfield, value);
       undoHandlers.push(undoHandler);
     }
   }
 
   undoHandlers.reverse();
   var undoHandler = prepareUndoHandlerBulkOperation(undoHandlers, "paste");
   addUndoOperation(undoHandler);
   // now sending the Ajax Request
   var optArgs = {
       undoRedo: undoHandler
   };
 
   createBulkReq(changesAdd, function(json){
       updateStatus('report', gRESULT_CODES[json['resultCode']])}, optArgs);
 
   // tags have to be redrawn in the increasing order
 
   tags = [];
   for (tag in record){
     tags.push(tag);
   }
   tags.sort();
   for (tagInd in tags){
       redrawFields(tags[tagInd]);
   }
   reColorFields();
 }
 function addUndoOperation(operation){
   gUndoList.push(operation);
   invalidateRedo();
   updateUrView();
 }
 
 function invalidateRedo(){
   /** Invalidates the redo list - after some modification*/
   gRedoList = [];
 }
 
 function adjustUndoRedoBtnsActivity(){
   /** Making the undo/redo buttons active/inactive according to the needs
    */
   if (gUndoList.length > 0){
     $("#btnUndo").addAttribute("disabled", "");
   }
   else{
     $("#btnUndo").removeAttr("disabled");
   }
 
   if (gRedoList.length > 0){
     $("#btnRedo").addAttribute("disabled", "");
   }
   else{
     $("#btnRedo").removeAttr("disabled");
   }
 }
 
 
 function undoMany(number){
   /** A function undoing many operations from the undo list
 
       Arguments:
         number: number of operations to undo
    */
 
   var undoOperations = []
   for (i=0;i<number;i++){
     undoOperations.push(getUndoOperation());
   }
   performUndoOperations(undoOperations);
   updateUrView();
 }
 
 function prepareUndoHandlerEmpty(){
   /** Creating an empty undo/redo handler - might be useful in some cases
       when undo operation is required but should not be registered
   */
   return {
     operation_type: "no_operation"
   };
 }
 
 function prepareUndoHandlerAddField(tag, ind1, ind2, fieldPosition, subfields,
                                     isControlField, value ){
   /** A function creating an undo handler for the operation of affing a new
       field
 
     Arguments:
       tag:            tag of the field
       ind1:           first indicator (a single character string)
       ind2:           second indicator (a single character string)
       fieldPosition:  a position of the field among other fields with the same
                       tag and possibly different indicators)
       subFields:      a list of fields subfields. each subfield is decribed by
                       a pair: [code, value]
       isControlField: a boolean value indicating if the field is a control field
       value:          a value of a control field. (important in case of passing
                       iscontrolField equal true)
   */
 
   var result = {};
   result.operation_type = "add_field";
   result.newSubfields = subfields;
   result.tag = tag;
   result.ind1 = ind1;
   result.ind2 = ind2;
   result.fieldPosition = fieldPosition;
   result.isControlField = isControlField;
   if (isControlField){
     // value == false means that we are dealing with a control field
     result.value = value;
   } else{
     result.subfields = subfields;
   }
 
   return result;
 }
 
 function prepareUndoHandlerVisualizeChangeset(changesetNumber, changesListBefore, changesListAfter){
   var result = {};
   result.operation_type = "visualize_hp_changeset";
   result.changesetNumber = changesetNumber;
   result.oldChangesList = changesListBefore;
   result.newChangesList = changesListAfter;
   return result;
 }
 
 function prepareUndoHandlerApplyHPChange(changeHandler, changeNo){
   /** changeHandler - handler to the original undo/redo handler associated with the action
    */
   var result = {};
   result.operation_type = "apply_hp_change";
   result.handler = changeHandler;
   result.changeNo = changeNo;
   result.changeType = gHoldingPenChanges[changeNo].change_type;
   return result;
 }
 
 function prepareUndoHandlerApplyHPChanges(changeHandlers, changesBefore){
   /** Producing the undo/redo handler associated with application of
       more than one HoldingPen change
 
       Arguments:
         changeHandlers - a list od undo/redo handlers associated with subsequent changes.
         changesBefore = a list of Holding Pen changes before the operation
    */
 
   var result = {};
   result.operation_type = "apply_hp_changes";
   result.handlers = changeHandlers;
   result.changesBefore = changesBefore;
   return result;
 }
 
 function prepareUndoHandlerRemoveAllHPChanges(hpChanges){
   /** A function preparing the undo handler associated with the
       removal of all the Holding Pen changes present in teh interface */
   var result = {};
   result.operation_type = "remove_all_hp_changes";
   result.old_changes_list = hpChanges;
   return result;
 }
 
 function prepareUndoHandlerBulkOperation(undoHandlers, handlerTitle){
   /*
     Preapring an und/redo handler allowing to treat the bulk operations
     ( like for example in case of pasting fields )
     arguments:
       undoHandlers : handlers of separate operations from the bulk
       handlerTitle : a message to be displayed in the undo menu
   */
   var result = {};
 
   result.operation_type = "bulk_operation";
   result.handlers = undoHandlers;
   result.title = handlerTitle;
 
   return result;
 }
 
 function urPerformAddSubfields(tag, fieldPosition, subfields, isUndo){
     var ajaxData = {
       recID: gRecID,
       requestType: 'addSubfields',
       tag: tag,
       fieldPosition: fieldPosition,
       subfields: subfields,
       undoRedo: (isUndo ? "undo": "redo")
     };
 
     gRecord[tag][fieldPosition][0] = gRecord[tag][fieldPosition][0].concat(subfields);
     redrawFields(tag);
     reColorFields();
 
     return ajaxData;
 }
 
 function performModifyHPChanges(changesList, isUndo){
   /** Undoing or redoing the operation of modifying the changeset
    */
   // first local updates
   gHoldingPenChanges = changesList;
   refreshChangesControls();
   var result = prepareOtherUpdateRequest(isUndo);
   result.undoRedo = isUndo ? "undo" : "redo";
   result.hpChanges = {toOverride: changesList};
   return result;
 }
 
 function hideUndoPreview(){
   $("#undoOperationVisualisationField").addClass("bibEditHiddenElement");
   // clearing the selection !
   $(".bibEditURDescEntrySelected").removeClass("bibEditURDescEntrySelected");
 }
 
 function getRedoOperation(){
   // getting the operation to be redoed
   currentElement = gRedoList[0];
   gRedoList.splice(0, 1);
   gUndoList.push(currentElement);
   return currentElement;
 }
 
 function getUndoOperation(){
   // getting the operation to be undoe
   currentElement = gUndoList[gUndoList.length - 1];
   gUndoList.splice(gUndoList.length - 1, 1);
   gRedoList.splice(0, 0, currentElement);
   return currentElement;
 }
 
 function setAllUnselected(){
   // make all the fields and subfields deselected
   setSelectionStatusAll(false);
 }
 
 function setSelectionStatusAll(status){
   // Changing the selection status for all the fields
   subfieldBoxes = $('.bibEditBoxSubfield');
   subfieldBoxes.each(function(e){
     if (subfieldBoxes[e].checked != status){
       subfieldBoxes[e].click();
     }
   });
 }
 
 function prepareApplyAllHPChangesHandler(){
     // a container for many undo/redo operations in the same time
     throw 'To implement';
 }
 
 
 /*** Handlers for specific operations*/
 
 function renderURList(list, idPrefix, isInverted){
   // rendering the view of undo/redo list into a human-readible HTML
   // list -> an undo or redo list
   // idPrefix -> te prefix of the DOM identifier
 
   var result = "";
   var isPair = false;
   var helperCnt = 0;
 
   var iterationBeginning = list.length - 1;
   var iterationJump = -1;
   var iterationEnd = -1;
 
   if (isInverted === true){
     iterationBeginning = 0;
     iterationJump = 1;
     iterationEnd = list.length;
   }
 
   for (entryInd = iterationBeginning ; entryInd != iterationEnd ; entryInd += iterationJump){
       result += "<div class=\"" + (isPair ? "bibEditURPairRow" : "bibEditUROddRow" )+ " bibEditURDescEntry\" id=\"" + idPrefix + "_" + helperCnt + "\">";
       result += getHumanReadableUREntry(list[entryInd]);
       result += "</div>";
       isPair = ! isPair;
       helperCnt += 1;
   }
   result += "";
   return result;
 }
 
 function prepareApplyHPChangeHandler(){
     // A handler for HoldingPen change application/rejection
     throw 'to implement';
 }
 
 function processURUntil(entry){
   // Executing the bulk undo/redo
   var idParts = $(entry).attr("id").split("_");
   var index = parseInt(idParts[1]);
 
   if (idParts[0] == "undo"){
     undoMany(index+1);
   }
   else{
     redoMany(index+1);
   }
 }
 
 function prepareUndoHandlerChangeSubfield(tag, fieldPos, subfieldPos, oldVal, 
          newVal, oldCode, newCode, operation_type){
   var result = {};
   result.operation_type = operation_type;
   result.tag = tag;
   result.oldVal = oldVal;
   result.newVal = newVal;
   result.oldCode = oldCode;
   result.newCode = newCode;
   result.fieldPos = fieldPos;
   result.subfieldPos = subfieldPos;
   return result;
 }
 
 function prepareUndoHandlerChangeFieldCode(oldTag, oldInd1, oldInd2, newTag, newInd1,
                                            newInd2, fieldPos, operation_type){
   var result = {};
   result.operation_type = operation_type;
   result.oldTag = oldTag;
   result.oldInd1 = oldInd1;
   result.oldInd2 = oldInd2;
   result.newTag = newTag;
   result.ind1 = newInd1;
   result.ind2 = newInd2;
   result.fieldPos = fieldPos;
   
   if (gRecord[newTag] == undefined) {
       result.newFieldPos = 0;
   }
   else {
       result.newFieldPos = gRecord[newTag].length - 1;
   }
 
   return result;
 }
 
 function setAllSelected(){
   // make all the fields and subfields selected
   setSelectionStatusAll(true);
 }
 
 function showUndoPreview(){
   $("#undoOperationVisualisationField").removeClass("bibEditHiddenElement");
 }
 
 function prepareUndoHandlerMoveSubfields(tag, fieldPosition, subfieldPosition, direction){
   var result = {};
   result.operation_type = "move_subfield";
   result.tag = tag;
   result.field_position = fieldPosition;
   result.subfield_position = subfieldPosition;
   result.direction = direction;
   return result;
 }
 // Handlers to implement:
 
 function setFieldUnselected(tag, fieldPos){
   // unselect a given field
   setSelectionStatusField(tag, fieldPos, false);
 }
 
 function urPerformRemoveField(tag, position, isUndo){
   var toDeleteData = {};
   var toDeleteTmp = {};
   toDeleteTmp[position] = [];
   toDeleteData[tag] =  toDeleteTmp;
 
   // first preparing the data of Ajax request
 
   var ajaxData = {
     recID: gRecID,
     requestType: 'deleteFields',
     toDelete: toDeleteData,
     undoRedo: (isUndo ? "undo": "redo")
   };
 
   // updating the local model
   gRecord[tag].splice(position,1);
   if (gRecord[tag] == []){
     gRecord[tag] = undefined;
   }
   redrawFields(tag);
   reColorFields();
 
   return ajaxData;
 }
 
 function prepareOtherUpdateRequest(isUndo){
   return {
     requestType : 'otherUpdateRequest',
     recID : gRecID,
       undoRedo: ((isUndo === true) ? "undo" : "redo"),
     hpChanges: {}
   };
 }
 
 function performUndoApplyHpChanges(subRequests, oldChanges){
   /**
    Arguemnts:
      subRequests - subrequests performing the appropriate undo operations
    */
 
   // removing all teh undo/redo informations as they should be passed globally
   for (ind in subRequests){
       subRequests[ind].undoRedo = undefined;
   }
 //  var gHoldingPenChanges
   return {
     requestType: 'applyBulkUpdates',
     undoRedo: "undo",
     requestsData: subRequests,
     hpChanges: {toOverride: oldChanges}
   };
 }
 
 function performBulkOperation(subHandlers, isUndo){
   /**
    return the bulk operation
    Arguments:
      subReqs : requests performing the sub-operations
      isUndo - is current request undo or redo ?
    */
   var subReqs = [];
   if (isUndo === true){
     subReqs = preparePerformUndoOperations(subHandlers);
   } else {
     // We can not simply assign and revers as the original would be modified
     var handlers = [];
     for (handlerInd = subHandlers.length -1; handlerInd >= 0; handlerInd--){
       handlers.push(subHandlers[handlerInd]);
     }
     subReqs = preparePerformRedoOperations(handlers);
   }
 
   for (ind in subReqs){
     subReqs[ind].undoRedo = undefined;
   }
 
   return {
     requestType: 'applyBulkUpdates',
     undoRedo: (isUndo === true ? "undo" : "redo"),
     requestsData: subReqs,
     hpChanges: {}
   };
 }
 
 function preparePerformRedoOperations(operations){
   /** Redos an operation passed as an argument */
   var ajaxRequestsData = [];
   for (operationInd in operations){
     var operation = operations[operationInd];
     var ajaxData = {};
     var isMultiple = false; // is the current decription a list of descriptors ?
     switch (operation.operation_type){
     case "no_operation":
       ajaxData = prepareOtherUpdateRequest(false);
       break;
     case "change_content":
       ajaxData = urPerformChangeSubfieldContent(operation.tag,
                                      operation.fieldPos,
                                      operation.subfieldPos,
                                      operation.newCode,
                                      operation.newVal,
                                      false);
       break;
     case "change_subfield_code":
       ajaxData = urPerformChangeSubfieldCode(operation.tag,
                                      operation.fieldPos,
                                      operation.subfieldPos,
                                      operation.newCode,
                                      operation.newVal,
                                      false);
       break;
     case "change_field_code":
         ajaxData = urPerformChangeFieldCode(operation.newTag,
                                             operation.ind1,
                                             operation.ind2,
                                             operation.oldTag,
                                             operation.oldInd1,
                                             operation.oldInd2,
                                             operation.fieldPos,
                                             false);
       break;
     case "add_field":
       ajaxData = urPerformAddField(operation.isControlField,
                         operation.fieldPosition,
                         operation.tag,
                         operation.ind1,
                         operation.ind2,
                         operation.subfields,
                         operation.value,
                         false);
       break;
      case "add_subfields":
        ajaxData = urPerformAddSubfields(operation.tag,
                              operation.fieldPosition,
                              operation.newSubfields,
                              false);
        break;
 
     case "delete_fields":
       ajaxData = urPerformDeletePositionedFieldsSubfields(operation.toDelete, false);
       break;
 
     case "move_field":
       ajaxData = performMoveField(operation.tag, operation.field_position, operation.direction , false);
       break;
     case "move_subfield":
       ajaxData = performMoveSubfield(operation.tag, operation.field_position, operation.subfield_position, operation.direction, false);
       break;
     case "bulk_operation":
       ajaxData = performBulkOperation(operation.handlers, false);
       break;
     case "apply_hp_change":
       removeViewedChange(operation.changeNo); // we redo the change application so the change itself gets removed
       ajaxData = preparePerformRedoOperations([operation.handler]);
       ajaxData[0].hpChange = {};
       ajaxData[0].hpChange.toDisable = [operation.changeNo]; // reactivate this change
       isMultiple = true;
       break;
 
     case "apply_hp_changes":
       // in this case many changes are applied at once and the list of changes is completely overriden
       ajaxData = performUndoApplyHpChanges();
     case "change_field":
       ajaxData = urPerformChangeField(operation.tag, operation.fieldPos,
                                       operation.newInd1, operation.newInd2,
                                       operation.newSubfields,
                                       operation.newIsControlField,
                                       operation.oldValue , false);
       break;
     case "visualize_hp_changeset":
       ajaxData = prepareVisualizeChangeset(operation.changesetNumber,
         operation.newChangesList, "redo");
       break;
     case "remove_all_hp_changes":
       ajaxData = performModifyHPChanges([], false);
       break;
 
     default:
       alert("Error: wrong operation to redo");
       break;
     }
     // now dealing with the results
     if (isMultiple){
       // in this case we have to merge lists rather than include inside
       for (elInd in ajaxData){
         ajaxRequestsData.push(ajaxData[elInd]);
       }
     }
     else{
       ajaxRequestsData.push(ajaxData);
     }
   }
   return ajaxRequestsData;
 }
 
 function performRedoOperations(operations){
   ajaxRequestsData = preparePerformRedoOperations(operations);
   // now submitting the bulk request
   var optArgs = {
 //      undoRedo: "redo"
   };
 
   createBulkReq(ajaxRequestsData, function(json){
     updateStatus('report', gRESULT_CODES[json['resultCode']]);
   }, optArgs);
 }
 
 function prepareUndoHandlerDeleteFields(toDelete){
   /*Creating Undo/Redo handler for the operation of removal of fields and/or subfields
     Arguments: toDelete - indicates fields and subfields scheduled to be deleted.
       this argument should have a following structure:
       {
         "fields" : { tag: {fieldsPosition: field_structure_similar_to_on_from_gRecord}}
         "subfields" : {tag: { fieldPosition: { subfieldPosition: [code, value]}}}
       }
   */
   var result = {};
   result.operation_type = "delete_fields";
   result.toDelete = toDelete;
   return result;
 }
 
 function setSubfieldUnselected(tag, fieldPos, subfieldPos){
  // unseelcting a subfield
   setSelectionStatusSubfield(tag, fieldPos, subfieldPos, false);
 }
 
 
 function prepareUndoHandlerAddSubfields(tag, fieldPosition, subfields){
   /**
     tag : tag of the field inside which the fields should be added
     fieldPosition: position of the field
     subfields: new subfields to be added. This argument should be a list
       of lists representing a single subfield. Each subfield is represented
       by a list, containing 2 elements. [subfield_code, subfield_value]
   */
   var result = {};
   result.operation_type = "add_subfields";
   result.tag = tag;
   result.fieldPosition = fieldPosition;
   result.newSubfields = subfields;
   return result;
 }
 
 function setFieldSelected(tag, fieldPos){
   // select a given field
   setSelectionStatusField(tag, fieldPos, true);
 }
 
 function redoMany(number){
   // redoing an indicated number of operations
   var redoOperations = [];
   for (i=0;i<number;i++){
     redoOperations.push(getRedoOperation());
   }
   performRedoOperations(redoOperations);
   updateUrView();
 }
 function urPerformAddField(controlfield, fieldPosition, tag, ind1, ind2, subfields, value, isUndo){
   var ajaxData = {
     recID: gRecID,
     requestType: 'addField',
     controlfield: controlfield,
     fieldPosition: fieldPosition,
     tag: tag,
     ind1: ind1,
     ind2: ind2,
     subfields: subfields,
     value: value,
     undoRedo: (isUndo? "undo": "redo")
   };
 
 //  createReq(data, function(json){
 //    updateStatus('report', gRESULT_CODES[json['resultCode']]);
 //  });
 
   // updating the local situation
   if (gRecord[tag] == undefined){
     gRecord[tag] = [];
   }
   var newField = [(controlfield ? [] : subfields), ind1, ind2,
                   (controlfield ? value: ""), 0];
   gRecord[tag].splice(fieldPosition, 0, newField);
   redrawFields(tag);
   reColorFields();
 
   return ajaxData;
 }
 
 function urPerformRemoveSubfields(tag, fieldPosition, subfields, isUndo){
   var toDelete = {};
   toDelete[tag] = {};
   toDelete[tag][fieldPosition] = []
   var startingPosition = gRecord[tag][fieldPosition][0].length - subfields.length;
   for (var i=startingPosition; i<gRecord[tag][fieldPosition][0].length ; i++){
     toDelete[tag][fieldPosition].push(i);
   }
 
   var ajaxData = {
     recID: gRecID,
     requestType: 'deleteFields',
     toDelete: toDelete,
     undoRedo: (isUndo ? "undo": "redo")
   };
 
 //  createReq(data, function(json){
 //    updateStatus('report', gRESULT_CODES[json['resultCode']]);
 //  });
   // modifying the client-side interface
   gRecord[tag][fieldPosition][0].splice( gRecord[tag][fieldPosition][0].length - subfields.length, subfields.length);
   redrawFields(tag);
   reColorFields();
 
   return ajaxData;
 }
 
 function updateUrView(){
   /*Updating the information box in the bibEdit menu
     (What are the current undo/redo handlers*/
   $('#undoOperationVisualisationFieldContent')[0].innerHTML = (gUndoList.length == 0) ? "(empty)" :
         renderURList(gUndoList, "undo");
 //        gUndoList[gUndoList.length - 1].operation_type;
   $('#redoOperationVisualisationFieldContent')[0].innerHTML = (gRedoList.length == 0) ? "(empty)" :
         renderURList(gRedoList, "redo", true);
 
   // now attaching the events ... the function is uniform for all the elements present inside the document
 
     var urEntries = $('.bibEditURDescEntry');
     urEntries.each(function(index){
         $(urEntries[index]).bind("mouseover", function (e){
           $(urEntries[index]).find(".bibEditURDescEntryDetails").removeClass("bibEditHiddenElement");
             urMarkSelectedUntil(urEntries[index]);
         });
         $(urEntries[index]).bind("mouseout", function(e){
           $(urEntries[index]).find(".bibEditURDescEntryDetails").addClass("bibEditHiddenElement");
         });
         $(urEntries[index]).bind("click", function(e){
             processURUntil(urEntries[index]);
         });
     });
 }
 
 function performMoveSubfield(tag, fieldPosition, subfieldIndex, direction, undoRedo){
   var newSubfieldIndex = parseInt(subfieldIndex) + (direction == "up" ? -1 : 1);
   var fieldID = tag + '_' + fieldPosition;
   var field = gRecord[tag][fieldPosition];
   var subfields = field[0];
 
   // Create Ajax request.
   var ajaxData = {
     recID: gRecID,
     requestType: 'moveSubfield',
     tag: tag,
     fieldPosition: fieldPosition,
     subfieldIndex: subfieldIndex,
     newSubfieldIndex: newSubfieldIndex,
     undoRedo: (undoRedo == true) ?  "undo" : ((undoRedo == false) ?  "redo" : undoRedo)
   };
 
   // Continue local updating.
   var subfieldToSwap = subfields[newSubfieldIndex];
   subfields[newSubfieldIndex] = subfields[subfieldIndex];
   subfields[subfieldIndex] = subfieldToSwap;
   var rowGroup = $('#rowGroup_' + fieldID);
   var coloredRowGroup = $(rowGroup).hasClass('bibEditFieldColored');
   $(rowGroup).replaceWith(createField(tag, field, fieldPosition));
   if (coloredRowGroup)
     $('#rowGroup_' + fieldID).addClass('bibEditFieldColored');
 
   // taking care of having only the new subfield position selected
   setAllUnselected();
   setSubfieldSelected(tag, fieldPosition, newSubfieldIndex);
 
   return ajaxData;
 }
 
 function onRedo(evt){
   if (gRedoList.length <= 0){
     alert("No Redo operations to process");
     return;
   }
   redoMany(1);
 }
 
 // functions related to the automatic field selection/unseletion
 
 function hideRedoPreview(){
   $("#redoOperationVisualisationField").addClass("bibEditHiddenElement");
   // clearing the selection !
   $(".bibEditURDescEntrySelected").removeClass("bibEditURDescEntrySelected");
 }
 
 function urPerformAddPositionedFieldsSubfields(toAdd, isUndo){
   return createFields(toAdd, isUndo);
 }
 
 function setSubfieldSelected(tag, fieldPos, subfieldPos){
   // selecting a subfield
   setSelectionStatusSubfield(tag, fieldPos, subfieldPos, true);
 }
 
 function getHumanReadableUREntry(handler){
   // rendering a human readable description of an undo/redo operation
   // handler : the u/r handler to render
   var operationDescription;
 
   switch (handler.operation_type){
     case "move_field":
       operationDescription = "move field";
       break;
     case "move_field":
       operationDescription = "change field";
       break;
     case "move_subfield":
       operationDescription = "move subfield";
       break;
     case "change_content":
       operationDescription = "edit subfield";
       break;
     case "change_subfield_code":
       operationDescription = "edit subfield code";
       break;
     case "change_field_code":
       operationDescription = "edit field code";
       break;
     case "add_field":
       operationDescription = "add field";
       break;
     case "add_subfields":
       operationDescription = "add field";
       break;
     case "delete_fields":
       operationDescription = "delete";
       break;
     case "bulk_operation":
       operationDescription = handler.title;
       break;
     case "apply_hp_change":
       operationDescription = "holding pen";
       break;
     case "visualize_hp_changeset":
       operationDescription = "show changes";
       break;
     case "remove_all_hp_changes":
       operationDescription = "remove changes";
       break;
     default:
       operationDescription = "unknown operation";
       break;
   }
 
   // now rendering parameters of the handler
   var readableDescriptors = {
     'tag' : 'tag',
     'operation_type' : false,
     'field_position' : false,
     'subfield_position' : false,
     'subfieldPos' : false,
     'newVal' : 'new value',
     'oldVal' : 'old value',
     'fieldPos' : false,
     'toDelete' : false,
     'handlers' : false,
     'newFieldPos' : false
   };
 
   var handlerDetails = '<table>';
 
   for (characteristic in handler){
     if (readableDescriptors[characteristic] != false){
       var characteristicString = characteristic;
       if (readableDescriptors[characteristic] != undefined){
           characteristicString = readableDescriptors[characteristic];
       }
       handlerDetails += '<tr><td class="bibEditURDescChar">'
         + characteristicString + ':</td><td>' + handler[characteristic]  + '</td></tr>';
     }
   }
 
   handlerDetails += '</table>';
   // now generating the final result
   return '<div class="bibEditURDescHeader">'
     + operationDescription + '</div><div class="bibEditURDescEntryDetails bibEditHiddenElement">'
     + handlerDetails + '</div>';
 }
 
 function urMarkSelectedUntil(entry){
     // marking all the detailed entries, until a given one as selected
     //  these entries have the same prefix but a smaller number
     var identifierParts = $(entry).attr("id").split("_");
     var position = parseInt(identifierParts[1]);
     var potentialElements = $(".bibEditURDescEntry");
     potentialElements.each(function(index){
         var curIdentifierParts = $(potentialElements[index]).attr("id").split("_");
         if ((curIdentifierParts[0] == identifierParts[0]) && (parseInt(curIdentifierParts[1]) <= position)){
            $(potentialElements[index]).addClass("bibEditURDescEntrySelected");
         }
         else {
            $(potentialElements[index]).removeClass("bibEditURDescEntrySelected");
         }
     });
 }
 
 function onUndo(evt){
   if (gUndoList.length <= 0){
     alert("No Undo operations to process");
     return;
   }
   undoMany(1);
 }
 
 function preparePerformUndoOperations(operations){
   /** Undos an operation passed as an argument */
   var ajaxRequestsData = [];
   for (operationInd in operations){
     var operation = operations[operationInd];
     var action = null;
     var actionData = null;
     var ajaxData = {};
     var isMultiple = false; // is the current oepration handler a list
       // of operations rather than a single op ?
 
     switch (operation.operation_type){
     case "no_operation":
       ajaxData = prepareOtherUpdateRequest(true);
       break;
     case "change_content":
       ajaxData = urPerformChangeSubfieldContent(operation.tag,
                                                 operation.fieldPos,
                                                 operation.subfieldPos,
                                                 operation.oldCode,
                                                 operation.oldVal,
                                                 true);
       break;
     case "change_subfield_code":
       ajaxData = urPerformChangeSubfieldCode(operation.tag,
                                              operation.fieldPos,
                                              operation.subfieldPos,
                                              operation.oldCode,
                                              operation.oldVal,
                                              true);
       break;
     case "change_field_code":
       ajaxData = urPerformChangeFieldCode(operation.oldTag,
                                           operation.oldInd1,
                                           operation.oldInd2,
                                           operation.newTag,
                                           operation.ind1,
                                           operation.ind2,
                                           operation.newFieldPos,
                                           true);
       break;
     case "add_field":
       ajaxData = urPerformRemoveField(operation.tag,
                                       operation.fieldPosition,
                                       true);
       break;
     case "add_subfields":
       ajaxData = urPerformRemoveSubfields(operation.tag,
                                           operation.fieldPosition,
                                           operation.newSubfields,
                                           true);
       break;
 
     case "delete_fields":
       ajaxData = urPerformAddPositionedFieldsSubfields(operation.toDelete, true);
       break;
 
     case "move_field":
       var newDirection = "up";
       var newPosition = operation.field_position + 1;
       if (operation.direction == "up"){
         newDirection = "down";
         newPosition = operation.field_position - 1;
       }
 
       ajaxData = performMoveField(operation.tag, newPosition, newDirection, true);
       break;
     case "move_subfield":
 
       var newDirection = "up";
       var newPosition = operation.subfield_position + 1;
       if (operation.direction == "up"){
         newDirection = "down";
         newPosition = operation.subfield_position - 1;
       }
       ajaxData = performMoveSubfield(operation.tag, operation.field_position,
         newPosition, newDirection, true);
       break;
     case "bulk_operation":
       ajaxData = performBulkOperation(operation.handlers, true);
       break;
     case "apply_hp_change":
       ajaxData = preparePerformUndoOperations([operation.handler]);
       ajaxData[0]["hpChange"] = {};
       ajaxData[0]["hpChange"]["toEnable"] = [operation.changeNo]; // reactivate
       isMultiple = true;
       revertViewedChange(operation.changeNo);
       break;
     case "visualize_hp_changeset":
       ajaxData = prepareUndoVisualizeChangeset(operation.changesetNumber,
         operation.oldChangesList);
       break;
     case "change_field":
       ajaxData = urPerformChangeField(operation.tag, operation.fieldPos,
                                       operation.oldInd1, operation.oldInd2,
                                       operation.oldSubfields,
                                       operation.oldIsControlField,
                                       operation.oldValue , true);
       break;
     case "remove_all_hp_changes":
       ajaxData = performModifyHPChanges(operation.old_changes_list, true);
       break;
     default:
       alert("Error: wrong operation to undo");
     }
 
     if (isMultiple){
       // in this case we have to merge lists rather than include inside
       for (elInd in ajaxData){
         ajaxRequestsData.push(ajaxData[elInd]);
       }
     }
     else{
       ajaxRequestsData.push(ajaxData);
     }
   }
 
   return ajaxRequestsData;
 }
 
 function performUndoOperations(operations){
   var ajaxRequestsData = preparePerformUndoOperations(operations);
   // now submitting the ajax request
   var optArgs={
 //    undoRedo: "undo"
   };
 
   createBulkReq(ajaxRequestsData, function(json){
     updateStatus('report', gRESULT_CODES[json['resultCode']]);
   }, optArgs);
 }
 
 function prepareUndoHandlerMoveField(tag, fieldPosition, direction){
   var result = {};
   result.tag = tag;
   result.operation_type = "move_field";
   result.field_position = fieldPosition;
   result.direction = direction;
   return result;
 }
 
 function prepareUndoHandlerChangeField(tag, fieldPos,
   oldInd1, oldInd2, oldSubfields, oldIsControlField, oldValue,
   newInd1, newInd2, newSubfields, newIsControlField, newValue){
   /** Function building a handler allowing to undo the operation of
       changing the field structure.
 
       Changing can happen only if tag and position remain the same,
       Otherwise we deal with removal and adding of a field
 
       Arguments:
         tag - tag of a field
         fieldPos - position of a field
 
         oldInd1, oldInd2 - indices of the old field
         oldSubfields - subfields present int the old structure
         oldIsControlField - a boolean value indicating if the field
                             is a control field
         oldValue - a value before change in case of field being a control field.
                    if the field is normal field, this should be equal ""
 
         newInd1, newInd2, newSubfields, newIsControlField, newValue -
            Similar parameters describing new structure of a field
   */
   var result = {};
   result.operation_type = "change_field";
   result.tag = tag;
   result.fieldPos = fieldPos;
   result.oldInd1 = oldInd1;
   result.oldInd2 = oldInd2;
   result.oldSubfields = oldSubfields;
   result.oldIsControlField = oldIsControlField;
   result.oldValue = oldValue;
   result.newInd1 = newInd1;
   result.newInd2 = newInd2;
   result.newSubfields = newSubfields;
   result.newIsControlField = newIsControlField;
   result.newValue = newValue;
 
   return result;
 }
 
 function showRedoPreview(){
   $("#redoOperationVisualisationField").removeClass("bibEditHiddenElement");
 }
 
 function deleteFields(toDeleteStruct, undoRedo){
   // a function deleting the specified fields on both client and server sides
   //
   // toDeleteFields : a structure describing fields and subfields to delete
   //   this structure is the same as for the function createFields
 
   var toDelete = {};
 
   // first we convert the data into a different format, loosing the informations about
   //   subfields of entirely removed fields
 
   // first the entirely deleted fields
   for (tag in toDeleteStruct.fields){
     if (toDelete[tag] == undefined){
       toDelete[tag] = {};
     }
     for (fieldPos in toDeleteStruct.fields[tag]){
       toDelete[tag][fieldPos] = [];
     }
   }
 
   for (tag in toDeleteStruct.subfields){
     if (toDelete[tag] == undefined){
       toDelete[tag] = {};
     }
     for (fieldPos in toDeleteStruct.subfields[tag]){
       toDelete[tag][fieldPos] = [];
       for (subfieldPos in toDeleteStruct.subfields[tag][fieldPos]){
         toDelete[tag][fieldPos].push(subfieldPos);
       }
     }
   }
 
   var tagsToRedraw = [];
 
   // reColorTable is true if any field are completely deleted.
   var reColorTable = false;
 
   // first we have to encode all the data in a single dictionary
 
   // Create Ajax request.
   var ajaxData = {
     recID: gRecID,
     requestType: 'deleteFields',
     toDelete: toDelete,
     undoRedo: (undoRedo == true) ? "undo" : ((undoRedo == false) ? "redo" : undoRedo)
   };
 
   // Continue local updating.
   // Parse data structure and delete accordingly in record.
   var fieldsToDelete, subfieldIndexesToDelete, field, subfields, subfieldIndex;
   for (var tag in toDelete) {
     tagsToRedraw.push(tag);
     fieldsToDelete = toDelete[tag];
     // The fields should be treated in the decreasing order (during the removal, indices may change)
     traversingOrder = [];
     for (fieldPosition in fieldsToDelete) {
       traversingOrder.push(fieldPosition);
     }
     // normal sorting will do this in a lexycographical order ! (problems if > 10 subfields
     // function provided, allows sorting in the reversed order
     var traversingOrder = traversingOrder.sort(function(a, b){
       return b - a;
     });
 
     for (var fieldInd in traversingOrder) {
       var fieldPosition = traversingOrder[fieldInd];
       var fieldID = tag + '_' + fieldPosition;
       subfieldIndexesToDelete = fieldsToDelete[fieldPosition];
       if (subfieldIndexesToDelete.length == 0)
         deleteFieldFromTag(tag, fieldPosition);
       else {
         // normal sorting will do this in a lexycographical order ! (problems if > 10 subfields
         subfieldIndexesToDelete.sort(function(a, b){
           return a - b;
         });
         field = gRecord[tag][fieldPosition];
         subfields = field[0];
         for (var j = subfieldIndexesToDelete.length - 1; j >= 0; j--){
           subfields.splice(subfieldIndexesToDelete[j], 1);
         }
       }
     }
   }
 
   // If entire fields has been deleted, redraw all fields with the same tag
   // and recolor the full table.
   for (tag in tagsToRedraw)
       redrawFields(tagsToRedraw[tag]);
   reColorFields();
 
   return ajaxData;
 }
 
 function getSelectedFields(){
   /** Function returning a list of selected fields
     Returns all the fields and subfields that are slected.
     The structure of a result is following:
     {
       "fields" : { tag: {fieldsPosition: field_structure_similar_to_on_from_gRecord}}
       "subfields" : {tag: { fieldPosition: { subfieldPosition: [code, value]}}}
     }
   */
   var selectedFields = {};
   var selectedSubfields = {};
 
   var checkedFieldBoxes = $('input[class="bibEditBoxField"]:checked');
   var checkedSubfieldBoxes = $('input[class="bibEditBoxSubfield"]:checked');
 
   if (!checkedFieldBoxes.length && !checkedSubfieldBoxes.length)
     // No fields selected
     return;
 
   // Collect fields to be deleted in toDelete.
   $(checkedFieldBoxes).each(function(){
     var tmpArray = this.id.split('_');
     var tag = tmpArray[1], fieldPosition = tmpArray[2];
     if (!selectedFields[tag]) {
       selectedFields[tag] = {};
     }
     selectedFields[tag][fieldPosition] = gRecord[tag][fieldPosition];
   });
 
   // Collect subfields to be deleted in toDelete.
   $(checkedSubfieldBoxes).each(function(){
     var tmpArray = this.id.split('_');
     var tag = tmpArray[1], fieldPosition = tmpArray[2], subfieldIndex = tmpArray[3];
     if (selectedFields[tag] == undefined || selectedFields[tag][fieldPosition] == undefined){
       // this field has not been selected entirely, we can proceed with processing subfield slection
       if (!selectedSubfields[tag]) {
         selectedSubfields[tag] = {};
         selectedSubfields[tag][fieldPosition] = {};
         selectedSubfields[tag][fieldPosition][subfieldIndex] =
           gRecord[tag][fieldPosition][0][subfieldIndex];
       }
       else {
         if (!selectedSubfields[tag][fieldPosition])
           selectedSubfields[tag][fieldPosition] = {};
         selectedSubfields[tag][fieldPosition][subfieldIndex] =
           gRecord[tag][fieldPosition][0][subfieldIndex];
       }
     } else {
       // this subfield is a part of entirely selected field... we have already included the information about subfields
     }
   });
   var result={};
   result.fields = selectedFields;
   result.subfields = selectedSubfields;
   return result;
 }
 
 function urPerformChangeSubfieldContent(tag, fieldPos, subfieldPos, code, val, isUndo){
   // changing the server side model
   var ajaxData = {
     recID: gRecID,
     requestType: 'modifyContent',
     tag: tag,
     fieldPosition: fieldPos,
     subfieldIndex: subfieldPos,
     subfieldCode: code,
     value: val,
     undoRedo: (isUndo ? "undo": "redo")
   };
 
   // changing the model
   gRecord[tag][fieldPos][0][subfieldPos][0] = code;
   gRecord[tag][fieldPos][0][subfieldPos][1] = val;
 
   // changing the display .... what if being edited right now ?
   redrawFields(tag);
   reColorFields();
 
   return ajaxData;
 }
 
 function urPerformChangeSubfieldCode(tag, fieldPos, subfieldPos, code, val, isUndo){
   // changing the server side model
   var ajaxData = {
     recID: gRecID,
     requestType: 'modifySubfieldTag',
     tag: tag,
     fieldPosition: fieldPos,
     subfieldIndex: subfieldPos,
     subfieldCode: code,
     value: val,
     undoRedo: (isUndo ? "undo": "redo")
   };
 
   gRecord[tag][fieldPos][0][subfieldPos][0] = code;
   gRecord[tag][fieldPos][0][subfieldPos][1] = val;
 
   // changing the display .... what if being edited right now ?
   redrawFields(tag);
   reColorFields();
 
   return ajaxData;
 }
 
 function urPerformChangeFieldCode(oldTag, oldInd1, oldInd2, newTag, ind1, ind2,
                                   fieldPos, isUndo){
   // changing the server side model
   var ajaxData = {
     recID: gRecID,
     requestType: 'modifyFieldTag',
     oldTag: newTag,
     oldInd1: ind1,
     oldInd2: ind2,
     newTag: oldTag,
     fieldPosition: fieldPos,
     ind1: oldInd1,
     ind2: oldInd2,
     undoRedo: (isUndo ? "undo": "redo")
   };
 
   // updating the local model
   var currentField = gRecord[newTag][fieldPos];
   currentField[1] = oldInd1;
   currentField[2] = oldInd2;
   gRecord[newTag].splice(fieldPos,1);
   if (gRecord[newTag].length == 0){
       delete gRecord[newTag];
   }
   var fieldNewPos;
   if (gRecord[oldTag] == undefined) {
       fieldNewPos = 0;
       gRecord[oldTag] = [];
       gRecord[oldTag][fieldNewPos] = currentField;
   }
   else {
       fieldNewPos = gRecord[oldTag].length;
       gRecord[oldTag].splice(fieldNewPos, 0, currentField);
   }
   // changing the display .... what if being edited right now ?
   redrawFields(newTag);
   redrawFields(oldTag);
   reColorFields();
 
   return ajaxData;
 }
 
 function performChangeField(tag, fieldPos, ind1, ind2, subFields, isControlfield,
   value, undoRedo){
   /** Function changing the field structure and generating an appropriate AJAX
       request handler
       Arguments:
         tag, fieldPos, ind1, ind2, subFields, isControlfield, value - standard
           values describing a field. tag, fieldPos are used to locate the field
           instance (which has to exist) and its content is modified accordingly.
         undoRedo - a undoRedo Handler or one of the words "undo"/"redo"
    */
   var ajaxData = {
     recID: gRecID,
     requestType: "modifyField",
     controlfield : isControlfield,
     fieldPosition : fieldPos,
     ind1: ind1,
     ind2: ind2,
     tag: tag,
     subFields: subFields,
     undoRedo : undoRedo,
     hpChanges: {}
   }
 
   // local changes
   gRecord[tag][fieldPos][0] = subFields;
   gRecord[tag][fieldPos][1] = ind1;
   gRecord[tag][fieldPos][2] = ind2;
   gRecord[tag][fieldPos][3] = value;
   redrawFields(tag);
   reColorFields();
 
   return ajaxData;
 }
 
 function urPerformChangeField(tag, fieldPos, ind1, ind2, subFields,
   isControlfield, value, isUndo){
   /**
    */
   return performChangeField(tag, fieldPos, ind1, ind2, subFields,
     isControlfield, value, (isUndo ? "undo" : "redo"));
 }
 
 function performMoveField(tag, oldFieldPosition, direction, undoRedo){
   var newFieldPosition = oldFieldPosition + (direction == "up" ? -1 : 1);
   // Create Ajax request.
   var ajaxData = {
     recID: gRecID,
     requestType: 'moveField',
     tag: tag,
     fieldPosition: oldFieldPosition,
     direction: direction,
     undoRedo: (undoRedo == true) ? "undo" : ((undoRedo == false) ? "redo" : undoRedo)
   };
 
   //continue updating locally
   var currentField = gRecord[tag][oldFieldPosition];
   gRecord[tag][oldFieldPosition] = gRecord[tag][newFieldPosition];
   gRecord[tag][newFieldPosition] = currentField;
 
   $('tbody#rowGroup_'+tag+'_'+(newFieldPosition)).replaceWith(
       createField(tag, gRecord[tag][newFieldPosition], newFieldPosition));
   $('tbody#rowGroup_'+tag+'_'+oldFieldPosition).replaceWith(
       createField(tag, gRecord[tag][oldFieldPosition], oldFieldPosition));
 
   reColorFields();
 
   // Now taking care of having the new field selected and the rest unselected
   setAllUnselected();
   setFieldSelected(tag, newFieldPosition);
 //$('#boxField_'+tag+'_'+(newFieldPosition)).click();
   return ajaxData;
 }
 
 function setSelectionStatusField(tag, fieldPos, status){
   var fieldCheckbox = $('#boxField_' + tag + '_' + fieldPos);
   var subfieldCheckboxes = $('#rowGroup_' + tag + '_' + fieldPos + ' .bibEditBoxSubfield');
 
   fieldCheckbox.each(function(ind){
       if (fieldCheckbox[ind].checked != status)
       {
           fieldCheckbox[ind].click();
       }
   });
 }
 
 function urPerformDeletePositionedFieldsSubfields(toDelete, isUndo){
   return deleteFields(toDelete, isUndo);
 }
 
 /** General Undo/Redo treatment lists */
 
 function setSelectionStatusSubfield(tag, fieldPos, subfieldPos, status){
   var subfieldCheckbox = $('#boxSubfield_' + tag + '_' + fieldPos + '_' + subfieldPos);
   if (subfieldCheckbox[0].checked != status)
   {
       subfieldCheckbox[0].click();
   }
 }
 
 function createFields(toCreateFields, isUndo){
   // a function adding fields.
   // toCreateFields : a structure describing fields and subfields to create
   //   this structure is the same as for the function deleteFields
 
   // 1) Preparing the AJAX request
   var tagsToRedraw = {}
   var ajaxData = {
     recID: gRecID,
     requestType: 'addFieldsSubfieldsOnPositions',
     fieldsToAdd: toCreateFields.fields,
     subfieldsToAdd: toCreateFields.subfields
   };
 
   if (isUndo != undefined){
     ajaxData['undoRedo'] = (isUndo ? "undo": "redo");
   }
 
   // 2) local processing -> creating the fields locally
   //   - first creating the missing fields so all the subsequent field indices are correcr
   for (tag in toCreateFields.fields){
     if (gRecord[tag] == undefined){
       gRecord[tag] = [];
     }
     tagsToRedraw[tag] = true;
     var fieldIndices = [];
     for (fieldPos in toCreateFields.fields[tag]){
       fieldIndices.push(fieldPos);
     }
     fieldIndices.sort(); // we have to add fields in the increasing order
       for (indInd in fieldIndices){
         var fieldIndexToAdd = fieldIndices[indInd]; // index of the field index to add in the indices array
         var newField = toCreateFields.fields[tag][fieldIndexToAdd];
         gRecord[tag].splice(fieldIndexToAdd, 0, newField);
       }
   }
 
   //   - now appending the remaining subfields
 
   for (tag in toCreateFields.subfields){
     tagsToRedraw[tag] = true;
     for (fieldPos in toCreateFields.subfields[tag]){
       var subfieldPositions = [];
       for (subfieldPos in toCreateFields.subfields[tag][fieldPos]){
         subfieldPositions.push(subfieldPos);
       }
       subfieldPositions.sort();
       for (subfieldInd in subfieldPositions){
         subfieldPosition = subfieldPositions[subfieldInd];
         gRecord[tag][fieldPos][0].splice(
           subfieldPosition, 0,
           toCreateFields.subfields[tag][fieldPos][subfieldPosition]);
       }
     }
   }
 
   // - redrawint the affected tags
 
   for (tag in tagsToRedraw){
    redrawFields(tag);
   }
   reColorFields();
 
   return ajaxData;
 }
 
 
 /* Bibcirculation Panel functions */
 
 function isBibCirculationPanelNecessary(){
   /** A function checking if the BibCirculation connectivity panel should
       be displayed. This information is derieved from the state of the record.
       Returns true or false
   */
 
   if (gRecID === null){
     return false;
   }
 
   // only if the record is saved and exists in the database and belongs
   // to a particular colelction
   return gDisplayBibCircPanel;
 }
 
 
 function updateBibCirculationPanel(){
   /** Updates the BibCirculation panel contents and visibility
   */
   if (gDisplayBibCircPanel === false){
     // in case, the panel is present, should be hidden
     $("#bibEditBibCircConnection").addClass("bibEditHiddenElement");
   }
   else {
     // the panel must be present - we have to show it
     $(".bibEditBibCircConnection").removeClass("bibEditHiddenElement");
   }
 
   var interfaceElement = $("#bibEditBibCircConnection");
   if (isBibCirculationPanelNecessary()){
     interfaceElement.removeClass("bibEditHiddenElement");
   } else {
     interfaceElement.addClass("bibEditHiddenElement");
   }
 
   // updating the content
   var copiesCountElement = $('#bibEditBibCirculationCopies');
   copiesCountElement.attr("innerHTML", gPhysCopiesNum);
 }
 
 function bibCircIntGetEditCopyUrl(recId){
   /**A function returning the address under which, the edition of a
       given record is possible
   */
 
 //  return "/admin/bibcirculation/bibcirculationadmin.py/get_item_details?recid=" + recId;
   return gBibCircUrl;
 }
 
 
 function onBibCirculationBtnClicked(e){
   /** A function redirecting the user to the BibCiculation web interface
   */
   var link = bibCircIntGetEditCopyUrl(gRecID);
   window.open(link);
 }