npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@prokomssp/edoc-viewer

v10.204.0

Published

Client for viewing and posting forms.

Readme

viewer.js

Pakken inneholder koden for vise skjema.

Installasjon

Legg inn viewer.min.js nederst på HTML siden før body slutt tag.

    <body>
        ...
        <script src="viewer.min.js"></script>
    </body>

Dersom du ønsker å benytte samme stilsett som på skjema.no, kan du legge inn styles.css i head taggen.

    <head>
        ...
        <link rel='stylesheet' href='styles.css' type='text/css'  />
    </head>

Opprett et tomt element der skjemaet skal rendres. Du bestemmer elementets id og oppgir denne i kall til viewer.init() (beskrevet nedenfor).

<body>
    <div id="skjema"></div>
</body>

For å vise skjema, kalles .init() og deretter .form(). Koden nedenfor viser strukturen for oppsett av viewer.js for visning av et skjema.

document.addEventListener("DOMContentLoaded", function(){
    viewer
        .init({
            apiUrl: "<api url>",
            customerId: "<customer id>",
        })
        .form({
            divId: "<id til div der skjema skal rendres>",
            formId: "<id til skjema som skal vises>"
        });
});

API

init()

.init() initialiserer viewer.js og må være det første kallet til viewer.js.

viewer.init({...})

init object:

viewer.init({
    apiUrl : "<api url>",
    customerId: "<customer id>",
    hide : {
        title: true, 
        buttons: true, 
    }
})

|Egenskap|Eksempel|Obligatorisk|Beskrivelse| |--------|--------|------------|-----------| |apiUrl |https://api.skjema.no|Ja|Url til API-et| |customerId|9998|Ja|Kunde-id| |hide.title|true|Nei|Oppgi true dersom det er ønskelig å skjule tittel| |hide.buttons|true|Nei|Oppgi true dersom det er ønskelig å skjule knappene for "avbryt", "lagre" og til "kontroll"|

form()

.form() forteller viewer.js hvilket skjema som skal vises. .init() må kalles før .form().

viewer
    .init({...})
    .form({...})

form object:

viewer
    .init({...})
    .form({
        divId: "<id til div>",
        formId: "<id til skjema som skal vises eller function() som returnerer denne>",
        refId: "<id til mellomlagret utkast som skal vises eller function() som returnerer denne>",
        previewId: "<id til forhåndsvisning eller function() som returnerer denne>",
        onAborting: function(proceed) {},
        onAborted: function() {},
        onSaving: function(proceed) {},
        onSaved: function() {},
        onSubmitted: function() {}        
    });

divId er obligatorisk og må oppgis.

Angi skjema

viewer.js trenger én av følgende for å vise et skjema: formId, refId eller previewId.

  • formId benyttes når et nytt, tomt skjema skal vises. For å se hvilke formId-er som er tilgjengelig, kan du gjøre et kall til viewer.getForms() (beskrevet nedenfor).
  • refId benyttes når et mellomlagret utkast skal gjenopptas. For å se hvilke refId-er som er tilgjengelig, kan du gjøre et kall til viewer.getCases() (beskrevet nedenfor).
  • previewId vil bli sendt med når edoc-designer åpner URL for forhåndsvisning av skjema.

Det er vanlig at formId, refId eller previewId sendes med som querystring-parametre til HTML-siden. viewer.js har en utility-metode for uthenting av parameter fra querystring: viewer.util.getQuery(paramName). Eksempelet nedenfor henter parametre med navn "formId", "refId" og "previewId" fra querystring. Dersom parameteren ikke finnes, returnerer funksjonen null.

viewer
    .init({...})
    .form({
        ...
        formId: function() {
            return viewer.util.getQuery("formId");
        },
        refId: function() {
            return viewer.util.getQuery("refId");
        },        
        previewId: function() {
            return viewer.util.getQuery("previewId");
        }					
    });

Verdien for formId, refId eller previewId kan alternativt "hardkodes" slik:

viewer
    .init({...})
    .form({
        ...
        formId: "701660",
    });

Merk at viewer.js vil hive en exception dersom mer enn én av formId, refId eller previewId er satt.

Event-handling

Når et skjema er startet, kan utfyller avbryte, lagre eller sende inn skjemaet. viewer.js tilbyr event-handlere som gjør det mulig å hooke seg på disse hendelsene.

Koden nedenfor viser et eksempel på hvordan disse event-handlerne kan implementeres.

viewer
    .init({...})
    .form({
        ...
        onAborting: function(proceed) {
            proceed();
        },
        onAborted: function() {
            window.location = "index.html";
        },
        onSaved: function(saveInfo) {
            if(saveInfo.isAuthenticated) {
                window.location = "cases.html";
            } else {
                window.location = "saveReceipt.html?refId=" + saveInfo.externalRefId;
            }
        },
        onSubmitted: function(receipt) {
            window.location = "submitReceipt.html?refId=" + receipt.refId;
        }
    });
onAborting

onAborting blir kalt når utfyller trykker avbryt og før selve avbrytelsen blir utført. Det er valgfritt å registrere en eventhandler til dette eventet. Du kan bruke eventet til å vise en "vil du virkelig avbryte"-dialog. Dersom utfyller bekrefter avbryting, kaller du proceed() eller proceed(true). Dersom utfyller ikke ønsker å avbryte, kaller du proceed(false).

Eksempelet nedenfor tar utgangspunkt i at du har laget en funksjon showAbortDialog() som viser et bekreftelses-vindu. Avhengig av om utfyller klikker ja eller nei, kalles proceed() med true eller false.

viewer
    .init({...})
    .form({
        ...
        onAborting: function(proceed) {
            showAbortConfirmationDialog() //må implementeres av deg
                .on("click", "#yes",
                    function() {
                        proceed(true);
                    })
                .on("click", "#no",
                    function() {
                        proceed(false);
                    });            
        },        
    });
onAborted

onAborted blir kalt etter at avbrytelsen er fullført. Her har du eksempelvis mulighet for å laste en ny URL i nettleseren.

viewer
    .init({...})
    .form({
        ...
        onAborted: function() {
            window.location = "index.html";
        },        
    });
onSaved

onSaved blir kalt etter at en mellomlagrring er fullført. Her har du eksempelvis mulighet for å laste en ny URL i nettleseren.

viewer
    .init({...})
    .form({
        ...
        onSaved: function() {
            window.location = "cases.html";
        }
    });
onSubmitted

onSubmitted blir kalt etter at en innsending er fullført. Her har du eksempelvis mulighet for å laste en ny URL i nettleseren. Funksjonen får et receipt-objekt. Dette objektet inneholder referanse id for innsendingen i receipt.refId. Dette kan du eksempelvis bruke for å laste en side som viser info om innsendelsen. Se avsnittet for getCaseInfo() nedenfor.

Eksempelet nedenfor laster en ny side med referanse id i querystring.

viewer
    .init({...})
    .form({
        ...
        onSubmitted: function(receipt) {
            window.location = "submitReceipt.html?refId=" + receipt.refId;
        }
    });

getCaseInfo() - uthenting av info for kvittering

Etter innsending av skjema er det vanlig å vise en side som viser skjemaets navn, tidspunkt for innsendelse og referanse id. Denne informasjonen hentes via kall til viewer.getCaseInfo(refId). refId får du fra onSubmitted()-eventet når skjemaet sendes inn.

Eksempelet nedenfor viser hvordan referanse id, skjemaets navn og tidspunkt for innsendelse hentes.

<script>
    document.addEventListener("DOMContentLoaded", () => {
        const refId = viewer.util.getQuery("refId");

        viewer
            .init(...)
            .getCaseInfo(refId)
                .then(info => {
                    document.getElementById("receipt").innerHTML = 
                    `
                        refId: ${info.refId} <br/>
                        name: ${info.name} <br/>
                        updatedOn: ${info.updatedOn} <br/>
                    `;
                }).catch((error) => {
                    console.log(error);
                });
        });
</script>

<div id="receipt"></div>

session()

viewer.js benytter HTML 5 sessionStorage for lagring av skjemadata under utfylling. .session() gjør det mulig å fortelle viewer.js etter hvor lang inaktivitet disse skal fjernes fra sessionStorage. .init() må kalles før .session().

viewer
    .init({...})
    .session({...})

session object:

Eksempelet nedenfor setter opp 20 minutter som inaktiv periode, med varsling 5 minutter før disse 20 minuttene nåes. onIdleTimeoutWarning() blir da kalt et gitt antall minutter før sesjonen utgår. Eventet gjør det mulig å vise en dialog der bruker kan forlenge eller avslutte sesjonen sin. Kall extendSession() dersom sesjonen skal forlenges, eller endSession() dersom sesjonen skal avsluttes. Det er valgfritt å registrere en handler på onIdleTimeoutWarning. Dersom 20 minutter med inaktivitet passerer, eller utfyller i onIdleTimeoutWarning velger å avslutte sesjonen, blir onIdleTimeout kalt.

viewer
    .init({...})
    .session({
        idleTimeoutMinutes: 20,
        warningTimeoutMinutes: 5,
        onIdleTimeoutWarning: function(extendSession, endSession, sessionOptions) {
            showTimeoutWarning(sessionOptions.warningTimeoutMinutes) //må implementeres av deg
                .on("click", "#yes", function () { 
                    extendSession();
                })
                .on("click", "#no", function () {
                    endSession();
                });
        },
        onIdleTimeout: function() {
            document.location = "idleTimeout.html";
        }
    })

sessionOptions.warningTimeoutMinutes viser hvor mange minutter det er igjen til sesjonen avsluttes på det tidspunktet da funksjonen ble kalt. Dersom du skal lage en nedtellingsfunksjon, kan du ta utgangspunkt i denne verdien.

|Egenskap|Eksempel|Obligatorisk|Beskrivelse| |--------|--------|------------|-----------| |idleTimeoutMinutes |60|Nei, default er 20|Antall minutter med inaktivitet før skjemadata fjernes.| |warningTimeoutMinutes|5|Nei|Utfyller blir gitt en advarsel om at sesjonen vil tømmes dette antall minutter i forveien.|

Brukerhåndtering

Dersom utfyller ikke er pålogget, men gjør en handling i viewer.js som krever pålogging, vil edoc-api sende brukeren til en identity-provider for pålogging. Handlinger i viewer.js som krever pålogging er mellomlagring av utkast og gjenopptaking av utkast, samt oppstart av skjema der det er satt krav til sikkerhetsnivå.

Eksempelet nedenfor viser hvordan du kan få tak i informasjon om bruker som blir logget på av viewer.js:

viewer
    .init({...})
    .session({
        ...
        onAuthenticated: (getUser) => {
            getUser() //if you need to get the user's id, invoke getUser.
                .then((user) => {
                    alert(`You are logged in as ${user.id}!`); //do something with user.id
                });
        }        
    })

Dersom du eksplisitt ønsker å logge en bruker inn via edoc-api, kan du kalle viewer.logIn(). Du vil motta eventet som vist ovenfor etter at pålogging er fullført.

viewer.logIn();

For å logge bruker ut fra edoc-api, kaller du viewer.logOut().

viewer.logOut()
    .then(() => {
        alert("Your session has ended.");
        window.location = "index.html";            
    });

getForms()

viewer.getForms() returnerer tilgjengelige skjema for kunden. Eksempelet nedenfor viser hvordan skjema kan hentes og listes ut på en HTML-side.

<!DOCTYPE html>
<html>
<body>
    <script>
        document.addEventListener("DOMContentLoaded", () => {
            setLoaderVisibility(true);

            viewer
                .init(...)
                .getForms()
                    .then(forms => {
                        const createFormLink = (form) => {
                            var fragment = document.createDocumentFragment();
                            const formLink = document.createElement("a");
                            formLink.setAttribute("href", `form.html?formId=${form.formId}`);
                            formLink.text = `${form.name}`;

                            fragment.appendChild(formLink);
                            const br = document.createElement("br");
                            fragment.appendChild(br);
                            return fragment;
                        }

                        const formsElement = document.getElementById("forms");

                        if(forms) {
                            forms.forEach(function(form) {
                                formsElement.appendChild(createFormLink(form));
                            });
                        } else {
                            formsElement.appendChild(document.createTextNode("No forms"));
                        }
                    });
        });
    </script>    

    <div id="forms"></div>

    <script src="viewer.min.js"></script>
</body>
</html>

getCases() og deleteCase()

viewer.getCases() returnerer mellomlagrede utkast for en utfyller. Eksempelet nedenfor viser hvordan utkast kan hentes og listes ut på en HTML-side. Eksempelet viser også hvordan utkastene kan slettes via viewer.deleteCase().

<!DOCTYPE html>
<html>
<body>
    <script>
        document.addEventListener("DOMContentLoaded", () => {
            viewer.init(...);

            const renderCases = () => 
                viewer.getCases().then(cases => {
                    document.getElementById("content").style.display = "block";

                    const createCaseLink = (c, isSaved) => {
                        var fragment = document.createElement("div");
                        fragment.setAttribute("id", c.refId);

                        const caseLink = document.createElement("a");
                        if(isSaved) {
                            caseLink.setAttribute("href", `form.html?refId=${c.refId}`);
                        }
                        caseLink.text = `${c.name}`;
                        fragment.appendChild(caseLink);

                        const deleteLink = document.createElement("a");
                        deleteLink.setAttribute("href", "#");
                        deleteLink.text = " delete";
                        deleteLink.onclick = function(event) {
                            viewer.deleteCase(c.refId)
                            .then(() => {
                                document.getElementById(c.refId).remove();
                            }).catch((error) => {
                                alert(JSON.stringify(error));
                            });
                        };
                        fragment.appendChild(deleteLink);

                        const br = document.createElement("br");
                        fragment.appendChild(br);

                        return fragment;
                    }

                    const savedCasesElement = document.getElementById("savedCases");
                    savedCasesElement.innerHTML = "";

                    if(cases.saved) {
                        cases.saved.forEach(function(c) {
                            savedCasesElement.appendChild(createCaseLink(c, true));
                        });
                    } else {
                        savedCasesElement.appendChild(document.createTextNode("No saved cases"));
                    }

                    const submittedCasesElement = document.getElementById("submittedCases");
                    submittedCasesElement.innerHTML = "";

                    if(cases.submitted) {
                        cases.submitted.forEach( (c) => {
                            submittedCasesElement.appendChild(createCaseLink(c, false));
                        });
                    } else {
                        submittedCasesElement.appendChild(document.createTextNode("No submitted cases"));
                    }
                });

            renderCases();
        });
    </script>    

    <div id="content">
        <h2>Saved cases</h1>
        <div id="savedCases"></div>

        <h2>Submitted cases</h1>
        <div id="submittedCases"></div>
    </div>

    <script src="viewer.min.js"></script>
</body>
</html>

getPdf()

PDF for innsendte saker kan lastes ned via viewer.getPdf(refId). PDF-en genereres on the fly av edoc-api. Edoc-api sjekker at innlogget bruker har rettighet på saken det blir forsøkt lastet ned PDF for

Progresjonsvisning og feilhåndtering

Alle viewer metoder som gjør et kall til edoc-api returnerer et Promise-objekt. Fra det tidspunktet metoden blir kalt, og til operasjonen er fullført, kan det være lurt å vise en progresjons-indikator. Eksempelet nedenfor viser hvordan det kan gjøres.

<!DOCTYPE html>
<html>
<body>
    <script>
        function setLoaderVisibility (isVisible) {
            const loader = document.getElementById("loader");

            if(loader) {
                loader.style.display = isVisible ? "block" : "none";
            }
        };

        document.addEventListener("DOMContentLoaded", () => {
            setLoaderVisibility(true);
            
            viewer
                .init(...)
                .form(...)
                .then(() => {
                    setLoaderVisibility(false);
                }).catch((error) => {
                    alert(error);
                }).finally(() => {
                    setLoaderVisibility(false);
                });
        });
    </script>

    <style>
        .loader {
            border: 16px solid #f3f3f3; /* Light grey */
            border-top: 16px solid #3498db; /* Blue */
            border-radius: 50%;
            width: 120px;
            height: 120px;
            animation: spin 2s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
    </style>

    <div id="viewer"></div>
    <div id="loader" class="loader"></div>

    <script src="viewer.min.js"></script>
</body>
</html>

Innhold

Viewer

  • Babel Polyfill
  • Handlebars
  • jQuery
  • jQuery UI
  • DropZone
  • i18next
  • mathjs
  • moment.js
  • opn
  • urijs

Styles

  • Bootstrap 3.3.7
  • Budicons