User:Magnus Manske/less edit clutter.js

From Wikipedia, the free encyclopedia
Jump to navigation Jump to search
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: hold down the Ctrl key and click the Refresh or Reload button. Firefox: hold down the Shift key while clicking Reload (or press Ctrl-Shift-R). Google Chrome and Safari users can just click the Reload button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
if ( ( wgAction == "submit" || wgAction == "edit" ) && wgNamespaceNumber == 0 ) {
  addOnloadHook ( less_edit_clutter_init ) ;
}

var lec_parse_references = 1 ;

var lec_parent ;
var lec_tb1 ;
var lec_original ;
var lec_tb_top ;
var lec_tb_ill ;
var lec_tb_cat ;
var lec_tb_bt ;
var lec_tb_ref ;
var lec_active ;
var lec_last_edited = null ;


function less_edit_clutter_init () {
  lec_active = 1 ;
  less_edit_clutter_create_elements () ;
  less_edit_clutter_hook_button ( 'wpSave' ) ;
  less_edit_clutter_hook_button ( 'wpPreview' ) ;
  less_edit_clutter_hook_button ( 'wpDiff' ) ;
  less_edit_clutter_parse_main_textbox () ;
  if(window.AJAXPreview) AJAXPreview.getTextContent = less_edit_clutter_get_rejoined_text ;
}

function less_edit_clutter_insert_at_cursor ( field , value ) {
  if (document.selection) {
    field.focus();
    sel = document.selection.createRange();
    sel.text = value;
  } else if (field.selectionStart || field.selectionStart == '0') {
    var startPos = field.selectionStart;
    var endPos = field.selectionEnd;
    field.value = field.value.substring(0, startPos)+ value+ field.value.substring(endPos, field.value.length);
  }
}

function less_edit_clutter_hook_button ( id ) {
  var b = document.getElementById ( id ) ;
  b.onclick = function () { less_edit_clutter_rejoin() ; return true ; } ;
}

function less_edit_clutter_delete_reference () {
  var si = lec_tb_ref.selectedIndex ;
  if ( !si || si == null ) return ; // Nothing selected
  var text = lec_tb_ref[si].firstChild.nodeValue ;
  text = text.split ( ' : ' ) ;
  var value = text.shift() ;
  text = text.join ( ' : ' ) ;
  text = text.split ( ' | ' ) ;
  var refstuff = text.shift() ;
  text = text.join ( ' | ' ) ;
  
  var key = '<<REF' + value + '>>' ;
  lec_tb_top.value = lec_tb_top.value.split(key).join('') ;
  lec_tb1.value = lec_tb1.value.split(key).join('') ;
  lec_tb_bt.value = lec_tb_bt.value.split(key).join('') ;
  less_edit_clutter_rejoin () ;
  less_edit_clutter_parse_main_textbox () ;
  return false ;
}

function less_edit_clutter_insert_new_reference () {
  if ( lec_last_edited == null ) return ;

  var refstuff = prompt ( "Enter reference name:" , '' ) ;
  if ( null == refstuff ) return ; // Cancel
  var text = prompt ( "Enter reference contents:" , '' ) ;
  if ( null == text ) return ; // Cancel

  var max = lec_tb_ref.length + 2 ;

  less_edit_clutter_insert_at_cursor ( lec_last_edited , '<<REF' + max + '>>' ) ;

  text = max + ' : ' + refstuff + ' | ' + text ;
  
  var opt = document.createElement ( 'option' ) ;
  opt.value = max-1 ;
  opt.appendChild ( document.createTextNode ( text ) ) ;
  lec_tb_ref.appendChild ( opt ) ;
  
  less_edit_clutter_rejoin () ;
  less_edit_clutter_parse_main_textbox () ;
  return false ;
}

function less_edit_clutter_mark_text_range ( ctrl , from , to ) {
  if(ctrl.setSelectionRange) {
    ctrl.focus();
    ctrl.setSelectionRange ( from , to ) ;
  }
  else if (ctrl.createTextRange) {
    var range = ctrl.createTextRange();
    range.collapse ( true ) ;
    range.moveEnd ( 'character', from ) ;
    range.moveStart ( 'character', to ) ;
    range.select();
  }
}

function less_edit_clutter_tb1_select ( ta ) {
  var selection = ta.value.substr(ta.selectionStart, ta.selectionEnd - ta.selectionStart);
  if ( ! /^\<*REF\d+\>*$/.test ( selection ) ) return ;
  var num = selection.match ( /^\<*REF(\d+)\>*$/ ) ;
  num = num.pop() ;
  num-- ;
  lec_tb_ref[num].selected = true ;
}

function less_edit_clutter_find_and_mark ( text , ctrl ) {
  var pos = ctrl.value.search ( text ) ;
  if ( pos < 0 ) return true ; // Continue search
  less_edit_clutter_mark_text_range ( ctrl , pos , pos + text.length ) ;
  return false ;
}

function less_edit_clutter_refsel_changed () {
  var si = lec_tb_ref.selectedIndex + 1 ;
  var key = '<<REF' + si + '>>' ;
  var cont = true ;
  if ( cont ) cont = less_edit_clutter_find_and_mark ( key , lec_tb_top ) ;
  if ( cont ) cont = less_edit_clutter_find_and_mark ( key , lec_tb1 ) ;
  if ( cont ) cont = less_edit_clutter_find_and_mark ( key , lec_tb_bt ) ;
  if ( cont ) alert ( "Something's wrong - could not find reference " + key + "! Better reload this edit in the standard edit box!" ) ;
}

function less_edit_clutter_refsel_double_clicked () {
  var si = lec_tb_ref.selectedIndex ;
  var text = lec_tb_ref[si].firstChild.nodeValue ;
  text = text.split ( ' : ' ) ;
  var value = text.shift() ;
  text = text.join ( ' : ' ) ;
  text = text.split ( ' | ' ) ;
  var refstuff = text.shift() ;
  text = text.join ( ' | ' ) ;
  refstuff = prompt ( "Enter reference name:" , refstuff ) ;
  if ( null == refstuff ) return ; // Cancel
  text = prompt ( "Enter reference contents:" , text ) ;
  if ( null == text ) return ; // Cancel
  lec_tb_ref[si].firstChild.nodeValue = value + ' : ' + refstuff + ' | ' + text ;
}

function less_edit_clutter_get_rejoined_text () {
  if ( lec_active != 1 ) return '' ;
  v = lec_tb_top.value ;
  v = v.replace(/^\s+|\s+$/g,"") ;
  if ( v != '' ) v += "\n" ;
  v += lec_tb1.value ;
  v = v.replace(/^\s+|\s+$/g,"") ;
  if ( v != '' ) v += "\n\n" ;
  v += lec_tb_bt.value ;
  v = v.replace(/^\s+|\s+$/g,"") ;
  if ( v != '' ) v += "\n\n" ;

  // Categories
  n = lec_tb_cat.value.split ( "\n" ) ;
  n = n.sort() ;
  for ( i = 0 ; i < n.length ; i++ ) {
    s = n[i].replace(/^\s+|\s+$/g,"") ;
    if ( s == '' ) continue ;
    v += '[[Category:' + 
         s + "]]\n" ;
  }
  v = v.replace(/^\s+|\s+$/g,"") ;
  if ( v != '' ) v += "\n\n" ;

  // Interlanguage links
  n = lec_tb_ill.value.split ( "\n" ) ;
  n = n.sort() ;
  for ( i = 0 ; i < n.length ; i++ ) {
    s = n[i].replace(/^\s+|\s+$/g,"") ;
    if ( s == '' ) continue ;
    v += '[[' + s + "]]\n" ;
  }
  v = v.replace(/^\s+|\s+$/g,"") ;
  
  if ( lec_parse_references ) {
    for ( var n = lec_tb_ref.firstChild ; n ; n = n.nextSibling ) {
      var text = n.firstChild.nodeValue ;
      text = text.split ( ' : ' ) ;
      var value = text.shift() ;
      text = text.join ( ' : ' ) ;
      text = text.split ( ' | ' ) ;
      var refstuff = text.shift() ;
      text = text.join ( ' | ' ) ;
      if ( refstuff != '' ) {
      	var r = refstuff.match ( /^(.*)::(.*)$/ ) ;
      	if ( r == null ) {
	      	refstuff = ' name="' + refstuff + '"' ;
      	} else {
      		var gn = r.pop() ;
      		var rn = r.pop() ;
      		refstuff = '' ;
      		if ( gn != '' ) refstuff += ' group="' + gn + '"' ;
      		if ( rn != '' ) refstuff += ' name="' + rn + '"' ;
      	}
      	
      }
      text = '<ref' + refstuff + '>' + text + '</ref>' ;
      var key = '<<REF' + value + '>>' ;
      v = v.split(key).join(text) ;
    }
  }
  return v ;
}

function less_edit_clutter_rejoin () {
  if ( lec_active != 1 ) return ;
  lec_tb1.value = less_edit_clutter_get_rejoined_text() ;
}

function less_edit_clutter_create_elements () {
  lec_tb1 = document.getElementById ( 'wpTextbox1' ) ;
  lec_parent = lec_tb1.parentNode ;

  lec_tb_top = document.createElement ( 'textarea' ) ;
  lec_tb_top.id = 'lec_tb_top' ;
  lec_tb_top.name = 'lec_tb_top' ;
  lec_tb_top.cols = 80 ;
  lec_tb_top.rows = 5 ;
  
  lec_tb_ill = document.createElement ( 'textarea' ) ;
  lec_tb_ill.id = 'lec_tb_ill' ;
  lec_tb_ill.name = 'lec_tb_ill' ;
  lec_tb_ill.cols = 30 ;
  lec_tb_ill.rows = 5 ;

  lec_tb_cat = document.createElement ( 'textarea' ) ;
  lec_tb_cat.id = 'lec_tb_cat' ;
  lec_tb_cat.name = 'lec_tb_cat' ;
  lec_tb_cat.cols = 30 ;
  lec_tb_cat.rows = 5 ;

  lec_tb_bt = document.createElement ( 'textarea' ) ;
  lec_tb_bt.id = 'lec_tb_bt' ;
  lec_tb_bt.name = 'lec_tb_bt' ;
  lec_tb_bt.cols = 30 ;
  lec_tb_bt.rows = 5 ;
  
  lec_bottom_table = document.createElement ( 'table' ) ;
  lec_bottom_tbody = document.createElement ( 'tbody' ) ;
  lec_bottom_tr = document.createElement ( 'tr' ) ;
  lec_bottom_tr2 = document.createElement ( 'tr' ) ;
  lec_bottom_td1 = document.createElement ( 'td' ) ;
  lec_bottom_td2 = document.createElement ( 'td' ) ;
  lec_bottom_td3 = document.createElement ( 'td' ) ;

  lec_bottom_td1.style.width = '40%' ;
  lec_bottom_td2.style.width = '30%' ;
  lec_bottom_td3.style.width = '30%' ;

  lec_bottom_td1.appendChild ( document.createTextNode ( 'End templates and magic words' ) ) ;
  lec_bottom_td1.appendChild ( document.createElement ( 'br' ) ) ;
  lec_bottom_td1.appendChild ( lec_tb_bt ) ;

  lec_bottom_td2.appendChild ( document.createTextNode ( 'Categories' ) ) ;
  lec_bottom_td2.appendChild ( document.createElement ( 'br' ) ) ;
  lec_bottom_td2.appendChild ( lec_tb_cat ) ;

  lec_bottom_td3.appendChild ( document.createTextNode ( 'Interlanguage links' ) ) ;
  lec_bottom_td3.appendChild ( document.createElement ( 'br' ) ) ;
  lec_bottom_td3.appendChild ( lec_tb_ill ) ;

  if ( lec_parse_references ) {
    lec_tb1.onselect = function () { less_edit_clutter_tb1_select ( lec_tb1 ) ; } ;
    lec_tb_top.onselect = function () { less_edit_clutter_tb1_select ( lec_tb_top ) ; } ;
    lec_tb_bt.onselect = function () { less_edit_clutter_tb1_select ( lec_tb_bt ) ; } ;

    lec_tb1.onfocus = function () { lec_last_edited = lec_tb1 ; } ;
    lec_tb_top.onfocus = function () { lec_last_edited = lec_tb_top ; } ;
    lec_tb_bt.onfocus = function () { lec_last_edited = lec_tb_bt ; } ;

    lec_tb_ref = document.createElement ( 'select' ) ;
    lec_tb_ref.id = 'lec_tb_ref' ;
    lec_tb_ref.name = 'lec_tb_ref' ;
    lec_tb_ref.size = 5 ;
    lec_tb_ref.style.width = '100%' ;
    lec_tb_ref.onchange = less_edit_clutter_refsel_changed ;
    lec_tb_ref.ondblclick = less_edit_clutter_refsel_double_clicked ;

    var a_new_reference = document.createElement ( 'a' ) ;
    a_new_reference.appendChild ( document.createTextNode ( 'insert new reference' ) ) ;
    a_new_reference.href = '#' ;
    a_new_reference.onclick = less_edit_clutter_insert_new_reference ;

    var a_delete_reference = document.createElement ( 'a' ) ;
    a_delete_reference.appendChild ( document.createTextNode ( 'delete reference' ) ) ;
    a_delete_reference.href = '#' ;
    a_delete_reference.onclick = less_edit_clutter_delete_reference ;

    lec_bottom_td4 = document.createElement ( 'td' ) ;
    lec_bottom_td4.appendChild ( document.createTextNode ( 'References (' ) ) ;
    lec_bottom_td4.appendChild ( a_new_reference ) ;
    lec_bottom_td4.appendChild ( document.createTextNode ( ' | ' ) ) ;
    lec_bottom_td4.appendChild ( a_delete_reference ) ;
    lec_bottom_td4.appendChild ( document.createTextNode ( ')' ) ) ;
    lec_bottom_td4.appendChild ( document.createElement ( 'br' ) ) ;
    lec_bottom_td4.appendChild ( lec_tb_ref ) ;
    lec_bottom_td4.colSpan = '3' ;

    lec_bottom_tr2.appendChild ( lec_bottom_td4 ) ;
    lec_bottom_tbody.appendChild ( lec_bottom_tr2 ) ;
  }
  
  lec_bottom_tr.appendChild ( lec_bottom_td1 ) ;
  lec_bottom_tr.appendChild ( lec_bottom_td2 ) ;
  lec_bottom_tr.appendChild ( lec_bottom_td3 ) ;
  lec_bottom_tbody.appendChild ( lec_bottom_tr ) ;
  lec_bottom_table.appendChild ( lec_bottom_tbody ) ;

  var a = document.createElement ( 'a' ) ;
  a.href = '#' ;
  a.appendChild ( document.createTextNode ( "reload in standard edit box" ) ) ;
  a.onclick = function () {
    u = document.getElementById('lec_div_top') ;
    u.parentNode.removeChild ( u ) ;
    u = document.getElementById('lec_div_bottom') ;
    u.parentNode.removeChild ( u ) ;
    lec_tb1.value = lec_original ;
    lec_active = 0 ;
    return false ;
  }

  var b = document.createElement ( 'a' ) ;
  b.href = '#' ;
  b.appendChild ( document.createTextNode ( "redo for current contents" ) ) ;
  b.onclick = function () {
    less_edit_clutter_rejoin () ;
    less_edit_clutter_parse_main_textbox () ;
    return false ;
  }
  var top = document.createElement ( 'div' ) ;
  top.id = 'lec_div_top' ;

  var adiv = document.createElement ( 'div' ) ;
  adiv.style.display = 'block' ;
  adiv.appendChild ( document.createTextNode ( "Main text (" ) ) ;
  adiv.appendChild ( a ) ;
  adiv.appendChild ( document.createTextNode ( " | " ) ) ;
  adiv.appendChild ( b ) ;
  adiv.appendChild ( document.createTextNode ( ")" ) ) ;

  top.appendChild ( document.createTextNode ( "Header templates and images" ) ) ;
  top.appendChild ( lec_tb_top ) ;
  top.appendChild ( adiv ) ;

  var bottom = document.createElement ( 'div' ) ;
  bottom.id = 'lec_div_bottom' ;

  bottom.appendChild ( document.createTextNode ( 'Elements at the end' ) ) ;
  bottom.appendChild ( lec_bottom_table ) ;

  lec_parent.insertBefore ( bottom , lec_tb1.nextSibling ) ;
  lec_parent.insertBefore ( top , lec_tb1 ) ;

  lec_bottom_table.id = 'lec_tb_bottom' ;
  lec_bottom_table.style.width = '100%' ;
  lec_bottom_table.style.cellSpacing = '2' ;
  lec_bottom_table.style.cellPadding = '2' ;


  less_edit_clutter_append_show_hide ( 'lec_tb_top' ) ;
  less_edit_clutter_append_show_hide ( 'lec_tb_bottom' ) ;
}

function less_edit_clutter_toggle_show_hide ( id , a ) {
  var x = document.getElementById ( id ) ;
  if ( x.style.display == 'none' ) {
    x.style.display = '' ;
    while ( a.firstChild ) a.removeChild ( a.firstChild ) ;
    a.appendChild (  document.createTextNode ( 'hide' ) ) ;
  } else {
    x.style.display = 'none' ;
    while ( a.firstChild ) a.removeChild ( a.firstChild ) ;
    a.appendChild ( document.createTextNode ( 'show' ) ) ;
  }
}

function less_edit_clutter_append_show_hide ( id ) {
  var x = document.getElementById ( id ) ;
  var n = document.createElement ( 'span' ) ;

  var a = document.createElement ( 'a' ) ;
  a.href = '#' ;
  a.onclick = function () { less_edit_clutter_toggle_show_hide ( id , this ) ; return false ; }
  a.appendChild ( document.createTextNode ( 'hide' ) ) ;

  n.appendChild ( document.createTextNode ( ' (' ) ) ;
  n.appendChild ( a ) ;
  n.appendChild ( document.createTextNode ( ')' ) ) ;
  n.appendChild ( document.createElement ( 'br' ) ) ;

  x.parentNode.insertBefore ( n , x ) ;
//  x.style.display = 'none' ;
}

function less_edit_clutter_parse_main_textbox () {
  lec_original = lec_tb1.value ;
  var lines = lec_original.split("\n") ;
  var in_template = 0 ;
  var begin_templates = "" ;
  
  // References
  if ( lec_parse_references && /\<\<REF\d+\>\>/.test ( lec_original ) ) lec_parse_references = 0 ; // Already contains pattern, aborting
  if ( lec_parse_references ) {
    cnt = 1 ;
    v = lec_original ;
    v = v.split ( /\<ref/ig ) ;
    o = v.shift () ;
    refs = new Array () ;
    while ( lec_tb_ref.firstChild ) lec_tb_ref.removeChild ( lec_tb_ref.firstChild ) ;
    for ( i = 0 ; i < v.length ; i++ ) {
      if ( v[i].substr(0,1) != ' ' && v[i].substr(0,1) != '>' ) { // Something that is not a reference tag
        o += '<ref' + v[i] ;
        continue ;
      }
      n = v[i].split ( '>' ) ;
      if ( n.length < 2 ) { o += '<ref' + v[i] ; continue ; }
      
      var attrs = n.shift() ;
      
      var name_attr = attrs ;
      rs = name_attr.match ( /name=\"([^"]*)\"/ ) ;
      if ( rs == null ) rs = name_attr.match ( /name=\'([^']*)\'/ ) ;
      if ( rs == null ) rs = name_attr.match ( /name=([a-zA-Z0-9_\-]*)/ ) ;
      name_attr = rs ;
      if ( null == name_attr ) name_attr = '' ;
      else name_attr = name_attr.pop() ;

      var group_attr = attrs ;
      rs = group_attr.match ( /group=\"([^"]*)\"/ ) ;
      if ( rs == null ) rs = group_attr.match ( /group=\'([^']*)\'/ ) ;
      if ( rs == null ) rs = group_attr.match ( /group=([a-zA-Z0-9_\-]*)/ ) ;
      group_attr = rs ;
      if ( null == group_attr ) group_attr = '' ;
      else group_attr = group_attr.pop() ;
      
      refstuff = name_attr ;
      if ( group_attr != '' ) refstuff += "::" + group_attr ;
      
      
      n = n.join ( '>' ) ;
      n = n.split ( '</ref>' ) ;
      if ( n.length < 2 ) { o += '<ref' + v[i] ; continue ; }
      refcontents = n.shift() ;
//      if ( n.length > 1 ) { o += '<ref' + v[i] ; continue ; }
      n = n.join ( '</ref>' ) ;
      o += '<<REF' + cnt + '>>' + n ;
      refs.push ( cnt + ' : ' + refstuff + ' | ' + refcontents ) ;
      cnt++ ;
    }
    for ( i = 0 ; i < refs.length ; i++ ) {
      var opt = document.createElement ( 'option' ) ;
      opt.value = i ;
      opt.appendChild ( document.createTextNode ( refs[i] ) ) ;
      lec_tb_ref.appendChild ( opt ) ;
    }
    lines = o.split("\n") ;
  }

  // Begin of text
  var in_table = 0 ;
  while ( lines.length > 0 ) {
    var no_ws = lines[0].replace(/^\s+|\s+$/g,"") ;
    var lc = no_ws.toLowerCase() ;
    if ( lc == "" ) {
      lines.shift() ;
      if ( begin_templates != '' ) begin_templates += "\n" ;
    } else if ( lc.match(/^\{\{[^\{\}]*\}\}$/) ) {
      lines.shift() ;
      begin_templates = begin_templates + no_ws + "\n" ;
    } else if ( lc.match(/^\{\{[^\{\}]*$/) ) {
      begin_templates = begin_templates + lines.shift() + "\n" ;
      in_template++ ;
    } else if ( in_template && lc.match(/^[^\}\{]*\}\}\s*$/) ) {
      begin_templates = begin_templates + lines.shift() + "\n" ;
      in_template-- ;
    } else if ( in_template > 0 ) {
      begin_templates = begin_templates + lines.shift() + "\n" ;
    } else if ( lc.match(/^[-_]+$/) || lc.match(/^\s*\<hr\s*\/*\>\s*$/) ) {
      begin_templates = begin_templates + lines.shift() + "\n" ;
    } else if ( lc.match(/^\[\[image\:.*\]\]$/) ) {
      begin_templates = begin_templates + lines.shift() + "\n" ;
    } else if ( lc.match(/^\[\[file\:.*\]\]$/) ) {
      begin_templates = begin_templates + lines.shift() + "\n" ;
      
    } else if ( lc.match(/^:/) ) { // Indented "For other uses..."
      begin_templates = begin_templates + lines.shift() + "\n" ;
      
    } else if ( lc.match(/^\{\|/) ) { // Table open
      in_table++ ;
      begin_templates = begin_templates + lines.shift() + "\n" ;
    } else if ( lc.match(/^\s*\|\}/) && in_table > 0 ) { // Table close
      in_table-- ;
      begin_templates = begin_templates + lines.shift() + "\n" ;
    } else if ( in_table > 0 ) {
      begin_templates = begin_templates + lines.shift() + "\n" ;

    } else break ;
  }

  begin_templates = begin_templates.replace(/^\s+|\s+$/g,"") ;


  var categories = new Array () ;
  var languages = new Array () ;
  var end_templates = "" ;
  
  // End of text
  in_template = 0 ;
  end_templates_append = "" ;
  while ( lines.length > 0 ) {
    var lp = lines.length - 1 ;
    var no_ws = lines[lp].replace(/^\s+|\s+$/g,"") ;
    var lc = no_ws.toLowerCase() ;
    if ( lc == "" ) {
      lines.pop() ;
      if ( end_templates != '' ) end_templates = "\n" + end_templates ;
    } else if ( lc.substr ( 0 , 11 ) == "[[category:" ) {
      lines.pop() ;
      var s = no_ws.substr ( 11 ) ;
      s = s.replace ( /\]\]$/ , "" ) ;
      categories.push ( s ) ;
    } else if ( lc.match(/^\[\[\w+\:.*\]\]$/) ) {
      lines.pop() ;
      var s = no_ws.substr ( 2 ) ;
      s = s.replace ( /\]\]$/ , "" ) ;
      languages.push ( s ) ;
    } else if ( lc.match(/^\{\{defaultsort\s*[\|\:].*\}\}$/) ) {
      end_templates_append += "\n\n" + lines.pop() ;
    } else if ( lc.match(/^\<!--.*-->$/) ) {
      end_templates = lines.pop() + "\n" + end_templates ;
    } else if ( lc.match(/^\{\{.*\}\}$/) ) {
      end_templates = lines.pop() + "\n" + end_templates ;
    } else if ( lc.match(/^[^\{\}]*\}\}$/) ) {
      end_templates = lines.pop() + "\n" + end_templates ;
      in_template++ ;
    } else if ( lc.match(/^\{\{[^\{\}]*$/) ) {
      end_templates = lines.pop() + "\n" + end_templates ;
      in_template-- ;
    } else if ( in_template > 0 ) {
      end_templates = lines.pop() + "\n" + end_templates ;
    } else break ;
  }

  var oet ;
  do {
    oet = end_templates ;
    end_templates = end_templates.split("\n\n\n").join("\n\n") ;
  } while ( end_templates != oet ) ;
  end_templates = end_templates.replace(/^\s+|\s+$/g,"") ;
  end_templates_append = end_templates_append.replace(/^\s+|\s+$/g,"") ;
  if ( end_templates != '' && end_templates_append != '' ) end_templates += "\n\n" ;
  end_templates += end_templates_append ;

  // Set boxes
  lec_tb_top.value = begin_templates ;
  lec_tb_cat.value = categories.sort().join("\n") ;
  lec_tb_ill.value = languages.sort().join("\n") ;
  lec_tb_bt.value = end_templates ;
  lec_tb1.value = lines.join("\n") ;
}