Subversion Repositories oidplus

Rev

Rev 218 | View as "text/javascript" | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * OIDplus 2.0
  3.  * Copyright 2019 Daniel Marschall, ViaThinkSoft
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17.  
  18. /*jshint esversion: 6 */
  19.  
  20. // $('#html').jstree();
  21.  
  22. var current_node = "";
  23. var popstate_running = false;
  24.  
  25. function oidplus_loadScript(src) {
  26.         var js = document.createElement('script');
  27.         js.src = src;
  28.         js.onload = function() {
  29.         };
  30.         js.onerror = function() {
  31.         };
  32.         document.head.appendChild(js);
  33. }
  34.  
  35. function oidplus_external_polyfill() {
  36.         // Disable this code by adding following line to includes/config.inc.php
  37.         // define('RECAPTCHA_ENABLED', false);
  38.         var ua = window.navigator.userAgent;
  39.         if ((ua.indexOf("MSIE ") > 0) || (ua.indexOf("Trident/") > 0)) {
  40.                 // Compatibility with Internet Explorer
  41.                 oidplus_loadScript('https://polyfill.io/v3/polyfill.min.js?features=fetch%2CURL');
  42.         }
  43. }
  44.  
  45. function oidplus_external_recaptcha() {
  46.         // Disable this code by adding following lines to includes/config.inc.php
  47.         // define('DISABLE_MSIE_COMPAT', true);
  48.         oidplus_loadScript('https://www.google.com/recaptcha/api.js');
  49. }
  50.  
  51. String.prototype.explode = function (separator, limit) {
  52.         // https://stackoverflow.com/questions/4514323/javascript-equivalent-to-php-explode
  53.         const array = this.split(separator);
  54.         if (limit !== undefined && array.length >= limit) {
  55.                 array.push(array.splice(limit - 1).join(separator));
  56.         }
  57.         return array;
  58. };
  59.  
  60. String.prototype.htmlentities = function () {
  61.         return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
  62. };
  63.  
  64. String.prototype.html_entity_decode = function () {
  65.         return $('<textarea />').html(this).text();
  66. };
  67.  
  68. function getMeta(metaName) {
  69.         const metas = document.getElementsByTagName('meta');
  70.  
  71.         for (let i = 0; i < metas.length; i++) {
  72.                 if (metas[i].getAttribute('name') === metaName) {
  73.                         return metas[i].getAttribute('content');
  74.                 }
  75.         }
  76.  
  77.         return '';
  78. }
  79.  
  80. function getOidPlusSystemTitle() {
  81.         return getMeta('OIDplus-SystemTitle');
  82. }
  83.  
  84. function combine_systemtitle_and_pagetitle(systemtitle, pagetitle) {
  85.         if (systemtitle == pagetitle) {
  86.                 return systemtitle;
  87.         } else {
  88.                 return systemtitle + ' - ' + pagetitle;
  89.         }
  90. }
  91.  
  92. function getTreeLoadURL() {
  93.         var url = new URL(window.location.href);
  94.         var goto = url.searchParams.get("goto");
  95.         return (goto != null) ? "ajax.php?action=tree_load&goto="+encodeURIComponent(goto)
  96.                               : "ajax.php?action=tree_load";
  97. }
  98.  
  99. function reloadContent() {
  100.         // window.location.href = "?goto="+encodeURIComponent(current_node);
  101.         openOidInPanel(current_node, false);
  102.         $('#oidtree').jstree("refresh");
  103. }
  104.  
  105. function x_rec(x_data, i) {
  106.         $('#oidtree').jstree('open_node', x_data[i], function(e, data) {
  107.                 if (i+1 < x_data.length) {
  108.                         x_rec(x_data, i+1);
  109.                 } else {
  110.                         popstate_running = true; // don't call openOidInPanel again
  111.                         try {
  112.                                 $('#oidtree').jstree('select_node', x_data[i]);
  113.                         } catch (err) {
  114.                                 popstate_running = false;
  115.                         } finally {
  116.                                 popstate_running = false;
  117.                         }
  118.                 }
  119.         });
  120. }
  121.  
  122. function openOidInPanel(id, reselect/*=false*/, anchor/*=''*/) {
  123.         reselect = (typeof reselect === 'undefined') ? false : reselect;
  124.         anchor = (typeof anchor === 'undefined') ? '' : anchor;
  125.  
  126.         if (reselect) {
  127.                 $('#oidtree').jstree('deselect_all');
  128.  
  129.                 popstate_running = true; // don't call openOidInPanel during tree selection
  130.                 try {
  131.                         // If the node is already loaded in the tree, select it
  132.                         if (!$('#oidtree').jstree('select_node', id)) {
  133.                                 // If the node is not loaded, then we try to search it.
  134.                                 // If it can be found, then open all parent nodes and select the node
  135.                                 $.ajax({
  136.                                         url:"ajax.php",
  137.                                         method:"POST",
  138.                                         data:{
  139.                                                 action:"tree_search",
  140.                                                 search:id
  141.                                         },
  142.                                         error:function(jqXHR, textStatus, errorThrown) {
  143.                                                 console.error("Error: " + errorThrown);
  144.                                         },
  145.                                         success:function(data) {
  146.                                                 if ("error" in data) {
  147.                                                         console.error(data);
  148.                                                 } else if ((data instanceof Array) && (data.length > 0)) {
  149.                                                         x_rec(data, 0);
  150.                                                 } else {
  151.                                                         console.error(data);
  152.                                                 }
  153.                                         }
  154.                                 });
  155.                         }
  156.                 } catch (err) {
  157.                         popstate_running = false;
  158.                 } finally {
  159.                         popstate_running = false;
  160.                 }
  161.         }
  162.  
  163.         // This loads the actual content
  164.  
  165.         document.title = "";
  166.         $('#real_title').html("&nbsp;");
  167.         $('#real_content').html("Loading...");
  168.         $('#static_link').attr("href", "index.php?goto="+encodeURIComponent(id));
  169.         $("#gotoedit").val(id);
  170.  
  171.         // Normal opening of a description
  172.         fetch('ajax.php?action=get_description&id='+encodeURIComponent(id))
  173.         .then(function(response) {
  174.                 response.json()
  175.                 .then(function(data) {
  176.                         if ("error" in data) {
  177.                                 alert("Failed to load content: " + data.error);
  178.                                 console.error(data.error);
  179.                                 return;
  180.                         }
  181.  
  182.                         data.id = id;
  183.  
  184.                         document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.title);
  185.                         var state = {
  186.                                 "node_id":id,
  187.                                 "titleHTML":(data.icon ? '<img src="'+data.icon+'" width="48" height="48" alt="'+data.title.htmlentities()+'"> ' : '') + data.title.htmlentities(),
  188.                                 "textHTML":data.text,
  189.                                 "staticlinkHREF":"index.php?goto="+encodeURIComponent(id),
  190.                         };
  191.                         if (current_node != id) {
  192.                                 window.history.pushState(state, data.title, "?goto="+encodeURIComponent(id));
  193.                         } else {
  194.                                 window.history.replaceState(state, data.title, "?goto="+encodeURIComponent(id));
  195.                         }
  196.  
  197.                         if (data.icon) {
  198.                                 $('#real_title').html('<img src="'+data.icon+'" width="48" height="48" alt="'+data.title.htmlentities()+'"> ' + data.title.htmlentities());
  199.                         } else {
  200.                                 $('#real_title').html(data.title.htmlentities());
  201.                         }
  202.                         $('#real_content').html(data.text);
  203.                         document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.title);
  204.                         current_node = id;
  205.  
  206.                         if (anchor != '') {
  207.                                 jumpToAnchor(anchor);
  208.                         }
  209.                 })
  210.                 .catch(function(error) {
  211.                         alert("Failed to load content: " + error);
  212.                         console.error(error);
  213.                 });
  214.         })
  215.         .catch(function(error) {
  216.                 alert("Failed to load content: " + error);
  217.                 console.error(error);
  218.         });
  219. }
  220.  
  221. function updateDesc() {
  222.         $.ajax({
  223.                 url:"ajax.php",
  224.                 method:"POST",
  225.                 data: {
  226.                         action:"Update2",
  227.                         id:current_node,
  228.                         title:(document.getElementById('titleedit') ? document.getElementById('titleedit').value : null),
  229.                         //description:(document.getElementById('description') ? document.getElementById('description').value : null)
  230.                         description:tinyMCE.get('description').getContent()
  231.                 },
  232.                 error:function(jqXHR, textStatus, errorThrown) {
  233.                         alert("Error: " + errorThrown);
  234.                 },
  235.                 success:function(data) {
  236.                         if ("error" in data) {
  237.                                 alert("Error: " + data.error);
  238.                         } else if (data.status == 0) {
  239.                                 alert("Update OK");
  240.                                 //reloadContent();
  241.                                 $('#oidtree').jstree("refresh");
  242.                                 var h1s = document.getElementsByTagName("h1");
  243.                                 for (var i = 0; i < h1s.length; i++) {
  244.                                         var h1 = h1s[i];
  245.                                         h1.innerHTML = document.getElementById('titleedit').value.htmlentities();
  246.                                 }
  247.                                 document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), document.getElementById('titleedit').value);
  248.  
  249.                                 var mce = tinymce.get('description');
  250.                                 if (mce != null) mce.isNotDirty = 1;
  251.                         } else {
  252.                                 alert("Error: " + data.error);
  253.                         }
  254.                 }
  255.         });
  256. }
  257.  
  258. function crudActionSendInvitation(origin, email) {
  259.         // window.location.href = "?goto=oidplus:invite_ra$"+encodeURIComponent(email)+"$"+encodeURIComponent(origin);
  260.         openOidInPanel('oidplus:invite_ra$'+email+'$'+origin, false);
  261. }
  262.  
  263. function crudActionInsert(parent) {
  264.         $.ajax({
  265.                 url:"ajax.php",
  266.                 method:"POST",
  267.                 data:{
  268.                         action:"Insert",
  269.                         id:document.getElementById('id').value,
  270.                         ra_email:document.getElementById('ra_email').value,
  271.                         comment:document.getElementById('comment').value,
  272.                         asn1ids:(document.getElementById('asn1ids') ? document.getElementById('asn1ids').value : null),
  273.                         iris:(document.getElementById('iris') ? document.getElementById('iris').value : null),
  274.                         confidential:(document.getElementById('hide') ? document.getElementById('hide').checked : null),
  275.                         weid:(document.getElementById('weid') ? document.getElementById('weid').checked : null),
  276.                         parent:parent
  277.                 },
  278.                 error:function(jqXHR, textStatus, errorThrown) {
  279.                         alert("Error: " + errorThrown);
  280.                 },
  281.                 success:function(data) {
  282.                         if ("error" in data) {
  283.                                 alert("Error: " + data.error);
  284.                         } else if (data.status == 0/*OK*/) {
  285.                                 //alert("Insert OK");
  286.                                 reloadContent();
  287.                                 // TODO: auf reloadContent() verzichten. stattdessen nur tree links aktualisieren, und rechts eine neue zeile zur tabelle hinzufügen
  288.                         } else if (data.status == 1/*RaNotExisting*/) {
  289.                                 if (confirm("Update OK. However, the email address you have entered ("+document.getElementById('ra_email').value+") is not in our system. Do you want to send an invitation, so that the RA can register an account to manage their OIDs?")) {
  290.                                         crudActionSendInvitation(parent, document.getElementById('ra_email').value);
  291.                                 } else {
  292.                                         reloadContent();
  293.                                         // TODO: auf reloadContent() verzichten. stattdessen nur tree links aktualisieren, und rechts eine neue zeile zur tabelle hinzufügen
  294.                                 }
  295.                         } else if (data.status == 2/*RaNotExistingNoInvitation*/) {
  296.                                 //alert("Insert OK");
  297.                                 reloadContent();
  298.                                 // TODO: auf reloadContent() verzichten. stattdessen nur tree links aktualisieren, und rechts eine neue zeile zur tabelle hinzufügen
  299.                         } else {
  300.                                 alert("Error: " + data);
  301.                         }
  302.                 }
  303.         });
  304. }
  305.  
  306. function crudActionUpdate(id, parent) {
  307.         $.ajax({
  308.                 url:"ajax.php",
  309.                 method:"POST",
  310.                 data: {
  311.                         action:"Update",
  312.                         id:id,
  313.                         ra_email:document.getElementById('ra_email_'+id).value,
  314.                         comment:document.getElementById('comment_'+id).value,
  315.                         asn1ids:(document.getElementById('asn1ids_'+id) ? document.getElementById('asn1ids_'+id).value : null),
  316.                         iris:(document.getElementById('iris_'+id) ? document.getElementById('iris_'+id).value : null),
  317.                         confidential:(document.getElementById('hide_'+id) ? document.getElementById('hide_'+id).checked : null),
  318.                         parent:parent
  319.                 },
  320.                 error:function(jqXHR, textStatus, errorThrown) {
  321.                         alert("Error: " + errorThrown);
  322.                 },
  323.                 success:function(data) {
  324.                         if ("error" in data) {
  325.                                 alert("Error: " + data.error);
  326.                         } else if (data.status == 0/*OK*/) {
  327.                                 alert("Update OK");
  328.                                 // reloadContent();
  329.                                 $('#oidtree').jstree("refresh");
  330.                         } else if (data.status == 1/*RaNotExisting*/) {
  331.                                 if (confirm("Update OK. However, the email address you have entered ("+document.getElementById('ra_email_'+id).value+") is not in our system. Do you want to send an invitation, so that the RA can register an account to manage their OIDs?")) {
  332.                                         crudActionSendInvitation(parent, document.getElementById('ra_email_'+id).value);
  333.                                 } else {
  334.                                         // reloadContent();
  335.                                         $('#oidtree').jstree("refresh");
  336.                                 }
  337.                         } else if (data.status == 2/*RaNotExistingNoInvitation*/) {
  338.                                 alert("Update OK");
  339.                                 // reloadContent();
  340.                                 $('#oidtree').jstree("refresh");
  341.                         } else {
  342.                                 alert("Error: " + data);
  343.                         }
  344.                 }
  345.         });
  346. }
  347.  
  348. function crudActionDelete(id, parent) {
  349.         if(!window.confirm("Are you sure that you want to delete "+id+"?")) return false;
  350.  
  351.         $.ajax({
  352.                 url:"ajax.php",
  353.                 method:"POST",
  354.                 data: {
  355.                         action:"Delete",
  356.                         id:id,
  357.                         parent:parent
  358.                 },
  359.                 error:function(jqXHR, textStatus, errorThrown) {
  360.                         alert("Error: " + errorThrown);
  361.                 },
  362.                 success:function(data) {
  363.                         if ("error" in data) {
  364.                                 alert("Error: " + data.error);
  365.                         } else if (data.status == 0) {
  366.                                 reloadContent();
  367.                                 // TODO: auf reloadContent() verzichten. stattdessen nur tree links aktualisieren, und rechts die zeile aus der tabelle löschen
  368.                         } else {
  369.                                 alert("Error: " + data.error);
  370.                         }
  371.                 }
  372.         });
  373. }
  374.  
  375. function deleteRa(email, goto) {
  376.         if(!window.confirm("Are you really sure that you want to delete "+email+"? (The OIDs stay active)")) return false;
  377.  
  378.         $.ajax({
  379.                 url:"ajax.php",
  380.                 method:"POST",
  381.                 data: {
  382.                         action:"delete_ra",
  383.                         email:email,
  384.                 },
  385.                 error:function(jqXHR, textStatus, errorThrown) {
  386.                         alert("Error: " + errorThrown);
  387.                 },
  388.                 success:function(data) {
  389.                         if ("error" in data) {
  390.                                 alert("Error: " + data.error);
  391.                         } else if (data.status == 0) {
  392.                                 alert("Done.");
  393.                                 if (goto != null) {
  394.                                         $("#gotoedit").val(goto);
  395.                                         window.location.href = "?goto="+encodeURIComponent(goto);
  396.                                 }
  397.                                 // reloadContent();
  398.                         } else {
  399.                                 alert("Error: " + data.error);
  400.                         }
  401.                 }
  402.         });
  403. }
  404.  
  405. // This function opens the "parentID" node, and then selects the "childID" node (which should be beneath the parent node)
  406. function openAndSelectNode(childID, parentID) {
  407.         if ($('#oidtree').jstree(true).get_node(parentID)) {
  408.                 $('#oidtree').jstree('open_node', parentID, function(e, data) { // open parent node
  409.                         if ($('#oidtree').jstree(true).get_node(childID)) { // is the child there?
  410.                                 $('#oidtree').jstree('deselect_all').jstree('select_node', childID); // select it
  411.                         } else {
  412.                                 // This can happen if the content page contains brand new items which are not in the treeview yet
  413.                                 $("#gotoedit").val(childID);
  414.                                 window.location.href = "?goto="+encodeURIComponent(childID);
  415.                         }
  416.                 }, true);
  417.         } else {
  418.                 // This should usually not happen
  419.                 $("#gotoedit").val(childID);
  420.                 window.location.href = "?goto="+encodeURIComponent(childID);
  421.         }
  422. }
  423.  
  424. $(window).on("popstate", function(e) {
  425.         popstate_running = true;
  426.         try {
  427.                 var data = e.originalEvent.state;
  428.  
  429.                 current_node = data.node_id;
  430.                 $('#oidtree').jstree('deselect_all').jstree('select_node', data.node_id);
  431.                 $('#real_title').html(data.titleHTML);
  432.                 $('#real_content').html(data.textHTML);
  433.                 $('#static_link').attr("href", data.staticlinkHREF);
  434.                 document.title = combine_systemtitle_and_pagetitle(getOidPlusSystemTitle(), data.titleHTML.html_entity_decode());
  435.         } catch (err) {
  436.                 popstate_running = false;
  437.         } finally {
  438.                 popstate_running = false;
  439.         }
  440. });
  441.  
  442. $(document).ready(function () {
  443.  
  444.         // --- JsTree
  445.  
  446.         $('#oidtree')
  447.         .jstree({
  448.                 plugins: ['massload','search','conditionalselect'],
  449.                 'core' : {
  450.                         'data' : {
  451.                                 "url" : getTreeLoadURL(),
  452.                                 "data" : function (node) {
  453.                                         return { "id" : node.id };
  454.                                 }
  455.                         },
  456.                         "multiple": false
  457.                 },
  458.                 'conditionalselect' : function (node) {
  459.                         if (node.original.conditionalselect !== undefined) {
  460.                                 return eval(node.original.conditionalselect);
  461.                         } else {
  462.                                 return true; // allow select
  463.                         }
  464.                 },
  465.         })
  466.         .on('ready.jstree', function (e, data) {
  467.                 var url = new URL(window.location.href);
  468.                 var goto = url.searchParams.get("goto");
  469.                 if (goto == null) goto = "oidplus:system"; // the page was not called with ?goto=...
  470.                 $("#gotoedit").val(goto);
  471.  
  472.                 // By setting current_node, select_node() will not cause ajax.php?action=get_description to load (since we already loaded the first static content via PHP, for search engines mainly)
  473.                 // But then we need to set the history state manually
  474.                 current_node = goto;
  475.                 window.history.replaceState({
  476.                         "node_id":goto,
  477.                         "titleHTML":$('#real_title').html(),
  478.                         "textHTML":$('#real_content').html(),
  479.                         "staticlinkHREF":"index.php?goto="+encodeURIComponent(goto),
  480.                 }, $('#real_title').html(), "?goto="+encodeURIComponent(goto));
  481.  
  482.                 if (goto != null) data.instance.select_node([goto]);
  483.  
  484.                 setTimeout(glayoutWorkaroundA, 100);
  485.                 setTimeout(glayoutWorkaroundB, 100);
  486.         })
  487.         .on('select_node.jstree', function (node, selected, event) {
  488.                 mobileNavClose();
  489.  
  490.                 var id = selected.node.id;
  491.                 if ((!popstate_running) && (current_node != id)) {
  492.                         openOidInPanel(id, false);
  493.                 }
  494.         });
  495.  
  496.         // --- Layout
  497.  
  498.         document.getElementById('system_title_menu').style.display = "block";
  499.  
  500.         $('#oidtree').addClass('ui-layout-west');
  501.         $('#content_window').addClass('ui-layout-center');
  502.         $('#system_title_bar').addClass('ui-layout-north');
  503.         glayout = $('#frames').layout({
  504.                 north__size:                  40,
  505.                 north__slidable:              false,
  506.                 north__closable:              false,
  507.                 north__resizable:             false,
  508.                 west__size:                   450,
  509.                 west__spacing_closed:         20,
  510.                 west__togglerLength_closed:   230,
  511.                 west__togglerAlign_closed:    "top",
  512.                 west__togglerContent_closed:  "O<br>B<br>J<br>E<br>C<br>T<br><br>T<BR>R<BR>E<BR>E",
  513.                 west__togglerTip_closed:      "Open & Pin Menu",
  514.                 west__sliderTip:              "Slide Open Menu",
  515.                 west__slideTrigger_open:      "mouseover",
  516.                 center__maskContents:         true // IMPORTANT - enable iframe masking
  517.         });
  518.  
  519.         $("#gotobox").addClass("mobilehidden");
  520.         document.getElementById('gotobox').style.display = "block";
  521.         $('#gotoedit').keypress(function(event) {
  522.                 var keycode = (event.keyCode ? event.keyCode : event.which);
  523.                 if (keycode == '13') {
  524.                         gotoButtonClicked();
  525.                 }
  526.         });
  527. });
  528.  
  529. function glayoutWorkaroundA() {
  530.         // "Bug A": Sometimes, the design is completely destroyed after reloading the page. It does not help when glayout.resizeAll()
  531.         //          is called at the beginning (e.g. during the ready function), and it does not help if we wait 500ms.
  532.         //          So we do it all the time. It has probably something to do with slow loading times, since the error
  533.         //          does only appear when the page is "blank" for a short while while it is loading.
  534.         glayout.resizeAll();
  535.         setTimeout(glayoutWorkaroundA, 100);
  536. }
  537.  
  538. function glayoutWorkaroundB() {
  539.         // "Bug B": Sometimes, after reload, weird space between oidtree and content window, because oidtree has size of 438px
  540.         document.getElementById("oidtree").style.width = "450px";
  541. }
  542.  
  543. function mobileNavClose() {
  544.         if ($("#system_title_menu").is(":hidden")) {
  545.                 return;
  546.         }
  547.  
  548.         $("#oidtree").slideUp("medium").promise().done(function() {
  549.                 $("#oidtree").addClass("ui-layout-west");
  550.                 $("#oidtree").show();
  551. //              $("#gotobox").hide();
  552.                 $("#gotobox").addClass("mobilehidden");
  553.         });
  554.         $("#system_title_menu").removeClass("active");
  555. }
  556.  
  557. function mobileNavOpen() {
  558.         $("#oidtree").hide();
  559.         $("#oidtree").removeClass("ui-layout-west");
  560.         $("#oidtree").slideDown("medium");
  561. //      $("#gotobox").show();
  562.         $("#gotobox").removeClass("mobilehidden");
  563.         $("#system_title_menu").addClass("active");
  564. }
  565.  
  566. function mobileNavButtonClick(sender) {
  567.         if ($("#oidtree").hasClass("ui-layout-west")) {
  568.                 mobileNavOpen();
  569.         } else {
  570.                 mobileNavClose();
  571.         }
  572. }
  573.  
  574. function mobileNavButtonHover(sender) {
  575.         sender.classList.toggle("hover");
  576. }
  577.  
  578. function gotoButtonClicked() {
  579.         openOidInPanel($("#gotoedit").val(), 1);
  580. }
  581.  
  582. function frdl_weid_change() {
  583.         var from_base = 36;
  584.         var from_control = "#weid";
  585.         var to_base = 10;
  586.         var to_control = "#id";
  587.  
  588.         var inp = $(from_control).val().trim();
  589.         if (inp == "") {
  590.                 $(to_control).val("");
  591.         } else {
  592.                 var x = BigNumber(inp, from_base);
  593.                 if (isNaN(x)) {
  594.                         $(to_control).val("");
  595.                 } else {
  596.                         $(to_control).val(x.toString(to_base));
  597.                 }
  598.         }
  599. }
  600.  
  601. function frdl_oidid_change() {
  602.         var from_base = 10;
  603.         var from_control = "#id";
  604.         var to_base = 36;
  605.         var to_control = "#weid";
  606.  
  607.         var inp = $(from_control).val().trim();
  608.         if (inp == "") {
  609.                 $(to_control).val("");
  610.         } else {
  611.                 var x = BigNumber(inp, from_base);
  612.                 if (isNaN(x)) {
  613.                         $(to_control).val("");
  614.                 } else {
  615.                         $(to_control).val(x.toString(to_base));
  616.                 }
  617.         }
  618. }
  619.  
  620. function jumpToAnchor(anchor) {
  621.         window.location.href = "#" + anchor;
  622. }
  623.  
  624.