• Tags
  • Documentation
  • Order
  • Register
  • Login
Duet3D Logo Duet3D
  • Tags
  • Documentation
  • Order
  • Register
  • Login

Gcode documentation change

Scheduled Pinned Locked Moved
General Discussion
14
54
3.5k
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • undefined
    sinned6915 @droftarts
    last edited by sinned6915 10 Mar 2021, 04:36 3 Oct 2021, 04:34

    @droftarts said in Gcode documentation change:

    1. To maintain existing links (yes, they should all still work), the headings have to be shown in the new page, as they appeared in the old page, without a link in them. This lead to the layout with the link to the individual page and description on another line.

    Nope, not universally true. There are MANY that are formatted like this one-

    https://duet3d.dozuki.com/Wiki/Gcode#Section_M558_in_RepRapFirmware_Num_3

    this one works, but not the above one

    https://duet3d.dozuki.com/Wiki/Gcode#Section_M558_Set_Z_probe_type

    1 Reply Last reply Reply Quote 0
    • undefined
      theKM
      last edited by 8 Oct 2021, 16:26

      This post is deleted!
      1 Reply Last reply Reply Quote 0
      • undefined
        theKM
        last edited by theKM 10 Oct 2021, 03:42 8 Oct 2021, 18:05

        For what it's worth...

        A script that puts a link at the top of the left hand menu, that if clicked, will re-assemble the single mega-page from all the separate pages.

        It is written in a way that if included as a script tag in the wiki's root html template, it will only wake up on the correct page, and simply add a link to the menu. User can click it to assemble the mega page, or ignore it all together to leave it as-is. I'd recommend putting it in a file somewhere and referring to it so the browser can cache it so there's no download impact each page load.

        For anyone that wants to run it themselves, just go to the gcode page, open JS console ( ctrl + shift + J for chrome, ctrl + shift + i for firefox ) , paste it in, press enter...

        // ==UserScript==
        // @name     GCode Wiki script
        // @version  1
        // @include     https://duet3d.dozuki.com/Wiki/Gcode*
        // ==/UserScript==
        
        /** for processing injected menu clicks, gets changed
         * to proper implementation when needed
         */
        let processMegaPage = () => {};
        let crossLinkDoc = () => {};
        let setupGcodeBrowser = () => {};
        
        let codeMap = {};
        let crossLinked = false;
        
        // for identifying gcode references
        let codeRx = /[GM]+[0-9]+(.[0-9])?/g;
        
        /** Helper function with finding things, so I don't need a framework
         */
        let docE = (f, inp) => {
            if (Array.isArray(inp)) {
                return (inp.map(i => docE(f, i))).flat();
            }
            let seek = document[f](inp);
            if (!seek || seek instanceof HTMLElement) return seek;
            let tmp = [];
            for (let t of seek) tmp.push(t);
            return tmp;
        };
        
        let content = document.getElementById('content');
        let isInContent = function (e) {
            if (!e) return false;
            if (!e.parentElement || e.parentElement === document.body) return false;
            if (e.parentElement === content) return true;
            return isInContent(e.parentElement);
        }
        
        /** Handler to take input and process links in gcode browser
         */
        let ref = null;
        let paster = () => {
            if (ref) clearTimeout(ref);
            ref = setTimeout(() => {
                let linkStyle = 'all:unset;cursor:pointer;text-decoration:underline;color:blue;';
                let v = docE('getElementById', 'gcode-paste-input').value;
                v = v.replace(codeRx, (s) => {
                    if (codeMap[s]) return '<a href="#' + codeMap[s] + '" style="' + linkStyle + '">' + s + '</a>';
                    return s;
                });
        
                docE('getElementById', 'gcode-paste').innerHTML = '<pre style="text-align:left">' + v + '</pre>';
            }, 500);
        };
        
        
        // check to see if this page is the one we want, otherwise do nothing
        let loc = null;
        let pos = null;
        let hash = null;
        let qstring = null;
        
        const evalLocation = () => {
            loc = document.location + '';
            pos = loc.indexOf('#');
            hash = null;
            if (pos > -1) {
                hash = loc.substring(pos);
                loc = loc.substring(0, pos);
            }
        
            qstring = '';
            pos = loc.indexOf('?');
            if (pos > -1) {
                qstring = loc.substring(pos + 1);
                loc = loc.substring(0, pos);
            }
        };
        
        const moveToHash = () => {
            if (hash) {
                document.location = hash;
            }
        };
        
        // current location details...
        evalLocation();
        
        if (loc.endsWith('/Wiki/Gcode')) {
            // current page is the gcode wiki...
        
            // find the menu
            let topTitle = docE('getElementsByClassName', 'toc-title')[0];
        
            // add the link to run the mega-page import...
            let squirt = document.createElement('div');
            squirt.innerHTML = '<a id="create-mega-page-link" href="javascript:;">Create Mega-Page</a>';
        
            topTitle.parentElement.insertBefore(squirt, topTitle.nextSibling);
        
            setTimeout(() => {
                // take a beat, wire the event clicker (greasemonkey complication)...
                let tmp = null;
                (tmp = document.getElementById('create-mega-page-link')) ? tmp.addEventListener('click', () => processMegaPage()) : null;
            }, 50);
        
            // function handler for the click...
            processMegaPage = () => {
                squirt.innerHTML = '';
        
                // find all the specific links
                let glinks = docE('getElementsByTagName', 'a').filter(a => {
                    let t = a.innerText;
                    let h = '' + a.href;
                    h = h.substring(h.indexOf('/', 10));
                    return (t.match(codeRx) && !h.startsWith('/Wiki/Gcode') && (h.startsWith('/Wiki/M') || h.startsWith('/Wiki/G')));
                });
        
                // a function that represents the work for a page download
                let processor = a => {
        
                    return new Promise((resolve, reject) => {
        
                        // download...
                        fetch(a.href).then(async response => {
        
                            // the document dext...
                            let t = await response.text();
        
                            // pull out the good stuff...
                            let from = t.indexOf('<div id="Wiki_Details">');
                            let to = t.lastIndexOf('<div class="clearer">', t.lastIndexOf('<div itemprop="author"'));
                            t = t.substring(from, to);
        
                            // dont need this link in there now...
                            t = t.replace('<p>Back to the <a href="/Wiki/Gcode">Gcode Dictionary</a></p>', '');
        
                            // make a div for it
                            const d = document.createElement('div');
                            d.innerHTML = t;
        
                            // replace the link tag's parent <p>
                            let p = a.parentElement;
                            p.parentNode.replaceChild(d, p);
        
                            // end of task
                            resolve();
        
                        }).catch(reject);
                    });
                };
        
                let count = 0;
        
                // a function that represents a processing thread so we can start N of them
                let runner = async () => {
                    while (glinks.length > 0) {
                        count++;
                        if (count % 25 === 0) console.log(count);
                        let x = glinks.shift();
                        try {
                            await processor(x);
                        } catch (e) {
                            console.log(e);
                        }
                    }
                };
        
                // start the runners...
                let runnerCount = 1;
                (async () => {
                    let time = new Date().getTime();
        
                    console.log('links to process: ' + glinks.length);
        
                    let runners = [];
                    for (let i = 0; i < runnerCount; i++) runners.push(runner());
        
                    await Promise.all(runners);
        
                    console.log('DONE!!! (' + ((new Date().getTime() - time) / 1000) + ' seconds)');
        
                    moveToHash();
        
                    squirt.innerHTML = '<a id="cross-linker-link" href="javascript:;">Cross-link gcodes</a><br>'
                        + '<a id="setup-gcode-browser-link" href="javascript:;">Setup GCode Browser</a><br><br>';
        
                    setTimeout(() => {
                        // take a beat, wire the event clicker (greasemonkey complication)...
                        let tmp = null;
                        (tmp = document.getElementById('cross-linker-link')) ? tmp.addEventListener('click', () => crossLinkDoc()) : null;
                        (tmp = document.getElementById('setup-gcode-browser-link')) ? tmp.addEventListener('click', () => setupGcodeBrowser()) : null;
                    }, 50);
                })();
        
                crossLinkDoc = () => {
                    if (crossLinked) return;
                    crossLinked = true;
        
                    let link = document.getElementById('cross-linker-link');
                    link.parentElement.removeChild(link);
        
                    /** Parse the references out of the document
                     */
                    docE('getElementsByClassName', 'header').forEach(sect => {
                        let s = sect.id + '';
                        s.replace(codeRx, sx => {
                            sx = sx.replace('_', '.');
                            if (!codeMap[sx]) {
                                codeMap[sx] = s;
                            }
                        });
                    });
        
                    /** Cross-link gcode references through the document
                     */
                    docE('getElementsByTagName', ['p', 'li', 'pre', 'strong']).forEach(tag => {
                        if (!tag) return;
                        if (!isInContent(tag)) return;
                        let linkStyle = 'all:unset;cursor:pointer;text-decoration:underline;color:blue;';
                        let h = ('' + tag.innerHTML).trim();
                      	if (h.startsWith('<div/')) return;
                        tag.innerHTML = h.replace(/(?<!_)([GM]+[0-9]+(.[0-9])?)/g, (s) => {
                            if (codeMap[s]) return '<a href="#' + codeMap[s] + '" style="' + linkStyle + '" class="crosslink">' + s + '</a>';
                            return s;
                        });
                    });
        
                    evalLocation();
                    moveToHash();
                };
        
                setupGcodeBrowser = () => {
                    crossLinkDoc();
        
                    if (squirt) {
                        squirt.parentElement.removeChild(squirt);
                        squirt = null;
                    }
        
                    /** Strip the main wrapper element of styling
                     */
                    let wrap = docE('getElementById', 'page');
                    wrap.className = '';
                    wrap.id = 'gnavPage';
        
                    /** Remove styling of sidebar nested element
                     */
                    docE('getElementById', 'sidebar-wiki-toc').className = '';
                    docE('getElementById', 'sidebar-wiki-toc').id = 'gnavSidebar';
        
                    /** Strip the sidebar
                     */
                    let sb = null;
                    sb = docE('getElementById', 'page-sidebar');
                    sb.innerHTML = '';
                    sb.id = 'gnavSidebar';
        
                    /** Strip the main area
                     */
                    let main = docE('getElementById', 'main');
                    main.id = 'gnavMain';
                    docE('getElementsByClassName', 'articleContainer')[0].className = '';
        
                    /** Clear our other elements not needed
                     */
                    let mb = docE('getElementById', 'mainBody');
                    for (let kid of mb.children) {
                        if (kid.id !== 'contentFloat') mb.removeChild(kid);
                    }
        
                    let bg = docE('getElementById', 'background');
                    for (let kid of bg.children) {
                        if (kid.id === 'gnavPage') break;
                        else bg.removeChild(kid);
                    }
        
                    for (let kid of document.body.children) {
                        if (kid.id !== 'background') document.body.removeChild(kid);
                    }
        
                    docE('getElementById', 'content').id = 'offContent';
        
                    /** Apply new styles to the wrapper, sidebar and main areas
                     */
                    wrap.setAttribute('style', 'display:flex;gap:1em;');
                    sb.setAttribute('style', 'flex: 1 1 45%; height: 100vh;');
                    main.setAttribute('style', 'flex: 1 1 50%; height: 100vh');
        
                    /** Input field to paste the gcode
                     */
                    sb.innerHTML = `
        <div style="width: 45vw; height: 100vh; position: fixed;overflow: scroll;">
            <textarea id="gcode-paste-input"></textArea>
          <hr />
          <pre id="gcode-paste" style="text-align: left"><center>( paste gcode above )</center></pre>
        </div>`;
        
                    setTimeout(() => {
                        // take a beat, wire the event clicker (greasemonkey complication)...
                        let tmp = null;
                        (tmp = document.getElementById('gcode-paste-input')) ? tmp.addEventListener('keyup', () => paster()) : null;
                    }, 50);
                };
            };
        }
        
        // auto-trigger...
        if (qstring === 'inflateContent') {
            processMegaPage();
        }
        
        undefined 1 Reply Last reply 8 Oct 2021, 18:23 Reply Quote 1
        • undefined
          zapta @theKM
          last edited by 8 Oct 2021, 18:23

          Works for me! (Using chrome/mac so had to open the console in a different way).

          Can we have the official documentation page running this script automatically when opened? Loading time was very fast.

          undefined undefined 3 Replies Last reply 8 Oct 2021, 18:25 Reply Quote 0
          • undefined
            zapta @zapta
            last edited by 8 Oct 2021, 18:25

            ... also, is it possible to have links to this overall page? E.g. a link for G1 that will take you to the G1 in that page?

            1 Reply Last reply Reply Quote 0
            • undefined
              theKM @zapta
              last edited by theKM 10 Sept 2021, 00:51 9 Oct 2021, 00:47

              @zapta said in Gcode documentation change:

              Works for me! (Using chrome/mac so had to open the console in a different way).

              woot

              Can we have the official documentation page running this script automatically when opened? Loading time was very fast.

              way above my pay grade to include it, but it is written in a way that has it do nothing if the user's not on the right page.

              also, is it possible to have links to this overall page? E.g. a link for G1 that will take you to the G1 in that page?

              The page is inflated after loading, the browser doesn't know how to cope with sub-linking into a page that's altered after the main document as loaded, so some things are simply off the table.

              That said, try the script I put here... https://forum.duet3d.com/topic/25459/mega-gcode-docco-page-gcode-file-navigator

              ...specifically the "cross linking" mentioned, and see if that's what you're after.

              undefined 1 Reply Last reply 9 Oct 2021, 00:50 Reply Quote 0
              • undefined
                zapta @theKM
                last edited by zapta 10 Sept 2021, 00:51 9 Oct 2021, 00:50

                @thekm said in Gcode documentation change:

                The page is inflated after loading, the browser doesn't know how to cope with sub-linking into a page that's altered after the main document as loaded

                If the target section link is represented in the URL, the loader could potentially parse it after loading the parts and jump there, or something like that, but it's also above my pay grade. 😉

                undefined 1 Reply Last reply 9 Oct 2021, 02:10 Reply Quote 0
                • undefined
                  theKM @zapta
                  last edited by theKM 10 Sept 2021, 16:21 9 Oct 2021, 02:10

                  @zapta said in Gcode documentation change:

                  If the target section link is represented in the URL, the loader could potentially parse it after loading the parts and jump there, or something like that, but it's also above my pay grade. 😉

                  See, then you went and made me feel bad 🙂

                  ...script above is updated to reevaluate the hash link to re-bump into the correct location after the content injection.

                  It is also looking for "inflate content" in the URL query string, if it's there it will automatically inflate the content without needing to click.

                  1 Reply Last reply Reply Quote 0
                  • undefined
                    theKM @zapta
                    last edited by theKM 10 Oct 2021, 03:27 9 Oct 2021, 19:22

                    @zapta said in Gcode documentation change:

                    Can we have the official documentation page running this script automatically when opened? Loading time was very fast.

                    I updated and tested the script in greasemonkey (firefox) / tampermonkey (chrome) plugins... so if you want it to work automagically, that's one way to do it without the wiki admins applying the script.

                    With the plugin, this link will automatically make the large page without needing to click:
                    https://duet3d.dozuki.com/Wiki/Gcode?inflateContent

                    And if the 'inflateContent' link is too much of a hassle, you can always have it build the page by changing the last part in the script from ...

                    // auto-trigger...
                    
                    if (qstring === 'inflateContent') {
                        processMegaPage();
                    }
                    

                    ...to...

                    processMegaPage();
                    
                    royal32undefined 1 Reply Last reply 4 Nov 2021, 01:31 Reply Quote 1
                    • royal32undefined
                      royal32 @theKM
                      last edited by 4 Nov 2021, 01:31

                      @thekm Your script works beautifully and I wanted you to know how much your work is appreciated.
                      My workflow will probably be to run this whenever the dictionary is updated, and save the page locally for regular reference, since it's hammering the site for 45 seconds straight to load all of the content...
                      The crosslinking and gcode browser features are really great too, thanks for that. This is what the gcode dictionary should be.

                      Seth

                      4x Railcore 300ZL in various states of completion

                      1 Reply Last reply Reply Quote 0
                      • First post
                        Last post
                      Unless otherwise noted, all forum content is licensed under CC-BY-SA