Welcome to the detailed analysis for qdb.us. This domain is officially recognized as welcome. According to their official web presence, their primary focus is: "Detailed SEO and authority metrics for qdb.us. Qdb currently holds an estimated domain authority score of 89/100 in the .US namespace based on our global index mapping.".
"Welcome # Welcome to welcome page. This message is designed to welcome you. Operator, please enhance this message. New Installation Message # Welcome to Pollyanna! Your install was successful! You should run `hike setup` to enable the most commonly-used features. Thank you for installing Pollyanna! Image(149) ; Settings Welcome JavaScript # <fieldset><b class=noscript>*</b> Some features may require JavaScript</fieldset>document.write('<fieldset>JavaScript is enabled.</fieldset>'); <!-- // == begin avatar.js var configJsOpenPgp = 1; // this is templated from config/setting/admin/js/openpgp function setAva () { // sets avatar widgets (and italicizes Profile link) //alert('DEBUG: setAva() begins'); if (document.getElementById && String.fromCharCode) { var myidBox = document.getElementById('myid'); // displays username (if preference is set) var signinBox = document.getElementById('signin'); // Profile link //var gt = String.fromCharCode(62); var gt = unescape('%3E'); if (myidBox && signinBox && window.localStorage) { // check for elements and features var myAvatar = localStorage.getItem('avatar'); // #todo add provision for cookie auth here too if (!myAvatar) { // less error prone than checking for == null, i think // no avatar, probably not signed in signinBox.innerHTML = '<a href="/profile.html"' + gt + 'Register</a' + gt + ''; } else { // there's an avatar, probably signed in signinBox.innerHTML = ''; var myFp = localStorage.getItem('fingerprint'); if (window.location.pathname == '/author/' + myFp + '/' || window.location.pathname == '/author/' + myFp + '/index.html') { var itsYou = document.getElementById('itsyou'); itsYou.innerHTML = 'This is your profile!'; } if (window.GetPrefs) { if (GetPrefs('display_username')) { myidBox.innerHTML = '<a href="/profile.html" class=avatar' + gt + myAvatar + '</a' + gt; signinBox.innerHTML = ''; } else { myidBox.innerHTML = ''; signinBox.innerHTML = '<a href="/profile.html"' + gt + '<i' + gt + 'Change</i' + gt + '</a' + gt + ''; } } else { myidBox.innerHTML = ''; signinBox.innerHTML = '<a href="/profile.html"' + gt + '<i' + gt + 'Change</i' + gt + '</a' + gt + ''; } var configJsOpenPgp = 1; // this is templated from config/setting/admin/js/openpgp if (configJsOpenPgp && !window.openpgp && document.head && document.getElementById && window.localStorage) { //alert('DEBUG: setAva: loading openpgp.js'); window.openPgpJsLoadBegin = 1; var script = document.createElement('script'); script.src = '/openpgp.js'; script.async = false; // This is required for synchronous execution document.head.appendChild(script); } if (!window.setAvatar && document.head && document.head.appendChild && document.getElementById && window.localStorage) { //alert('DEBUG: setAva: loading crypto2.js'); var script2 = document.createElement('script'); script2.src = '/crypto2.js'; script2.async = false; // This is required for synchronous execution document.head.appendChild(script2); } } } } return true; } // setAva() if (window.localStorage && document.getElementById) { setAva(); } function getAvatar () { // retrieve previously built avatar from localStorage (already in html form) if (window.localStorage) { var myAvatar = localStorage.getItem("avatar"); if (!myAvatar || myAvatar.length == 0) { return ''; } else { return myAvatar; } } else { return 'Anonymous*'; } return false; } // getAvatar() // == end avatar.js // puzzle.js if (document.createElement && document.head) { // include sha512.js library instead of embedding it in page // because it's big and contains (gt) characters // and because it is large var script = document.createElement('script'); script.src = '/sha512.js'; script.async = false; // This is required for synchronous execution document.head.appendChild(script); } function getSolvedPuzzle (userFp, desiredPrefix, timeLimit, iterationLimit) { // userFp example: ABCDEF0123456789 // desiredPrefix example: 1337 // timeLimit example: 15 // iterationLimit example: 1000000 var i = 0; // counts iterations var done = 0; // done status var r = 0 + ''; // stores random number as string var lookingFor = desiredPrefix; // required hash prefix var lookingForLength = lookingFor.length; var cycleLimit = iterationLimit; // give up after this many tries var secondsLimit = time; // give up after this many seconds var puzzle = ''; // finished puzzle var fp = userFp; var hash = ''; // starting salt provided by server var puzzleResult = ''; var d = new Date(); var epochStart = d.getTime(); epochStart = Math.ceil(epochStart / 1000); // current time in epoch format while(done < 1) { var d = new Date(); var epoch = d.getTime(); epoch = Math.ceil(epoch / 1000); // current time in epoch format // look for a puzzle which fits criteria i = i + 1; // counter r = Math.random() + ''; puzzle = fp + ' ' + epochStart + ' ' + r; hash = hex_sha512(puzzle); if (hash.substring(0, lookingForLength) == lookingFor) { // match found puzzleResult = puzzleResult + puzzle + "\n"; done++; } if (cycleLimit < i) { // give up done = 100; } if (epochStart + secondsLimit < epoch) { done = 100; } } // while(!done) -- solving puzzle if (puzzleResult) { return puzzleResult; } else { return ''; } } function doSolvePuzzle () { // solves puzzle // called from a timeout set by solvePuzzle() /* depends on the following: ========================= window.WriteSubmit() is called after document.getElementById('btnSolvePuzzle') caption is changed document.compose is a form if it is not found, looks for frmSession document.compose.comment is a textarea that's appended to window.getUserFp() is used to get user's fingerprint */ if (!window.WriteSubmit) { //alert('DEBUG: warning: missing window.WriteSubmit'); } if (!document.getElementById('btnSolvePuzle')) { //alert('DEBUG: warning: btnSolvePuzzle missing'); } if (!document.compose) { //alert('DEBUG: warning: document.compose missing'); } if (!document.compose.comment) { //alert('DEBUG: warning: document.compose.comment missing'); } if (!window.getUserFp) { //alert('DEBUG: warning: window.getUserFp missing'); } var fp = '0000000000000000'; if (window.getUserFp) { fp = getUserFp(); } // user's fp or default to 000 var d = new Date(); var epochStart = d.getTime(); epochStart = Math.ceil(epochStart / 1000); // current time in epoch format var txtComment = ''; if (document && document.compose && document.compose.comment) { txtComment = document.compose.comment; } var lookingFor = '1337'; // this line is updated by InjectJs() var cycleLimit = 1000000; // this line is updated by InjectJs() var secondsLimit = 10; // this line is updated by in InjectJs() var promptForPrefix = 0; // this line is templated by InjectJs() if (promptForPrefix) { var userPrefix = prompt('Prefix:', (lookingFor ? lookingFor : '')); } else { var userPrefix = lookingFor; } if (userPrefix) { // #todo sanity check lookingFor = userPrefix; } var puzzleResult = getSolvedPuzzle(fp, lookingFor, secondsLimit, cycleLimit); // #todo this should be templated? // add to compose form, sign, and submit //var txtComment = document.compose.comment; // dupe from above if (txtComment && window.solvePuzzle) { if (puzzleResult) { // if (txtComment.value.substr(txtComment.value.length - 2, 2) == "\n\n") { txtComment.value += puzzleResult; } else { if (txtComment.value.substr(txtComment.value.length - 1, 1) == "\n") { txtComment.value += "\n" + puzzleResult; } else { txtComment.value += "\n\n" + puzzleResult; } } } } var btnSolvePuzzle = document.getElementById('btnSolvePuzzle'); if (window.SignMessage) { if (btnSolvePuzzle) { btnSolvePuzzle.value = 'Signing...'; } SignMessage(); } if (window.WriteSubmit) { WriteSubmit(); if (btnSolvePuzzle) { btnSolvePuzzle.value = 'Sending...'; } } } // doSolvePuzzle() function solvePuzzle (t) { // t = button pressed ; begins puzzle solving process and indicates to user // done with timeout to give button a chance to change caption before pegging cpu if (!window.hex_sha512 || !window.doSolvePuzzle) { // required function is missing return true; } if (t) { // update button caption t.value = 'Solving...'; } // set timeout to solve puzzle... i forget why it has to be done this way, but this should be documented #todo var timeoutSolvePuzzle = setTimeout('doSolvePuzzle()', 500); return false; // do not let the calling form submit, doSolvePuzzle() will do it } // solvePuzzle() // / puzzle.js /* settings.js */ var showAdvancedLastAction = ''; var showBeginnerLastAction = ''; var showMeaniesLastAction = ''; var showAdminLastAction = ''; var showTimestampsLastAction = ''; var showPageInfoLastAction = ''; var modernMode = 0; // templated var timerShowAdvanced; function SetElementVisible (element, displayValue, bgColor, borderStyle) { // sets element's visible status based on tag type // displayValue = 'none' or 'initial' // when 'initial', will try to substitute appropriate default for tag type // also sets background color // used for hiding/showing and highlighting beginner, advanced element classes on page. if (element) { //alert('DEBUG: SetElementVisible: before: ' + element.nodeName + ' : ' + element.style.display); } else { //alert('DEBUG: SetElementVisible: before: warning: no element'); return ''; } var changesMade = 0; //alert('DEBUG: SetElementVisible:' + element.tagName + "; displayValue:" + displayValue + "; bgColor:" + bgColor + "; borderStyle:" + borderStyle + "\n"); if (bgColor && (element.tagName != 'SPAN') && (!modernMode)) { // don't do this in modern mode, because it should be done with css classes instead // background color if (bgColor == 'initial') { bgColor = '#c0c0c0'; } if (element.style.backgroundColor != bgColor) { element.style.backgroundColor = bgColor; changesMade++; } // this may cause issues in some themes } // depending on element type, we set different display style // block, table-row, table-cell, or default of 'initial' if (displayValue == 'initial' && (element.nodeName == 'P' || element.nodeName == 'H3' || element.nodeName == 'FIELDSET' || element.nodeName == 'HR')) { if (element.style.display != '') { element.style.display = ''; changesMade++; } // element.style.display = 'block'; } else if (displayValue == 'initial' && element.nodeName == 'TR') { if (element.style.display != '') { element.style.display = ''; changesMade++; } // element.style.display = 'table-row'; } else if (displayValue == 'initial' && (element.nodeName == 'TH' || element.nodeName == 'TD' || element.nodeName == 'TBODY')) { if (element.innerHTML != '') { if (element.style.display != '') { element.style.display = ''; changesMade++ } // element.style.display = 'table-cell'; } else { if (element.style.display != 'none') { element.style.display = 'none'; // empty table cells display = none #why? } } } else { if (displayValue == 'initial') { displayValue = ''; // displayValue = 'inline'; } if (element.style.display != displayValue) { element.style.display = displayValue; changesMade++; } if (borderStyle) { // border style if (element.style.border != borderStyle) { element.style.border = borderStyle; changesMade++; } //element.style.borderRadius = '3pt'; } } if (element) { //alert('DEBUG: SetElementVisible: after: ' + element.nodeName + ' : ' + element.style.display); if (changesMade) { return changesMade; } else { return 0; } } else { //alert('DEBUG: SetElementVisible: after: warning: no element'); return changesMade; } return changesMade; } // SetElementVisible() function ShowAll (t, container) { // t = clicked link ; container = document by default ; shows all elements, overriding settings // admin elements are excluded. only beginner, advanced class elements are shown if (!document.getElementsByClassName) { //alert('DEBUG: ShowAll: warning: getElementsByClassName feature check FAILED'); return false; } var gt = unescape('%3E'); if (!container) { container = document; } var isMore = 1; // if 0, it is 'Less' link // change link caption, there are different variations if (t.innerHTML == 'Less') { // when without accesskey t.innerHTML = 'More'; isMore = 0; } if (t.innerHTML == 'Less (<u' + gt + 'O</u' + gt + ')') { // when with accesskey t.innerHTML = 'M<u' + gt + 'o</u' + gt + 're'; isMore = 0; } if (t.innerHTML == '<u' + gt + 'O</u' + gt + '') { // just the letter with accesskey t.innerHTML = '<u' + gt + 'o</u' + gt + ''; isMore = 0; } if (isMore && container.getElementsByClassName) { // change link caption, there are different variations if (t.innerHTML == 'More') { // without accesskey t.innerHTML = 'Less'; } if (t.innerHTML == 'M<u' + gt + 'o</u' + gt + 're') { // with accesskey t.innerHTML = 'Less (<u' + gt + 'O</u' + gt + ')'; } if (t.innerHTML == '<u' + gt + 'o</u' + gt + '') { // just the letter with accesskey t.innerHTML = '<u' + gt + 'O</u' + gt + ''; } var display; display = 'initial'; var elements = container.getElementsByClassName('advanced'); for (var i = 0; i < elements.length; i++) { SetElementVisible(elements[i], display, '#ffe0e0', 0); } if (0) { // #todo var elements = container.getElementsByClassName('heading'); for (var i = 0; i < elements.length; i++) { SetElementVisible(elements[i], display, '#ffe0e0', 0); } var elements = container.getElementsByClassName('menubar'); for (var i = 0; i < elements.length; i++) { SetElementVisible(elements[i], display, '#ffe0e0', 0); } //var elements = container.getElementsByClassName('statusbar'); //for (var i = 0; i < elements.length; i++) { // SetElementVisible(elements[i], display, '#ffe0e0', 0); //} } elements = container.getElementsByClassName('beginner'); for (var i = 0; i < elements.length; i++) { SetElementVisible(elements[i], display, '#f0f0d0', 0); } elements = container.getElementsByClassName('expand'); for (var i = 0; i < elements.length; i++) { SetElementVisible(elements[i], 'none', '', 0); } if (timerShowAdvanced) { clearTimeout(timerShowAdvanced); } //timerShowAdvanced = setTimeout('ShowAdvanced(1);', 10000); // //if (t && t.getAttribute('onclick')) { //t.setAttribute('onclick', ''); //} //if (window.ArrangeAll) { // ArrangeAll(); //} return false; } else { ShowAdvanced(1, 0); return false; } return true; } // ShowAll() function ShowAdvanced (force, container) { // show or hide controls based on preferences //handles class=advanced based on 'show_advanced' preference //handles class=beginner based on 'beginner' preference //force parameter // 1 = does not re-do setTimeout (called this way from checkboxes) // 0 = previous preference values are remembered, and are not re-done (called by timer) //alert('DEBUG: ShowAdvanced(' + force + ')'); if (!container) { container = document; // allows for localized effects (not document-wide) // this feature may or may not be actually used or tested } var counterChangesMade = 0; if (document.getElementById && window.localStorage && container.getElementsByClassName) { //alert('DEBUG: ShowAdvanced: feature check passed!'); /////////// var styleAssistShowAdvanced = document.getElementById('styleAssistShowAdvanced'); if (styleAssistShowAdvanced && styleAssistShowAdvanced.remove) { styleAssistShowAdvanced.remove(); } // this hides the special stylesheet which we inject into the page // so that there is no jittery dialog repositioning var displayTimestamps = '0'; if (GetPrefs('timestamps_format')) { displayTimestamps = 1; } if (force || window.showTimestampsLastAction != displayTimestamps) { //ShowTimestamps(); window.showTimestampsLastAction = displayTimestamps; counterChangesMade++; } { // #show_admin var displayAdmin = 'none'; // not voting by default if (GetPrefs('show_admin') == 1) { // check value of show_admin preference displayAdmin = 'initial'; // display } if (force || showAdminLastAction != displayAdmin) { var elemAdmin = container.getElementsByClassName('admin'); for (var i = 0; i < elemAdmin.length; i++) { SetElementVisible(elemAdmin[i], displayAdmin, 0, 0); } //// #todo make this optional //var elemAdmin = container.getElementsByClassName('heading'); // //for (var i = 0; i < elemAdmin.length; i++) { // SetElementVisible(elemAdmin[i], displayAdmin, 0, 0); //} // //var elemAdmin = container.getElementsByClassName('statusbar'); // //for (var i = 0; i < elemAdmin.length; i++) { // SetElementVisible(elemAdmin[i], displayAdmin, 0, 0); //} counterChangesMade++; } } { // #show_advanced var displayValue = 'none'; // hide by default if (GetPrefs('show_advanced') == 1) { // check value of show_advanced preference displayValue = 'initial'; // display } var bgColor = 'initial'; if (GetPrefs('advanced_highlight') == 1) { // check value of advanced_highlight preference bgColor = '#ffe0e0'; // advanced_highlight } if (force || showAdvancedLastAction != (displayValue + bgColor)) { // thank you stackoverflow var divsToHide = container.getElementsByClassName("advanced"); //divsToHide is an array #todo nn3 compat for (var i = 0; i < divsToHide.length; i++) { //divsToHide[i].style.visibility = "hidden"; // or SetElementVisible(divsToHide[i], displayValue, bgColor, 0); } if (0) { // #todo var divsToHide = container.getElementsByClassName("heading"); //divsToHide is an array #todo nn3 compat for (var i = 0; i < divsToHide.length; i++) { //divsToHide[i].style.visibility = "hidden"; // or SetElementVisible(divsToHide[i], displayValue, bgColor, 0); } var divsToHide = container.getElementsByClassName("menubar"); //divsToHide is an array #todo nn3 compat for (var i = 0; i < divsToHide.length; i++) { //divsToHide[i].style.visibility = "hidden"; // or SetElementVisible(divsToHide[i], displayValue, bgColor, 0); } // var divsToHide = container.getElementsByClassName("statusbar"); //divsToHide is an array #todo nn3 compat // for (var i = 0; i < divsToHide.length; i++) { // //divsToHide[i].style.visibility = "hidden"; // or // SetElementVisible(divsToHide[i], displayValue, bgColor, 0); // } } // var clock = document.getElementById('txtClock'); // if (clock) { // SetElementVisible(clock, displayValue, bgColor, 0); // } showAdvancedLastAction = displayValue + bgColor; counterChangesMade++; } } // show_advanced { // #beginner_highlight displayValue = 'initial'; // show by default if (GetPrefs('beginner') == 0) { // check value of beginner preference displayValue = 'none'; } bgColor = 'initial'; if (GetPrefs('beginner_highlight') == 1) { // check value of beginner preference bgColor = '#f0f0d0'; // beginner_highlight } if (force || showBeginnerLastAction != displayValue + bgColor) { var divsToShow = container.getElementsByClassName('beginner');//#todo nn3 compat for (var i = 0; i < divsToShow.length; i++) { SetElementVisible(divsToShow[i], displayValue, bgColor, 0); } showBeginnerLastAction = displayValue + bgColor; counterChangesMade++; } } // // if (window.freshTimeoutId) { // // reset the page change notifier state // clearTimeout(window.freshTimeoutId); // // if (GetPrefs('notify_on_change')) { // // check if page has changed, notify user if so // if (window.EventLoop) { // EventLoop(); // } // } // } if (window.setAva) { setAva(); // #todo caching similar to above } //if (!force) { //if (timerShowAdvanced) { // clearTimeout(timerShowAdvanced); //} //timerShowAdvanced = setTimeout('ShowAdvanced()', 3000); //} //SettingsOnload(); } else { //alert('DEBUG: ShowAdvanced: feature check FAILED!'); //alert('DEBUG: window.localStorage: ' + !!window.localStorage + '; document.getElementsByClassName: ' + document.getElementsByClassName); } if (counterChangesMade) { LoadCheckboxValues(); } //alert('DEBUG: ShowAdvanced: returning false'); return ''; } // ShowAdvanced() function GetPrefs (prefKey, storeName) { // get prefs value from localstorage // function GetConfig () { // function GetSetting () { if (!storeName) { // settings beginning with gtgt go into separate container // this is a local record of the user's votes and // is used to avoid attempting to double-vote var gt = unescape('%3E'); if (prefKey.substr(0, 2) == gt+gt) { storeName = 'voted'; } else { storeName = 'settings'; } } if (!prefKey) { //alert('DEBUG: GetPrefs: warning: missing prefKey'); return ''; } //alert('DEBUG: GetPrefs(' + prefKey + ')'); if (window.localStorage && window.JSON) { // #todo workaround for when there is no localStorage or no JSON var currentPrefs = localStorage.getItem(storeName); var prefsObj; if (currentPrefs) { try { prefsObj = JSON.parse(currentPrefs); //alert('DEBUG: GetPrefs: prefsObj = ' + prefsObj); } catch (e) { //alert('DEBUG: GetPrefs: error encountered: ' + e); return ''; } } else { prefsObj = Object(); //alert('DEBUG: GetPrefs: prefsObj = Object()'); } var prefValue = prefsObj[prefKey]; //alert('DEBUG: GetPrefs: prefKey = ' + prefKey + '; prefValue = ' + prefValue); if (!prefValue && prefValue != 0 && prefValue != '') { //alert('DEBUG: GetPrefs: prefKey = ' + prefKey + ' not found in prefsObj, getting default'); prefValue = GetDefault(prefKey); SetPrefs(prefKey, prefValue); } return prefValue; } //alert('DEBUG: GetPrefs: fallthrough, returning '); return ''; } // GetPrefs() function SetPrefs (prefKey, prefValue, storeName) { // set prefs key prefKey to value prefValue // storeName defaults to 'settings' // special case: if prefKey begins with gt+gt, it is 'voted' // the preferences are stored as json in LocalStorage // some preferences are also copied into cookies: // show_advanced // beginner // show_admin // some preferences update their global variables: // performance_optimization updates window.performanceOptimization if (!prefKey || !prefKey.substr) { //alert('DEBUG: GetPrefs: warning: missing prefKey'); return ''; } if (!storeName) { var gt = unescape('%3E'); // #todo this should be elsewhere if (prefKey.substr(0, 2) == gt+gt) { storeName = 'voted'; } else { storeName = 'settings'; } } //alert('DEBUG: SetPrefs(' + prefKey + ', ' + prefValue + ', ' + storeName + ')'); if (prefKey == 'show_advanced' || prefKey == 'beginner' || prefKey == 'show_admin') { // SetPrefs() //alert('DEBUG: SetPrefs: setting cookie to match LocalStorage'); if (window.SetCookie) { SetCookie(prefKey, (prefValue ? 1 : 0)); } else { //alert('DEBUG: warning: window.SetCookie missing'); } } if (prefKey == 'opened_dialogs') { // copying to cookie in SetPrefs() //alert('DEBUG: SetPrefs: setting cookie to match LocalStorage'); if (window.SetCookie) { SetCookie(prefKey, (prefValue ? prefValue : '')); } else { //alert('DEBUG: warning: window.SetCookie missing'); } } if (prefKey == 'performance_optimization') { window.performanceOptimization = prefValue; //alert('DEBUG: SetPrefs: setting cookie to match LocalStorage'); if (prefValue != 'none') { //if (window.EventLoop) { // todo enable/disable eventloop? // this is disabled because it can cause race condition // the race condition manifests itself as checkbox changing state //EventLoop(); //} } } if (window.localStorage && window.JSON) { var currentPrefs = localStorage.getItem(storeName); var prefsObj; if (currentPrefs) { try { prefsObj = JSON.parse(currentPrefs); } catch (e) { alert(e); // error encountered prefsObj = Object(); } } else { prefsObj = Object(); } prefsObj[prefKey] = prefValue; var newPrefsString = JSON.stringify(prefsObj); localStorage.setItem(storeName, newPrefsString); if (prefKey != 'prefs_timestamp') { // remember time preferences were last changed var d = new Date(); var t = d.getTime(); SetPrefs('prefs_timestamp', t); } return 0; } return 1; } // SetPrefs() function SaveCheckbox (ths, prefKey) { // saves value of checkbox, toggles affected elements // id = id of pane to hide or show; not required // ths = "this" of calling checkbox) // prefKey = key of preference value to set with checkbox // // this function is a bit of a mess, could use a refactor #todo //alert('DEBUG: SaveCheckbox(' + ths + ',' + prefKey); var checkboxState = (ths.checked ? 1 : 0); //alert('DEBUG: SaveCheckbox: checkboxState = ' + checkboxState); /////////////////////////////// // BEFORE SAVE ACTIONS BEGIN // //if (prefKey == '' + 'draggable_scale') { if (prefKey == '' + 'draggable_scale') { // this is done in case prefKey is somehow a number if (window.SetActiveDialog) { //alert('DEBUG: SaveCheckbox: calling SetActiveDialog(0)'); SetActiveDialog(0); } } if (prefKey == 'draggable') { if (checkboxState && window.DraggingInit) { DraggingInit(0); } else { if (window.displayNotification) { displayNotification('Please reload page'); // #todo make this nicer } } } // BEFORE SAVE ACTIONS FINISH // //////////////////////////////// /////////////////////// // ACTUAL SAVE BEGIN // if (prefKey == 'timestamps_format' || prefKey == 'performance_optimization' && window.ShowTimestamps) { //#todo SetPrefs(prefKey, ths.value); ShowTimestamps(); } else { // saves checkbox's value as 0/1 value to prefs(prefKey) SetPrefs(prefKey, checkboxState); } // ACTUAL SAVE FINISH // //////////////////////// ////////////////////////////// // AFTER SAVE ACTIONS BEGIN // if (prefKey == 'draggable_scale' || prefKey == 'draggable_activate') { if (window.SetActiveDialog) { //alert('DEBUG: SaveCheckbox: calling SetActiveDialog(0)'); SetActiveDialog(0); } } if (prefKey == 'show_advanced' || prefKey == 'beginner' || prefKey == 'show_admin' && window.ShowAdvanced) { // SaveCheckbox() ShowAdvanced(1, 0); } if (prefKey == 'draggable_restore' && checkboxState) { if (document.getElementsByClassName) { var dialogs = document.getElementsByClassName('dialog'); if (dialogs) { for (var i = 0; i < dialogs.length; i++) { SaveDialogPosition(dialogs[i]); } } } } // AFTER SAVE ACTIONS FINISH // /////////////////////////////// //alert('DEBUG: after SetPrefs, GetPrefs(' + prefKey + ') returns: ' + GetPrefs(prefKey)); // call ShowAdvanced(1) to update ui appearance // ShowAdvanced(1); return 1; } // SaveCheckbox() function SetInterfaceMode (ab, thisButton) { // updates several settings to change to "ui mode" (beginner, advanced, etc.) //alert('DEBUG: SetInterfaceMode(' + ab + ')'); if (window.localStorage && window.SetPrefs) { if (ab == 'beginner') { // switching to beginner mode resets most preferences to their beginner-friendly defaults SetPrefs('show_advanced', 0); SetPrefs('advanced_highlight', 0); SetPrefs('beginner', 1); SetPrefs('beginner_highlight', 1); SetPrefs('notify_on_change', 1); SetPrefs('show_admin', 0); SetPrefs('write_enhance', 0); SetPrefs('write_autosave', 0); SetPrefs('timestamps_format', 'adjusted'); // reset to beginner SetPrefs('performance_optimization', 'faster'); SetPrefs('draggable', 0); SetPrefs('draggable_scale', 0); SetPrefs('draggable_arrange_viewport_resize', 0); SetPrefs('draggable_activate', 0); SetPrefs('draggable_restore', 1); SetPrefs('draggable_restore_collapsed', 1); SetPrefs('draggable_spawn', 0); SetPrefs('focus_reply', 0); SetPrefs('sign_by_default', 1); if (window.DraggingReset) { DraggingReset(); } //if (window.displayNotification) { //displayNotification('', thisButton); //} } else if (ab == 'intermediate') { if (window.DraggingInit) { DraggingInit(); } SetPrefs('show_advanced', 1); SetPrefs('advanced_highlight', 1); SetPrefs('beginner', 1); SetPrefs('beginner_highlight', 1); SetPrefs('notify_on_change', 1); // SetPrefs('show_admin', 0); } else if (ab == 'expert') { if (thisButton && window.GetParentDialog) { var parentDialog = GetParentDialog(thisButton); if (parentDialog) { //alert('DEBUG: SetInterfaceMode: calling DraggingInitDialog(parentDialog)'); DraggingInitDialog(parentDialog); } } SetPrefs('show_advanced', 1); SetPrefs('advanced_highlight', 0); SetPrefs('beginner', 0); SetPrefs('beginner_highlight', 0); SetPrefs('notify_on_change', 1); } ShowTimestamps(); ShowAdvanced(1, 0); LoadCheckboxValues(); //alert('DEBUG: window.SetPrefs() was found, and ShowAdvanced(1) was called'); return false; } //alert('DEBUG: returning true'); return true; } // SetInterfaceMode() function LoadCheckbox (c, prefKey) { // updates checkbox state to reflect settings // function RestoreCheckbox () { // c = checkbox object // prefKey = key of preference value //console.log(prefKey); if (!c) { //alert('DEBUG: LoadCheckbox: warning: c was missing'); // this happens a lot because LoadCheckboxes doesn't verify that elements exist before calling #todo // #todo this should really find the checkbox automatically and have only one argument //return ''; } //alert('DEBUG: LoadCheckbox(..., ' + prefKey + ')'); if (prefKey == 'timestamps_format') { // it's a radio button group, not a checkbox //alert('DEBUG: LoadCheckbox: timestamps_format'); var checkboxState = GetPrefs(prefKey); if (document.frmSettings && document.frmSettings.optTimestampsFormat) { document.frmSettings.optTimestampsFormat.value = checkboxState; } } else if (prefKey == 'performance_optimization') { // it's a radio button group, not a checkbox //alert('DEBUG: LoadCheckbox: performance_optimization'); var checkboxState = GetPrefs(prefKey); if (document.frmSettings && document.frmSettings.optPerformanceOptimization) { document.frmSettings.optPerformanceOptimization.value = checkboxState; } } else { //alert('DEBUG: LoadCheckbox: ' + prefKey); var checkboxState = GetPrefs(prefKey); if (c && c.checked != (checkboxState ? 1 : 0)) { c.checked = (checkboxState ? 1 : 0); } return 1; } return 1; } // LoadCheckbox() function LoadCheckboxValues () { // function LoadCheckbox () { //alert('DEBUG: LoadCheckboxValues()'); // #todo check if being called too often? LoadCheckbox(document.getElementById('chkDraggable'), 'draggable'); LoadCheckbox(document.getElementById('chkDraggableRestore'), 'draggable_restore'); LoadCheckbox(document.getElementById('chkDraggableReopen'), 'draggable_reopen'); LoadCheckbox(document.getElementById('chkDraggableRestoreCollapsed'), 'draggable_restore_collapsed'); LoadCheckbox(document.getElementById('chkDraggableScale'), 'draggable_scale'); LoadCheckbox(document.getElementById('chkArrangeViewportResize'), 'draggable_arrange_viewport_resize'); LoadCheckbox(document.getElementById('chkDraggableActivate'), 'draggable_activate'); LoadCheckbox(document.getElementById('chkDraggableSpawn'), 'draggable_spawn'); LoadCheckbox(document.getElementById('chkDraggableSpawnFocus'), 'draggable_spawn_focus'); LoadCheckbox(document.getElementById('chkShowAdmin'), 'show_admin'); LoadCheckbox(document.getElementById('chkShowBeginner'), 'beginner'); LoadCheckbox(document.getElementById('chkShowAdvanced'), 'show_advanced'); LoadCheckbox(document.getElementById('chkWriteEnhance'), 'write_enhance'); LoadCheckbox(document.getElementById('chkWriteAutoSave'), 'write_autosave'); LoadCheckbox(document.getElementById('chkFocusReply'), 'focus_reply'); LoadCheckbox(document.getElementById('chkSignByDefault'), 'sign_by_default'); LoadCheckbox(document.getElementById('chkUncheckSignWhenPasting'), 'uncheck_sign_when_pasting'); //alert('DEBUG: LoadCheckboxValues: about to do option groups'); LoadCheckbox(document.getElementById('optTimestampsFormat'), 'timestamps_format'); LoadCheckbox(document.getElementById('optPerformanceOptimization'), 'performance_optimization'); //LoadCheckbox(document.getElementById('chkExpertTimestamps'), 'expert_timestamps'); } // LoadCheckboxValues() function SettingsOnload () { // onload function for settings page //alert('debug: SettingsOnload() begin'); if (document.getElementById) { // below is code which sets the checked state of settings checkboxes // based on settings state //var pane; LoadCheckboxValues(); //if (GetPrefs('sign_by_default') == 1) { // var cbM = document.getElementById('chkSignByDefault'); // if (cbM) { // cbM.checked = 1; // } //} } //alert('debug: SettingsOnload: returning false'); return false; } // SettingsOnload() if (window.EventLoop) { window.eventLoopShowAdvanced = 1; } else { ShowAdvanced(0, 0); } /* / settings.js */ // profile.js var configJsOpenPgp = 1; // this is templated from config/setting/admin/js/openpgp if (configJsOpenPgp && !window.openpgp && document.head && document.head.appendChild && document.getElementById && window.localStorage) { //alert('DEBUG: loading openpgp.js'); window.openPgpJsLoadBegin = 1; var script = document.createElement('script'); script.src = '/openpgp.js'; script.async = false; // This is required for synchronous execution document.head.appendChild(script); //alert('DEBUG: finished loading openpgp.js; window.openpgp: ' + !!window.openpgp); } else { //alert('DEBUG: not loading openpgp.js; window.openpgp: ' + !!window.openpgp + ' document.getElementById: ' + !!document.getElementById + ' window.localStorage: ' + !!window.localStorage + ' window.Promise: ' + !!window.Promise); } if (!(window.MakeKey) && document.head && document.head.appendChild && document.getElementById && window.localStorage) { //alert('DEBUG: loading crypto2.js'); var script2 = document.createElement('script'); script2.src = '/crypto2.js'; script2.async = false; // This is required for synchronous execution document.head.appendChild(script2); //alert('DEBUG: finished loading crypto2.js; window.cryptoJs: ' + !!window.cryptoJs + '; document.getPrivateKey: ' + !!document.getPrivateKey + '; window.openpgp: ' + !!window.openpgp); } else { //alert('DEBUG: not loading crypto2.js; ' + ' window.MakeKey = ' + window.MakeKey + '; document.getElementById = ' + document.getElementById + ' window.localStorage = ' + window.localStorage ); } function btnSignOut_Click (t) { // event for 'Sign Out' button's click // function btnExit_Click () { // function btnLogOut_Click () { //alert('DEBUG: btnSignOut_Click() begin'); if (window.localStorage) { //alert('DEBUG: btnSignOut_Click: window.localStorage is true, removing preferences'); var ls = window.localStorage; ls.removeItem('privatekey'); ls.removeItem('publickey'); ls.removeItem('fingerprint'); ls.removeItem('avatar'); ls.removeItem('settings'); ls.removeItem('dialogPosition'); ls.removeItem('voted'); ls.removeItem('replyCart'); SetPrefs('latest_pubkey_ping', 0); } if (window.SetCookie) { //alert('DEBUG: btnSignOut_Click: window.SetCookie is true, removing cookies'); SetCookie('cookie', 0); SetCookie('checksum', 0); } if (0) { //#todo // postmessage // this would announce the user's exit var form = document.createElement('form'); form.setAttribute("action", "/post.html"); form.setAttribute("method", "get"); //form.setAttribute("target", "ifrPubKeyShare"); //alert('DEBUG: PubKeyShare: creating input'); var txtComment = document.createElement('input'); txtComment.setAttribute("type", "hidden"); txtComment.setAttribute("value", 'exiting... ' + GetTime()); txtComment.setAttribute("name", "comment"); //alert('DEBUG: PubKeyShare: adding txtComment to form'); form.appendChild(txtComment); //alert('DEBUG: PubKeyShare: adding form to body'); //document.getElementsByTagName('body')[0].appendChild(form); document.body.appendChild(form); //alert('DEBUG: submitting form'); SignMessage(); //form.submit(); } return true; } // btnSignOut_Click() function btnBegin_Click (t) { // event for 'Register' button's click // t is clicked button's "this" object //alert('DEBUG: btnBegin_Click() begin'); if (t) { if (t.value) { t.value = 'Meditate...'; // i learned this is bad to do, create an alternative pls #todo } } //if (window.localStorage && window.Promise) { // this extra check is disabled for some reason, I think IE? if (window.localStorage && document.getElementById) { //alert('DEBUG: btnBegin_Click: localStorage and Promise feature check pass'); if (window.MakeKey) { //alert('DEBUG: btnBegin_Click: window.MakeKey exists, calling MakeKey()'); var chkEnablePGP = document.getElementById('chkEnablePGP'); if (chkEnablePGP && chkEnablePGP.checked) { //alert('DEBUG: chkEnablePGP is present and checked'); var intKeyGenResult = MakeKey(t); //alert('DEBUG: btnBegin_Click: intKeyGenResult = ' + intKeyGenResult); SetPrefs('latest_pubkey_ping', 1); //alert('DEBUG: returning intKeyGenResult = ' + intKeyGenResult); myFingerprint = window.localStorage.getItem('fingerprint'); if (myFingerprint) { //window.location = '/profile.html?' + myFingerprint; } else { //window.location = '/profile.html'; // #todo this needs to be fixed to work with relativized urls } //return intKeyGenResult; // TRUE if failed, FALSE if failed, //alert('Registration success.\nYou may need to reload the page.\nPlease forgive us for not being better at JavaScript.'); setTimeout("window.location.reload()", 1000); return false; //return true; //return false; // because it is used to determine whether to submit the form to get a cookie } } } else { return true; } return true; } // btnBegin_Click() function getUserFp () { // retrieve stored user fingerprint from LocalStorage // function getFp () { // function GetFingerprint () { // function GetUserFingerprint () { //alert('DEBUG: getUserFp() begin'); if (window.localStorage) { // LocalStorage mode var fingerprint = localStorage.getItem('fingerprint'); if (fingerprint) { return fingerprint; } } else { // fallback to cookie mode var fingerprint = GetCookie('cookie'); if (fingerprint) { return fingerprint; } } // nothing found, we looked everywhere return ''; } // getUserFp() function PubKeyShare (t) { // shares current user's public key via injected form and iframe // function PubKeySharePing () { // function sendPubKey () { // t is the clicked link's "this", which is used to display a notification next to it //alert('DEBUG: profile.js: PubKeyShare() begins'); if (window.getPublicKey) { var pubKey = getPublicKey(); //alert('DEBUG: PubKeyShare: pubKey = ' + (pubKey ? pubKey : '(false)')); if (pubKey) { if (window.displayNotification) { if (t) { displayNotification('Profile created', t); } else { // #todo this appears at the bottom of the page // probably not visible to most users // so the redirect is a surprise displayNotification('Profile created'); } } if (0) { //alert('DEBUG: PubKeyShare: creating form'); var form = document.createElement('form'); form.setAttribute("action", "/post.html"); form.setAttribute("method", "GET"); //form.setAttribute("target", "ifrPubKeyShare"); //alert('DEBUG: PubKeyShare: creating input'); var txtComment = document.createElement('input'); txtComment.setAttribute("type", "hidden"); txtComment.setAttribute("value", pubKey); txtComment.setAttribute("name", "comment"); //alert('DEBUG: PubKeyShare: adding txtComment to form'); form.appendChild(txtComment); //alert('DEBUG: PubKeyShare: adding form to body'); //document.getElementsByTagName('body')[0].appendChild(form); document.body.appendChild(form); //alert('DEBUG: submitting form'); form.submit(); return false; } // if (0) if (1) { var postPubKeyUrl = '/post.html?comment=' + encodeURIComponent(pubKey); PingUrl(postPubKeyUrl); } } else { //alert('DEBUG: PubKeyShare: pubKey was FALSE'); return true; } } ///// alternative method 1 //window.open('/write.html#inspubkey', '_self'); ///// alternative method 2 //var iframe = document.createElement("iframe"); //iframe.src = '/write.html#inspubkey'; //iframe.name = "inspubkey" //iframe.style.display = 'none'; //document.body.appendChild(iframe); return true; } // PubKeyShare() function AddPrivateKeyLinks () { // adds save/load links to profile page if features are available // #todo make it so that this can be called repeatedly and hide/show appropriate links // this will allow to avoid having to reload profile page on status change //alert('DEBUG: AddPrivateKeyLinks() begin'); if (document.getElementById && window.getPrivateKey) { //alert('DEBUG: AddPrivateKeyLinks: document.getElementById && window.getPrivateKey'); var privateKey = getPrivateKey(); var fieldset = document.getElementById('fldRegistration'); if (fieldset && document.createElement) { //alert('DEBUG: AddPrivateKeyLinks: fieldset && document.createElement'); if (privateKey) { //alert('DEBUG: AddPrivateKeyLinks: privateKey: true'); // [go to profile] var pProfileLink = document.getElementById('spanProfileLink'); if (!pProfileLink) { // profile link not there or the p is empty pProfileLink = document.createElement('p'); pProfileLink.setAttribute('id', 'spanProfileLink'); fieldset.appendChild(pProfileLink); } if (pProfileLink && !pProfileLink.innerHTML) { // ATTENTION! // THERE IS A GOTCHA HERE: THIS LINK MAY ALSO BE // ADDED BY PHP; THEN THIS CODE WILL NOT EXECUTE! // BECAUSE pProfileLink WILL ALREADY BE TRUE ABOVE // "Go to profile" link var aProfile = document.createElement('a'); aProfile.setAttribute('href', '/author/' + getUserFp() + '/index.html'); aProfile.setAttribute('onclick', 'if (window.PubKeyShare) { return PubKeyShare(this); }'); aProfile.setAttribute('id', 'linkGoToProfile'); aProfile.innerHTML = 'Go to profile'; // 'Go to profile' "Go to profile" // Append both to fieldset pProfileLink.appendChild(aProfile); } if (0) { // [save as file] var pSaveKeyAsTxt = document.createElement('p'); var aSaveKeyAsTxt = document.createElement('a'); aSaveKeyAsTxt.setAttribute('href', '#'); aSaveKeyAsTxt.setAttribute('id', 'linkSavePrivateKey'); aSaveKeyAsTxt.setAttribute('onclick', 'if (window.SavePrivateKeyAsTxt) { return SavePrivateKeyAsTxt(); }'); aSaveKeyAsTxt.innerHTML = 'Save as file'; // hint for [save as file] var hintSaveKeyAsTxt = document.createElement('span'); hintSaveKeyAsTxt.setAttribute('class', 'beginner'); hintSaveKeyAsTxt.innerHTML = 'Save key to use again later'; // insert [save as file] link into dom pSaveKeyAsTxt.appendChild(aSaveKeyAsTxt); var brSaveKeyAs = document.createElement('br'); pSaveKeyAsTxt.appendChild(brSaveKeyAs); pSaveKeyAsTxt.appendChild(hintSaveKeyAsTxt); fieldset.appendChild(pSaveKeyAsTxt); } // [show private key] var linkShowPrivateKey = document.getElementById('linkShowPrivateKey'); if (!linkShowPrivateKey) { var pShowPrivateKey = document.createElement('p'); var aShowPrivateKey = document.createElement('a'); pShowPrivateKey.setAttribute('class', 'advanced'); aShowPrivateKey.setAttribute('href', '#'); aShowPrivateKey.setAttribute('id', 'linkShowPrivateKey'); aShowPrivateKey.setAttribute('onclick', 'if (window.ShowPrivateKey) { return ShowPrivateKey(); }'); aShowPrivateKey.innerHTML = 'Show private key'; // hint for [show private key] var hintShowPrivateKey = document.createElement('span'); hintShowPrivateKey.setAttribute('class', 'beginner'); hintShowPrivateKey.innerHTML = 'Display as text you can copy'; pShowPrivateKey.appendChild(aShowPrivateKey); brElement = document.createElement('br'); pShowPrivateKey.appendChild(brElement); pShowPrivateKey.appendChild(hintShowPrivateKey); fieldset.appendChild(pShowPrivateKey); } } // privateKey is true else { //alert('DEBUG: AddPrivateKeyLinks: privateKey: false'); var pLoadKeyFromTxt = document.createElement('p'); //alert('DEBUG: AddPrivateKeyLinks: creating file input...'); } // privateKey is FALSE if (window.ShowAdvanced) { ShowAdvanced(1, 0); } } // if (fieldset && document.createElement) else { //alert('DEBUG: AddPrivateKeyLinks: checks FAILED (fieldset && document.createElement)'); } } else { //alert('DEBUG: AddPrivateKeyLinks: checks FAILED (document.getElementById && window.getPrivateKey)'); } return true; } // AddPrivateKeyLinks() function ShowPrivateKey () { // displays private key in textarea //alert('DEBUG: ShowPrivateKey() begin'); if (document.getElementById) { //alert('DEBUG: ShowPrivateKey: document.getElementById is true'); var txtPrivateKey = document.getElementById('txtPrivateKey'); if (txtPrivateKey) { //alert('DEBUG: ShowPrivateKey: txtPrivateKey is true'); if (txtPrivateKey.style.display == 'none') { //alert('DEBUG: style is none, set to block'); txtPrivateKey.style.display = 'block'; } else { //alert('DEBUG: style is block, set to none'); txtPrivateKey.style.display = 'none'; } var linkShowPrivateKey = document.getElementById('linkShowPrivateKey'); if (linkShowPrivateKey) { if (txtPrivateKey.style.display == 'none') { linkShowPrivateKey.innerHTML = 'Show private key'; } else { linkShowPrivateKey.innerHTML = 'Hide private key'; } } return false; } } if (window.getPrivateKey) { var privateKey = getPrivateKey(); if (privateKey && document.createElement) { var txtPrivKey = document.createElement('textarea'); txtPrivKey.setAttribute('cols', 80); txtPrivKey.setAttribute('rows', 24); txtPrivKey.setAttribute('id', 'txtPrivateKey'); txtPrivKey.innerHTML = privateKey; var fldRegistration = document.getElementById('fldRegistration'); if (fldRegistration) { fldRegistration.appendChild(txtPrivKey); } else { document.body.appendChild(txtPrivKey); } var linkShowPrivateKey = document.getElementById('linkShowPrivateKey'); if (linkShowPrivateKey) { linkShowPrivateKey.innerHTML = 'Hide private key'; } txtPrivKey.focus(); return false; } } return true; } // ShowPrivateKey() function openFile (event) { //alert('DEBUG: openFile() begin'); var input = event.target; if (window.FileReader) { reader = new FileReader(); // this eval is for hiding the "=function(){}" syntax from incompatible browsers // they shouldn't try to execute it because they don't make it here due to other tests eval('reader.onload = function() { var text = reader.result; LoadPrivateKeyFromTxt(text); }'); reader.readAsText(input.files[0]); } return true; } // openFile() function LoadPrivateKeyFromTxt (text) { if (window.setPrivateKeyFromTxt) { setPrivateKeyFromTxt(text); } return true; } // LoadPrivateKeyFromTxt() function StripToFilename (text) { // strips provided text to only filename-valid characters if (!text) return ''; text = text.trim(); if (!text) return ''; var charsAllowed = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'; for (var i = 0; i < text.length; i++) { if (-1 < charsAllowed.indexOf(text.substr(i, 1))) { // ok } else { text = text.substr(0, i) + '' + text.substr(i + 1); i = i - 1; } } return text; } // StripToFilename() function getUsername2 () { // returns pgp username // can be optimized with caching, but would also need to be // un-cached when it changes. at this time, caching seems // like over-optimization here var openpgp = window.openpgp; if (openpgp) { // read it into pgp object var privKeyObj = openpgp.key.readArmored(getPrivateKey()); // get the public key out of it var pubKeyObj = privKeyObj.keys[0].toPublic(); var myUsername = pubKeyObj.users[0].userId.userid; return myUsername; } return ''; } // getUsername2() function SavePrivateKeyAsTxt () { // initiates "download" of private key as text file var myFp = getUserFp(); var myUsername = getUsername2(); var text = getPrivateKey(); myUsername = StripToFilename(myUsername); window.blockPreNavigateNotification = 1; return DownloadAsTxt(myUsername + '_' + myFp + '.txt', text); } // SavePrivateKeyAsTxt() // override cookie if we have a profile in LocalStorage //if (document.cookie) { if (window.GetCookie) { if (GetCookie('cookie')) { //alert('DEBUG: cookie=' + document.cookie); } else { //alert('DEBUG: document.cookie missing'); if (window.localStorage) { //alert('DEBUG: window.localStorage exists'); var fp = localStorage.getItem('fingerprint'); if (fp) { //alert('DEBUG: fp exists, setting cookie via js'); document.cookie = 'test=' + fp; } } } } else { //alert('DEBUG: profile.js: warning: GetCookie() is missing'); } function PubkeyCheckProfileExists (fp) { // check if profile exists on server //alert('DEBUG: PubkeyCheckProfileExists() begin'); //alert('DEBUG: PubkeyCheckProfileExists: fp = ' + fp); var profileUrl = '/author/' + fp + '.txt'; // this depends on feeds being enabled //alert('DEBUG: profileUrl = ' + profileUrl); if (UrlExists(profileUrl)) { //alert('DEBUG: lastPubKeyPing: profile exists'); return true; } else { //alert('DEBUG: lastPubKeyPing: profile NOT FOUND'); return false; } return true; } // PubkeyCheckProfileExists() function GetTime () { var d = new Date(); var n = d.getTime(); n = Math.ceil(n / 1000); return n; } // GetTime() function GetFineTime () { // returns epoch in 10th of seconds var d = new Date(); var n = d.getTime(); n = Math.ceil(n / 100); return n; } // GetFineTime() function PubKeyPing () { // checks if user's public key is on server // function PingProfile () // function PingPubKey () // function PingPublicKey () // uploads it to server if it is missing // //alert('DEBUG: PubKeyPing() begin'); var latestPing = GetPrefs('latest_pubkey_ping'); if (latestPing && (GetTime() < (latestPing + 3600))) { //alert('DEBUG: PubKeyPing: latestPing+10 = ' + (latestPing+10) + ' < time() = ' + time()); } else { //alert('DEBUG: PubKeyPing: latestPing was false or stale, doing a check at ' + time()); if (window.getUserFp) { //alert('DEBUG; PubKeyPing: window.getUserFp check passed'); var myFingerprint = getUserFp(); //alert('DEBUG: PubKeyPing: myFingerprint = ' + myFingerprint); if (myFingerprint) { if (PubkeyCheckProfileExists(myFingerprint)) { //alert('DEBUG: PubKeyPing: profile already exists'); } else { if (window.PubKeyShare) { //alert('DEBUG: PubKeyPing: latestPing: (window.PubKeyShare) check passed, doing it...'); PubKeyShare(); latestPing = GetTime(); SetPrefs('latest_pubkey_ping', latestPing); } else { //alert('DEBUG: PubKeyPing: latestPing: (window.PubKeyShare) check FAILED'); } } } else { //alert('DEBUG: PubKeyPing: myFingerprint: false'); } //alert('DEBUG: PubKeyPing: latestPing check complete, saving time'); } else { //alert('DEBUG: PubKeyPing: window.getUserFp check FAILED'); } } return true; } // PubKeyPing() function selectKeyPopulate () { if (window.localStorage) { if (document.formSelectKey && document.formSelectKey.selectKey) { if (1 < document.formSelectKey.selectKey.length) { // already populated } else { // #todo put this in event loop? if ((window.SetPrefs) && (window.GetPrefs)) { var iPrivKey = 0; var currentKey = window.localStorage.getItem('privatekey'); // #todo this should use GetPrefs() instead of using localStorage directly //var foundSelected = 0; while (GetPrefs('pk' + iPrivKey, 'PrivateKey1')) { //if (GetPrefs('pk' + iPrivKey, 'PrivateKey1') == keyArmored) { // return 1; // already stored //} var keyLabel = GetPrefs('pk' + iPrivKey, 'PrivateKeyName') || 'pk' + iPrivKey; var o = new Option(keyLabel, 'pk' + iPrivKey); // it should also add selected attribute to the option if it is the one matching the private key in the 'privatekey' localstorage entry: if (currentKey == GetPrefs('pk' + iPrivKey, 'PrivateKey1')) { o.setAttribute('selected', 'selected'); //foundSelected = 1; } document.formSelectKey.selectKey.add(o); iPrivKey++; } //if (foundSelected) { // var o = new Option('[LogOut]', 2); // document.formSelectKey.selectKey.add(o); //} else { // var o = new Option('[NewAuthor]', 1); // document.formSelectKey.selectKey.add(o); //} //SetPrefs('pk' + iPrivKey, keyArmored, 'PrivateKey1'); } } } else { //alert('DEBUG: selectKeyPopulate: document.formSelectKey.selectKey check FAILED'); } } else { //alert('DEBUG: selectKeyPopulate: window.localStorage check FAILED'); } //alert(document.formSelectKey.selectKey.value); } // selectKeyPopulate() function selectLoadKey (t) { var keyName = t.value; //if (keyName == 1) { // // #todo // btnBegin_Click(); //} else if (keyName == 2) { // btnSignOut_Click(); //} else { var newKey = GetPrefs(keyName, 'PrivateKey1'); if (newKey) { setPrivateKeyFromTxt(newKey); var authorName = window.localStorage.getItem('avatar'); if (keyName && authorName) { if (authorName) { // save author name from key in preferences SetPrefs(keyName, authorName, 'PrivateKeyName'); } } } //} } // selectLoadKey() function ProfileOnLoad () { // onload event for profile page //alert('DEBUG: ProfileOnLoad() begin'); if (document.getElementById) { //alert('DEBUG: ProfileOnLoad: document.getElementById check passed'); var lblSigningIndicator = document.getElementById('lblSigningIndicator'); selectKeyPopulate(); if (window.getPrivateKey) { //alert('DEBUG: ProfileOnLoad: window.getPrivateKey check passed'); if (window.localStorage) { //alert('DEBUG: ProfileOnLoad: window.localStorage check passed, calling getPrivateKey()...'); var configJsOpenPgp = 1; // this is templated from config/setting/admin/js/openpgp var pk = getPrivateKey(); if (configJsOpenPgp && pk) { //alert('DEBUG: ProfileOnLoad: pk = GetPrivateKey() = ' + !!pk); // span used to indicate whether openpgp signing is available if (lblSigningIndicator) { //alert('DEBUG: lblSigningIndicator TRUE'); // display value of "algorithm" which openpgp gives us // in reality, this only give us rsa/not-rsa, and formatted poorly // there's the bit count and the actual algo for non-rsa which needs // to be displayed more nicely here var privKeyObj = openpgp.key.readArmored(pk); var pubKeyObj = privKeyObj.keys[0].toPublic(); var myAlgo = pubKeyObj.primaryKey.algorithm.toString(); if (myAlgo) { //lblSigningIndicator.innerHTML = myAlgo; var gt = unescape('%3E'); lblSigningIndicator.innerHTML = 'Signed in with private key.'; //lblSigningIndicator.innerHTML = 'Signed in with private key. <a href="/profile.html" onclick="return btnSignOut_Click()"' + gt + 'Delete</a' + gt; //#todo this is a hack, make it less hacky } else { lblSigningIndicator.innerHTML = 'Signed in.'; } AddPrivateKeyLinks(); // ProfileOnLoad() var pBeginButton = document.getElementById('pBeginButton'); if (pBeginButton) { pBeginButton.style.display = 'none'; } } else { //alert('DEBUG: lblSigningIndicator FALSE'); } lblHandle = document.getElementById('lblHandle'); if (lblHandle) { var strHandle = localStorage.getItem('avatar'); if (strHandle) { lblHandle.innerHTML = strHandle; } } lblFingerprint = document.getElementById('lblFingerprint'); if (lblFingerprint) { var strFingerprint = localStorage.getItem('fingerprint'); if (strFingerprint) { lblFingerprint.innerHTML = strFingerprint; } } //alert('DEBUG: ProfileOnLoad: calling PubKeyPing()'); PubKeyPing(); } // pk is true else { //alert('DEBUG: pk = false') if (configJsOpenPgp && lblSigningIndicator) { //alert('DEBUG: lblSigningIndicator check passed'); if (window.openpgp) { var lblFingerprint = document.getElementById('lblFingerprint'); ////alert('DEBUG: lblFingerprint = ' + lblFingerprint.innerHTML); if (lblFingerprint && lblFingerprint.innerHTML && (lblFingerprint.innerHTML != '')) { //#todo ... //pgp is available, but we're already logged in via cookies lblSigningIndicator.innerHTML = 'Signed in with cookie.'; } else { // #todo why is window.openpgp false here?? //alert('DEBUG: window.openpgp check passed, setting no (available)'); var pExitButton = document.getElementById('pExitButton'); if (pExitButton) { pExitButton.style.display = 'none'; } lblSigningIndicator.innerHTML = ''; var lblEnablePGP = document.createElement('label'); var chkEnablePGP = document.createElement('input'); var txtEnablePGP = document.createTextNode('Create private key (PGP)'); var chkEnablePgpOn = 0; // this flag is set based on config setting/admin/js/openpgp_checked chkEnablePGP.setAttribute('type', 'checkbox'); chkEnablePGP.setAttribute('name', 'chkEnablePGP'); chkEnablePGP.setAttribute('id', 'chkEnablePGP'); if (chkEnablePgpOn) { chkEnablePGP.setAttribute('checked', '1'); } lblEnablePGP.setAttribute('for', 'chkEnablePGP'); lblEnablePGP.appendChild(chkEnablePGP); lblEnablePGP.appendChild(txtEnablePGP); lblSigningIndicator.appendChild(lblEnablePGP); AddPrivateKeyLinks(); // ProfileOnLoad() } } else { //alert('DEBUG: warning: window.openpgp check FAILED'); lblSigningIndicator.innerHTML = 'Unavailable'; } } else { //alert('DEBUG: lblSigningIndicator check FAILED'); } //AddPrivateKeyLinks(); } } else { //alert('DEBUG: ProfileOnLoad: window.localStorage check FAILED'); } } else { //alert('debug: ProfileOnLoad: window.getPrivateKey check FAILED'); } } else { //alert('DEBUG: ProfileOnLoad: document.getElementById check FAILED'); } return true; } // ProfileOnLoad() // / profile.js // == begin utils.js // begin html escape hack (credit stacko) // only works with createElement #backlog if (document.createElement) { var escapeTA = document.createElement('textarea'); } function escapeHTML (html) { if (window.escapeTA) { escapeTA.textContent = html; return escapeTA.innerHTML; } } // escapeHTML() function unescapeHTML (html) { if (window.escapeTA) { escapeTA.innerHTML = html; return escapeTA.textContent; } } // unescapeHTML() // end html escape hack //#todo above hack seems to be broken, because escapeTA is not global? function LogWarning (text) { if (text.indexOf('warning') != -1) { var hasLogger = !!(window.console && window.console.log); if (hasLogger) { console.log(text); } else { if (document && document.title) { document.title = text; } } } } // LogWarning() function OnLoadEverything () { // checks for each onLoad function and calls it // function OnLoadAll () { // function BodyOnLoad () { // body onload body.onload // function OnLoad { // typically called from body.onload //alert('DEBUG: OnLoadEverything() begins'); if ((window.AddLoadingIndicator) && (!window.loadingIndicator)) { //alert('DEBUG: OnLoadEverything: AddLoadingIndicator()'); AddLoadingIndicator('Meditate...'); } else { //alert('DEBUG: OnLoadEverything: (window.AddLoadingIndicator) is FALSE'); } if (window.setClock) { //alert('DEBUG: OnLoadEverything: setClock()'); window.eventLoopSetClock = 1; setClock(); } if (window.ItsYou) { //alert('DEBUG: OnLoadEverything: ItsYou()'); ItsYou(); } if (window.ShowTimestamps) { //alert('DEBUG: OnLoadEverything: ShowTimestamps()'); window.eventLoopShowTimestamps = 1; ShowTimestamps(); } if (window.SettingsOnload) { //alert('DEBUG: OnLoadEverything: SettingsOnload()'); SettingsOnload(); } if (window.ProfileOnLoad) { //alert('DEBUG: OnLoadEverything: ProfileOnLoad()'); ProfileOnLoad(); } if (window.WriteOnload) { //alert('DEBUG: OnLoadEverything: WriteOnload()'); WriteOnload(); } if (window.ShowAdvanced) { //alert('DEBUG: OnLoadEverything: ShowAdvanced()'); window.eventLoopShowAdvanced = 1; ShowAdvanced(0, 0); } //alert('DEBUG: OnLoadEverything: ShowAdvanced() finished!'); if (window.SearchOnload) { //alert('DEBUG: OnLoadEverything: SearchOnload()'); SearchOnload(); } if (window.DesktopOnLoad) { //alert('DEBUG: OnLoadEverything: DesktopOnLoad()'); DesktopOnLoad(); } if (window.UploadAddImagePreviewElement) { //alert('DEBUG: OnLoadEverything: UploadAddImagePreviewElement()'); UploadAddImagePreviewElement(); } //alert('DEBUG: OnLoadEverything: checking for editable field...'); if (window.location && document.compose && window.location.href.indexOf) { if ( window.location && window.location.href && window.location.href.indexOf('write') != -1 || window.location.hash.indexOf('reply') != -1 || ( window.location.href.indexOf('message') != -1 && (window.GetPrefs) && GetPrefs('focus_reply') ) && document.compose && document.compose.comment && document.compose.comment.focus ) { //alert('DEBUG: OnLoadEverything: document.compose.comment.focus()()'); document.compose.comment.focus(); } } if (window.location.href && (window.location.href.indexOf('search') != -1) && document.search.q) { //alert('DEBUG: OnLoadEverything: document.search.q.focus()'); document.search.q.focus(); } if (0 && window.localStorage) { // #todo improve crumbs var crumbs1 = localStorage.getItem('crumbs'); if (crumbs1) { crumbs1 = crumbs1 + '\n' + window.location.href; localStorage.setItem('crumbs', crumbs1); } else { localStorage.setItem('crumbs', window.location.href); } } if (window.EventLoop) { //alert('DEBUG: OnLoadEverything: EventLoop()'); if (window.CheckIfFresh) { window.eventLoopFresh = 1; } window.eventLoopEnabled = 1; EventLoop(); } // if (window.EventLoop) // FetchDialog('help'); if ((window.DraggingInit) && GetPrefs('draggable')) { //alert('DEBUG: OnLoadEverything: DraggingInit()'); if (window.location.href.indexOf('settings') != -1) { // exclude settings page to avoid difficult situations // one day, it will no longer be necessary DraggingInit(1); } else { DraggingInit(1); } } else { if (document.getElementById) { // this gets rid of the style which hides dialogs on // page load so that they can be positioned first // dragging_hide_dialogs.js // #todo optimize this if (document.getElementById('styleHideDialogs')) { UnhideHiddenElements(); } } } if (window.btnReprint) { //alert('DEBUG: OnLoadEverything: btnReprint()'); if (document.getElementById) { var timePrinted = document.getElementById('timePrinted'); if (timePrinted) { var timePrintedEpoch = timePrinted.getAttribute('epoch'); if (timePrintedEpoch) { if (100 < GetTime() - timePrintedEpoch) { btnReprint.style.color = 'orange'; } } } } } if (window.HideLoadingIndicator) { //alert('DEBUG: OnLoadEverything: HideLoadingIndicator()'); HideLoadingIndicator(); } if (document.getElementById && document.getElementById('plus')) { // #todo this is only used by rh24 theme //alert('DEBUG: OnLoadEverything: plus()'); if (GetPrefs('show_advanced')) { if (document.getElementById('plus').innerHTML) { document.getElementById('plus').innerHTML = '-'; } } } if (window.AutoRegister) { setTimeout('AutoRegister()', 1000); } // everything is set now, start event loop // } // OnLoadEverything() function OnUnloadEverything () { // does all the things that should happen when onunload is triggered // ATTENTION: this may not work on current browsers if (window.ShowPreNavigateNotification) { ShowPreNavigateNotification(); // OnUnloadEverything() } if (document.getElementById && document.getElementById('iospaste')) { // upload field } } // OnUnloadEverything() if (!window.performanceOptimization && window.GetPrefs) { // if performanceOptimization setting hasn't been initialized yet, // and we have a way to do it via GetPrefs() go ahead and do it now window.performanceOptimization = GetPrefs('performance_optimization'); // utils.js } function EventLoop () { // for calling things which need to happen on a regular basis // sets another timeout for itself when done // replaces several independent timeouts // #backlog add secondary EventLoopWatcher timer which ensures this one runs when needed var d = new Date(); var eventLoopBegin = d.getTime(); // eventLoopStart if (!window.eventLoopPrevious) { window.eventLoopPrevious = 1; } window.eventLoopBegin = eventLoopBegin; if ((window.GetPrefs) && GetPrefs('draggable') && window.innerWidth && window.innerHeight) { // if viewport size has changed, retile dialogs // #todo needs some debugging and fixing on mobile devices, where // innerWidth and innerHeight seem to change continuously if (!window.rememberInnerWidth) { window.rememberInnerWidth = window.innerWidth; } if (!window.rememberInnerHeight) { window.rememberInnerHeight = window.innerHeight; } if (window.rememberInnerWidth != window.innerWidth || window.rememberInnerHeight != window.innerHeight) { //alert('DEBUG: detected viewport resize: window.innerWidth = ' + window.innerWidth + ', window.innerHeight = ' + window.innerHeight); window.rememberInnerWidth = window.innerWidth; window.rememberInnerHeight = window.innerHeight; if (GetPrefs('draggable_arrange_viewport_resize') && window.DraggingRetile) { DraggingRetile(); } } } if (window.FetchDialog) { // #todo this may not be the best place for this code var welcomeSeen = GetPrefs('welcome_seen'); // try to show this only once if (welcomeSeen) { if (welcomeSeen == 2) { SetPrefs('welcome_seen', 3); //FetchDialog('welcome'); //alert('welcome!'); } else { if (welcomeSeen == 1) { SetPrefs('welcome_seen', 2); } // verify it can be read and updated } } else { SetPrefs('welcome_seen', 1); // verify it can be set } } if (window.eventLoopSetClock && window.setClock) { // update time displayed in clock setClock(); } var m = 500; // multiplier for performance thresholds if (window.performanceOptimization) { if (window.performanceOptimization == 'quicker') { m = 100; } if (window.performanceOptimization == 'none') { // this is the 'None' setting in Settings m = 0; return ''; } } //alert('DEBUG: EventLoop: eventLoopBegin = ' + eventLoopBegin + ' - window.eventLoopPrevious = ' + window.eventLoopPrevious + ' = ' + (eventLoopBegin - window.eventLoopPrevious)); if (10*m < (eventLoopBegin - window.eventLoopPrevious)) { // ACTUAL EVENT LOOP WORK BEGINS // ACTUAL EVENT LOOP WORK BEGINS // ACTUAL EVENT LOOP WORK BEGINS window.eventLoopPrevious = eventLoopBegin; // store begin time if (window.flagUnloaded) { // show loading indicator if user has started navigating away from page // window.flagUnloaded is set by OnUnload event if (window.ShowPreNavigateNotification) { ShowPreNavigateNotification(); // EventLoop() } } //return; // uncomment to disable event loop // makes js debugging easier if (window.eventLoopShowTimestamps && window.ShowTimestamps) { // update timestamp widgets on page if (13*m < (eventLoopBegin - window.eventLoopShowTimestamps)) { // only every 13 seconds in regular performance mode ShowTimestamps(); window.eventLoopShowTimestamps = eventLoopBegin; } else { // do nothing } } if (window.eventLoopDoAutoSave && window.DoAutoSave) { // autosave if (5*m < (eventLoopBegin - window.eventLoopDoAutoSave)) { // autosave interval // autosave every 5 seconds in normal performance mode DoAutoSave(); window.eventLoopDoAutoSave = eventLoopBegin; } else { // do nothing } } if (window.localStorage && document.getElementById) { // update reply cart dialog displayed count // #todo move this to separate module if (window.ReplyCartUpdateCount) { ReplyCartUpdateCount(); } } if (window.eventLoopShowAdvanced && window.ShowAdvanced) { // update visibility of advanced/beginner layers // but only if necessary ShowAdvanced(0, 0); } if (window.eventLoopFresh && window.CheckIfFresh) { // check for page changes by sending a HEAD request for current url if (10000 < (eventLoopBegin - window.eventLoopFresh)) { //if (10*m < (eventLoopBegin - window.eventLoopFresh)) { // this is commented because it may hammer the server. uncomment if using localhost //window.eventLoopFresh = eventLoopBegin; if ( window.eventLoopFresh && (!(window.GetPrefs) || GetPrefs('notify_on_change')) ) { // notify_on_change client-side setting needs to be on CheckIfFresh(); window.eventLoopFresh = eventLoopBegin; } } } if ( (window.UpdateDialogList) && (document.getElementById) && (document.getElementsByClassName) ) { // update list of dialogs on page UpdateDialogList(); } if (window.GetPrefs) { // if performance setting has changed in another window, update it here too window.performanceOptimization = GetPrefs('performance_optimization'); // EventLoop() } } // 10000 < (eventLoopBegin - window.eventLoopPrevious) if (window.eventLoopEnabled) { // set the next setTimeout for the next "loop" iteration // see how long this last iteration took var d = new Date(); var eventLoopEnd = d.getTime(); var eventLoopDuration = eventLoopEnd - eventLoopBegin; //document.title = eventLoopDuration; // for debugging performance // unset any timeout if already set if (window.timeoutEventLoop) { clearTimeout(window.timeoutEventLoop); } if (30 < eventLoopDuration) { // if loop went longer than 100ms, run every 3 seconds or more //document.title = eventLoopDuration; if (GetPrefs('notify_event_loop')) { displayNotification('EventLoop: ' + eventLoopDuration + 'ms'); } // // // #todo make it known to user that hitting performance limit // if (document.title.substr(0,3) != '/ ') { // // for now we just prepend the title with a slash // document.title = '/ ' + document.title; // } // set performance setting to 'faster' //SetPrefs('performance_optimization', 'faster'); eventLoopDuration = eventLoopDuration * 10; } else { // otherwise run again after 1 interval time eventLoopDuration = 1*m; } window.timeoutEventLoop = setTimeout('EventLoop()', eventLoopDuration); } // window.eventLoopEnabled return ''; } // EventLoop() function UrlExists (url) { // checks if url exists // #todo use async // #todo Q: how to do pre-xhr browsers? A: use img.src = and check the resulting image url //alert('DEBUG: UrlExists(' + url + ')'); if (window.XMLHttpRequest) { //alert('DEBUG: UrlExists: window.XMLHttpRequest check passed'); var http = new XMLHttpRequest(); http.open('HEAD', url, false); //http.timeout = 5000; //#xhr.timeout http.send(); var httpStatusReturned = http.status; //alert('DEBUG: UrlExists: httpStatusReturned = ' + httpStatusReturned); return (httpStatusReturned == 200); } } // UrlExists() function DisplayStatus (status) { // #todo this doesn't seem to be used anywhere yet if (document.getElementById) { var statusBar = document.getElementById('status'); // #todo finish this } } // DisplayStatus() function DownloadAsTxt (filename, text) { var element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('download', filename); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); } // DownloadAsTxt() function displayNotificationWithTimeout (strMessage, thisButton) { var spanNotification = displayNotification(strMessage, thisButton); if (spanNotification) { var d = new Date(); var spanId = d.getTime(); spanNotification.setAttribute('id', spanId); setTimeout('document.getElementById(' + spanId + ').remove()', 5000); return spanNotification; } } // displayNotificationWithTimeout() function displayNotification (strMessage, thisButton) { // adds notification to page // function progressIndicator () { // progress indicator // function showNotification () ( // used for loading indicator bar (to top of page, depending on style) // also used for "creating profile" and "already voted" notifications var spanNotification = document.createElement('span'); spanNotification.setAttribute('class', 'notification'); spanNotification.setAttribute('role', 'alert'); spanNotification.setAttribute('onclick', 'this.remove(); return false;'); spanNotification.innerHTML = strMessage; spanNotification.style.zIndex = GetFineTime(); if ((window.GetPrefs) && GetPrefs('draggable')) { thisButton = 0; // #todo this is a workaround for floating notification being messed up in draggable mode } if (thisButton) { thisButton.parentNode.appendChild(spanNotification); if (thisButton.after) { thisButton.after(spanNotification); } // set element's position based on its initial box model position var rect = spanNotification.getBoundingClientRect(); spanNotification.style.top = (rect.top) + "px"; spanNotification.style.left = (rect.left) + "px"; spanNotification.style.position = 'absolute'; return spanNotification; } else { // #todo this should be in stylesheet; floating notification should have different class spanNotification.style.position = 'fixed'; spanNotification.style.top = '0'; spanNotification.style.right = '0'; spanNotification.style.margin = '0'; document.body.appendChild(spanNotification); return spanNotification; } } // displayNotification() function newA (href, target, innerHTML, parent) { // makes new a element and appends to parent var newLink = document.createElement('a'); if (href) { newLink.setAttribute('href', href); } if (target) { newLink.setAttribute('target', target); } if (innerHTML) { innernewLink.setAttribute('innerHTML', innerHTML); } parent.appendChild(newLink); return newLink; } // newA() function SetCookie (cname, cvalue, exdays) { // set cookie //alert('DEBUG: SetCookie(' + cname + ', ' + cvalue + ', ' + exdays + ')'); var d = new Date(); if (!exdays) { exdays = 1; } d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); var expires = "expires=" + d.toUTCString(); document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; var testSetCookie = GetCookie(cname); if (cvalue == testSetCookie) { return 1; } else { return 0; } } // SetCookie() function GetCookie (cname) { // get cookie value // in js, cookies are accessed via one long string of the form // key1=value1; key2=value2; // so we make an array, splitting the string using the ; separator if (document.cookie && document.cookie.split) { //todo add support for ie3, which does not have a split() method on strings var dc = document.cookie; var ca = dc.split(';'); // the value we are looking for will be prefixed with cname= var name = cname + "="; for(var i = 0; i < ca.length; i++) { // loop through ca array until we find prefix we are looking for var c = ca[i]; while (c.charAt(0) == ' ') { // remove any spaces at beginning of string c = c.substring(1); } if (c.indexOf(name) == 0) { // if prefix matches, return value return c.substring(name.length, c.length); } } } // at this point, nothing left to do but return empty string return ""; } // GetCookie() function GetParentElement (el, parentTagName) { // #todo maybe make this more flexible? if (el) { var parentElement = el; while (parentElement && (parentElement.tagName != parentTagName)) { parentElement = parentElement.parentElement; } if (parentElement) { return parentElement; } } return ''; } // GetParentElement() function UnmaskBlurredImages () { var im = document.images; if (im) { var i = 0; for (i = 0; i < im.length; i++) { if (im[i].getAttribute('src')) { var src = im[i].getAttribute('src'); var gPos = src.indexOf('_g_'); if (gPos != -1 && 0 < gPos) { im[i].setAttribute('src', src.substr(0, gPos) + '' + src.substr(gPos + 2)); } } } } return ''; } // UnmaskBlurredImages() //https://stackoverflow.com/questions/123999/how-can-i-tell-if-a-dom-element-is-visible-in-the-current-viewport function elementInViewport (el) { var top = el.offsetTop; var left = el.offsetLeft; var width = el.offsetWidth; var height = el.offsetHeight; while (el.offsetParent) { el = el.offsetParent; top += el.offsetTop; left += el.offsetLeft; } return ( window.pageYOffset <= top && window.pageXOffset <= left && (top + height) <= (window.pageYOffset + window.innerHeight) && (left + width) <= (window.pageXOffset + window.innerWidth) ); } // elementInViewport() //You could modify this simply to determine if any part of the element is visible in the viewport: function elementInViewport2 (el) { var top = el.offsetTop; var left = el.offsetLeft; var width = el.offsetWidth; var height = el.offsetHeight; while (el.offsetParent) { el = el.offsetParent; top += el.offsetTop; left += el.offsetLeft; } return ( top < (window.pageYOffset + window.innerHeight) && left < (window.pageXOffset + window.innerWidth) && window.pageYOffset < (top + height) && window.pageXOffset < (left + width) ); } // elementInViewport2() function PingUrl (url, ele) { // loads arbitrary url via image or xhr // compatible with most js //alert('DEBUG: PingUrl() begins'); // another option below // var img = document.createElement('img'); // img.setAttribute("src", url); // document.body.appendChild(img); if (!ele) { ele = 0; } if (!url) { // #todo more sanity here //alert('DEBUG: PingUrl: warning: url was FALSE'); return ''; } //alert('DEBUG: PingUrl: url = ' + url); if (window.XMLHttpRequest) { //alert('DEBUG: PingUrl: window.XMLHttpRequest was true'); var xmlhttp; if (window.xmlhttp) { xmlhttp = window.xmlhttp; } else { window.xmlhttp = new XMLHttpRequest(); xmlhttp = window.xmlhttp; } if ((window.GetPrefs) && GetPrefs('show_admin')) { // skip callback to save resources } else { xmlhttp.onreadystatechange = window.PingUrlCallback; } xmlhttp.open("HEAD", url, true); //xmlhttp.timeout = 5000; //#xhr.timeout xmlhttp.send(); return false; } else { //alert('DEBUG: PingUrl: using image method, no xhr here'); if (document.images) { //alert('DEBUG: PingUrl: document.images was true'); if (document.images.length) { // use last image on page, if possible. this should be the special pixel image. var img = document.images[document.images.length - 1]; if (img) { img.setAttribute("src", url); return false; } } else { var img = document.images[0]; if (img) { img.setAttribute("src", url); return false; } } } else { //alert('DEBUG: PingUrl: warning: document.images was FALSE'); } } return true; } // PingUrl() // function EscapeUrl () { // function UriEscape () { // function encode () { // function urlencode () { // function encodeurl () { // USE encodeURIComponent() //function ChangeInputToTextarea (input) { // called by onpaste ////#input_expand_into_textarea // //#todo more sanity // if (!input) { // return ''; // } // // if (document.createElement) { // var parent = input.parentElement; // var textarea = document.createElement('textarea'); // var cols = input.getAttribute('cols'); // var name = input.getAttribute('name'); // var id = input.getAttribute('id'); // var rows = 5; // var width = cols + 'em'; // // textarea.setAttribute('name', name); // textarea.setAttribute('id', id); // textarea.setAttribute('cols', cols); // textarea.setAttribute('rows', rows); // //textarea.style.width = width; // textarea.innerHTML = input.value; // // //parent.appendChild(t); // parent.insertBefore(textarea, input.nextSibling); // input.style.display = 'none'; // // textarea.focus(); // textarea.selectionStart = textarea.innerHTML.length; // textarea.selectionEnd = textarea.innerHTML.length; // // if (window.inputToChange) { // window.inputToChange = ''; // } // } // // return true; //} // //function ConvertSubmitsToButtonsWithAccessKey (parent) { // if (!parent) { // //alert('DEBUG: ConvertSubmitsToButtons: warning: sanity check failed'); // return ''; // } // // if (parent.getElementsByClassName) { // var buttons = parent.getElementsByClassName('btnSubmit'); // // convert each submit to button with accesskey // } else { // //todo // } // return '' //} // ConvertSubmitsToButtonsWithAccessKey() // developer // SetPrefs('notify_event_loop', 1); // SetPrefs('notify_event_loop', 0); // == end utils.js // == begin timestamp.js function RoundNumber (num) { var ret = Math.floor(num); //var ret = Math.floor(num * 10) / 10; //leave one digit after the decimal point ////alert('DEBUG: RoundNumber: num = ' + num + '; ret = ' + ret + ''); return ret; } function LongAgo (seconds) { // returns string with time units // takes seconds as parameter // returns a string like "3 days ago" or "3 days from now" var flip = 0; // default is '... ago' if (seconds < 0) { flip = 1; // '... from now' instead of '... ago' seconds = 0 - seconds; } var unit = ''; var number = seconds; if (seconds < 5) { // seconds should always be positive because of flip above returnValue = 'just now!' return returnValue; } if (number < 60) { number = number; if (RoundNumber(number) != 1) { unit = ' seconds'; } else { unit = ' second'; } } else { number = number / 60; if (number < 60) { if (RoundNumber(number) != 1) { unit = ' minutes'; } else { unit = ' minute'; } } else { number = number / 60; if (number < 24) { if (RoundNumber(number) != 1) { unit = ' hours'; } else { unit = ' hour'; } } else { number = number / 24; if (number < 7) { if (RoundNumber(number) != 1) { unit = ' days'; } else { unit = ' day'; } } else { if (number < 30) { number = number / 7; if (RoundNumber(number) != 1) { unit = ' weeks'; } else { unit = ' week'; } } else { if (number < 365) { number = number / 30; if (RoundNumber(number) != 1) { unit = ' months'; } else { unit = ' month'; } } else { number = number / 365; if (RoundNumber(number) != 1) { unit = ' years'; } else { unit = ' year'; } } // years } // months } // weeks } // days } // hours } // minutes //number = RoundNumber(number); var returnValue = ''; if (seconds % 1 == 0) { returnValue = RoundNumber(number) + ' ' + unit; } else { returnValue = number + ' ' + unit; } if (flip) { returnValue = returnValue + ' ago'; } else { returnValue = returnValue + ' from now'; } //alert(returnValue); return returnValue; } // LongAgo() function ShowTimestamps () { // finds any class=timestamp, updates its displayed time as needed // currently requires getElementsByClassName() // in the future, ie4+, nn4+, and others compat can be improved //alert('DEBUG: ShowTimestamps()'); // function FormatTimestamps () { var restAfter = 100; // stop after this many changes to avoid slowing things down if ( (window.GetPrefs) && (GetPrefs('performance_optimization') == 'faster') ) { restAfter = 30; } //alert('DEBUG: ShowTimestamps() BEGIN'); if (document.getElementsByClassName) { //alert('DEBUG: ShowTimestamps: document.getElementsByClassName feature check passed'); var d = new Date(); var curTime = d.getTime() / 1000; //var curTime = Math.floor(d.getTime() / 1000); var changeLogged = 0; var showTimestampsFormat = 0; if (window.GetPrefs) { if (GetPrefs('timestamps_format')) { showTimestampsFormat = GetPrefs('timestamps_format'); } else { showTimestampsFormat = 0; } } // find elements with class=timestamp var te = document.getElementsByClassName("timestamp"); //#timestampTagFormat //var te = document.getElementsByTagName("time"); //#timestampTagFormat //alert('DEBUG: ShowTimestamps: class=timestamp elements found: ' + te.length); for (var i = 0; i < te.length; i++) { // loop through all the timestamp elements on the page var timeValue = te[i].getAttribute('datetime'); //#timestampTagFormat if (!timeValue) { var timeValue = te[i].getAttribute('epoch'); //#timestampTagFormat } if (!isNaN(timeValue)) { //if (!isNaN(te[i].getAttribute('epoch'))) { //#timestampTagFormat // element also has an attribute called 'epoch', and it is // a number, which would represent epoch seconds var secs = 0 - (curTime - timeValue); // number of seconds since epoch begin var longAgo = ''; if (timeValue % 1 == 0) { secs = RoundNumber(secs); } //alert(showTimestampsFormat); //if (te[i].getAttribute('format')) { //showTimestampsFormat = te[i].getAttribute('format'); //} if (showTimestampsFormat) { if (showTimestampsFormat == 'exact') { //#todo longAgo = te[i].getAttribute('title'); } if (showTimestampsFormat == 'exact_full') { var date = new Date(timeValue * 1000); var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); var hours = date.getHours(); var minutes = date.getMinutes(); if (month < 10) { month = '0' + month; } if (day < 10) { day = '0' + day; } if (hours < 10) { hours = '0' + hours; } if (minutes < 10) { minutes = '0' + minutes; } longAgo = year + "-" + month + "-" + day + " " + hours + ":" + minutes; } if (showTimestampsFormat == 'adjusted') { longAgo = LongAgo(RoundNumber(secs)); // what the element's displayed value should be } if (showTimestampsFormat == 'seconds') { longAgo = secs; // what the element's displayed value should be } if (showTimestampsFormat == 'epoch') { longAgo = RoundNumber(timeValue); } if (showTimestampsFormat == 'iso') { if (d.toISOString) { var dd = new Date(timeValue * 1000); longAgo = dd.toISOString(); var gt = unescape('%3E'); longAgo = longAgo.substr(0,10) + '<wbr' + gt + longAgo.substr(10); // wrapping hint } } if (!longAgo) { showTimestampsFormat = 'adjusted'; longAgo = LongAgo(RoundNumber(secs)); } } else { longAgo = secs; } //longAgo = secs; var modernMode = 0; // templated if (te[i].innerHTML != longAgo) { // element's content does not already equal what it should equal te[i].innerHTML = longAgo; if (modernMode) { if ((secs * (-1)) < 3600) { te[i].classList.add('veryRecent'); } else { te[i].classList.remove('veryRecent'); } if ((secs * (-1)) < 86400) { te[i].classList.add('recent'); } else { te[i].classList.remove('recent'); } } else { if ((secs * (-1)) < 3600) { // less than an hour ago = bold te[i].style.fontWeight = 'bold'; } else { te[i].style.fontWeight = ''; } if ((secs * (-1)) < 86400) { // less than a day ago = highlight var colorHighlightAlert = '#ffc080'; // templated if (colorHighlightAlert) { te[i].style.backgroundColor = colorHighlightAlert; } } else { te[i].style.backgroundColor = ''; } } //var rect = te[i].getBoundingClientRect(); //if (!te[i].getAttribute('maxw') || (te[i].getAttribute('maxw') < rect.width)) { // te[i].setAttribute('maxw', rect.width); // te[i].style.width = (rect.width) + 'px'; // document.title = te[i].getAttribute('maxw') + ',' + te[i].style.width; //} changeLogged++; // count change logged } } if (restAfter < changeLogged) { setTimeout('ShowTimestamps()', 500); i = te.length; return changeLogged; } } // for (var i = 0; i < te.length; i++) if (window.EventLoop) { // do nothing, EventLoop() will call us when needed } else { // allow ShowTimestamps() to run decoupled from EventLoop() if (changeLogged) { setTimeout('ShowTimestamps()', 5000); } else { setTimeout('ShowTimestamps()', 15000); } } return changeLogged; } } // ShowTimestamps() // //if (window.EventLoop) { // // do nothing, EventLoop() will take care of us //} else { // // if no EventLoop(), we do it ourselves // ShowTimestamps(); //} // == end timestamp.js // == begin clock/epoch.js function setClock () { if (document.frmTopMenu) { if (document.frmTopMenu.txtClock) { if (document.frmTopMenu.txtClock.value) { var d = new Date(); var n = d.getTime(); n = Math.ceil(n / 1000); document.frmTopMenu.txtClock.value = n; if (document.frmTopMenu.txtClock.style) { //document.frmTopMenu.txtClock.style.border = 0; //document.frmTopMenu.txtClock.setAttribute('size', 10); } } } } } // == end clock/epoch.js // == begin fresh.js var freshClient; function FreshCallback() { // callback for requesting HEAD for current page //alert('DEBUG: FreshCallback() this.readyState = ' + this.readyState); if ( document.getElementById && this.readyState == this.HEADERS_RECEIVED || this.status == 200 ) { // headers received -- what we've been waiting for //alert('DEBUG: FreshCallback() this.readyState == this.HEADERS_RECEIVED'); var eTag = freshClient.getResponseHeader("ETag"); // etag header contains page 'fingerprint' if (!eTag) { if (window.myOwnETag) { //alert('DEBUG: fresh.js: FreshCallback: warning: eTag is FALSE; setting to equal myOwnETag'); eTag = window.myOwnETag; } else { //alert('DEBUG: fresh.js: FreshCallback: warning: eTag is FALSE; and myOwnETag is also FALSE'); } } //alert('DEBUG: fresh.js: FreshCallback: eTag = ' + eTag); if (eTag) { // if ETag header has a value if (window.myOwnETag) { //alert('DEBUG: fresh.js: FreshCallback: eTag = ' + eTag + '; window.myOwnETag = ' + window.myOwnETag); if (eTag != window.myOwnETag) { if (eTag == window.lastEtag) { // if it's equal to the one we saved last time // no new change change } else { var freshUserWantsReload = 0; // templated if (freshUserWantsReload) { // user wants reload //alert('DEBUG: fresh.js: FreshCallback: user wants automatic page reload'); location.reload(); } else { // user doesn't want reload, just show notification //alert('DEBUG: fresh.js: FreshCallback: user does not want automatic page reload, notify'); window.lastEtag = eTag; var ariaAlert; ariaAlert = document.getElementById('ariaAlert'); if (!ariaAlert) { //alert('DEBUG: fresh.js: FreshCallback: ariaAlert created successfully'); ariaAlert = document.createElement('p'); ariaAlert.setAttribute('role', 'alert'); ariaAlert.setAttribute('id', 'ariaAlert'); ariaAlert.style.zIndex = '1337'; //#todo var txtUpdated = document.createTextNode('Page updated '); ariaAlert.appendChild(txtUpdated); //document.body.appendChild(ariaAlert); document.body.insertBefore(ariaAlert, document.body.firstChild); //window.newPageContent = //FetchNewPageContent(window.mypath + '?' + new Date().getTime()); //ariaAlert.innerHTML = ariaAlert.innerHTML + '+'; var d = new Date(); var n = d.getTime(); n = Math.ceil(n / 1000); var space = document.createElement('span'); space.innerHTML = ' '; ariaAlert.appendChild(space); var a = document.createElement('a'); a.setAttribute('id', 'freshAria'); a.setAttribute('href', '#'); a.setAttribute('onclick', 'location.reload()'); ariaAlert.appendChild(a); var newTs = document.createElement('span'); newTs.setAttribute('class', 'timestamp'); newTs.setAttribute('epoch', n); newTs.setAttribute('id', 'freshTimestamp'); newTs.innerHTML = 'just now!'; a.appendChild(newTs); } // !ariaAlert if (window.freshTimeoutId) { clearTimeout(window.freshTimeoutId); } //window.eventLoopFresh = 0; // stop checking for updates if (document.title.substring(0, 2) != '! ') { document.title = '! ' + document.title; } } // NOT freshUserWantsReload } // lastEtag also didn't match } // eTag != window.myOwnETag else { //document.title = 'FreshCallback: x ' + window.myOwnETag + ';' + new Date().getTime(); if (window.freshTimeoutId) { clearTimeout(window.freshTimeoutId); } window.freshTimeoutId = setTimeout('CheckIfFresh()', 15000); } } // if (window.myOwnETag) else { window.myOwnETag = eTag; } } // if (eTag) // ETag header has value } // status == 200 if (this.status == 404 && document.getElementById) { //alert('DEBUG: fresh.js: FreshCallback: page has gone away on server (404)'); var ariaAlert; ariaAlert = document.getElementById('ariaAlert'); if (!ariaAlert) { //alert('DEBUG: fresh.js: FreshCallback: ariaAlert not found on page, creating...'); ariaAlert = document.createElement('p'); ariaAlert.setAttribute('role', 'alert'); ariaAlert.setAttribute('id', 'ariaAlert'); ariaAlert.style.zIndex = '1337'; //#todo ariaAlert.innerHTML = 'Page was deleted from server.'; //document.body.appendChild(ariaAlert); document.body.insertBefore(ariaAlert, document.body.firstChild); } // window.eventLoopFresh = 0; // stop checking for updates } // status == 404 return true; } // FreshCallback() function CheckIfFresh () { var d = new Date(); //alert('DEBUG: CheckIfFresh: ' + d.getTime()); var freshCheckRecent = window.freshCheckRecent; if (freshCheckRecent) { //alert('DEBUG: CheckIfFresh: freshCheckRecent = ' + freshCheckRecent); var d = new Date(); var curTime = d.getTime(); if (curTime < freshCheckRecent + 3000) { return true; } } //alert('DEBUG: CheckIfFresh: checkpoint passed'); var d = new Date(); window.freshCheckRecent = d.getTime(); var xhr = null; if (window.XMLHttpRequest){ xhr = new XMLHttpRequest(); } else { if (window.ActiveXObject) { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } } if (xhr) { var mypath = window.mypath; if (!mypath) { mypath = window.location; window.mypath = mypath; } freshClient = xhr; if (0 && mypath.toString().indexOf('?') == -1) { // NO question mark (or params) // cachebuster // this ensures no caching, but may cause other problems // q: what problems? freshClient.open("HEAD", mypath + '?' + d.getTime(), true); } else { // below we strip the page arguments if they begin with ?message= if (mypath.toString().indexOf('?message=') == -1) { // leave it freshClient.open("HEAD", mypath, true); } else { // remove the parameters mypath = mypath.toString().substr(0, mypath.toString().indexOf('?message=')); freshClient.open("HEAD", mypath, true); } } //freshClient.timeout = 5000; //#xhr.timeout freshClient.setRequestHeader('Cache-Control', 'no-cache'); freshClient.onreadystatechange = FreshCallback; freshClient.send(); } return true; } // CheckIfFresh() //alert('DEBUG: fresh.js'); if (window.EventLoop) { if (!window.GetPrefs) { // if no prefs, enable it window.eventLoopEnabled = 1; window.eventLoopFresh = 1; } EventLoop(); } else { CheckIfFresh(); } // == end fresh.js /* table_sort.js */ function SortTable (t, sortOrder) { // TableSort ( //alert('DEBUG: SortTable() begins'); //caution: bubble sort inside if (! document.body.textContent) { //alert('DEBUG: SortTable: warning: textContent feature check FAILED'); return ''; } var table, rows, switching, i, x, y, shouldSwitch, sortColumn, sortMethod; sortColumn = 0; sortMethod = 0; // sortMethod = 0 innerHTML // sortMethod = 1 textContent // sortMethod = 2 parseInt(innerHTML) if (1 < sortOrder) { return ''; } var rowColor0 = '#ffffff'; // these are templated from theme/.../color/row0 var rowColor1 = '#e0e0e0'; // these are templated from theme/.../color/row1 sortOrder = sortOrder ? 1 : 0; var anyChanges = 0; var tOrig = t; if (!t) { //alert('DEBUG: SortTable: warning: t missing'); return ''; } var sortField = t.textContent; if (t.cellIndex || t.cellIndex == 0) { sortColumn = t.cellIndex; // default sortMethod is 0, defined above // innerHTML if ( t.textContent && t.textContent.indexOf('_title') != -1 || t.textContent.indexOf('author_key') != -1 || t.textContent.indexOf('author_id') != -1 ) { sortMethod = 1; // textContent } if ( t.textContent && ( t.textContent.indexOf('_count') != -1 || t.textContent.indexOf('_order') != -1 || t.textContent.indexOf('_sequence') != -1 || t.textContent.indexOf('_score') != -1 ) ) { sortMethod = 2; // parseInt(innerHTML) } if ( t.textContent && ( t.textContent.indexOf('_timestamp') != -1 ) ) { sortMethod = 3; // timestamp widget } } while (!table && t.parentNode) { t = t.parentNode; if (t.tagName == 'TABLE') { table = t; } } if (!table) { //alert('DEBUG: SortTable: warning: table missing'); return ''; } else { //alert('DEBUG: SortTable: table exists, proceeding'); } if (table && table.getAttribute) { var tableId = table.getAttribute('id'); if (tableId) { if (window.SetPrefs) { SetPrefs('TableSort:' + tableId, sortField + ':' + sortOrder + ':' + sortMethod); } } } else { //alert('DEBUG: SortTable: warning: table is missing'); return ''; } //alert('DEBUG: SortTable: sortOrder = ' + sortOrder + '; sortMethod = ' + sortMethod); // bubble sort below by some website... switching = true; /* Make a loop that will continue until no switching has been done: */ while (switching) { // Start by saying: no switching is done: switching = false; rows = table.rows; /* Loop through all table rows (except the first, which contains table headers): */ for (i = 1; i < (rows.length - 2); i++) { // Start by saying there should be no switching: shouldSwitch = false; /* Get the two elements you want to compare, one from current row and one from the next: */ x = rows[i].getElementsByTagName("TD")[sortColumn]; y = rows[i + 1].getElementsByTagName("TD")[sortColumn]; // Check if the two rows should switch place: if ( x && y && x.innerHTML && y.innerHTML ) { var xValue = 0; var yValue = 0; if (sortMethod == 0) { // this is the default and fallthrough xValue = x.innerHTML; yValue = y.innerHTML; } if (sortMethod == 1) { // textContent // title, author_key, author_id xValue = x.textContent; // #todo lowercase yValue = y.textContent; // #todo lowercase } if (sortMethod == 2) { // parseInt(innerHTML) // numeric: count order sequence score if (x.textContent == '-') { xValue = 0; } else { xValue = parseInt(x.innerHTML); } if (y.textContent == '-') { yValue = 0; } else { yValue = parseInt(y.innerHTML); } } if (sortMethod == 3) { // timestamp inside timestamp widget // epoch timestamp var xWidget = x.getElementsByClassName('timestamp'); xValue = xWidget[0].getAttribute('datetime'); var yWidget = y.getElementsByClassName('timestamp'); yValue = yWidget[0].getAttribute('datetime'); } ////// if ( ( sortOrder == 0 && xValue < yValue ) || ( sortOrder == 1 && yValue < xValue ) ) { // If so, mark as a switch and break the loop: shouldSwitch = true; anyChanges++; break; } } } if (shouldSwitch) { /* If a switch has been marked, make the switch and mark that a switch has been done: */ rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); switching = true; } } // while (switching) if (!anyChanges) { // if the table was already sorted, that means it should be reversed // to make the code simpler, we just recurse into SortTable() again sortOrder = (sortOrder ? 0 : 1); return SortTable(tOrig, sortOrder); } if (anyChanges) { // if there have been any changes, we have to re-do the alternating row colors rows = table.rows; var rowsLength = rows.length; for (i = 2; i < rowsLength - 1; i++) { if ( rows[i] && rows[i].style.backgroundColor == rowColor0 || rows[i].style.backgroundColor == rowColor1 || rows[i].getAttribute('bgcolor') == rowColor0 || rows[i].getAttribute('bgcolor') == rowColor1 ) { // the above check avoids changing the color of highlighted rows if (i % 2) { rows[i].style.backgroundColor = rowColor0; } else { rows[i].style.backgroundColor = rowColor1; } } } } //alert('DEBUG: SortTable() finished'); return ''; } // SortTable() /* / table_sort.js */ // == begin voting.js function PingUrlCallback () { var xmlhttp = window.xmlhttp; var xmlhttpElement = window.xmlhttpElement; if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { //alert('DEBUG: PingUrlCallback() found status 200!'); // #todo this feature is broken and is not consistent //if (xmlhttpElement) { // var elemOK = document.createElement('span'); // //elemOK.setAttribute('disabled', true); // elemOK.innerHTML = '✓'; // checkmark // //#todo: get rect, and check if it is too wide, // // which means escaped char didn't work // // and should be replaced (ff 3.x, camino) // //elemOK.innerHTML = 'OK'; // xmlhttpElement.setAttribute('disabled', true); // xmlhttpElement.appendChild(elemOK); //} //if (xmlhttp.responseURL.indexOf('message') != -1) { // this works, but is not always desirable. // it should happen from a page reprint request #todo //window.location.replace(xmlhttp.responseURL); //} //if (xmlhttp.responseUrl.indexOf('message') != -1) { //window.location.replace(xmlhttp.responseURL); //} // this is very janky but has potential // document.open(); // document.write(xmlhttp.responseText); // document.close(); window.xmlhttp = 0; } //else if (xmlhttp.readyState == 4 && xmlhttp.status == 303) { //} // could be useful in the future else if (xmlhttp.readyState == 4 && xmlhttp.status == 401) { // server returned 401, which most likely means that we need a cookie // redirect user to profile.html page so that they can register // this is very basic, jarring, and unfriendly, but it is better than failing silently // relative links setting should also be taken into account // #todo window.location = '/session.html'; // #todo relativize } else { //alert('DEBUG: PingUrlCallback: warning: unrecognized: xmlhttp.status = ' + xmlhttp.status + '; xmlhttp.readyState = ' + xmlhttp.readyState); } } //function OptionsDefault(token, privKeyObj) { // this.data = token; // this.privateKeys = [privKeyObj]; //} function signCallback (signed) { var postUrl = '/post.html'; var url = postUrl + '?comment=' + encodeURIComponent(signed.data); if (PingUrl(url)) { // todo incrememnt counter } } function IncrementTagLink (t) { // increments number of votes in tag button // function IncrementVoteLink () { // function AddVote () { // adds a number if there isn't one already // #todo adapt to accommodate buttons as well if (!t) { // if t is missing, return true, so that click event can go through //alert('DEBUG: IncrementTagLink: warning: t is missing'); return true; } if (t.innerHTML) { // update count in vote link //alert('DEBUG: IncrementTagLink: t.innerHTML'); var ih = t.innerHTML; if (ih.indexOf('(') == -1) { // there is no count yet, add a 1 //alert('DEBUG: IncrementTagLink: ( not found'); t.innerHTML = ih + '(1)'; } else { // there is a count already, increment it //alert('DEBUG: IncrementTagLink: ( found'); var numVal = ih.substring(ih.indexOf('(') + 1, ih.indexOf(')')); var newVal = parseInt(numVal) + 1; var hashTag = ih.substring(0, ih.indexOf('(')); t.innerHTML = hashTag + '(' + newVal + ')'; } var voteValue = t.innerHTML.substring(0, t.innerHTML.indexOf('(')); //alert('DEBUG: IncrementTagLink: voteValue = "' + voteValue + '"'); //alert('DEBUG: IncrementTagLink: finished with t.innerHTML'); return false; } // if (t.innerHTML) return true; } // IncrementTagLink() function SignVote (t, token) { // signs a vote from referenced vote button // t = reference to calling button's 'this' // token = full voting token, in the format (gt)(gt)fileHash\n#tag // where (gt) is a greater-than sign, omitted here // function SendVote () { // function StoreVote () { // function SaveVote () { //alert('DEBUG: SignVote(' + t + ',' + token +')'); if ( t.nextSibling && t.nextSibling.tagName && t.nextSibling.getAttribute && t.nextSibling.getAttribute('class') == 'notification' ) { // removes a notification if it is immediately afer this button if (t.nextSibling.remove) { // #todo there is a bug here, somehow remove() isn't always there t.nextSibling.remove(); } } //if (window.xmlhttp) { //only allow one vote a time to be happening //unless user is operator // #todo this feature is very broken and causes user inconvenience //if (GetPrefs('show_admin')) { // // user has assumed operator role, continue without check //} else { // // user has not assumed operator role, // // show notification and cancel vote // if (window.displayNotificationWithTimeout) { // displayNotificationWithTimeout('Too fast', t); // } // return false; //} //} if (document.getElementById) { // basic dumb feature check #todo make smarter feature check ; // needs better compatibility for older browsers // get private key if (!GetPrefs('show_admin') && GetPrefs(token)) { // don't let user vote twice -- basic version // the token we'd send to vote is stored as the key to a preference setting // #todo this could be nicer? // doesn't apply if user is showing operator controls if (window.displayNotificationWithTimeout) { window.duplicateVoteTries ? window.duplicateVoteTries++ : window.duplicateVoteTries = 1; if (3 <= window.duplicateVoteTries) { // display alternative message if user has tried to duplicate-vote 3 or more times displayNotificationWithTimeout('Hey!', t); } else { displayNotificationWithTimeout('Already voted', t); } } else { //alert('DEBUG: window.displayNotificationWithTimeout() was missing'); } // returning false will keep the link from navigating to non-js fallback return false; } IncrementTagLink(t); var privkey = 0; //also serves as feature check flag, sorry if (window.getPrivateKey && window.openpgp) { var privkey = getPrivateKey(); } //alert('DEBUG: SignVote: privkey: ' + !!privkey); window.xmlhttpElement = t; if (GetPrefs('show_admin') || !privkey) { //alert('DEBUG: !privkey'); // if there is no private key, just do a basic unsigned vote; // if user is operator, they also do this for faster voting if (PingUrl(t.href)) { return false; } } else { // there is a private key //alert('DEBUG: privkey is true'); // load the private key into openpgp var privKeyObj = openpgp.key.readArmored(privkey).keys[0]; var options; options = new Object(); options.data = token; options.privateKeys = privKeyObj; openpgp.config.show_version = false; openpgp.config.show_comment = false; // sign the voting token and send to post.html when finished openpgp.sign(options).then(signCallback); } // remember that we voted for this already SetPrefs(token, 1); if (window.displayNotification) { // displayNotification('Success!', t); } else { //alert('DEBUG: window.displayNotification() was missing'); } return false; // cancel link click-through } else { // if (document.images) { // var myUrl = window.location; // var postUrl = '/post.html'; // document.images[0].src = postUrl + '?mydomain=' + myUrl; // // //alert('DEBUG: t = ' + t); // // return false; // } } //alert('DEBUG: SignVote: warning: fall-through'); return true; // allow link click to happen } // SignVote() // == end voting.js /* write.js */ function WriteOnload () { // onload handler for write page //alert('DEBUG: WriteOnload() begin'); if (document.getElementById) { //alert('DEBUG: WriteOnload: document.getElementById is true'); if (0) { var comment = document.getElementById('comment'); if (comment && comment.style) { // store current width // compare to viewport width // if wider than viewport reduce // otherwise, leave exactly the same var curWidth = comment.clientWidth; //alert(curWidth); var curHeight = comment.clientHeight; //alert(curHeight); comment.removeAttribute('cols'); comment.removeAttribute('rows'); comment.style.maxWidth = '95%'; comment.style.width = curWidth + 'px'; comment.style.height = curHeight + 'px'; } } if (window.GetPrefs) { //alert('DEBUG: (window.GetPrefs) = TRUE'); if (GetPrefs('write_enhance')) { //alert('DEBUG: write_enhance = TRUE'); var comment = document.getElementById('comment'); if (comment) { if (window.location.href.indexOf('write') != -1) { // write page CommentMakeWp(comment); } else { // not write page comment.setAttribute('onfocus', 'CommentMakeWp(this)'); } } } else { //alert('DEBUG: write_enhance = FALSE'); } } else { //alert('DEBUG: (window.GetPrefs) = FALSE'); } var pubKey = ''; if (window.getPublicKey) { //alert('DEBUG: window.getPublicKey exists'); pubKey = getPublicKey(); } var privKey = ''; if (window.getPrivateKey) { //alert('DEBUG: window.getPrivateKey exists'); privKey = getPrivateKey(); } var configJsOpenPgp = 1; // this is templated from config/setting/admin/js/openpgp if (configJsOpenPgp && privKey) { //alert('DEBUG: privKey was true, adding options...'); if (document.getElementById('spanSignAs')) { var gt = unescape('%3E'); if (window.getAvatar) { if (window.solvePuzzle) { //alert('DEBUG: window.solvePuzzle was true, adding button...'); var spanWriteAdvanced = document.getElementById('spanWriteAdvanced'); if (spanWriteAdvanced && window.solvePuzzle) { var btnSolvePuzzle = document.createElement('input'); btnSolvePuzzle.setAttribute('id', 'btnSolvePuzzle'); btnSolvePuzzle.setAttribute('type', 'button'); btnSolvePuzzle.setAttribute('value', 'Solve Puzzle'); btnSolvePuzzle.setAttribute('onclick', "if (window.solvePuzzle) { return solvePuzzle(this); } else { return true; }"); spanWriteAdvanced.appendChild(btnSolvePuzzle); var br = document.createElement('br'); spanWriteAdvanced.appendChild(br); var lblSolvePuzzle = document.createElement('span'); lblSolvePuzzle.setAttribute('class', 'beginner'); var gt = unescape('%3E'); lblSolvePuzzle.innerHTML = 'Solving puzzles may improve reputation.'; spanWriteAdvanced.appendChild(lblSolvePuzzle); } } // window.solvePuzzle var spanSignAs = document.getElementById('spanSignAs'); var lblSignAs = document.createElement('label'); lblSignAs.setAttribute('for', 'chkSignAs'); var chkSignAs = document.createElement('input'); chkSignAs.setAttribute('name', 'chkSignAs'); chkSignAs.setAttribute('id', 'chkSignAs'); chkSignAs.setAttribute('type', 'checkbox'); if (!(window.GetPrefs) || GetPrefs('sign_by_default')) { chkSignAs.setAttribute('checked', 1); } if (window.solvePuzzle) { // assumes btnSolvePuzzle was created chkSignAs.setAttribute('onchange', 'document.getElementById(\'btnSolvePuzzle\').disabled = !this.checked'); // #todo does this need sanity check first? chkSignAs.onchange(); } // implied getElementById already been feature checked here //chkSignAs.setAttribute('onclick', "if (document.getElementById('btnSolvePuzzle')) { document.getElementById('btnSolvePuzzle').setAttribute('disabled', !chkSignAs.checked); }"); // this checkbox being checked means SignMessage() is called in WriteSubmit() lblSignAs.innerHTML = 'Sign as ' + getAvatar(); lblSignAs.appendChild(chkSignAs); spanSignAs.appendChild(lblSignAs); // #todo this should probably be advanced layer, as it's not relevant to most users and just introduces confusion } // window.getAvatar } // document.getElementById('spanSignAs') } //window.pubKeyForServer = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQGNBGH6CvoBDACvgqq2jQOgSAXZEx68Lhcq9HblnK6opiT5J4Msi365g+lXozye\nI/bfXWLv9Y1uxdIxXR/WjzqsUe5YJvd9vf+s6vz7lWR+xtNV/2XTTdtxKl1fPjFj\nC/Lg7Utv7+lpbag61TET1v9Lh2lCgY/rvLaHCvOkyu7TmdzOhkejt8pr3bDySvhZ\n3+12AvoWMiCgdjLQK+uGYV10vcKLvQ5FN+rwbVuCgE5h1RJs1lsKOZRY5SRgYzEF\nHOzuBTtpEdk2qwjoD2QHRYX1wf651EmoDKa8YZteMM87hbzwpR0ijU09zfzguTUl\npy9OOMYgSI8XlxS6+z5NR9c0CtEkt7I0Fg0Z4f8XMQCoQFe7OKVE4QsGUelNmbzP\nlou4/LTms6RCq0FcOEhkeXCINT27q1Cx5iQ0laUttkHf/5JQj039BOu8orENGtSV\n+WGp+70J+pzcrHtRN2ka9zmiaHc5m30lcMEGV9hYyOhubb2qmE6kmMjzrwE1lK0J\nIFqTnkC5NzP2Vr8AEQEAAbQFSm9obm6JAdQEEwEIAD4WIQTnn9zd9BEWrFcD9JvL\nAAYtw4wRaQUCYfoK+gIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAK\nCRDLAAYtw4wRaSPQC/0V/qd0uZtPOF11sM67GOr5eZuApej+ce9jZu5qFZt1HdlY\nEWQCXz/qDepZGVzXnHledkIdjFDanDrwT0VtrGMxOvj+9hyZ5cLKqZYoHOIIRp/T\n7Ul7F61Q5/+xJpUKb9hH7h89pHwSSvjT6wIHytuzenljmOu9B1Udh2KsqdUEMPP0\nHmuqHZdI4hLGcTkuh2+C6agEPT72cIFVd6Nf/Zy4jlTMoXdg1dUZT7xpmWVUsOzG\napTdsN3dzfQcLvDvT1dXFrBdX5NvHweIDO1ozOHSFN3fxT4jEfTnpd6BFyju2Rig\n2s1q5qoHpIRu1b1Igu9EC5RdabrXxREJVU2jZXIQWwHQI/VsGLYGGZwp9F4G66xU\nigSmi1NOZ66oyDhNCaCgIVZf2czvVaUXSIARIGDf+uw9iIAhysqE0rmI38Eiytcm\nH+jlrVJYnP1MuoGjSgy7oT+SVZePGKfN0YIv9uFcupQfAbV2bkLZV6k+Cpy+Gct8\n4eKU/M3urW9Bigt4egm5AY0EYfoK+gEMAK+wax1jw+Qkb/8wVS05YvxFyBVvxu5p\nIxAuUxhoIoCfDjqm9axudCVgXbHJovS6l26ReKWMlXhrMo0uRTyL2D9dEFRDwxci\nmrftu03SadBe/7c93facdcS1ToTZBdAFSzBeoe+CJmJsNpX4MfSNVIHAEi1w7zyG\nLs/OwVU79wCEVwBMvNOHGRiorLZdfPDJDRO+MMIOyjcORrAK0uYoD6RBhjqqobH7\njaZI02URmdwfftrsIM66L1IBkLncNseE68niBaiGatX8E/0Wz59YN/nqtUPDy0yN\nKuQUhn4QBmsKKUb7M2DOGNuHa/xGt3UFLB57Lk5DBSp78aRxpO8kenu+qj4N5R16\nuYZctl8PSZn2xeTGOc5ywWMCy6yUygStrvSJNiq5JT4OZgpjMc5NHWIwwRRrPirP\nLKbusBseA3DtVzsELDIPG3Sbt+2De5carkx1oNwuWyBtqxmybdg2A3zY1gwHm+XC\n6TMgUDgLKxCvt6DbkYrEAFd8l33xD4hypwARAQABiQG8BBgBCAAmFiEE55/c3fQR\nFqxXA/SbywAGLcOMEWkFAmH6CvoCGwwFCQPCZwAACgkQywAGLcOMEWmMsQv9EgJa\nMNa3jP7MetYf81NWIERdssba4pCpZEt/Zyuph79jEXXhafWcnaSSn0618mPWY6rI\nTJyBF+fZmOWJc8DrUuBqrTNR86oQDzL0yF4MYPyhmLRljtLNc3yAtiKr1aRPcpz3\n2BpKCG1S7N5HQFcYr0+e3GHdnNg2vQ+QT7pUKh96/5M/ckokYBBKZEoVPMI/QTrW\nh3ppHXK1afud4CejNluc2+gQt74Hv7+o7D9mt1mYUqHEMveOMTHrxAXNgNQ8HJrh\nzMuoD2uRqzmUJ7qkrwYo54geCOVmEOXbcHv8qaQ9oFGcXozqghC5EyvbBR7KNpRg\n26RnrklX6lCQEcw1e5ZCkRTdy09nOYyu2p4L7oJr2ovfjDQ3pZKBNk+7LHpLkgkp\nhHHYlRCPfdHbwCuMz1HbUxGvEAJUChdG+Cx8eqitL4KmPvTCZ3BW7d3PogRw62DC\nGMIHc3dm67l5Y1OI+V+XmA+kT94ydeDR2zYMmntW8nx49QztUbmso3xmDirI\n=Jwcw\n-----END PGP PUBLIC KEY BLOCK-----'; if (window.pubKeyForServer) { var btnEncrypt = document.createElement('button'); btnEncrypt.setAttribute('title', 'Encrypt'); btnEncrypt.innerHTML = 'Encrypt'; // todo add text node instead btnEncrypt.setAttribute('onclick', 'return EncryptComment()'); if (document.getElementById('spanEncrypt')) { var spanEncrypt = document.getElementById('spanEncrypt') spanEncrypt.appendChild(btnEncrypt); } } if (pubKey) { //alert('DEBUG: pubKey was true, calling PubKeyPing()'); if (window.PubKeyPing) { PubKeyPing(); } } if (window.location.hash) { //alert('DEBUG: window.location.hash = ' + window.location.hash); if (window.location.hash == '#inspubkey') { //alert('DEBUG: #inspubkey found'); if (pubKey) { //alert('DEBUG: pubKey is true, inserting it into comment'); var comment = document.getElementById('comment'); if (comment) { // set comment textarea to public key text comment.value = pubKey; } if (comment.style) { // expand comment textarea to size of public key text comment.style.width = '90ex'; comment.style.height = '50ex'; } // uncheck the 'sign as' checkbox var chkSignAs = document.getElementById('chkSignAs'); if (chkSignAs.checked) { chkSignAs.removeAttribute('checked'); } // hide unrelated options var spanSignAs = document.getElementById('spanSignAs'); if (spanSignAs) { spanSignAs.style.display = 'none'; } var spanWriteAdvanced = document.getElementById('spanWriteAdvanced'); if (spanWriteAdvanced) { spanWriteAdvanced.style.display = 'none'; } var addtext = document.getElementById('addtext'); if (addtext && addtext.value) { addtext.value = 'Share Public Key'; } } else { //alert('DEBUG: pubKey was false, this is unexpected. Giving up.'); } } } } // document.getElementById else { //alert('DEBUG: WriteOnload: document.getElementById was FALSE'); } return true; } // WriteOnload() function CommentMakeWp (comment) { // makes editor textarea larger and gives it wp color scheme // called when write_enhance is on if (comment) { comment.style.backgroundColor = '#102080'; comment.style.color = 'ffffff'; comment.style.fontWeight = 'bold'; comment.style.width = '95%'; comment.style.height = '50%'; comment.style.padding = '1em'; comment.setAttribute('cols', 80); comment.setAttribute('rows', 24); } return ''; } // CommentMakeWp() function WriteSubmit (t) { // called when user submits write form // function SignMessage () { //alert('DEBUG: WriteSubmit() begin'); if (window.localStorage) { //alert('DEBUG: WriteSubmit: window.localStorage'); if (window.ClearAutoSave) { ClearAutoSave(); } } else { //alert('DEBUG: WriteSubmit: no window.localStorage'); } var configJsOpenPgp = 1; // this is templated from config/setting/admin/js/openpgp if (configJsOpenPgp && window.getPrivateKey && window.SignMessage) { //alert('DEBUG: WriteSubmit: (window.getPrivateKey) && (window.SignMessage) test passed'); if (getPrivateKey()) { //alert('DEBUG: WriteSubmit: getPrivateKey() is true, calling SignMessage()'); if (document.getElementById) { var chkSignAs = document.getElementById('chkSignAs'); if (!chkSignAs || (chkSignAs && chkSignAs.checked)) { // if there's a "sign as" checkbox, it should be checked if (window.SignMessage) { var signMessageResult = SignMessage(); if (!signMessageResult) { signMessageResult = 0; } // once the message is signed, callback will submit the form if (signMessageResult) { // #todo there's a bug here where this is reached when it shouldn't be, and form fails to submit //alert('DEBUG: WriteSubmit: signMessageResult is FALSE, returning false'); return false; // uncomment this for duplicate unsigned messages feature } else { // #todo: if GetPrefs('draggable_spawn') is set, it should try to spawn item in new dialog instead of going to a new page return true; } } } else { // user choose not to sign return true; } } } else { // no private key //alert('DEBUG: WriteSubmit: no private key, basic submit'); } } else { // #todo add featureflag if (0) { //alert('DEBUG: WriteSubmit: (window.getPrivateKey) && (window.SignMessage) test failed, falling back to Sent: footnote'); var d = new Date(); var n = d.getTime(); n = Math.ceil(n / 1000); var textbox = document.getElementById('comment'); var composeForm = document.getElementById('compose'); if (textbox && composeForm) { var message = textbox.value; message = message + '\n-- \nSent: ' + n + '\n'; //textbox.value = message; #todo polish and uncomment this composeForm.submit(); } } else { // chose not to add client-side timestamp return true; } } window.eventLoopFresh = 0; // disables fresh.js. may not be a wise move here. //alert('DEBUG: WriteSubmit: about to return true'); return true; } // WriteSubmit() function DoAutoSave() { var initDone = window.autoSaveInitDone; if (!initDone) { window.autoSaveInitDone = 1; var ls = window.localStorage; if (window.localStorage && ls) { var storedValue = ls.getItem('autosave'); if (storedValue) { var comment = document.getElementById('comment'); if (comment) { comment.value += storedValue; } } } return 0; } if (document.getElementById) { //alert('DEBUG: DoAutoSave: document.getElementById is true'); if (window.GetPrefs) { //alert('DEBUG: DoAutoSave: (window.GetPrefs) = TRUE'); if (GetPrefs('write_autosave')) { // #todo this can't be right //alert('DEBUG: DoAutoSave: write_autosave = TRUE'); var comment = document.getElementById('comment'); if (comment) { if (window.localStorage) { var ls = window.localStorage; if (window.localStorage && ls) { ls.setItem('autosave', comment.value); } } } } else { //alert('DEBUG: write_autosave = FALSE'); } } else { //alert('DEBUG: (window.GetPrefs) = FALSE'); } } return ''; } // DoAutoSave() function ClearAutoSave () { var ls = window.localStorage; if (window.localStorage && ls) { window.eventLoopDoAutoSave = 0; ls.removeItem('autosave'); } } // ClearAutoSave() function writeAddTag (tag) { if (document.compose && document.compose.comment) { document.compose.comment.value = tag + ' ' + document.compose.comment.value; } } // writeAddTag() window.eventLoopDoAutoSave = 1; /* / write.js */ // settings_default.js function GetDefault (prefKey) { // get default value of preference // function GetSetting () { if (!prefKey) { //alert('DEBUG: GetDefault: warning: missing prefKey'); return ''; } // Correctly define the object with key-value pairs var defaultPrefs = { 'show_advanced': 0, 'beginner': 1, 'beginner_highlight': 1, 'show_admin': 0, 'notify_on_change': 1, 'timestamps_format': 'adjusted', 'performance_optimization': 'faster', 'draggable': 0, 'draggable_restore': 0, 'draggable_scale': 0, 'draggable_arrange_viewport_resize': 0 }; // Check if the prefKey exists in the defaultPrefs object if (defaultPrefs.hasOwnProperty(prefKey)) { //alert('DEBUG: GetDefault(' + prefKey + ')' + ' = ' + defaultPrefs[prefKey]); return defaultPrefs[prefKey]; } else { //alert('DEBUG: GetDefault: warning: prefKey = ' + prefKey + ' not found in defaultPrefs'); return ''; } } // GetDefault() // / settings_default.js // --> <!-- // begin loading_end.js function HideLoadingIndicator () { var loadingIndicator = window.loadingIndicator; if (!loadingIndicator) { if (document.getElementById) { loadingIndicator = document.getElementById('loadingIndicator'); if (!loadingIndicator && document.getElementsByClassName) { var allNotificationElements = document.getElementsByClassName('notification'); if (allNotificationElements) { loadingIndicator = allNotificationElementsp[0]; } } } else { // #todo forms fallback } } if (!loadingIndicator) { //alert('DEBUG: HideLoadingIndicator: warning: loadingIndicator is FALSE'); return ''; } if (window.loadingIndicatorShowTimeout) { clearTimeout(loadingIndicatorShowTimeout); } loadingIndicator.innerHTML = 'Ready.'; loadingIndicator.style.backgroundColor = '#e0ffa0'; setTimeout('window.loadingIndicator.style.opacity = "0.9"', 500); setTimeout('window.loadingIndicator.style.opacity = "0.7"', 2000); setTimeout('window.loadingIndicator.style.opacity = "0.6"', 3000); setTimeout('window.loadingIndicator.style.opacity = "0.5"', 4000); window.loadingIndicator = loadingIndicator; //loadingIndicator.setAttribute('onclick', 'this.remove()'); setTimeout('if (window.loadingIndicator && window.loadingIndicator.remove) { window.loadingIndicator.remove(); } else { if (window.loadingIndicator.style) { window.loadingIndicator.style.display = "none"; } }', 5000); //#todo fix this long line // #todo this causes a page shift in ie4 and ie6 // } else { // if (loadingIndicator) { loadingIndicator.style.display = 'none' } // } return ''; } // HideLoadingIndicator() function WaitForOpenPgp () { //alert('debug: WaitForOpenPgp()'); var d = new Date(); if (window.openPgpJsLoadBegin && window.openpgp) { HideLoadingIndicator(); } else { setTimeout('if (window.WaitForOpenPgp) { WaitForOpenPgp() }', 500); } } // WaitForOpenPgp() // #todo see if this is still necessary //if (!window.OnLoadEverything && window.HideLoadingIndicator) { // HideLoadingIndicator(); //} // end loading_end.js // -->"
By comparing qdb.us to other leading websites in its niche, marketers and researchers can identify key traffic sources and growth opportunities. Explore our related resources below to find websites similar to qdb.us.
Yes, according to our latest analysis, we detected a valid SSL certificate ensuring a secure connection.
As of July 24, 2026, qdb.us holds an estimated domain authority score of 34/100 based on our VisitRank tracking algorithms.
You can find the best alternatives and similar sites to qdb.us in our explore section, which includes competitors in the E-commerce & Retail sector.
Common Misspellings & Typo Domains for qdb.us:
"Welcome to welcome page. This message is designed to welcome you. Operator, please enhance this message."
"Welcome to Pollyanna! Your install was successful! You should run `hike setup` to enable the most commonly-used features. Thank you for installing Pollyanna!"