Simple javascript functions to scroll next/previous H1 to top of screen – in an HTA application run with MSHTA.exe

I am a hobby programmer, and have made an HTA file, with some JavaScript and a single contentEditable <DIV>. Using minimal JavaScript I can make keyboard shortcuts to format, save, and exit.

I am using mshta32.exe to run the file, in a fully updated Windows 10 system. My empty HTA is only 12k and for this I get word wrapping, formatting, linked images, print (including to PDF) and live spellchecking! It s not a word processor, but for distraction free composition I am loving the experience.

My next goal is to use these files for presentations; the minimum functionality I need is a “next slide” and “previous slide” shortcut. It seems reasonable to use <H1> tags as slide titles and therefore my shortcuts only need to scroll so the next, or previous, <H1> is at the top of the screen (yes HTA does save tags in upper case).

On the internet/ChatGPT there are solutions using document.querySelector but this does not seem to be supported within HTA/MSHTA (I have tried a meta tag with content=ie=edge and http-equiv=X-UA-Compatible). Not keen on JQuery as this is a minimalist project and needs to work offline, so I tried translating a suggestion in jQuery:

making a skip button that scrolls to the next heading

$('html, body').scrollTop($(this).nextInDOM($('h1, h2, h3, h4, h5, h6')).position().top); 

event.preventDefault();

To JavaScript:

document.querySelector('html, body').scrollTop(document.querySelector(this).nextInDOM(document.querySelector('h1, h2, h3, h4, h5, h6')).position().top); 
event.preventDefault();

This did not work! Any guidance welcome.

Kind Regards Gavin Holt

Whole HTA

<!DOCTYPE html>
<HTML>
<HEAD unselectable="on">
<TITLE unselectable="on"> ContentEditor - O:MyProfileeditortemplatesdefault.hta</TITLE><?XML:NAMESPACE PREFIX = "HTA" />
<HTA:Application id=document.currentScript VERSION="2" SYSMENU="yes" Singleinstance="no" ShowInTaskBar="yes" scroll="yes" NAVIGABLE="yes" MinimizeButton="yes" MaximizeButton="yes" Icon="O:MyProfilecmdIcoFXContentEditor.ico" ContextMenu="No" Border="No" APPLICATIONNAME="MSI-BUILD"></HTA:Application>
<BASE target=_blank unselectable="on">
<META name=viewport content="width=device-width, initial-scale=1" unselectable="on">
<META content=ie=edge unselectable="on">
<META http-equiv=X-UA-Compatible unselectable="on">
<STYLE unselectable="on">
@media Unknown    
{
.sidenav {
    PADDING-TOP: 15px
}
    }
HTML {
    COLOR: #657b83; MARGIN: 1em; BACKGROUND-COLOR: #fdf6e3
}
BODY {
    FONT-SIZE: 24px; FONT-FAMILY: Helvetica, arial, sans-serif; LETTER-SPACING: 0px; BACKGROUND-COLOR: #fdf6e3
}
.sidenav {
    FONT-SIZE: 22px; OVERFLOW: hidden; HEIGHT: 100%; WIDTH: 0px; OVERFLOW-X: hidden; POSITION: fixed; PADDING-TOP: 4px; LEFT: 0px; Z-INDEX: 1; TOP: 0px; BACKGROUND-COLOR: #111; transition: 0.5s
}
.sidenav A {
    TEXT-DECORATION: none; COLOR: #818181; PADDING-BOTTOM: 8px; PADDING-TOP: 8px; PADDING-LEFT: 32px; DISPLAY: block; PADDING-RIGHT: 8px; transition: 0.3s
}
.sidenav P {
    COLOR: #818181; PADDING-BOTTOM: 4px; PADDING-TOP: 8px; PADDING-LEFT: 4px; PADDING-RIGHT: 4px
}
TD {
    COLOR: #818181; PADDING-BOTTOM: 4px; PADDING-TOP: 8px; PADDING-LEFT: 4px; PADDING-RIGHT: 4px
}
TH {
    COLOR: #818181; PADDING-BOTTOM: 4px; PADDING-TOP: 8px; PADDING-LEFT: 4px; PADDING-RIGHT: 4px
}
B {
    COLOR: #818181; PADDING-BOTTOM: 4px; PADDING-TOP: 8px; PADDING-LEFT: 4px; PADDING-RIGHT: 4px
}
U {
    COLOR: #818181; PADDING-BOTTOM: 4px; PADDING-TOP: 8px; PADDING-LEFT: 4px; PADDING-RIGHT: 4px
}
.sidenav A:hover {
    COLOR: #f1f1f1
}
.sidenav TABLE {
    BORDER-LEFT-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; LINE-HEIGHT: 1; BORDER-TOP-WIDTH: 0px
}
TR {
    BORDER-LEFT-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; LINE-HEIGHT: 1; BORDER-TOP-WIDTH: 0px
}
TD {
    BORDER-LEFT-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; LINE-HEIGHT: 1; BORDER-TOP-WIDTH: 0px
}
TH {
    BORDER-LEFT-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; LINE-HEIGHT: 1; BORDER-TOP-WIDTH: 0px
}
#editor {
    PADDING-BOTTOM: 16px; PADDING-TOP: 16px; PADDING-LEFT: 16px; PADDING-RIGHT: 16px; transition: margin-left .5s
}
H1 {
    FONT-SIZE: 24px; TEXT-ALIGN: left; LINE-HEIGHT: 1.2
}
H2 {
    FONT-SIZE: 24px; TEXT-ALIGN: left; LINE-HEIGHT: 1.2
}
H3 {
    FONT-SIZE: 24px; TEXT-ALIGN: left; LINE-HEIGHT: 1.2
}
P {
    FONT-SIZE: 24px; TEXT-ALIGN: left; LINE-HEIGHT: 1.2
}
A {
    FONT-SIZE: 24px; TEXT-ALIGN: left; LINE-HEIGHT: 1.2
}
CODE {
    FONT-SIZE: 24px; TEXT-ALIGN: left; LINE-HEIGHT: 1.2
}
H1 {
    FONT-SIZE: 26px; FONT-VARIANT: small-caps
}
TABLE {
    WIDTH: 95%; BORDER-COLLAPSE: collapse
}
TABLE {
    BORDER-TOP-STYLE: none; BORDER-LEFT-STYLE: none; BORDER-BOTTOM-STYLE: none; BORDER-RIGHT-STYLE: none
}
TD {
    BORDER-TOP-STYLE: none; BORDER-LEFT-STYLE: none; BORDER-BOTTOM-STYLE: none; BORDER-RIGHT-STYLE: none
}
TH {
    BORDER-TOP-STYLE: none; BORDER-LEFT-STYLE: none; BORDER-BOTTOM-STYLE: none; BORDER-RIGHT-STYLE: none
}
TR {
    VERTICAL-ALIGN: top; TEXT-ALIGN: left; LINE-HEIGHT: 1.2
}
TD {
    VERTICAL-ALIGN: top; TEXT-ALIGN: left; LINE-HEIGHT: 1.2
}
TD {
    
}
TH {
    
}
TABLE {
    PAGE-BREAK-INSIDE: auto
}
TR {
    PAGE-BREAK-INSIDE: avoid; PAGE-BREAK-AFTER: auto
}
THEAD {
    DISPLAY: table-header-group
}
TFOOT {
    DISPLAY: table-footer-group
}
</STYLE>

<SCRIPT language=JScript type=text/jscript unselectable="on">
<!--
function preventDefault(e){
    if (e.preventDefault) {
        e.preventDefault();
    } else {
        e.returnValue = false;
    }
}
function toggleNav() {
    if (document.getElementById("mySidenav").style.width=="260px") {
    closeNav();
    } else {
    openNav();
    }
}
function openNav() {
    document.getElementById("mySidenav").style.width = "260px";
    document.getElementById("editor").style.marginLeft = "260px";
    document.getElementById("mySidenav").style.overflow = "scroll";
}
function closeNav() {
    document.getElementById("mySidenav").style.width = "0";
    document.getElementById("editor").style.marginLeft= "0";
    document.getElementById("mySidenav").style.overflow = "hidden";
}
function writeFile(){
    // Deal with funny  at work!
    var filename = window.location.pathname

    var fso, fileHandle;
    fso = new ActiveXObject("Scripting.FileSystemObject");
    fileHandle = fso.CreateTextFile(filename.replace(///,""), true);

    fileHandle.write("<!DOCTYPE html>");
    fileHandle.write("<HTML>");
    fileHandle.write(document.documentElement.innerHTML);
    fileHandle.write("</HTML>");
    fileHandle.close();
}
function getSelected() {
    if (window.getSelection) {
        return window.getSelection();
    } else if (document.getSelection) {
        return document.getSelection();
    } else {
        var selection = document.selection && document.selection.createRange();
        if (selection.text) {
            return selection.text;
        }
        return false;
    }
}
function insertText(text) {
    if (document.selection){
        var range = document.selection.createRange();
        range.pasteHTML(text);
    }
}
function followlink(){
    alert('followlink called');
}
function popupmenu(event) {
    alert('popupmenu called');
    // Need to know the event.target - but don't want jquery!
    // use window.screenLeft window.screenTop
}
function Shortcuts(e){
    if (!e) var e = window.event;

    var key = e.keyCode
    if (e.ctrlKey)  { key = "ctrl"+key;     }
    if (e.altKey)   { key = "alt"+key;      }
    if (e.shiftKey) { key = "shift"+key;    }

    // alert(key)

    // ESC
    if ( key == 27) {
        writeFile();
        window.close();
    }

    // TAB alone
    if ( key == 9) {
        preventDefault(e);
        document.execCommand("indent", true, null);
        return false;
    }

    // Shift+TAB
    if (key == "shift9") {
        preventDefault(e);
        document.execCommand("outdent", true, null);
        return false;
    }

    // Ctrl+>
    if ( key == "ctrl190") {
        document.execCommand("indent", true);
    }

    // Ctrl+<
    if ( key == "ctrl188") {
        document.execCommand("outdent", true);
    }

    // Ctrl+Up TODO: Fails with this key
    if ( key == "ctrl38") {
        document.execCommand("superscript", true);
    }

    // Ctrl+Down TODO: Fails with this key
    if ( key == "ctrl40") {
        document.execCommand("subscript", true);
    }

    // Ctrl++ - Built in zoom+
    // Ctrl+- - Built in zoom-

    // Ctrl+/ Try to wrap any selection
    if ( key == "ctrl191") {
        var sText = getSelected();
        var code =    "<code>" + sText +  "</code>"
        insertText(code);
    }

    // Ctrl+ Clear formatting
    if ( key == "ctrl220") {
        document.execCommand("removeFormat", true);
    }

    // Ctrl+A - Built in select all
    // Ctrl+B - Built in bold
    // Ctrl+C - Built in copy

    // Ctrl+D
    if ( key == "ctrl68") {
        document.execCommand("strikethrough", true);
    }

    // Ctrl+E - Editor
    if ( key == "ctrl69") {
        WshShell = new ActiveXObject("WScript.Shell");
        WshShell.Run("O:/MyProfile/editor/micro.bat " + window.location.pathname,1,true)
    }

    // Ctrl+F - Built in Find
    // Ctrl+G - Google
    if ( key == "ctrl71") {
        WshShell = new ActiveXObject("WScript.Shell");
        WshShell.run("http://www.google.com");
    }

    // Ctrl+H - Hyperlink
    if ( key == "ctrl72") {
        var sText = getSelected();
        var linkURL = prompt('Enter a URL:', 'http://');
        // This is to match the automated format when URL is pasted/typed
        var link =  '<A href="' + linkURL + '" target="_blank">' + sText + '</A>';
        insertText(link);
    }

    // Ctrl+I - Built in italic
    // Ctrl+J - Jump to next H1 - for slide presentations
    if ( key == "ctrl74") {

    }

    // Ctrl+K - Built in hyperlink 

    // Ctrl+L - Ordered list
    if ( key == "ctrl76") {
        document.execCommand("insertUnorderedList", true);
    }

    // Ctrl+M 
    if ( key == "ctrl77") {
        // Undo default action of CRLF
        return false;
    }

    // Ctrl+N - Numbered List
    if ( key == "ctrl78") {
        document.execCommand("insertOrderedList", true);
    }

    // Ctrl+O - Empty
    // Ctrl+P - Built in Print
    // Ctrl+Q - Empty

    // Ctrl+R - Revert
    if ( key == "ctrl82") {
        window.location.reload(false);
    }

    // Ctrl+S - Save
    if ( key == "ctrl83") {
        writeFile();
    }

    // Ctrl+T - Insert Table  - TODO: need some css or in line styles
    if ( key == "ctrl84") {
        document.execCommand("indent", true, null);
        var table =    "<table>"
        table = table +"<tr>"
        table = table +"  <th>Company</th>"
        table = table +"  <th>Contact</th>"
        table = table +"  <th>Country</th>"
        table = table +"</tr>"
        table = table +"<tr>"
        table = table +"  <td>Alfreds</td>"
        table = table +"  <td>Maria</td>"
        table = table +"  <td>Germany</td>"
        table = table +"</tr>"
        table = table +"<tr>"
        table = table +"  <td>Centro</td>"
        table = table +"  <td>Francisco</td>"
        table = table +"  <td>Mexico</td>"
        table = table +"</tr>"
        table = table +"</table>"
        insertText(table);
    }

    // Ctrl+U - Built in Underline
    // Ctrl+V - Built in Paste

    // Ctrl+W - Write and Close
    if ( key == "ctrl87") {
        writeFile();
        window.close();
    }

    // Ctrl+X - Built in Cut
    // Ctrl+Y - Built in Redo 
    // Ctrl+Z - Built in Undo

    // F1
    if ( key == 112) {
        toggleNav();
    }

    // Ctrl+0
    if ( key == "ctrl48") {
        document.execCommand("formatBlock", false, "<P>");
    }

    // Ctrl+1
    if ( key == "ctrl49") {
        document.execCommand("formatBlock", false, "<H1>");
    }

    // Ctrl+2
    if ( key == "ctrl50") {
        document.execCommand("formatBlock", false, "<H2>");
    }

    // Ctrl+3
    if ( key == "ctrl51") {
        document.execCommand("formatBlock", false, "<H3>");
    }

}

// Try to stop focus outside my div
for (i=0; i<document.all.length; i++){
    //ensure that all document elements except the content editable DIV are unselectable
    document.all(i).unselectable = "on";
}

// Change title
var filename = window.location.pathname
document.title = " ContentEditor - " + filename.replace(///,"")

// Focus on the editable section
window.location.hash = '#editor';

// Settings
document.execCommand("LiveResize", null, true);

//-->
</SCRIPT>
</HEAD>
<BODY tabIndex=-1>
<DIV tabIndex=-1 id=mySidenav class=sidenav style="OVERFLOW: scroll; WIDTH: 260px" unselectable="on"><U><B>Help</B></U> 
<TABLE>
<TBODY>
<TR>
<TD>ESC </TD>
<TD>Save + exit</TD></TR>
<TR>
<TD>TAB </TD>
<TD>Indent</TD></TR>
<TR>
<TD>Shift+TAB </TD>
<TD>Outdent</TD></TR>
<TR>
<TD>Ctrl+A </TD>
<TD>Select All</TD></TR>
<TR>
<TD>Ctrl+B </TD>
<TD>Bold</TD></TR>
<TR>
<TD>Ctrl+C </TD>
<TD>Copy</TD></TR>
<TR>
<TD>Ctrl+D </TD>
<TD>Strikeout</TD></TR>
<TR>
<TD>Ctrl+E </TD>
<TD>Edit page</TD></TR>
<TR>
<TD>Ctrl+F </TD>
<TD>Find</TD></TR>
<TR>
<TD>Ctrl+I </TD>
<TD>Italic</TD></TR>
<TR>
<TD>Ctrl+K </TD>
<TD>Hyperlink</TD></TR>
<TR>
<TD>Ctrl+L </TD>
<TD>Bullet list</TD></TR>
<TR>
<TD>Ctrl+N </TD>
<TD>Num list</TD></TR>
<TR>
<TD>Ctrl+P </TD>
<TD>Print</TD></TR>
<TR>
<TD>Ctrl+R </TD>
<TD>Revert</TD></TR>
<TR>
<TD>Ctrl+S </TD>
<TD>Save</TD></TR>
<TR>
<TD>Ctrl+T </TD>
<TD>Insert table</TD></TR>
<TR>
<TD>Ctrl+U </TD>
<TD>Underline</TD></TR>
<TR>
<TD>Ctrl+V </TD>
<TD>Paste</TD></TR>
<TR>
<TD>Ctrl+W </TD>
<TD>Save + exit</TD></TR>
<TR>
<TD>Ctrl+X </TD>
<TD>Cut</TD></TR>
<TR>
<TD>Ctrl+Y </TD>
<TD>Redo</TD></TR>
<TR>
<TD>Ctrl+Z </TD>
<TD>Undo</TD></TR>
<TR>
<TD>Ctrl+/ </TD>
<TD>Code</TD></TR>
<TR>
<TD>Ctrl+< </TD>
<TD>Superscript</TD></TR>
<TR>
<TD>Ctrl+> </TD>
<TD>Subscript</TD></TR>
<TR>
<TD>Ctrl+\ </TD>
<TD>Unformat</TD></TR>
<TR>
<TD>Ctrl+Del </TD>
<TD>Del EOW</TD></TR>
<TR>
<TD>Ctrl+Bksp </TD>
<TD>Del BOW</TD></TR>
<TR>
<TD>Ctrl+n </TD>
<TD>Heading 1-3</TD></TR>
<TR>
<TD>F1 </TD>
<TD>Toggle Help</TD></TR></TBODY></TABLE>
<P></P></DIV>
<DIV spellcheck=true tabIndex=-1 onkeyup=Shortcuts() id=editor contentEditable=true onkeydown="return (event.keyCode!=9);" style="MARGIN-LEFT: 260px" oncontextmenu=popupmenu()></DIV>
<SCRIPT type=text/javascript>
<!--

//-->
</SCRIPT>
</BODY></HTML>

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật