Showing preview only (6,660K chars total). Download the full file or copy to clipboard to get everything.
Repository: GetPublii/Publii
Branch: master
Commit: 1ea7e78bd4ec
Files: 777
Total size: 20.8 MB
Directory structure:
gitextract__icctd57/
├── .editorconfig
├── .github/
│ ├── DISCUSSION_TEMPLATE/
│ │ └── bug-report.yml
│ ├── FUNDING.yml
│ └── ISSUE_TEMPLATE/
│ ├── bug.yml
│ ├── config.yml
│ └── feature.yml
├── .gitignore
├── .nvmrc
├── LICENSE
├── README.md
├── app/
│ ├── back-end/
│ │ ├── app-preload.js
│ │ ├── app.js
│ │ ├── author.js
│ │ ├── authors.js
│ │ ├── builddata.json
│ │ ├── events/
│ │ │ ├── _modules.js
│ │ │ ├── app.js
│ │ │ ├── author.js
│ │ │ ├── authors.js
│ │ │ ├── backup.js
│ │ │ ├── content.js
│ │ │ ├── credits.js
│ │ │ ├── deploy.js
│ │ │ ├── file-manager.js
│ │ │ ├── image-uploader.js
│ │ │ ├── import.js
│ │ │ ├── menu.js
│ │ │ ├── notifications.js
│ │ │ ├── page.js
│ │ │ ├── plugin.js
│ │ │ ├── plugins-api.js
│ │ │ ├── post.js
│ │ │ ├── preview.js
│ │ │ ├── site.js
│ │ │ ├── sync.js
│ │ │ ├── tag.js
│ │ │ └── tags.js
│ │ ├── helpers/
│ │ │ ├── app-files.js
│ │ │ ├── avatar.js
│ │ │ ├── context-menu-builder.js
│ │ │ ├── db.utils.js
│ │ │ ├── file.js
│ │ │ ├── image.helper.js
│ │ │ ├── slug.js
│ │ │ ├── specs/
│ │ │ │ ├── avatar.spec.js
│ │ │ │ └── slug.spec.js
│ │ │ ├── updates.helper.js
│ │ │ ├── utils.js
│ │ │ └── validators/
│ │ │ ├── language-config.js
│ │ │ └── plugin-config.js
│ │ ├── image.js
│ │ ├── languages.js
│ │ ├── migrators/
│ │ │ └── site-config.js
│ │ ├── model.js
│ │ ├── modules/
│ │ │ ├── backup/
│ │ │ │ ├── backup.js
│ │ │ │ └── create-from-backup.js
│ │ │ ├── custom-changes/
│ │ │ │ └── ftp/
│ │ │ │ ├── LICENSE
│ │ │ │ ├── README.md
│ │ │ │ ├── TODO
│ │ │ │ ├── lib/
│ │ │ │ │ ├── connection.js
│ │ │ │ │ └── parser.js
│ │ │ │ └── package.json
│ │ │ ├── deploy/
│ │ │ │ ├── deployment.js
│ │ │ │ ├── ftp-alt.js
│ │ │ │ ├── ftp.js
│ │ │ │ ├── git.js
│ │ │ │ ├── github-pages.js
│ │ │ │ ├── gitlab-pages.js
│ │ │ │ ├── google-cloud.js
│ │ │ │ ├── libraries/
│ │ │ │ │ └── netlify-api.js
│ │ │ │ ├── manual.js
│ │ │ │ ├── netlify.js
│ │ │ │ ├── s3.js
│ │ │ │ └── sftp.js
│ │ │ ├── import/
│ │ │ │ ├── automatic-paragraphs.js
│ │ │ │ ├── import.js
│ │ │ │ └── wxr-parser.js
│ │ │ ├── plugins/
│ │ │ │ ├── plugins-api.js
│ │ │ │ └── plugins-helpers.js
│ │ │ └── render-html/
│ │ │ ├── contexts/
│ │ │ │ ├── 404.js
│ │ │ │ ├── author.js
│ │ │ │ ├── feed.js
│ │ │ │ ├── home.js
│ │ │ │ ├── page-preview.js
│ │ │ │ ├── page.js
│ │ │ │ ├── post-preview.js
│ │ │ │ ├── post.js
│ │ │ │ ├── search.js
│ │ │ │ ├── tag.js
│ │ │ │ └── tags.js
│ │ │ ├── handlebars/
│ │ │ │ └── helpers/
│ │ │ │ ├── _modules.js
│ │ │ │ ├── asset.js
│ │ │ │ ├── canonical-link.js
│ │ │ │ ├── check-if-all.js
│ │ │ │ ├── check-if-any.js
│ │ │ │ ├── check-if-none.js
│ │ │ │ ├── check-if.js
│ │ │ │ ├── concatenate.js
│ │ │ │ ├── contains.js
│ │ │ │ ├── css.js
│ │ │ │ ├── date.js
│ │ │ │ ├── encode-url-fragment.js
│ │ │ │ ├── encode-url.js
│ │ │ │ ├── feed-link.js
│ │ │ │ ├── font.js
│ │ │ │ ├── gdpr-script-blocker.js
│ │ │ │ ├── get-author.js
│ │ │ │ ├── get-authors.js
│ │ │ │ ├── get-page.js
│ │ │ │ ├── get-pages-by-custom-field.js
│ │ │ │ ├── get-pages.js
│ │ │ │ ├── get-post-by-tags.js
│ │ │ │ ├── get-post.js
│ │ │ │ ├── get-posts-by-custom-field.js
│ │ │ │ ├── get-posts-by-tags.js
│ │ │ │ ├── get-posts.js
│ │ │ │ ├── get-tag.js
│ │ │ │ ├── get-tags.js
│ │ │ │ ├── image-dimensions.js
│ │ │ │ ├── is-current-page.js
│ │ │ │ ├── is-empty.js
│ │ │ │ ├── is-not-empty.js
│ │ │ │ ├── is-not.js
│ │ │ │ ├── is.js
│ │ │ │ ├── join.js
│ │ │ │ ├── js.js
│ │ │ │ ├── json-ld.js
│ │ │ │ ├── jsonify.js
│ │ │ │ ├── lazyload.js
│ │ │ │ ├── math.js
│ │ │ │ ├── menu-item-classes.js
│ │ │ │ ├── menu-url.js
│ │ │ │ ├── meta-description.js
│ │ │ │ ├── meta-robots.js
│ │ │ │ ├── not-contains.js
│ │ │ │ ├── orderby.js
│ │ │ │ ├── page-url.js
│ │ │ │ ├── publii-footer.js
│ │ │ │ ├── publii-head.js
│ │ │ │ ├── responsive-image-attributes.js
│ │ │ │ ├── responsive-sizes.js
│ │ │ │ ├── responsive-srcset.js
│ │ │ │ ├── reverse.js
│ │ │ │ ├── social-meta-tags.js
│ │ │ │ ├── specs/
│ │ │ │ │ ├── check-if-all.spec.js
│ │ │ │ │ ├── check-if-any.spec.js
│ │ │ │ │ ├── check-if-none.spec.js
│ │ │ │ │ ├── check-if.spec.js
│ │ │ │ │ ├── feed-link.spec.js
│ │ │ │ │ ├── font.spec.js
│ │ │ │ │ ├── is-empty.spec.js
│ │ │ │ │ ├── is-not-empty.spec.js
│ │ │ │ │ ├── jsonify.spec.js
│ │ │ │ │ └── translate.spec.js
│ │ │ │ └── translate.js
│ │ │ ├── helpers/
│ │ │ │ ├── content.js
│ │ │ │ ├── deleteEmpty.js
│ │ │ │ ├── diffCopy.js
│ │ │ │ ├── files.js
│ │ │ │ ├── gdpr.js
│ │ │ │ ├── helpers.js
│ │ │ │ ├── sitemap.js
│ │ │ │ ├── specs/
│ │ │ │ │ └── url.spec.js
│ │ │ │ ├── template.js
│ │ │ │ ├── url.js
│ │ │ │ └── view-settings.js
│ │ │ ├── items/
│ │ │ │ ├── author.js
│ │ │ │ ├── featured-image.js
│ │ │ │ ├── page.js
│ │ │ │ ├── post.js
│ │ │ │ └── tag.js
│ │ │ ├── renderer-cache.js
│ │ │ ├── renderer-context.js
│ │ │ ├── renderer-plugins.js
│ │ │ ├── renderer.js
│ │ │ ├── text-renderers/
│ │ │ │ ├── blockeditor.js
│ │ │ │ └── markdown.js
│ │ │ └── validators/
│ │ │ └── theme-config.js
│ │ ├── page.js
│ │ ├── pages.js
│ │ ├── plugins.js
│ │ ├── post.js
│ │ ├── posts.js
│ │ ├── site.js
│ │ ├── sites.js
│ │ ├── sql/
│ │ │ └── 1.0.0.sql
│ │ ├── tag.js
│ │ ├── tags.js
│ │ ├── themes.js
│ │ ├── vendor/
│ │ │ └── locutus/
│ │ │ └── htmlspecialchars.js
│ │ ├── window-manager.js
│ │ └── workers/
│ │ ├── backup/
│ │ │ ├── create.js
│ │ │ └── restore.js
│ │ ├── deploy/
│ │ │ └── deployment.js
│ │ ├── import/
│ │ │ ├── check.js
│ │ │ └── import.js
│ │ ├── renderer/
│ │ │ └── preview.js
│ │ └── thumbnails/
│ │ ├── post-images.js
│ │ └── regenerate.js
│ ├── build/
│ │ └── config.gypi
│ ├── config/
│ │ ├── AST.app.config.js
│ │ └── AST.currentSite.config.js
│ ├── default-files/
│ │ ├── default-languages/
│ │ │ ├── en-gb/
│ │ │ │ ├── config.json
│ │ │ │ ├── translations.json
│ │ │ │ └── wysiwyg.json
│ │ │ └── pl/
│ │ │ ├── config.json
│ │ │ ├── translations.json
│ │ │ └── wysiwyg.json
│ │ ├── default-themes/
│ │ │ └── simple/
│ │ │ ├── 404.hbs
│ │ │ ├── CHANGELOG.md
│ │ │ ├── assets/
│ │ │ │ ├── css/
│ │ │ │ │ ├── editor.css
│ │ │ │ │ ├── main.css
│ │ │ │ │ └── style.css
│ │ │ │ ├── dynamic/
│ │ │ │ │ └── fonts/
│ │ │ │ │ ├── adventpro/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── albertsans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── aleo/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── andadapro/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── antonio/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── archivonarrow/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── asap/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── assistant/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── besley/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── bigshouldersdisplay/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── bitcount/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── bitter/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── bodonimoda/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── brygada1918/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── cabin/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── cairo/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── cinzel/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── comfortaa/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── comme/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── dancingscript/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── danfo/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── dmsans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── domine/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── dosis/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── doto/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── dynapuff/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── exo/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── familjengrotesk/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── faustina/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── figtree/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── finlandica/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── frankruhllibre/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── fredoka/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── funneldisplay/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── gantari/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── geistmono/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── glory/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── gluten/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── googlesanscode/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── grenzegotisch/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── handjet/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── heebo/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── hostgrotesk/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── imbue/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── inclusivesans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── instrumentsans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── jetbrainsmono/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── jura/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── kalnia/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── karla/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── kreon/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── kumbhsans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── labrada/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── leaguespartan/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── lemonada/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── lexend/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── lexenddeca/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── librefranklin/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── lora/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── manrope/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── manuale/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── mavenpro/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── merriweathersans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── montserrat/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── mulish/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── nunito/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── orbitron/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── oswald/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── outfit/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── oxanium/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── parkinsans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── petrona/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── playfairdisplay/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── playwriteusmodern/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── playwriteustrad/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── plusjakartasans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── pontanosans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── publicsans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── quicksand/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── radiocanadabig/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── raleway/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── redhatdisplay/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── redhatmono/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── redhattext/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── redrose/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── rem/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── robotoflex/
│ │ │ │ │ │ └── LICENSE.txt
│ │ │ │ │ ├── robotoslab/
│ │ │ │ │ │ └── LICENSE.txt
│ │ │ │ │ ├── rokkitt/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── rubik/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── ruda/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── smoochsans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── sora/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── sourcecodepro/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── spartan/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── sticknobills/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── susemono/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── teachers/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── tektur/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── tourney/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── urbanist/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── varta/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── victormono/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── wixmadefortext/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── workbench/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── worksans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── yanonekaffeesatz/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── yrsa/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ ├── zalandosans/
│ │ │ │ │ │ └── OFL.txt
│ │ │ │ │ └── zalandosansexpanded/
│ │ │ │ │ └── OFL.txt
│ │ │ │ └── js/
│ │ │ │ ├── scripts.js
│ │ │ │ ├── svg-fix.js
│ │ │ │ └── svg-map.js
│ │ │ ├── author.hbs
│ │ │ ├── computed-options.js
│ │ │ ├── config.json
│ │ │ ├── dynamic-assets-mapping.js
│ │ │ ├── index.hbs
│ │ │ ├── page-empty.hbs
│ │ │ ├── page.hbs
│ │ │ ├── partials/
│ │ │ │ ├── fonts.hbs
│ │ │ │ ├── footer.hbs
│ │ │ │ ├── head.hbs
│ │ │ │ ├── menu.hbs
│ │ │ │ ├── navbar.hbs
│ │ │ │ ├── pagination.hbs
│ │ │ │ ├── share-buttons.hbs
│ │ │ │ ├── simple-menu.hbs
│ │ │ │ └── subpages-list.hbs
│ │ │ ├── post.hbs
│ │ │ ├── posts.hbs
│ │ │ ├── search.hbs
│ │ │ ├── simple.lang.json
│ │ │ ├── tag.hbs
│ │ │ ├── tags.hbs
│ │ │ ├── theme-variables.js
│ │ │ └── visual-override.js
│ │ ├── gdpr-assets/
│ │ │ ├── gdpr.css
│ │ │ ├── gdpr.js
│ │ │ └── template.html
│ │ ├── theme-files/
│ │ │ ├── config.json
│ │ │ ├── feed-json.hbs
│ │ │ ├── feed-xml.hbs
│ │ │ ├── menu.hbs
│ │ │ ├── pagination.hbs
│ │ │ └── sitemap.xsl
│ │ └── vendor/
│ │ └── prism.js
│ ├── dist/
│ │ └── index.html
│ ├── license.txt
│ ├── licenses/
│ │ ├── LICENSES.chromium.html
│ │ ├── agent-base/
│ │ │ └── license.txt
│ │ ├── all-licenses.json
│ │ ├── assert-plus/
│ │ │ └── license.txt
│ │ ├── base64url/
│ │ │ └── license.txt
│ │ ├── bindings/
│ │ │ └── license.txt
│ │ ├── brace-expansion/
│ │ │ └── license.txt
│ │ ├── buffer-alloc/
│ │ │ └── license.txt
│ │ ├── buffer-alloc-unsafe/
│ │ │ └── license.txt
│ │ ├── buffer-equal/
│ │ │ └── license.txt
│ │ ├── buffer-fill/
│ │ │ └── license.txt
│ │ ├── buffer-from/
│ │ │ └── license.txt
│ │ ├── bufferjs/
│ │ │ └── license.txt
│ │ ├── capture-stack-trace/
│ │ │ └── license.txt
│ │ ├── chainsaw/
│ │ │ └── license.txt
│ │ ├── cli/
│ │ │ └── license.txt
│ │ ├── clipboard/
│ │ │ └── license.txt
│ │ ├── codemirror/
│ │ │ └── license.txt
│ │ ├── colors/
│ │ │ └── license.txt
│ │ ├── commander/
│ │ │ └── license.txt
│ │ ├── deep-equal/
│ │ │ └── license.txt
│ │ ├── devtron/
│ │ │ └── license.txt
│ │ ├── diff/
│ │ │ └── license.txt
│ │ ├── electron/
│ │ │ └── license.txt
│ │ ├── end-of-stream/
│ │ │ └── license.txt
│ │ ├── es6-promisify/
│ │ │ └── license.txt
│ │ ├── feathericons/
│ │ │ └── license.txt
│ │ ├── follow-redirects/
│ │ │ └── license.txt
│ │ ├── fresh/
│ │ │ └── license.txt
│ │ ├── generate-function/
│ │ │ └── license.txt
│ │ ├── get-stdin/
│ │ │ └── license.txt
│ │ ├── growl/
│ │ │ └── license.txt
│ │ ├── handlebars/
│ │ │ └── license.txt
│ │ ├── has/
│ │ │ └── license.txt
│ │ ├── he/
│ │ │ └── license.txt
│ │ ├── https-proxy-agent/
│ │ │ └── license.txt
│ │ ├── humps/
│ │ │ └── license.txt
│ │ ├── ignore/
│ │ │ └── license.txt
│ │ ├── imurmurhash/
│ │ │ └── license.txt
│ │ ├── invert-kv/
│ │ │ └── license.txt
│ │ ├── isarray/
│ │ │ └── license.txt
│ │ ├── jquery/
│ │ │ └── license.txt
│ │ ├── jquery-ui/
│ │ │ └── license.txt
│ │ ├── json-schema/
│ │ │ └── license.txt
│ │ ├── lazystream/
│ │ │ └── license.txt
│ │ ├── libvips/
│ │ │ └── license.txt
│ │ ├── licenses.json
│ │ ├── locutus/
│ │ │ └── license.txt
│ │ ├── log-driver/
│ │ │ └── license.txt
│ │ ├── lucide/
│ │ │ └── license.txt
│ │ ├── mocha/
│ │ │ └── license.txt
│ │ ├── ncname/
│ │ │ └── license.txt
│ │ ├── nested-sortable/
│ │ │ └── license.txt
│ │ ├── node-slug/
│ │ │ └── license.txt
│ │ ├── normalize.css/
│ │ │ └── license.txt
│ │ ├── parse-bmfont-ascii/
│ │ │ └── license.txt
│ │ ├── parse-bmfont-xml/
│ │ │ └── license.txt
│ │ ├── punycode/
│ │ │ └── license.txt
│ │ ├── range-parser/
│ │ │ └── license.txt
│ │ ├── read-chunk/
│ │ │ └── license.txt
│ │ ├── select2/
│ │ │ └── license.txt
│ │ ├── send/
│ │ │ └── license.txt
│ │ ├── slash/
│ │ │ └── license.txt
│ │ ├── sortablejs/
│ │ │ └── license.txt
│ │ ├── source-map/
│ │ │ └── license.txt
│ │ ├── stream-consume/
│ │ │ └── license.txt
│ │ ├── stream-events/
│ │ │ └── license.txt
│ │ ├── stream-to/
│ │ │ └── license.txt
│ │ ├── stream-to-buffer/
│ │ │ └── license.txt
│ │ ├── stubs/
│ │ │ └── license.txt
│ │ ├── tabler-icons/
│ │ │ └── license.txt
│ │ ├── tinycolorpicker/
│ │ │ └── license.txt
│ │ ├── tinymce/
│ │ │ └── license.txt
│ │ ├── tootallnate/
│ │ │ └── once/
│ │ │ └── license.txt
│ │ ├── topo/
│ │ │ └── license.txt
│ │ ├── tr46/
│ │ │ └── license.txt
│ │ ├── trim/
│ │ │ └── license.txt
│ │ ├── typo-js/
│ │ │ └── license.txt
│ │ ├── uri-js/
│ │ │ └── license.txt
│ │ ├── vendor-licenses.json
│ │ ├── window-size/
│ │ │ └── license.txt
│ │ ├── wordwrap/
│ │ │ └── license.txt
│ │ ├── xml-char-classes/
│ │ │ └── license.txt
│ │ ├── xml-parse-from-string/
│ │ │ └── license.txt
│ │ ├── xml2json/
│ │ │ └── license.txt
│ │ ├── xmlbuilder/
│ │ │ └── license.txt
│ │ └── xregexp/
│ │ └── license.txt
│ ├── main.js
│ ├── package.json
│ └── src/
│ ├── assets/
│ │ └── vendor/
│ │ ├── css/
│ │ │ ├── codemirror.css
│ │ │ └── normalize.css
│ │ └── js/
│ │ └── codemirror/
│ │ ├── addon/
│ │ │ ├── display/
│ │ │ │ ├── autorefresh.js
│ │ │ │ ├── fullscreen.css
│ │ │ │ ├── fullscreen.js
│ │ │ │ ├── panel.js
│ │ │ │ ├── placeholder.js
│ │ │ │ └── rulers.js
│ │ │ ├── scroll/
│ │ │ │ ├── annotatescrollbar.js
│ │ │ │ ├── scrollpastend.js
│ │ │ │ ├── simplescrollbars.css
│ │ │ │ └── simplescrollbars.js
│ │ │ └── search/
│ │ │ ├── jump-to-line.js
│ │ │ ├── match-highlighter.js
│ │ │ ├── matchesonscrollbar.css
│ │ │ ├── matchesonscrollbar.js
│ │ │ ├── search.js
│ │ │ └── searchcursor.js
│ │ ├── autorefresh.js
│ │ ├── codemirror.js
│ │ ├── css.js
│ │ └── xml.js
│ ├── components/
│ │ ├── About.vue
│ │ ├── AboutCredits.vue
│ │ ├── AboutCreditsList.vue
│ │ ├── App.vue
│ │ ├── AppLanguages.vue
│ │ ├── AppPlugins.vue
│ │ ├── AppSettings.vue
│ │ ├── AppThemes.vue
│ │ ├── AuthorForm.vue
│ │ ├── Authors.vue
│ │ ├── Backups.vue
│ │ ├── CustomCss.vue
│ │ ├── CustomHtml.vue
│ │ ├── ErrorPopup.vue
│ │ ├── FileManager.vue
│ │ ├── LanguagesList.vue
│ │ ├── LanguagesListItem.vue
│ │ ├── LogViewer.vue
│ │ ├── MenuItem.vue
│ │ ├── MenuItemEditor.vue
│ │ ├── MenuPositionPopup.vue
│ │ ├── Menus.vue
│ │ ├── Message.vue
│ │ ├── NotificationsCenter.vue
│ │ ├── Pages.vue
│ │ ├── PluginsList.vue
│ │ ├── PluginsListItem.vue
│ │ ├── PostEditorBlockEditor.vue
│ │ ├── PostEditorMarkdown.vue
│ │ ├── PostEditorTinyMCE.vue
│ │ ├── Posts.vue
│ │ ├── RegenerateThumbnails.vue
│ │ ├── RegenerateThumbnailsPopup.vue
│ │ ├── RenderingPopup.vue
│ │ ├── ServerSettings.vue
│ │ ├── Settings.vue
│ │ ├── Sidebar.vue
│ │ ├── SidebarMenu.vue
│ │ ├── SidebarSites.vue
│ │ ├── SidebarSyncButton.vue
│ │ ├── Site.vue
│ │ ├── SiteAddForm.vue
│ │ ├── SiteLogo.vue
│ │ ├── SitesList.vue
│ │ ├── SitesListItem.vue
│ │ ├── SitesPopup.vue
│ │ ├── SitesSearch.vue
│ │ ├── Splashscreen.vue
│ │ ├── SyncPopup.vue
│ │ ├── TagForm.vue
│ │ ├── Tags.vue
│ │ ├── ThemeSettings.vue
│ │ ├── ThemesList.vue
│ │ ├── ThemesListItem.vue
│ │ ├── Tools.vue
│ │ ├── ToolsPlugin.vue
│ │ ├── TopBar.vue
│ │ ├── TopBarAppBar.vue
│ │ ├── TopBarDropDown.vue
│ │ ├── TopBarDropDownItem.vue
│ │ ├── WPImport.vue
│ │ ├── WPImportStats.vue
│ │ ├── basic-elements/
│ │ │ ├── Alert.vue
│ │ │ ├── AuthorsDropDown.vue
│ │ │ ├── Button.vue
│ │ │ ├── ButtonDropdown.vue
│ │ │ ├── CharCounter.vue
│ │ │ ├── Checkbox.vue
│ │ │ ├── CodeMirrorEditor.vue
│ │ │ ├── Collection.vue
│ │ │ ├── CollectionCell.vue
│ │ │ ├── CollectionHeader.vue
│ │ │ ├── CollectionRow.vue
│ │ │ ├── ColorPicker.vue
│ │ │ ├── Confirm.vue
│ │ │ ├── DirSelect.vue
│ │ │ ├── Dropdown.vue
│ │ │ ├── EmbedConsentsGroups.vue
│ │ │ ├── EmptyState.vue
│ │ │ ├── Field.vue
│ │ │ ├── FieldsGroup.vue
│ │ │ ├── FileSelect.vue
│ │ │ ├── Footer.vue
│ │ │ ├── GConsentModeGroups.vue
│ │ │ ├── GdprGroups.vue
│ │ │ ├── Header.vue
│ │ │ ├── HeaderSearch.vue
│ │ │ ├── Icon.vue
│ │ │ ├── ImageUpload.vue
│ │ │ ├── LogoCreator.vue
│ │ │ ├── Overlay.vue
│ │ │ ├── PagesDropDown.vue
│ │ │ ├── PostsDropDown.vue
│ │ │ ├── ProgressBar.vue
│ │ │ ├── RadioButton.vue
│ │ │ ├── RangeSlider.vue
│ │ │ ├── Repeater.vue
│ │ │ ├── Separator.vue
│ │ │ ├── SmallImageUpload.vue
│ │ │ ├── SupportedFeaturesCheck.vue
│ │ │ ├── Switcher.vue
│ │ │ ├── Tabs.vue
│ │ │ ├── TagsDropDown.vue
│ │ │ ├── TextArea.vue
│ │ │ ├── TextInput.vue
│ │ │ └── ThemesDropdown.vue
│ │ ├── block-editor/
│ │ │ ├── PubliiBlockEditor.vue
│ │ │ ├── assets/
│ │ │ │ ├── prism-theme.scss
│ │ │ │ └── typography.scss
│ │ │ ├── available-blocks.json
│ │ │ ├── blocks-mapping.js
│ │ │ ├── components/
│ │ │ │ ├── Block.vue
│ │ │ │ ├── BlockAdvancedConfig.vue
│ │ │ │ ├── BlockEditor.vue
│ │ │ │ ├── BlockLinkPopup.vue
│ │ │ │ ├── BlockWrapper.vue
│ │ │ │ ├── BlocksList.vue
│ │ │ │ ├── default-blocks/
│ │ │ │ │ ├── publii-code/
│ │ │ │ │ │ ├── block.vue
│ │ │ │ │ │ ├── config-form.json
│ │ │ │ │ │ ├── conversions.js
│ │ │ │ │ │ └── render.js
│ │ │ │ │ ├── publii-embed/
│ │ │ │ │ │ ├── block.vue
│ │ │ │ │ │ ├── config-form.json
│ │ │ │ │ │ ├── embed.js
│ │ │ │ │ │ └── render.js
│ │ │ │ │ ├── publii-gallery/
│ │ │ │ │ │ ├── block.vue
│ │ │ │ │ │ ├── config-form.json
│ │ │ │ │ │ └── render.js
│ │ │ │ │ ├── publii-header/
│ │ │ │ │ │ ├── block.vue
│ │ │ │ │ │ ├── config-form.json
│ │ │ │ │ │ ├── conversions.js
│ │ │ │ │ │ └── render.js
│ │ │ │ │ ├── publii-html/
│ │ │ │ │ │ ├── aspect-ratio.js
│ │ │ │ │ │ ├── block.vue
│ │ │ │ │ │ ├── config-form.json
│ │ │ │ │ │ ├── content-filter.js
│ │ │ │ │ │ ├── conversions.js
│ │ │ │ │ │ └── render.js
│ │ │ │ │ ├── publii-image/
│ │ │ │ │ │ ├── block.vue
│ │ │ │ │ │ ├── config-form.json
│ │ │ │ │ │ └── render.js
│ │ │ │ │ ├── publii-list/
│ │ │ │ │ │ ├── block.vue
│ │ │ │ │ │ ├── config-form.json
│ │ │ │ │ │ ├── conversions.js
│ │ │ │ │ │ └── render.js
│ │ │ │ │ ├── publii-paragraph/
│ │ │ │ │ │ ├── block.vue
│ │ │ │ │ │ ├── config-form.json
│ │ │ │ │ │ ├── conversions.js
│ │ │ │ │ │ └── render.js
│ │ │ │ │ ├── publii-quote/
│ │ │ │ │ │ ├── block.vue
│ │ │ │ │ │ ├── config-form.json
│ │ │ │ │ │ ├── conversions.js
│ │ │ │ │ │ └── render.js
│ │ │ │ │ ├── publii-readmore/
│ │ │ │ │ │ ├── block.vue
│ │ │ │ │ │ ├── config-form.json
│ │ │ │ │ │ └── render.js
│ │ │ │ │ ├── publii-separator/
│ │ │ │ │ │ ├── block.vue
│ │ │ │ │ │ ├── config-form.json
│ │ │ │ │ │ ├── conversions.js
│ │ │ │ │ │ └── render.js
│ │ │ │ │ └── publii-toc/
│ │ │ │ │ ├── block.vue
│ │ │ │ │ ├── config-form.json
│ │ │ │ │ └── render.js
│ │ │ │ ├── elements/
│ │ │ │ │ ├── EditorIcon.vue
│ │ │ │ │ └── Switcher.vue
│ │ │ │ ├── extensions/
│ │ │ │ │ ├── ConversionHelpers.js
│ │ │ │ │ ├── ShortcutManager.js
│ │ │ │ │ └── UndoManager.js
│ │ │ │ ├── helpers/
│ │ │ │ │ ├── ContentEditableImprovements.vue
│ │ │ │ │ ├── InlineMenuUI.vue
│ │ │ │ │ └── TopMenuUI.vue
│ │ │ │ ├── mixins/
│ │ │ │ │ ├── AdvancedConfig.vue
│ │ │ │ │ ├── HasPreview.vue
│ │ │ │ │ ├── InlineMenu.vue
│ │ │ │ │ ├── LinkConfig.vue
│ │ │ │ │ └── LinkHelpers.vue
│ │ │ │ └── utils/
│ │ │ │ ├── SelectedText.js
│ │ │ │ └── Utils.js
│ │ │ └── vendors/
│ │ │ ├── _modularscale.scss
│ │ │ └── modularscale/
│ │ │ ├── _function.scss
│ │ │ ├── _pow.scss
│ │ │ ├── _respond.scss
│ │ │ ├── _round-px.scss
│ │ │ ├── _settings.scss
│ │ │ ├── _sort.scss
│ │ │ ├── _strip-units.scss
│ │ │ ├── _sugar.scss
│ │ │ ├── _target.scss
│ │ │ └── _vars.scss
│ │ ├── configs/
│ │ │ ├── defaultDeploymentSettings.js
│ │ │ ├── postEditor.config.js
│ │ │ ├── preloaderImages.js
│ │ │ ├── s3ACLs.js
│ │ │ ├── s3Regions.js
│ │ │ └── sidebar-icons.js
│ │ ├── mixins/
│ │ │ ├── BackToTools.js
│ │ │ ├── CollectionCheckboxes.js
│ │ │ ├── GoToLastOpenedWebsite.vue
│ │ │ └── PostEditorsCommon.vue
│ │ └── post-editor/
│ │ ├── AuthorPopup.vue
│ │ ├── CodeMirror/
│ │ │ ├── codemirror-4.inline-attachment.js
│ │ │ └── inline-attachment.js
│ │ ├── DatePopup.vue
│ │ ├── EasyMde.vue
│ │ ├── Editor.vue
│ │ ├── EditorBridge.js
│ │ ├── GalleryPopup.vue
│ │ ├── HelpPanelBlockEditor.vue
│ │ ├── HelpPanelMarkdown.vue
│ │ ├── InlineEditor.vue
│ │ ├── ItemHelper.js
│ │ ├── LinkPopup.vue
│ │ ├── LinkToolbar.vue
│ │ ├── SearchPopup.vue
│ │ ├── Sidebar.vue
│ │ ├── SourceCodeEditor.vue
│ │ ├── TopBar.vue
│ │ └── WritersPanel.vue
│ ├── config/
│ │ └── langs.js
│ ├── helpers/
│ │ ├── sass-colors.js
│ │ ├── utils.js
│ │ ├── vendor/
│ │ │ ├── locutus/
│ │ │ │ ├── strings/
│ │ │ │ │ └── strip_tags.js
│ │ │ │ └── xml/
│ │ │ │ ├── index.js
│ │ │ │ ├── utf8_decode.js
│ │ │ │ └── utf8_encode.js
│ │ │ └── tinymce/
│ │ │ ├── icons/
│ │ │ │ └── publii/
│ │ │ │ └── icons.js
│ │ │ ├── langs/
│ │ │ │ └── readme.md
│ │ │ ├── license.txt
│ │ │ ├── plugins/
│ │ │ │ └── emoticons/
│ │ │ │ └── js/
│ │ │ │ ├── emojiimages.js
│ │ │ │ └── emojis.js
│ │ │ └── tinymce.d.ts
│ │ └── version-comparator.js
│ ├── main.js
│ ├── router/
│ │ └── index.js
│ ├── scss/
│ │ ├── codemirror.scss
│ │ ├── css-variables.scss
│ │ ├── editor/
│ │ │ ├── editor-markdown.scss
│ │ │ ├── editor-options.scss
│ │ │ ├── editor-overrides.scss
│ │ │ ├── editor.scss
│ │ │ ├── post-editors-common.scss
│ │ │ └── scrollbar.scss
│ │ ├── empty-states.scss
│ │ ├── forms.scss
│ │ ├── global.scss
│ │ ├── help-panel-common.scss
│ │ ├── mixins.scss
│ │ ├── notifications.scss
│ │ ├── options-sidebar.scss
│ │ ├── popup-common.scss
│ │ ├── scope-fix.scss
│ │ ├── variables.scss
│ │ └── vendor/
│ │ ├── _modularscale.scss
│ │ ├── codemirror.css
│ │ ├── modularscale/
│ │ │ ├── _function.scss
│ │ │ ├── _pow.scss
│ │ │ ├── _respond.scss
│ │ │ ├── _round-px.scss
│ │ │ ├── _settings.scss
│ │ │ ├── _sort.scss
│ │ │ ├── _strip-units.scss
│ │ │ ├── _sugar.scss
│ │ │ ├── _target.scss
│ │ │ └── _vars.scss
│ │ ├── normalize.css
│ │ └── vue-multiselect.scss
│ └── store/
│ ├── default.state.js
│ ├── getters/
│ │ ├── app-version.js
│ │ ├── author-templates.js
│ │ ├── languages.js
│ │ ├── notifications-count.js
│ │ ├── notifications-status.js
│ │ ├── notifications.js
│ │ ├── plugins.js
│ │ ├── site-authors.js
│ │ ├── site-display-names.js
│ │ ├── site-names.js
│ │ ├── site-pages.js
│ │ ├── site-plugins.js
│ │ ├── site-posts.js
│ │ ├── site-tags.js
│ │ ├── tag-templates.js
│ │ ├── theme-select.js
│ │ └── themes.js
│ ├── helpers/
│ │ ├── mutations.js
│ │ ├── page-filter.js
│ │ ├── page-get-author.js
│ │ ├── post-filter.js
│ │ ├── post-get-author.js
│ │ └── post-get-tags.js
│ └── index.js
├── build/
│ ├── config.gypi
│ ├── entitlements.mac.plist
│ ├── installation/
│ │ ├── icon.icns
│ │ ├── volume-prerelease.icns
│ │ └── volume.icns
│ ├── installer.nsh
│ ├── license_en.txt
│ └── scripts/
│ ├── afterPack.js
│ └── update-build-number.js
├── gulpfile.js
├── internal-tools/
│ └── loc.js
├── package.json
└── webpack.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 4
================================================
FILE: .github/DISCUSSION_TEMPLATE/bug-report.yml
================================================
title: "[Bug report] "
labels: ["Thank you for reporting a bug!"]
body:
- type: markdown
attributes:
value: |
Before reporting a bug, please explore the existing topics in our [GitHub Discussions](https://github.com/GetPublii/Publii/discussions). If you can't find a discussion that addresses your concern, feel free to initiate a new discussion.
If you encounter issues with premium products purchased on the [Publii Marketplace](https://marketplace.getpublii.com/), please use the dedicated support platform provided on the marketplace for assistance.
---
Thank you for reporting a bug. We need some information to assist us in promptly investigating and resolving the issue.
- type: input
id: os
attributes:
label: Operating system
description: "Which operating system do you use to run the Publii app? Please provide the version as well."
placeholder: "macOS Monterey 12.2"
validations:
required: true
- type: input
id: publii
attributes:
label: Publii version
description: "Which Publii version do you use?"
placeholder: "0.38.3 (build 14239)"
validations:
required: true
- type: dropdown
id: issue_type
attributes:
label: Issue type
description: "What does the problem relate to?"
options:
- Application
- Free theme
- Free plugin
- Something else
validations:
required: true
- type: textarea
id: bug-description
attributes:
label: Bug description
description: What happened?
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: Which steps do we need to take to reproduce this error?
- type: textarea
id: logs
attributes:
label: Relevant log output
description: If applicable, provide relevant log output that can be generated with the Publii "Log Viewer" tool.
render: shell
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: GetPublii
open_collective: publii
custom: https://getpublii.com/donate/
================================================
FILE: .github/ISSUE_TEMPLATE/bug.yml
================================================
name: Bug
description: File a bug report
title: "[Bug]: "
body:
- type: markdown
attributes:
value: |
Before opening a bug report, please search for the behavior in the existing issues. If you can't find what you're looking for, then please open a new issue.
For questions about Publii functionality, **themes**, **plugins**, or other general queries, please contact our development team via the [community forum](https://forum.getpublii.com/).
---
Thank you for taking the time to file a bug report. In order to help us investigate and fix the issue as quickly as possible, we need some information.
- type: input
id: os
attributes:
label: Operating system
description: "Which operating system do you use to run Publii app? Please provide the version as well."
placeholder: "macOS Monterey 12.2"
validations:
required: true
- type: input
id: publii
attributes:
label: Publii version
description: "Which Publii version do you use?"
placeholder: "0.38.3 (build 14239)"
validations:
required: true
- type: dropdown
id: editor
attributes:
label: Post editor
description: If you're reporting a bug with a post editor, please specify which one.
options:
- WYSIWYG editor
- Block editor
- Markdown editor
validations:
required: false
- type: textarea
id: bug-description
attributes:
label: Bug description
description: What happened?
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: Which steps do we need to take to reproduce this error?
- type: textarea
id: logs
attributes:
label: Relevant log output
description: If applicable, provide relevant log output that can be generated with the Publii "Log Viewer" tool.
render: shell
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
- name: Check the docs
url: https://getpublii.com/docs/
about: 'This repository is for reporting bugs and proposing new features. If you need help getting started with Publii, check out the docs!'
- name: Visit the community forum
url: https://forum.getpublii.com/
about: 'For questions about Publii functionality, themes, plugins, or other general queries, please contact our development team via the community forum.'
================================================
FILE: .github/ISSUE_TEMPLATE/feature.yml
================================================
name: Feature Request
description: Propose a new feature for Publii
title: "[Feature Request]: "
labels: [feature request]
body:
- type: markdown
attributes:
value: |
Thanks for proposing a feature for Publii!
- type: textarea
id: feature-description
attributes:
label: Feature Description
description: How should this feature look like?
validations:
required: true
================================================
FILE: .gitignore
================================================
*~
.idea
.DS_Store
.coveralls.yml
npm-debug.log
/node_modules/
/app/node_modules/
/coverage
/app/dist/css
/app/dist/vendor
/app/dist/*.js
/app/dist/*.txt
/app/dist/*.js.map
/app/dist/*.png
/app/dist/*.svg
/app/dist/*.node
!/app/dist/index.html
/dist
/cache/
/StaticBlog-darwin-x64/
/StaticBlog-win32-x64/
/Publii-darwin-x64/
/Publii-win32-x64/
app/Publii-win32-x64/
/Publii-win32-ia32/
/Publii-linux-x64/
/Publii-win32-x64-backup/
app/licenses.txt
app/Publii-darwin-x64/
/Publii-darwin-x64/
/dmg-release/
/create-dmg/
licenses.txt
release/RELEASES
*.nupkg
release/Setup.exe
Publii.dmg
release/PubliiSetup.exe
*.msi
release/Setup.wixobj
*.wixpdb
release/Setup.wxs
.vscode
================================================
FILE: .nvmrc
================================================
v22.18.0
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
================================================
FILE: README.md
================================================
# Publii - Static CMS for privacy-focused, SEO-optimized websites.
[](https://github.com/GetPublii/Publii/blob/master/LICENSE)
[](https://github.com/GetPublii/Publii/graphs/commit-activity) [](https://opencollective.com/publii/) 
[Publii](https://getpublii.com/) is a desktop-based CMS for Windows, Mac and Linux that makes creating static websites fast
and hassle-free, even for beginners.
**Current version: 0.47.5 (build 17411)**
## Why Publii?
Unlike static-site generators that are often unwieldy and difficult to use, Publii provides an
easy-to-understand UI much like server-based CMSs such as WordPress or Joomla!, where users
can create posts and other site content, and style their site using a variety of built-in themes and
options. Users can enjoy the benefits of a super-fast and secure static website, with all the
convenience that a CMS provides.
What makes Publii even more unique is that the app runs locally on your desktop rather
than on the site's server. Available for Windows, Mac, Linux once the app has been installed
you can create a site in minutes, even without internet access; since Publii is a desktop app you
can create, update and modify your site offline, then upload the site changes to your server at
the click of a button. Publii supports multiple upload options, including standard HTTP/HTTPS
servers, Netlify, Amazon S3, GitHub Pages and Google Cloud or SFTP.

## Download
Publii is available for Mac, Windows, and Linux and can be downloaded from our website:
[Download Publii (.exe, .dmg, .deb, .rpm, .AppImage)](https://getpublii.com/download/)
## Developing
If you want to build newest version of Publii or contribute to the Publii code, please read about [app build process](https://github.com/GetPublii/Publii/wiki/App-build-process).
## Getting Started
You can learn more about getting started in our [User documentation](https://getpublii.com/docs/) or [Developer documentation](https://getpublii.com/dev/).
If you have any questions or suggestions, or just need some help with using Publii, you can
visit our [Community Hub](https://github.com/GetPublii/Publii/discussions) or follow us on [Twitter](https://twitter.com/GetPublii)
### Learn More
* [User docs](https://getpublii.com/docs/)
* [Developer docs](https://getpublii.com/dev/)
* [Wiki](https://github.com/GetPublii/Publii/wiki/)
* [Issues](https://github.com/GetPublii/Publii/issues/)
* [Community forum](https://forum.getpublii.com/)
## Contributors
This project exists thanks to all the people who contribute.
<a href="https://github.com/GetPublii/Publii/graphs/contributors"><img src="https://opencollective.com/Publii/contributors.svg?width=890&button=false" /></a>
## Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/Publii#backer)]
<a href="https://opencollective.com/Publii#backers" target="_blank"><img src="https://opencollective.com/Publii/backers.svg?width=890"></a>
## Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/Publii#sponsor)]
<a href="https://opencollective.com/Publii/sponsor/0/website" target="_blank"><img src="https://opencollective.com/Publii/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/Publii/sponsor/1/website" target="_blank"><img src="https://opencollective.com/Publii/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/Publii/sponsor/2/website" target="_blank"><img src="https://opencollective.com/Publii/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/Publii/sponsor/3/website" target="_blank"><img src="https://opencollective.com/Publii/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/Publii/sponsor/4/website" target="_blank"><img src="https://opencollective.com/Publii/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/Publii/sponsor/5/website" target="_blank"><img src="https://opencollective.com/Publii/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/Publii/sponsor/6/website" target="_blank"><img src="https://opencollective.com/Publii/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/Publii/sponsor/7/website" target="_blank"><img src="https://opencollective.com/Publii/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/Publii/sponsor/8/website" target="_blank"><img src="https://opencollective.com/Publii/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/Publii/sponsor/9/website" target="_blank"><img src="https://opencollective.com/Publii/sponsor/9/avatar.svg"></a>
## License
Copyright (c) 2026 TidyCustoms. General Public License v3.0, read [LICENSE](https://getpublii.com/license.html) for details.
================================================
FILE: app/back-end/app-preload.js
================================================
const { contextBridge, ipcRenderer, webUtils } = require('electron');
contextBridge.exposeInMainWorld('mainProcessAPI', {
shellShowItemInFolder: (url) => ipcRenderer.invoke('publii-shell-show-item-in-folder', url),
shellOpenPath: (filePath) => ipcRenderer.invoke('publii-shell-open-path', filePath),
shellOpenExternal: (url) => ipcRenderer.invoke('publii-shell-open-external', url),
existsSync: (pathToCheck) => ipcRenderer.invoke('publii-native-exists-sync', pathToCheck),
normalizePath: (pathToNormalize) => ipcRenderer.invoke('publii-native-normalize-path', pathToNormalize),
createMD5: (value) => ipcRenderer.invoke('publii-native-md5', value),
getPathForFile: (value) => webUtils.getPathForFile(value),
getEnv: () => ({
name: process.env.NODE_ENV,
nodeVersion: process.versions.node,
chromeVersion: process.versions.chrome,
electronVersion: process.versions.electron,
platformName: process.platform
}),
send: (channel, ...data) => {
const validChannels = [
'app-save-color-theme',
'app-license-load',
'app-config-save',
'app-backup-set-location',
'app-theme-upload',
'app-author-save',
'app-author-cancel',
'app-authors-load',
'app-author-delete',
'app-backups-list-load',
'app-backup-remove',
'app-backup-rename',
'app-backup-create',
'app-backup-restore',
'app-site-reload',
'app-site-css-load',
'app-site-css-save',
'app-site-config-save',
'app-site-check-website-to-restore',
'app-site-check-website-catalog-availability',
'app-site-restore-from-backup',
'app-site-remove-temporary-backup-files',
'app-site-restore-from-backup',
'app-file-manager-list',
'app-file-manager-delete',
'app-file-manager-create',
'app-file-manager-upload',
'app-log-files-load',
'app-log-file-load',
'app-menu-update',
'publii-set-spellchecker-language',
'app-post-load',
'app-post-save',
'app-post-cancel',
'app-page-load',
'app-page-save',
'app-page-cancel',
'app-pages-hierarchy-load',
'app-pages-hierarchy-save',
'app-image-upload',
'app-image-upload-remove',
'app-post-delete',
'app-post-duplicate',
'app-post-status-change',
'app-page-delete',
'app-page-duplicate',
'app-page-status-change',
'app-site-regenerate-thumbnails',
'app-site-abort-regenerate-thumbnails',
'app-preview-render',
'app-deploy-test',
'app-site-regenerate-thumbnails-required',
'app-site-switch',
'app-site-create',
'app-site-clone',
'app-site-delete',
'app-license-accept',
'app-deploy-render-abort',
'app-deploy-abort',
'app-deploy-continue',
'app-deploy-render',
'app-deploy-upload',
'app-sync-is-done',
'app-tag-save',
'app-tag-cancel',
'app-tags-load',
'app-tags-status-change',
'app-tag-delete',
'app-site-theme-config-save',
'app-theme-delete',
'app-notifications-retrieve',
'app-wxr-check',
'app-wxr-import',
'app-language-upload',
'app-language-delete',
'app-plugin-upload',
'app-plugin-delete',
'app-site-get-plugins-state',
'app-site-plugin-activate',
'app-site-plugin-deactivate',
'app-site-get-plugin-config',
'app-site-save-plugin-config',
'app-close',
'app-set-ui-zoom-level',
'app-set-notifications-center-state',
'app-get-notifications-file',
'app-pages-hierarchy-update',
'app-content-fields-update'
];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, ...data);
} else {
console.info('Event: ', channel, ' is not supported in send');
}
},
receive: (channel, func) => {
const validChannels = [
'app-data-loaded',
'app-deploy-render-error',
'app-theme-mode:changed',
'app-files-selected',
'app-site-regenerate-thumbnails-progress',
'app-rendering-progress',
'app-deploy-rendered',
'app-connection-in-progress',
'app-connection-error',
'app-connection-success',
'app-uploading-progress',
'app-wxr-import-progress',
'app-show-search-form',
'block-editor-undo',
'block-editor-redo',
'no-remote-files'
];
if (validChannels.includes(channel)) {
// Strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args));
} else {
console.info('Event: ', channel, ' is not supported in receive');
}
},
receiveOnce: (channel, func) => {
const validChannels = [
'app-license-loaded',
'app-config-saved',
'app-file-selected',
'app-theme-uploaded',
'app-author-saved',
'app-authors-loaded',
'app-author-deleted',
'app-backups-list-loaded',
'app-backup-removed',
'app-backup-renamed',
'app-backup-created',
'app-backup-restored',
'app-site-reloaded',
'app-site-css-loaded',
'app-site-css-saved',
'app-site-config-saved',
'app-site-backup-checked',
'app-site-restored-from-backup',
'app-site-website-catalog-availability-checked',
'app-site-restored-from-backup',
'app-file-manager-listed',
'app-file-manager-deleted',
'app-file-manager-created',
'app-file-manager-uploaded',
'app-log-files-loaded',
'app-log-file-loaded',
'app-post-loaded',
'app-post-saved',
'app-post-deleted',
'app-post-duplicated',
'app-post-status-changed',
'app-page-loaded',
'app-page-saved',
'app-page-deleted',
'app-page-duplicated',
'app-page-status-changed',
'app-pages-hierarchy-loaded',
'app-site-regenerate-thumbnails-error',
'app-site-regenerate-thumbnails-success',
'app-preview-rendered',
'app-preview-render-error',
'app-deploy-test-success',
'app-deploy-test-write-error',
'app-deploy-test-error',
'app-site-regenerate-thumbnails-required-status',
'app-site-switched',
'app-site-creation-error',
'app-site-creation-duplicate',
'app-site-creation-db-error',
'app-site-created',
'app-site-cloned',
'app-site-deleted',
'app-license-accepted',
'app-deploy-aborted',
'app-deploy-uploaded',
'app-sync-is-done-saved',
'app-tag-saved',
'app-tags-loaded',
'app-tags-status-changed',
'app-tag-deleted',
'app-site-theme-config-saved',
'app-theme-deleted',
'app-notifications-retrieved',
'app-wxr-imported',
'app-wxr-checked',
'app-directory-selected',
'app-image-uploaded',
'app-files-selected',
'app-language-uploaded',
'app-language-deleted',
'app-plugin-uploaded',
'app-plugin-deleted',
'app-site-plugin-config-saved',
'app-site-plugins-state-loaded',
'app-site-plugin-activated',
'app-site-plugin-deactivated',
'app-site-get-plugin-config-retrieved',
'app-content-fields-updated'
];
if (validChannels.includes(channel)) {
// Strip event as it includes `sender`
ipcRenderer.once(channel, (event, ...args) => func(...args));
} else {
console.info('Event: ', channel, ' is not supported in receiveOnce');
}
},
invoke: (command, ...data) => {
const validCommands = [
'app-theme-mode:set-light',
'app-theme-mode:set-dark',
'app-theme-mode:get-theme',
'app-theme-mode:set-system',
'app-credits-list:get-app-path',
'app-main-process-is-osx11-or-higher',
'app-main-process-select-file',
'app-main-process-create-slug',
'app-main-process-select-files',
'publii-get-spellchecker-language',
'app-main-get-spellchecker-languages',
'app-main-set-spellchecker-language-for-webview',
'app-main-process-load-password',
'app-window:minimize',
'app-window:maximize',
'app-window:unmaximize',
'app-window:close',
'app-main-process-select-directory',
'app-main-webview-search-find-in-page',
'app-main-webview-search-stop-find-in-page',
'app-main-load-language',
'app-plugins-api:save-config-file',
'app-plugins-api:save-language-file',
'app-plugins-api:read-config-file',
'app-plugins-api:read-language-file',
'app-plugins-api:read-theme-file',
'app-plugins-api:delete-config-file',
'app-plugins-api:delete-language-file'
];
if (validCommands.includes(command)) {
return ipcRenderer.invoke(command, ...data);
} else {
console.info('Event: ', channel, ' is not supported in invoke');
}
return false;
},
stopReceive: (channel, func) => {
const validChannels = [
'app-preview-render-error',
'app-connection-error',
'app-wxr-imported',
'app-wxr-import-progress'
];
if (validChannels.includes(channel)) {
ipcRenderer.removeListener(channel, func);
} else {
console.info('Event: ', channel, ' is not supported in stopReceive');
}
},
stopReceiveAll: (channel) => {
const validChannels = [
'app-license-accepted',
'app-files-selected',
'app-site-regenerate-thumbnails-error',
'app-site-regenerate-thumbnails-progress',
'app-site-regenerate-thumbnails-success',
'app-preview-render-error',
'app-rendering-progress',
'app-site-created',
'app-site-creation-duplicate',
'app-site-creation-db-error',
'app-site-creation-error',
'app-connection-error',
'app-show-search-form',
'block-editor-undo',
'block-editor-redo'
];
if (validChannels.includes(channel)) {
ipcRenderer.removeAllListeners(channel);
} else {
console.info('Event: ', channel, ' is not supported in stopReceiveAll');
}
}
});
================================================
FILE: app/back-end/app.js
================================================
/*
* Main Application class
*/
// Necessary packages
const fs = require('fs-extra');
const os = require('os');
const path = require('path');
const Database = os.platform() === 'linux' ? require('node-sqlite3-wasm').Database : require('better-sqlite3');
const compare = require('node-version-compare');
const normalizePath = require('normalize-path');
const url = require('url');
// Electron classes
const { screen, shell, nativeTheme, Menu, dialog, BrowserWindow } = require('electron');
// Collection classes
const Posts = require('./posts.js');
const Pages = require('./pages.js');
const Tags = require('./tags.js');
const Authors = require('./authors.js');
const Themes = require('./themes.js');
const Languages = require('./languages.js');
const Plugins = require('./plugins.js');
// Helper classes
const DBUtils = require('./helpers/db.utils.js');
const Site = require('./site.js');
const Utils = require('./helpers/utils.js');
const FileHelper = require('./helpers/file.js');
// List of the Event classes
const EventClasses = require('./events/_modules.js');
// Migration classes
const SiteConfigMigrator = require('./migrators/site-config.js');
// Default config
const defaultAstAppConfig = require('./../config/AST.app.config');
const defaultAstCurrentSiteConfig = require('./../config/AST.currentSite.config');
// Plugins packages
const PluginsAPI = require('./modules/plugins/plugins-api.js')
/**
* Main app class
*/
class App {
/**
* Constructor
*
* @param startupSettings
*/
constructor(startupSettings) {
this.mainWindow = startupSettings.mainWindow;
this.app = startupSettings.app;
this.basedir = startupSettings.basedir;
this.appDir = path.join(this.app.getPath('documents'), 'Publii');
this.app.appDir = this.appDir;
this.initPath = path.join(this.appDir, 'config', 'window-config.json');
this.appConfigPath = path.join(this.appDir, 'config', 'app-config.json');
this.tinymceOverridedConfigPath = path.join(this.appDir, 'config', 'tinymce.override.json');
this.versionData = JSON.parse(FileHelper.readFileSync(__dirname + '/builddata.json', 'utf8'));
this.versionData.os = os.platform() === 'darwin' ? 'mac' : os.platform() === 'linux' ? 'linux' : 'win';
this.windowBounds = null;
this.appConfig = null;
this.tinymceOverridedConfig = {};
this.sites = {};
this.sitesDir = null;
this.app.sitesDir = null;
this.db = false;
this.pluginsAPI = new PluginsAPI();
/*
* Run the app
*/
this.checkDirs();
let loadConfigResult = this.loadConfig();
if (!loadConfigResult) {
this.app.quit();
return;
}
this.loadAdditionalConfig();
this.checkThemes();
let loadingSitesResult = this.loadSites();
if (!loadingSitesResult) {
this.app.quit();
return;
}
this.loadThemes();
this.loadLanguages();
this.loadPlugins();
this.initWindow();
this.initWindowEvents();
}
/**
* Create the application dir if not exists
*/
checkDirs() {
if (!fs.existsSync(this.appDir)) {
fs.mkdirSync(this.appDir);
// Create also other dirs
fs.mkdirSync(path.join(this.appDir, 'sites'));
fs.mkdirSync(path.join(this.appDir, 'config'));
fs.mkdirSync(path.join(this.appDir, 'themes'));
fs.copySync(
path.join(__dirname, '..', 'default-files', 'default-themes').replace('app.asar', 'app.asar.unpacked'),
path.join(this.appDir, 'themes'),
{
filter: this.skipSystemFiles,
dereference: true
}
);
fs.mkdirSync(path.join(this.appDir, 'languages'));
fs.mkdirSync(path.join(this.appDir, 'plugins'));
}
if (!fs.existsSync(path.join(this.appDir, 'backups'))) {
fs.mkdirSync(path.join(this.appDir, 'backups'));
}
if (!fs.existsSync(path.join(this.appDir, 'languages'))) {
fs.mkdirSync(path.join(this.appDir, 'languages'));
}
if (!fs.existsSync(path.join(this.appDir, 'plugins'))) {
fs.mkdirSync(path.join(this.appDir, 'plugins'));
}
}
/**
* Check if some themes should be updated
*/
checkThemes() {
let appThemesPath = path.join(__dirname, '..', 'default-files', 'default-themes');
let userThemesPath = path.join(this.appDir, 'themes');
// Merge themes directory
let appThemeDirs = fs.readdirSync(appThemesPath);
for (let file of appThemeDirs) {
// Skip files and hidden files
if (file.indexOf('.') > -1) {
continue;
}
// Detect missing themes
if (!fs.existsSync(path.join(userThemesPath, file))) {
fs.mkdirSync(path.join(userThemesPath, file), { recursive: true });
try {
fs.copySync(
path.join(appThemesPath, file).replace('app.asar', 'app.asar.unpacked'),
path.join(userThemesPath, file),
{
filter: this.skipSystemFiles,
dereference: true
}
);
} catch (err) {
fs.appendFile(this.app.getPath('logs') + '/themes-copy-errors.txt', JSON.stringify(err));
}
} else {
// For existing themes - compare versions
let appThemeConfig = path.join(appThemesPath, file, 'config.json');
let userThemeConfig = path.join(userThemesPath, file, 'config.json');
// Check if both config.json files exists
if (fs.existsSync(appThemeConfig) && fs.existsSync(userThemeConfig)) {
let appThemeData = JSON.parse(FileHelper.readFileSync(appThemeConfig, 'utf8'));
let userThemeData = JSON.parse(FileHelper.readFileSync(userThemeConfig, 'utf8'));
// If app theme is newer version than the existing one
if(compare(appThemeData.version, userThemeData.version) === 1) {
// Remove all files from the theme dir
fs.emptyDirSync(path.join(userThemesPath, file));
// Copy updated theme files
fs.copySync(
path.join(appThemesPath, file).replace('app.asar', 'app.asar.unpacked'),
path.join(userThemesPath, file),
{
filter: this.skipSystemFiles,
dereference: true
}
);
}
}
}
}
}
// Reload website data
reloadSite (siteName) {
let siteData = this.switchSite(siteName);
let siteConfig = this.loadSite(siteName);
return {
data: siteData,
config: siteConfig
};
}
// Load website and their config and database
switchSite (site) {
if (!site) {
return { status: false };
}
const siteDir = path.join(this.sitesDir, site);
const menuConfigPath = path.join(siteDir, 'input', 'config', 'menu.config.json');
const themeConfigPath = path.join(siteDir, 'input', 'config', 'theme.config.json');
const dbPath = path.join(siteDir, 'input', 'db.sqlite');
if (!Utils.fileExists(dbPath)) {
return { status: false };
}
if (this.db) {
try {
this.db.close();
} catch (e) {
console.log('[SWITCH WEBSITE] DB already closed');
}
}
this.db = new DBUtils(new Database(dbPath));
let tags = new Tags(this, {site});
let posts = new Posts(this, {site});
let pages = new Pages(this, {site});
let authors = new Authors(this, {site});
let themes = new Themes(this, {site});
let themeDir = path.join(siteDir, 'input', 'themes', themes.currentTheme(true));
let themeOverridesDir = path.join(siteDir, 'input', 'themes', themes.currentTheme(true) + '-override');
let themeConfig = Themes.loadThemeConfig(themeConfigPath, themeDir);
let menuStructure = FileHelper.readFileSync(menuConfigPath, 'utf8');
let parsedMenuStructure = {};
try {
parsedMenuStructure = JSON.parse(menuStructure);
} catch (e) {
return { status: false };
}
return {
status: true,
posts: posts.load(),
pages: pages.load(),
tags: tags.load(),
authors: authors.load(),
postsTags: posts.loadTagsXRef(),
postsAuthors: posts.loadAuthorsXRef(),
pagesAuthors: pages.loadAuthorsXRef(),
postTemplates: themes.loadPostTemplates(),
pageTemplates: themes.loadPageTemplates(),
tagTemplates: themes.loadTagTemplates(),
authorTemplates: themes.loadAuthorTemplates(),
themes: themes.load(),
themeHasOverrides: Utils.dirExists(themeOverridesDir),
themeSettings: themeConfig,
menuStructure: parsedMenuStructure,
siteDir: siteDir
};
}
// Load specific website
loadSite (siteName) {
let dirPath = path.join(this.sitesDir, siteName);
let fileStat = fs.statSync(dirPath);
// check directories only
if (!fileStat.isDirectory()) {
return;
}
// check if the config file exists
let configFilePath = path.join(dirPath, 'input', 'config', 'site.config.json');
if (!Utils.fileExists(configFilePath)) {
return;
}
// check if all necessary files exists
Site.checkFilesConsistency(this, siteName);
// Load the config
let defaultSiteConfig = JSON.parse(JSON.stringify(defaultAstCurrentSiteConfig));
let siteConfig = FileHelper.readFileSync(configFilePath);
try {
siteConfig = JSON.parse(siteConfig);
} catch (e) {
dialog.showErrorBox('Publii cannot read site config', 'There is an issue with file: ' + configFilePath + "\n\nError details: " + e.message);
return;
}
if (siteConfig.name !== siteName) {
siteConfig.name = siteName;
fs.writeFileSync(configFilePath, JSON.stringify(siteConfig, null, 4));
}
siteConfig = Utils.mergeObjects(defaultSiteConfig, siteConfig);
// Migrate old author data if necessary
siteConfig = SiteConfigMigrator.moveOldAuthorData(this, siteConfig);
// set site data
this.sites[siteConfig.name] = JSON.parse(JSON.stringify(siteConfig));
if (this.sites[siteConfig.name].logo.icon.indexOf('#') > -1) {
this.sites[siteConfig.name].logo.icon = this.sites[siteConfig.name].logo.icon.split('#')[1];
}
// Fill displayName fields for old websites without it
if (!this.sites[siteConfig.name].displayName) {
this.sites[siteConfig.name].displayName = siteConfig.name;
}
return siteConfig;
}
// Load websites
loadSites() {
if (!fs.existsSync(this.sitesDir)) {
dialog.showErrorBox('Publii cannot find your sites folder.', 'Please check if the directory ' + this.sitesDir + ' exists or create it manually, then reopen the application.');
return false;
}
let files = fs.readdirSync(this.sitesDir);
this.sites = {};
for (let siteName of files) {
this.loadSite(siteName);
}
return true;
}
// Load themes
loadThemes() {
let themesLoader = new Themes(this);
this.themes = themesLoader.loadThemes();
this.themesPath = normalizePath(path.join(this.appDir, 'themes'));
this.dirPaths = {
sites: normalizePath(path.join(this.appDir, 'sites')),
temp: normalizePath(path.join(this.appDir, 'temp')),
logs: normalizePath(this.app.getPath('logs'))
};
}
// Load languages
loadLanguages() {
let languagesLoader = new Languages(this);
this.languages = languagesLoader.loadLanguages();
this.languagesPath = normalizePath(path.join(this.appDir, 'languages'));
this.languagesDefaultPath = normalizePath(path.join(__dirname, '..', 'default-files', 'default-languages').replace('app.asar', 'app.asar.unpacked'));
this.languageLoadingError = false;
if (this.appConfig.language && this.appConfig.languageType) {
this.currentLanguageName = this.appConfig.language;
this.currentLanguageType = this.appConfig.languageType;
this.currentLanguageTranslations = languagesLoader.loadTranslations(this.appConfig.language, this.appConfig.languageType);
let languageConfig = languagesLoader.loadLanguageConfig(this.appConfig.language, this.appConfig.languageType);
if (languageConfig) {
this.currentLanguageMomentLocale = languageConfig.momentLocale;
this.currentWysiwygTranslation = languagesLoader.loadWysiwygTranslation(this.appConfig.language, this.appConfig.languageType);
}
}
this.loadDefaultLanguage(languagesLoader, false);
}
// Load plugins
loadPlugins() {
let pluginsLoader = new Plugins(this.appDir, this.sitesDir);
this.plugins = pluginsLoader.loadPlugins();
this.pluginsPath = normalizePath(path.join(this.appDir, 'plugins'));
}
// Load default language
loadDefaultLanguage (languagesLoader, errorOccurred = false) {
this.defaultLanguageName = 'en-gb';
this.defaultLanguageType = 'default';
this.defaultLanguageTranslations = languagesLoader.loadTranslations('en-gb', 'default');
let languageConfig = languagesLoader.loadLanguageConfig('en-gb', 'default');
this.defaultLanguageMomentLocale = languageConfig.momentLocale;
this.defaultWysiwygTranslation = languagesLoader.loadWysiwygTranslation('en-gb', 'default');
if (errorOccurred) {
this.defaultLanguageLoadingError = true;
}
}
// Load language
loadLanguage (lang, type) {
if (type !== 'default' && type !== 'installed') {
type = 'default';
lang = 'en-gb';
}
let languagesLoader = new Languages(this);
this.currentLanguageName = lang.replace(/[^a-z\-\_\.]/gmi, '');
this.currentLanguageType = type;
this.currentLanguageTranslations = languagesLoader.loadTranslations(lang, type);
this.languageLoadingError = false;
let languageConfig = languagesLoader.loadLanguageConfig(lang, type);
if (languageConfig) {
this.currentLanguageMomentLocale = languageConfig.momentLocale;
this.currentWysiwygTranslation = languagesLoader.loadWysiwygTranslation(lang, type);
}
if (
!this.currentLanguageTranslations ||
!languageConfig ||
(!this.currentWysiwygTranslation && lang !== 'en-gb')
) {
this.languageLoadingError = true;
}
}
// Set language
setLanguage (lang, type) {
if (type !== 'default' && type !== 'installed') {
type = 'default';
lang = 'en-gb';
}
this.appConfig.language = lang.replace(/[^a-z\-\_\.]/gmi, '');
this.appConfig.languageType = type;
try {
fs.writeFileSync(this.appConfigPath, JSON.stringify(this.appConfig, null, 4), {'flags': 'w'});
} catch (e) {
if (this.hasPermissionsErrors(e)) {
return false;
}
}
return true;
}
// Read or create the application config
loadConfig () {
// Try to get window bounds
try {
this.windowBounds = JSON.parse(FileHelper.readFileSync(this.initPath, 'utf8'));
} catch (e) {
console.log('The window-config.json file will be created');
}
if (!this.windowBounds) {
let screens = screen.getAllDisplays();
let width = screens[0].workAreaSize.width;
let height = screens[0].workAreaSize.height;
for (let i = 0; i < screens.length; i++) {
if (screens[i].width < width) {
width = screens[i].width;
}
if (screens[i].height < height) {
height = screens[i].height;
}
}
this.windowBounds = {
width: width,
height: height
};
} else {
let screens = screen.getAllDisplays();
let isInsideScreenBounds = false;
for (let monitor of screens) {
if (
this.windowBounds.x >= monitor.bounds.x &&
this.windowBounds.y >= monitor.bounds.y &&
this.windowBounds.x + this.windowBounds.width <= monitor.bounds.x + monitor.bounds.width &&
this.windowBounds.y + this.windowBounds.height <= monitor.bounds.y + monitor.bounds.height
) {
isInsideScreenBounds = true;
break
}
}
if (!isInsideScreenBounds) {
let width = screens[0].workAreaSize.width;
let height = screens[0].workAreaSize.height;
this.windowBounds = {
width: width,
height: height
};
}
}
// Try to get application config
try {
this.appConfig = JSON.parse(FileHelper.readFileSync(this.appConfigPath, 'utf8'));
this.appConfig = Utils.mergeObjects(JSON.parse(JSON.stringify(defaultAstAppConfig)), this.appConfig);
} catch (e) {
if (this.hasPermissionsErrors(e)) {
return false;
}
console.log('The app-config.json file will be created');
this.appConfig = JSON.parse(JSON.stringify(defaultAstAppConfig));
try {
fs.writeFileSync(this.appConfigPath, JSON.stringify(this.appConfig, null, 4), {'flags': 'w'});
} catch (e) {
if (this.hasPermissionsErrors(e)) {
return false;
}
}
return true;
}
return true;
}
// Load additional config data
loadAdditionalConfig () {
// Try to get TinyMCE overrided config
try {
this.tinymceOverridedConfig = JSON.parse(FileHelper.readFileSync(this.tinymceOverridedConfigPath, 'utf8'));
} catch (e) {}
if (this.appConfig.sitesLocation) {
this.sitesDir = this.appConfig.sitesLocation;
this.app.sitesDir = this.appConfig.sitesLocation;
} else {
this.appConfig.sitesLocation = path.join(this.appDir, 'sites');
this.sitesDir = path.join(this.appDir, 'sites');
this.app.sitesDir = path.join(this.appDir, 'sites');
}
this.pluginsHelper = new Plugins(this.appDir, this.sitesDir);
}
// Check permissions errors
hasPermissionsErrors (error) {
if (error.code === 'EACCES') {
dialog.showErrorBox('Publii has no read/write access to the config folder', 'Please check the permissions of the Publii config folder and try to reopen the application.');
return true;
}
if (error.code === 'EPERM') {
dialog.showErrorBox('Publii has no read/write access to the config folder', 'If you are using macOS 10.15+ - please open "System Preferences", go to "Security & Privacy" and under "Privacy Tab" please check if Publii has proper permissions for the "Files and Documents". For other operating systems - please check the file permissions for the Publii configuration folder.');
return true;
}
return false;
}
// Create the window
initWindow() {
let self = this;
let windowParams = this.windowBounds;
windowParams.minWidth = 1200;
windowParams.minHeight = 700;
windowParams.webPreferences = {
nodeIntegration: false,
contextIsolation: true,
spellcheck: true,
preload: path.join(__dirname, 'app-preload.js'),
icon: path.join(__dirname, 'assets', 'icon.png')
};
if (this.appConfig.appTheme === 'dark' || (this.appConfig.appTheme === 'system' && nativeTheme.shouldUseDarkColors)) {
windowParams.backgroundColor = '#202128';
}
let displays = screen.getAllDisplays();
let externalDisplay = displays.find((display) => {
return display.bounds.x !== 0 || display.bounds.y !== 0;
});
// Detect case when Publii was displayed on the external display which is now unavailable
if (
!externalDisplay &&
(
windowParams.x < 0 ||
windowParams.x > screen.getPrimaryDisplay().workAreaSize.width ||
windowParams.y < 0 ||
windowParams.y > screen.getPrimaryDisplay().workAreaSize.height
)
) {
windowParams.x = 0;
windowParams.y = 0;
}
if((/^darwin/).test(process.platform)) {
windowParams.titleBarStyle = 'hidden';
}
if((/^win/).test(process.platform)) {
windowParams.frame = false;
}
Menu.setApplicationMenu(null);
this.mainWindow = new BrowserWindow(windowParams);
this.mainWindow.setMenu(null);
this.mainWindow.loadURL('file:///' + this.basedir + '/dist/index.html');
this.mainWindow.removeMenu();
// Register search shortcut listener
this.mainWindow.webContents.on('before-input-event', (event, input) => {
if (input.type === 'mouseDown' && (input.button === 'back' || input.button === 'forward')) {
event.preventDefault();
}
if (input.key === 'f' && (input.meta || input.control)) {
this.mainWindow.webContents.send('app-show-search-form');
} else if (input.key === 'z' && (input.meta || input.control) && !input.shift) {
this.mainWindow.webContents.send('block-editor-undo');
} else if (
(input.key === 'z' && (input.meta || input.control) && input.shift) ||
(input.key === 'y' && (input.meta || input.control) && !input.shift)
) {
this.mainWindow.webContents.send('block-editor-redo');
}
});
this.mainWindow.webContents.setWindowOpenHandler(({ url }) => {
if (typeof url !== 'string') {
return { action: 'deny' };
}
let urlToOpen;
let allowedProtocols = ['http:', 'https:', 'file:', 'dat:', 'ipfs:', 'dweb:'];
try {
urlToOpen = new URL(url);
} catch (e) {
return { action: 'deny' };
}
if (allowedProtocols.indexOf(urlToOpen.protocol) > -1) {
urlToOpen = urlToOpen.href.replace(/\s/gmi, '');
shell.openExternal(url);
}
return { action: 'deny' };
});
this.mainWindow.webContents.on('app-command', (e, cmd) => {
// disable back/forward mouse buttons
if (cmd === 'browser-backward' || cmd === 'browser-forward') {
e.preventDefault();
}
});
this.mainWindow.webContents.on('did-finish-load', function() {
let appData = {
version: self.versionData,
config: self.appConfig,
customConfig: {
tinymce: self.tinymceOverridedConfig
},
currentLanguage: {
name: self.currentLanguageName,
translations: self.currentLanguageTranslations,
wysiwygTranslation: self.currentWysiwygTranslation,
momentLocale: self.currentLanguageMomentLocale,
languageLoadingError: self.languageLoadingError
},
defaultLanguage: {
name: self.defaultLanguageName,
translations: self.defaultLanguageTranslations,
wysiwygTranslation: self.defaultWysiwygTranslation,
momentLocale: self.defaultLanguageMomentLocale,
languageLoadingError: self.languageLoadingError
},
languages: self.languages,
languagesPath: self.languagesPath,
languagesDefaultPath: self.languagesDefaultPath,
plugins: self.plugins,
pluginsPath: self.pluginsPath,
sites: self.sites,
themes: self.themes,
themesPath: self.themesPath,
dirs: self.dirPaths,
vendorPath: normalizePath(path.join(__dirname, '..', 'default-files', 'vendor').replace('app.asar', 'app.asar.unpacked'))
};
self.mainWindow.webContents.send('app-data-loaded', appData);
// Open Dev Tools
if (self.appConfig.openDevToolsInMain) {
self.mainWindow.webContents.openDevTools();
}
self.setCurrentZoomLevel();
});
this.mainWindow.on('resize', () => this.setCurrentZoomLevel());
this.mainWindow.on('maximize', () => this.setCurrentZoomLevel());
this.mainWindow.on('unmaximize', () => this.setCurrentZoomLevel());
this.mainWindow.on('restore', () => this.setCurrentZoomLevel());
if (process.platform === 'linux') {
this.mainWindow.webContents.on('before-input-event', (event, input) => {
if (input.control && input.key === 'q') {
this.app.quit();
}
});
}
// Create context menu
const ContextMenuBuilder = require('./helpers/context-menu-builder.js');
let contextMenuBuilder = new ContextMenuBuilder(this.mainWindow.webContents);
this.mainWindow.webContents.on('context-menu', (event, params) => {
event.preventDefault();
contextMenuBuilder.showPopupMenu(params);
});
}
// Add events to the window
initWindowEvents() {
this.mainWindow.on('close', () => {
let windowBounds = this.mainWindow.getBounds();
fs.writeFileSync(this.initPath, JSON.stringify(windowBounds, null, 4), {'flags': 'w'});
});
this.mainWindow.on('closed', () => {
this.mainWindow = null;
});
this.initializeCustomIpcMainEvents();
}
// Initializes all custom events for IPC Main thread
initializeCustomIpcMainEvents () {
// Create instances for all custom event classes
let classNames = Object.keys(EventClasses);
for (let className of classNames) {
new EventClasses[className](this);
}
}
// Getter for the main window object
getMainWindow() {
return this.mainWindow;
}
// Function used to filter unnecessary files
skipSystemFiles (src, dest) {
return src.indexOf('.DS_Store') > -1 ? false : true;
}
// Function used to add sites to the back-end sites list
addSite (siteCatalog, siteData) {
this.sites[siteCatalog] = siteData;
}
// Function used to restore current zoom level of window, because it is lost if zoom is changed after windo load
setCurrentZoomLevel () {
let zoom = parseFloat(this.appConfig.uiZoomLevel);
if (zoom && zoom > 0 && zoom <= 2.5) {
this.mainWindow.webContents.setZoomFactor(zoom);
}
}
}
module.exports = App;
================================================
FILE: app/back-end/author.js
================================================
const fs = require('fs-extra');
const path = require('path');
const Model = require('./model.js');
const Authors = require('./authors.js');
const Pages = require('./pages.js');
const Posts = require('./posts.js');
const slug = require('./helpers/slug');
const ImageHelper = require('./helpers/image.helper.js');
const Themes = require('./themes.js');
const Utils = require('./helpers/utils.js');
const FileHelper = require('./helpers/file.js');
/**
* Author Model - used for operations connected with author management
*/
class Author extends Model {
/**
* Creates an instance of the model
*
* @param appInstance {object} - instance of the application
* @param authorData {object} - object with author data
*/
constructor(appInstance, authorData, storeMode = true) {
super(appInstance, authorData);
this.id = parseInt(authorData.id, 10);
this.authorsData = new Authors(appInstance, authorData);
this.postsData = new Posts(appInstance, authorData);
this.pagesData = new Pages(appInstance, authorData);
this.storeMode = storeMode;
if (authorData.additionalData) {
this.additionalData = authorData.additionalData;
}
if (authorData.imageConfigFields) {
this.imageConfigFields = authorData.imageConfigFields;
}
if(authorData.name || authorData.name === '') {
this.name = authorData.name;
this.username = authorData.username;
this.config = authorData.config;
this.additionalData = authorData.additionalData;
this.prepareAuthorName();
}
if (typeof this.additionalData === 'string') {
try {
this.additionalData = JSON.parse(this.additionalData);
} catch (e) {
console.log('(!) An issue occurred during initial parsing author additional data', this.id);
}
}
}
/**
* Saves new/existing author data
*
* @returns {object} - object with created/edited author data
*/
save () {
if (this.name === '') {
return {
status: false,
message: 'author-empty-name'
};
}
if (this.username === '' || slug(this.username) === '') {
this.username = slug(this.name);
}
if (slug(this.username).trim() === '') {
return {
status: false,
message: 'author-empty-username'
};
}
if (!this.isAuthorNameUnique()) {
return {
status: false,
message: 'author-duplicate-name',
authors: this.authorsData.load()
};
}
if (!this.isAuthorUsernameUnique()) {
return {
status: false,
message: 'author-duplicate-username',
authors: this.authorsData.load()
};
}
if (this.id !== 0) {
return this.updateAuthor();
}
return this.addAuthor();
}
/**
* Stores new author in the DB
*
* @returns {{status: boolean, message: string, authors: *}}
*/
addAuthor() {
let sqlQuery = this.db.prepare(`INSERT INTO authors VALUES(null, @name, @slug, '', @config, @additionalData)`);
sqlQuery.run({
name: this.name,
slug: slug(this.username),
config: this.config,
additionalData: JSON.stringify(this.additionalData)
});
// Get the newly added item ID if necessary
if (this.id === 0) {
this.id = this.db.prepare('SELECT last_insert_rowid() AS id').get().id;
// Move images from the temp directory
let tempDirectoryExists = true;
let tempImagesDir = path.join(this.siteDir, 'input', 'media', 'authors', 'temp');
try {
fs.statSync(tempImagesDir).isDirectory();
} catch (err) {
tempDirectoryExists = false;
}
if (tempDirectoryExists) {
let finalImagesDir = path.join(this.siteDir, 'input', 'media', 'authors', (this.id).toString());
fs.copySync(tempImagesDir, finalImagesDir);
fs.removeSync(tempImagesDir);
}
}
this.checkAndCleanImages();
return {
status: true,
message: 'author-added',
authorID: this.id,
postsAuthors: this.postsData.loadAuthorsXRef(),
pagesAuthors: this.pagesData.loadAuthorsXRef(),
authors: this.authorsData.load()
};
}
/**
* Updates existing author in the DB
*
* @returns {{status: boolean, message: string}}
*/
updateAuthor() {
let sqlQuery = this.db.prepare(`UPDATE authors
SET
name = @name,
username = @slug,
password = '',
config = @config,
additional_data = @additionalData
WHERE
id = @id`);
sqlQuery.run({
name: this.name,
slug: slug(this.username),
config: this.config,
additionalData: JSON.stringify(this.additionalData),
id: this.id
});
this.checkAndCleanImages();
return {
status: true,
message: 'author-updated',
postsAuthors: this.postsData.loadAuthorsXRef(),
authors: this.authorsData.load()
};
}
/**
* Creates author name without leading/ending spaces
*/
prepareAuthorName() {
if(typeof this.name == 'undefined') {
this.name = '';
}
// Remove leading and ending spaces (trim it)
// it will also exclude case when author name contains only
// whitespaces
this.name = this.name.replace(/^\s+/, '').replace(/\s+$/, '');
}
/**
* Check if the author name is unique
*
* @returns {boolean}
*/
isAuthorNameUnique() {
let query = this.db.prepare('SELECT * FROM authors WHERE name LIKE @name AND id != @id');
let queryParams = {
name: this.escape(this.name),
id: this.id
};
let foundedAuthors = query.all(queryParams);
if (foundedAuthors.length) {
for (const author of foundedAuthors) {
if (author.name === this.name) {
return false;
}
}
}
return true;
}
/**
* Checks if author username (slug) is unique
*
* @returns {boolean}
*/
isAuthorUsernameUnique() {
let query = this.db.prepare('SELECT username FROM authors WHERE id != @id');
let queryParams = {
id: this.id
};
let foundedAuthors = query.all(queryParams);
if (foundedAuthors.length) {
for (const author of foundedAuthors) {
if (slug(this.username) === slug(author.username)) {
return false;
}
}
}
return true;
}
/**
* Removes current author
*
* @returns {{status: boolean, message: string}}
*/
delete() {
if(this.id === 1) {
return {
status: false,
message: 'cannot-delete-main-author'
};
}
this.db.exec(`DELETE FROM authors WHERE id = ${parseInt(this.id, 10)}`);
this.db.prepare(`UPDATE posts SET authors = '1' WHERE authors LIKE @id`).run({ id: this.id.toString() });
ImageHelper.deleteImagesDirectory(this.siteDir, 'authors', this.id);
return {
status: true,
message: 'author-deleted',
posts: this.postsData.load(),
postsAuthors: this.postsData.loadAuthorsXRef(),
authors: this.authorsData.load()
};
}
/*
* Remove unused images
*/
checkAndCleanImages (cancelEvent = false) {
let authorDir = this.id;
if(this.id === 0) {
authorDir = 'temp';
}
let imagesDir = path.join(this.siteDir, 'input', 'media', 'authors', (authorDir).toString());
let authorDirectoryExists = true;
try {
fs.statSync(imagesDir).isDirectory();
} catch (err) {
authorDirectoryExists = false;
}
if(!authorDirectoryExists) {
return;
}
let images = fs.readdirSync(imagesDir);
this.cleanImages(images, imagesDir, cancelEvent);
}
/*
* Removes images from a given image dir
*/
cleanImages(images, imagesDir, cancelEvent) {
let authorDir = this.id;
let featuredImage = '';
let viewConfig = {};
if (this.additionalData && this.additionalData.featuredImage) {
featuredImage = path.parse(this.additionalData.featuredImage).base;
}
if (this.additionalData && this.additionalData.viewConfig) {
viewConfig = this.additionalData.viewConfig;
}
// If author is cancelled - get the previous featured image
if (cancelEvent && this.id !== 0) {
let additionalDataQuery = `SELECT additional_data FROM authors WHERE id = @id`;
let additionalDataResult = this.db.prepare(additionalDataQuery).all({ id: this.id });
if (additionalDataResult) {
try {
featuredImage = JSON.parse(additionalDataResult[0].additional_data).featuredImage;
viewConfig = JSON.parse(additionalDataResult[0].additional_data).viewConfig;
} catch (e) {
console.log('(!) An issue occurred during parsing author additional data', this.id);
}
}
}
if (this.id === 0) {
authorDir = 'temp';
}
let imagesInViewSettings = [];
imagesInViewSettings = Object.keys(viewConfig).filter((fieldName) => {
return this.imageConfigFields.indexOf(fieldName) !== -1 && viewConfig[fieldName] !== '';
}).map((fieldName) => {
return viewConfig[fieldName];
});
// Iterate through images
for (let i in images) {
let imagePath = images[i];
let fullPath = path.join(imagesDir, imagePath);
// Skip dirs and symlinks
if (imagePath === '.' || imagePath === '..' || imagePath === 'responsive') {
continue;
}
// Remove files which does not exist as featured image and authorViewSettings
if (
(cancelEvent && authorDir === 'temp') ||
(
imagesInViewSettings.indexOf(imagePath) === -1 &&
featuredImage !== imagePath
)
) {
try {
fs.unlinkSync(fullPath);
} catch(e) {
console.error(e);
}
this.removeResponsiveImages(fullPath);
}
}
// Clean unused avatar images
let themesHelper = new Themes(this.application, { site: this.site });
let themeConfigPath = path.join(this.application.sitesDir, this.site, 'input', 'config', 'theme.config.json');
if (fs.existsSync(themeConfigPath)) {
let themeConfigString = FileHelper.readFileSync(themeConfigPath, 'utf8');
themesHelper.checkAndCleanImages(themeConfigString);
}
}
/*
* Remove unused responsive images
*/
removeResponsiveImages(originalPath) {
let themesHelper = new Themes(this.application, { site: this.site });
let currentTheme = themesHelper.currentTheme();
// If there is no selected theme
if (currentTheme === 'not selected') {
return;
}
// Load theme config
let themeConfig = Utils.loadThemeConfig(path.join(this.siteDir, 'input'), currentTheme);
// check if responsive images config exists
if(Utils.responsiveImagesConfigExists(themeConfig)) {
let dimensions = Utils.responsiveImagesDimensions(themeConfig, 'contentImages');
let featuredDimensions = Utils.responsiveImagesDimensions(themeConfig, 'authorImages');
if (featuredDimensions !== false) {
featuredDimensions.forEach(item => {
if (dimensions.indexOf(item) === -1) {
dimensions.push(item);
}
});
}
let responsiveImagesDir = path.parse(originalPath).dir;
responsiveImagesDir = path.join(responsiveImagesDir, 'responsive');
if (typeof dimensions === "boolean") {
return;
}
let forceWebp = !!this.application.sites[this.site]?.advanced?.forceWebp;
// Remove responsive images of each size
for(let dimensionName of dimensions) {
let filename = path.parse(originalPath).name;
let extension = path.parse(originalPath).ext;
if (forceWebp && ['.png', '.jpg', '.jpeg'].indexOf(extension.toLowerCase()) > -1) {
extension = '.webp';
}
let responsiveImagePath = path.join(responsiveImagesDir, filename + '-' + dimensionName + extension);
if(Utils.fileExists(responsiveImagePath)){
fs.unlinkSync(responsiveImagePath);
}
}
}
}
}
module.exports = Author;
================================================
FILE: app/back-end/authors.js
================================================
/*
* Authors instance
*/
const Model = require('./model.js');
class Authors extends Model {
/**
* Authors constructor
*
* @param appInstance
* @param authorsData
*/
constructor(appInstance, authorsData) {
super(appInstance, authorsData);
}
/**
* Load authors
*/
load() {
let sqlQuery = `SELECT
id,
name,
username,
config,
additional_data AS additionalData
FROM
authors
GROUP BY
id
ORDER BY
id ASC`;
return this.db.prepare(sqlQuery).all();
}
}
module.exports = Authors;
================================================
FILE: app/back-end/builddata.json
================================================
{
"version": "0.47.5",
"build": 17411
}
================================================
FILE: app/back-end/events/_modules.js
================================================
/*
* Module which loads all Event classes
*/
module.exports = {
AppEvents: require('./app.js'),
ContentEvents: require('./content.js'),
CreditsEvents: require('./credits'),
ImageUploaderEvents: require('./image-uploader.js'),
PageEvents: require('./page.js'),
PostEvents: require('./post.js'),
SiteEvents: require('./site.js'),
TagEvents: require('./tag.js'),
TagsEvents: require('./tags.js'),
DeployEvents: require('./deploy.js'),
SyncEvents: require('./sync.js'),
MenuEvents: require('./menu.js'),
PreviewEvents: require('./preview.js'),
NotificationsEvents: require('./notifications.js'),
BackupEvents: require('./backup.js'),
AuthorEvents: require('./author.js'),
AuthorsEvents: require('./authors.js'),
ImportEvents: require('./import.js'),
FileManagerEvents: require('./file-manager.js'),
PluginEvents: require('./plugin.js'),
PluginsApiEvents: require('./plugins-api.js')
};
================================================
FILE: app/back-end/events/app.js
================================================
const fs = require('fs-extra');
const path = require('path');
const FileHelper = require('../helpers/file.js');
const ipcMain = require('electron').ipcMain;
const Themes = require('../themes.js');
const Languages = require('../languages.js');
const Plugins = require('../plugins.js');
const AppFiles = require('../helpers/app-files.js');
const AdmZip = require("adm-zip");
/*
* Events for the IPC communication regarding app
*/
class AppEvents {
constructor(appInstance) {
/*
* Close app
*/
ipcMain.on('app-close', function(event, config) {
appInstance.app.quit();
});
/*
* Save licence acceptance
*/
ipcMain.on('app-license-accept', function(event, config) {
fs.writeFileSync(appInstance.appConfigPath, JSON.stringify({licenseAccepted: true}, null, 4));
appInstance.appConfig = config;
event.sender.send('app-license-accepted', true);
});
/*
* Save app config
*/
ipcMain.on('app-config-save', function (event, config) {
if (config.sitesLocation === '') {
config.sitesLocation = appInstance.dirPaths.sites;
}
if (config.sitesLocation !== appInstance.appConfig.sitesLocation) {
let result = true;
if (appInstance.appConfig.sitesLocation) {
let appFilesHelper = new AppFiles(appInstance);
if (appInstance.db) {
try {
appInstance.db.close();
} catch (e) {
console.log('[SITE LOCATION CHANGE] DB already closed');
}
}
setTimeout(() => {
if (config.changeSitesLocationWithoutCopying) {
fs.writeFileSync(appInstance.appConfigPath, JSON.stringify(config, null, 4));
appInstance.appConfig = config;
appInstance.sitesDir = config.sitesLocation;
} else {
result = appFilesHelper.relocateSites(
appInstance.appConfig.sitesLocation,
config.sitesLocation,
event
);
if (result) {
fs.writeFileSync(appInstance.appConfigPath, JSON.stringify(config, null, 4));
appInstance.appConfig = config;
appInstance.sitesDir = config.sitesLocation;
}
}
appInstance.loadSites();
event.sender.send('app-config-saved', {
status: true,
message: 'success-save',
sites: appInstance.sites
});
}, 500);
return;
}
}
event.sender.send('app-config-saved', {
status: true,
message: 'success-save'
});
fs.writeFileSync(appInstance.appConfigPath, JSON.stringify(config, null, 4));
appInstance.appConfig = config;
});
/*
* Save app color theme config
*/
ipcMain.on('app-save-color-theme', function (event, theme) {
let appConfig = FileHelper.readFileSync(appInstance.appConfigPath, 'utf8');
try {
appConfig = JSON.parse(appConfig);
appConfig.appTheme = theme;
fs.writeFileSync(appInstance.appConfigPath, JSON.stringify(appConfig, null, 4));
} catch (e) {
console.log('(!) App was unable to save the color theme');
}
});
/*
* Delete theme
*/
ipcMain.on('app-theme-delete', function(event, config) {
let themesLoader = new Themes(appInstance);
if(config.directory !== '') {
themesLoader.removeTheme(config.directory);
appInstance.themes = appInstance.themes.filter(function (theme) {
return theme.name !== config.name;
});
event.sender.send('app-theme-deleted', {
status: true,
themes: appInstance.themes
});
}
});
/*
* Delete language
*/
ipcMain.on('app-language-delete', function(event, config) {
let languagesLoader = new Languages(appInstance);
if(config.directory !== '') {
languagesLoader.removeLanguage(config.directory);
appInstance.languages = appInstance.languages.filter(function (language) {
return language.name !== config.name;
});
event.sender.send('app-language-deleted', {
status: true,
languages: appInstance.languages
});
}
});
/*
* Delete plugin
*/
ipcMain.on('app-plugin-delete', function(event, config) {
let pluginsLoader = new Plugins(appInstance.appDir, appInstance.sitesDir);
if(config.directory !== '') {
pluginsLoader.removePlugin(config.directory);
appInstance.plugins = appInstance.plugins.filter(function (plugin) {
return plugin.name !== config.name;
});
event.sender.send('app-plugin-deleted', {
status: true,
plugins: appInstance.plugins
});
}
});
/*
* Add new theme
*/
ipcMain.on('app-theme-upload', function(event, config) {
let themesLoader = new Themes(appInstance);
let newThemeDir = path.parse(config.sourcePath).name;
let extension = path.parse(config.sourcePath).ext;
let status = '';
if (extension === '.zip' || extension === '') {
if (extension === '.zip') {
let zipPath = path.join(themesLoader.themesPath, '__TEMP__');
let zip = new AdmZip(config.sourcePath);
fs.mkdirSync(zipPath, { recursive: true });
zip.extractAllTo(zipPath, true);
let dirs = fs.readdirSync(zipPath).filter(function(file) {
if(file.substr(0,1) === '_' || file.substr(0,1) === '.') {
return false;
}
return fs.statSync(path.join(zipPath, file)).isDirectory();
});
if (dirs.length !== 1) {
event.sender.send('app-theme-uploaded', {
status: 'wrong-format',
themes: appInstance.themes
});
fs.removeSync(zipPath);
return;
}
newThemeDir = dirs[0];
let directoryPath = path.join(themesLoader.themesPath, newThemeDir);
try {
fs.statSync(directoryPath);
status = 'updated';
fs.removeSync(directoryPath);
} catch (e) {
status = 'added';
}
fs.copySync(path.join(zipPath, newThemeDir), directoryPath);
fs.removeSync(zipPath);
appInstance.themes = themesLoader.loadThemes();
event.sender.send('app-theme-uploaded', {
status: status,
themes: appInstance.themes
});
return;
} else {
let directoryPath = path.join(themesLoader.themesPath, newThemeDir);
try {
fs.statSync(directoryPath);
status = 'updated';
fs.removeSync(directoryPath);
} catch (e) {
status = 'added';
}
fs.copySync(config.sourcePath, directoryPath);
appInstance.themes = themesLoader.loadThemes();
}
} else {
status = 'wrong-format';
}
event.sender.send('app-theme-uploaded', {
status: status,
themes: appInstance.themes
});
});
/*
* Add new language
*/
ipcMain.on('app-language-upload', function(event, config) {
let languagesLoader = new Languages(appInstance);
let newLanguageDir = path.parse(config.sourcePath).name;
let extension = path.parse(config.sourcePath).ext;
let status = '';
if (extension === '.zip' || extension === '') {
if (extension === '.zip') {
let zipPath = path.join(languagesLoader.languagesPath, '__TEMP__');
let zip = new AdmZip(config.sourcePath);
fs.mkdirSync(zipPath, { recursive: true });
zip.extractAllTo(zipPath, true);
let dirs = fs.readdirSync(zipPath).filter(function(file) {
if(file.substr(0,1) === '_' || file.substr(0,1) === '.') {
return false;
}
return fs.statSync(path.join(zipPath, file)).isDirectory();
});
if (dirs.length !== 1) {
event.sender.send('app-language-uploaded', {
status: 'wrong-format',
languages: appInstance.languages
});
fs.removeSync(zipPath);
return;
}
newLanguageDir = dirs[0];
let directoryPath = path.join(languagesLoader.languagesPath, newLanguageDir);
try {
fs.statSync(directoryPath);
status = 'updated';
fs.removeSync(directoryPath);
} catch (e) {
status = 'added';
}
fs.copySync(path.join(zipPath, newLanguageDir), directoryPath);
fs.removeSync(zipPath);
appInstance.languages = languagesLoader.loadLanguages();
event.sender.send('app-language-uploaded', {
status: status,
languages: appInstance.languages
});
return;
} else {
let directoryPath = path.join(languagesLoader.languagesPath, newLanguageDir);
try {
fs.statSync(directoryPath);
status = 'updated';
fs.removeSync(directoryPath);
} catch (e) {
status = 'added';
}
fs.copySync(config.sourcePath, directoryPath);
appInstance.languages = languagesLoader.loadLanguages();
}
} else {
status = 'wrong-format';
}
event.sender.send('app-language-uploaded', {
status: status,
languages: appInstance.languages
});
});
/*
* Add new plugin
*/
ipcMain.on('app-plugin-upload', function(event, config) {
let pluginsLoader = new Plugins(appInstance.appDir, appInstance.sitesDir);
let newPluginDir = path.parse(config.sourcePath).name;
let extension = path.parse(config.sourcePath).ext;
let status = '';
if (extension === '.zip' || extension === '') {
if (extension === '.zip') {
let zipPath = path.join(pluginsLoader.pluginsPath, '__TEMP__');
fs.mkdirSync(zipPath, { recursive: true });
let zip = new AdmZip(config.sourcePath);
zip.extractAllTo(zipPath, true);
let dirs = fs.readdirSync(zipPath).filter(function(file) {
if(file.substr(0,1) === '_' || file.substr(0,1) === '.') {
return false;
}
return fs.statSync(path.join(zipPath, file)).isDirectory();
});
if (dirs.length !== 1) {
event.sender.send('app-plugin-uploaded', {
status: 'wrong-format',
plugins: appInstance.plugins
});
fs.removeSync(zipPath);
return;
}
newPluginDir = dirs[0];
let directoryPath = path.join(pluginsLoader.pluginsPath, newPluginDir);
try {
fs.statSync(directoryPath);
status = 'updated';
fs.removeSync(directoryPath);
} catch (e) {
status = 'added';
}
fs.copySync(path.join(zipPath, newPluginDir), directoryPath);
fs.removeSync(zipPath);
appInstance.plugins = pluginsLoader.loadPlugins();
event.sender.send('app-plugin-uploaded', {
status: status,
plugins: appInstance.plugins
});
return;
} else {
let directoryPath = path.join(pluginsLoader.pluginsPath, newPluginDir);
try {
fs.statSync(directoryPath);
status = 'updated';
fs.removeSync(directoryPath);
} catch (e) {
status = 'added';
}
fs.copySync(config.sourcePath, directoryPath);
appInstance.plugins = pluginsLoader.loadPlugins();
}
} else {
status = 'wrong-format';
}
event.sender.send('app-plugin-uploaded', {
status: status,
plugins: appInstance.plugins
});
});
/*
* Load log files list
*/
ipcMain.on('app-log-files-load', function(event) {
let logPath = appInstance.app.getPath('logs');
let files = fs.readdirSync(logPath).filter(function(file) {
return file.substr(-4) === '.txt' || file.substr(-4) === '.log';
});
event.sender.send('app-log-files-loaded', {
files: files
});
});
/*
* Load specific log file
*/
ipcMain.on('app-log-file-load', function(event, filename) {
let logPath = appInstance.app.getPath('logs');
let logFiles = fs.readdirSync(logPath).filter(function(file) {
return file.substr(-4) === '.txt' || file.substr(-4) === '.log';
});
if (logFiles.indexOf(filename) === -1) {
event.sender.send('app-log-file-loaded', {
fileContent: 'File not found!'
});
}
let filePath = path.join(appInstance.app.getPath('logs'), filename);
let fileContent = FileHelper.readFileSync(filePath, 'utf8');
event.sender.send('app-log-file-loaded', {
fileContent: fileContent
});
});
/*
* Set zoom level
*/
ipcMain.on('app-set-ui-zoom-level', function(event, zoomLevel) {
zoomLevel = parseFloat(zoomLevel);
if (!zoomLevel || zoomLevel < 0 || zoomLevel > 2.5) {
console.log('(!) Invalid zoom level: ', parseFloat(zoomLevel));
return;
}
let appConfig = FileHelper.readFileSync(appInstance.appConfigPath, 'utf8');
try {
appConfig = JSON.parse(appConfig);
appConfig.uiZoomLevel = zoomLevel;
fs.writeFileSync(appInstance.appConfigPath, JSON.stringify(appConfig, null, 4));
} catch (e) {
console.log('(!) App was unable to save the UI zoom level');
}
appInstance.mainWindow.webContents.setZoomFactor(zoomLevel);
});
/**
* Set notifications center state
*/
ipcMain.on('app-set-notifications-center-state', function(event, state) {
let appConfig = fs.readFileSync(appInstance.appConfigPath, 'utf8');
try {
appConfig = JSON.parse(appConfig);
appConfig.notificationsStatus = state;
fs.writeFileSync(appInstance.appConfigPath, JSON.stringify(appConfig, null, 4));
} catch (e) {
console.log('(!) App was unable to save the notifications center state');
}
});
}
}
module.exports = AppEvents;
================================================
FILE: app/back-end/events/author.js
================================================
const ipcMain = require('electron').ipcMain;
const Author = require('../author.js');
/*
* Events for the IPC communication regarding single tags
*/
class AuthorEvents {
constructor(appInstance) {
// Save
ipcMain.on('app-author-save', function (event, authorData) {
let author = new Author(appInstance, authorData);
let result = author.save();
event.sender.send('app-author-saved', result);
});
// Delete
ipcMain.on('app-author-delete', function (event, authorData) {
let result = false;
for(let i = 0; i < authorData.ids.length; i++) {
let author = new Author(appInstance, {
site: authorData.site,
id: authorData.ids[i]
});
result = author.delete();
}
event.sender.send('app-author-deleted', result);
});
// Cancelled edition
ipcMain.on('app-author-cancel', function(event, authorData) {
let author = new Author(appInstance, authorData);
let result = author.checkAndCleanImages(true);
event.sender.send('app-author-cancelled', result);
});
}
}
module.exports = AuthorEvents;
================================================
FILE: app/back-end/events/authors.js
================================================
const ipcMain = require('electron').ipcMain;
const Posts = require('../posts.js');
const Authors = require('../authors.js');
/*
* Events for the IPC communication regarding authors list
*/
class AuthorsEvents {
constructor(appInstance) {
// Load
ipcMain.on('app-tags-load', function (event, siteData) {
let postsData = new Posts(appInstance, siteData);
let authorsData = new Authors(appInstance, siteData);
event.sender.send('app-tags-loaded', {
authors: authorsData.load(),
postsAuthors: postsData.loadAuthorsXRef()
});
});
}
}
module.exports = AuthorsEvents;
================================================
FILE: app/back-end/events/backup.js
================================================
const fs = require('fs-extra');
const path = require('path');
const ipcMain = require('electron').ipcMain;
const Backup = require('../modules/backup/backup.js');
class BackupEvents {
constructor(appInstance) {
let self = this;
this.app = appInstance;
this.backupsLocation = this.app.appConfig.backupsLocation;
if (this.backupsLocation === '') {
this.backupsLocation = path.join(this.app.appDir, 'backups');
}
ipcMain.on('app-backups-list-load', function (event, siteData) {
if(siteData.site) {
self.loadBackupsList(siteData.site, event);
} else {
event.sender.send('app-backups-list-loaded', {
status: false
});
}
});
ipcMain.on('app-backup-create', function(event, siteData) {
if(siteData.site) {
self.createBackup(siteData.site, siteData.filename, event);
} else {
event.sender.send('app-backup-created', {
status: false
});
}
});
ipcMain.on('app-backup-remove', function(event, siteData) {
if(siteData.site && siteData.backupsNames) {
self.removeBackups(siteData.site, siteData.backupsNames, event);
} else {
event.sender.send('app-backup-removed', {
status: false
});
}
});
ipcMain.on('app-backup-rename', function(event, siteData) {
if(siteData.site && siteData.oldBackupName && siteData.newBackupName) {
self.renameBackup(siteData.site, siteData.oldBackupName, siteData.newBackupName, event);
} else {
event.sender.send('app-backup-renamed', {
status: false
});
}
});
ipcMain.on('app-backup-restore', function(event, siteData) {
if(siteData.site && siteData.backupName) {
self.restoreBackup(siteData.site, siteData.backupName, event);
} else {
event.sender.send('app-backup-restored', {
status: false
});
}
});
ipcMain.on('app-backup-set-location', (event, newLocation) => {
this.backupsLocation = newLocation;
if (this.backupsLocation === '') {
this.backupsLocation = path.join(this.app.appDir, 'backups');
}
});
}
loadBackupsList(siteName, event) {
let backups = Backup.loadList(siteName, this.backupsLocation);
event.sender.send('app-backups-list-loaded', {
status: true,
backups: backups
});
}
async removeBackups(siteName, backupsNames, event) {
let result = await Backup.remove(siteName, backupsNames, this.backupsLocation);
event.sender.send('app-backup-removed', {
status: result.status,
backups: result.backups
});
}
renameBackup(siteName, oldBackupName, newBackupName, event) {
let result = Backup.rename(siteName, oldBackupName, newBackupName, this.backupsLocation);
event.sender.send('app-backup-renamed', {
status: result.status,
backups: result.backups
});
}
async createBackup(siteName, filename, event) {
let backupsDir = this.backupsLocation;
let sourceDir = path.join(this.app.sitesDir, siteName);
let backupResult = await Backup.create(siteName, filename, backupsDir, sourceDir);
if (backupResult.type === 'app-backup-create-success') {
event.sender.send('app-backup-created', {
status: true,
backups: backupResult.backups
});
} else {
event.sender.send('app-backup-created', {
status: false,
error: backupResult.error
});
}
}
async restoreBackup(siteName, backupName, event) {
let backupsDir = this.backupsLocation;
let destinationDir = this.app.sitesDir;
let tempDir = path.join(this.app.appDir, 'temp');
let backupResult = await Backup.restore(siteName, backupName, backupsDir, destinationDir, tempDir, this.app);
if (backupResult.type === 'app-backup-restore-success') {
event.sender.send('app-backup-restored', {
status: true
});
} else {
event.sender.send('app-backup-restored', {
status: false,
error: backupResult.error
});
}
}
}
module.exports = BackupEvents;
================================================
FILE: app/back-end/events/content.js
================================================
const ipcMain = require('electron').ipcMain;
const Model = require('../model.js');
/*
* Events for the IPC communication regarding content items
*/
class ContentEvents {
constructor(appInstance) {
// Save
ipcMain.on('app-content-fields-update', function (event, contentData) {
let model = new Model(appInstance, {
site: contentData.site
});
let result = model.updateField(contentData.table, contentData.itemID, contentData.fieldsToUpdate);
event.sender.send('app-content-fields-updated', result);
});
}
}
module.exports = ContentEvents;
================================================
FILE: app/back-end/events/credits.js
================================================
const fs = require('fs-extra');
const path = require('path');
const ipcMain = require('electron').ipcMain;
const FileHelper = require('../helpers/file.js');
/*
* Events for the IPC communication regarding credits
*/
class CreditsEvents {
constructor(appInstance) {
/*
* Load license text
*/
ipcMain.on('app-license-load', function(event, config) {
let filePath = path.join(__dirname, '../../', config.url);
let licenseText = {
translation: 'core.credits.errorLoadingLicenseMsg'
}
if(fs.existsSync(filePath)) {
licenseText = FileHelper.readFileSync(filePath, 'utf-8');
}
event.sender.send('app-license-loaded', licenseText);
});
}
}
module.exports = CreditsEvents;
================================================
FILE: app/back-end/events/deploy.js
================================================
const fs = require('fs-extra');
const ipcMain = require('electron').ipcMain;
const Deployment = require('../modules/deploy/deployment.js');
const childProcess = require('child_process');
const stripTags = require('striptags');
class DeployEvents {
constructor(appInstance) {
let self = this;
this.app = appInstance;
this.deploymentProcess = false;
this.rendererProcess = false;
ipcMain.on('app-deploy-render', function (event, siteData) {
if(siteData.site && siteData.theme) {
self.renderSite(siteData.site, event);
} else {
event.sender.send('app-deploy-rendered', {
status: false
});
}
});
ipcMain.on('app-deploy-render-abort', function(event, siteData) {
if(self.rendererProcess) {
try {
self.rendererProcess.send({
type: 'abort'
});
self.rendererProcess = false;
} catch(e) {
console.log(e);
self.rendererProcess = false;
}
}
event.sender.send('app-deploy-aborted', true);
});
ipcMain.on('app-deploy-upload', function(event, siteData) {
if(siteData.site) {
self.deploySite(siteData.site, siteData.password, event.sender);
} else {
event.sender.send('app-deploy-uploaded', {
status: false
});
}
});
ipcMain.on('app-deploy-abort', function(event, siteData) {
if(self.deploymentProcess) {
try {
self.deploymentProcess.send({
type: 'abort'
});
self.deploymentProcess = false;
} catch(e) {
console.log(e);
self.deploymentProcess = false;
}
}
event.sender.send('app-deploy-aborted', true);
});
ipcMain.on('app-deploy-continue', function() {
if (self.deploymentProcess) {
try {
self.deploymentProcess.send({
type: 'continue-sync'
});
self.deploymentProcess = false;
} catch(e) {
console.log(e);
self.deploymentProcess = false;
}
}
});
ipcMain.on('app-deploy-test', async (event, data) => {
try {
await this.testConnection(data.deploymentConfig, data.siteName, data.uuid);
} catch (err) {
console.log('Test connection error:', err);
}
});
}
renderSite(site, event) {
this.rendererProcess = childProcess.fork(__dirname + '/../workers/renderer/preview', {
stdio: [
null,
fs.openSync(this.app.app.getPath('logs') + "/rendering-deployment-process.log", "w"),
fs.openSync(this.app.app.getPath('logs') + "/rendering-deployment-errors.log", "w"),
'ipc'
]
});
this.rendererProcess.send({
type: 'dependencies',
appDir: this.app.appDir,
sitesDir: this.app.sitesDir,
siteConfig: this.app.sites[site],
itemID: false,
postData: false,
previewMode: false,
singlePageMode: false,
homepageOnlyMode: false,
tagOnlyMode: false,
authorOnlyMode: false,
previewLocation: this.app.appConfig.previewLocation
});
this.rendererProcess.on('message', function(data) {
if(data.type === 'app-rendering-results') {
if(data.result === true) {
event.sender.send('app-deploy-rendered', {
status: true
});
} else {
let errorDesc = {
translation: 'core.rendering.renderingProcessCrashedMsg'
};
let errorTitle = {
translation: 'core.rendering.renderingProcessCrashed'
};
if (data.result && data.result[0] && data.result[0].message) {
errorTitle = {
translation: 'core.rendering.renderingProcessFailed'
};
errorDesc = data.result[0].message + "\n\n" + data.result[0].desc;
}
event.sender.send('app-deploy-render-error', {
message: [{
message: errorTitle,
desc: stripTags((errorDesc).toString())
}]
});
}
} else {
event.sender.send(data.type, {
progress: data.progress,
message: stripTags((data.message).toString())
});
}
});
}
deploySite(site, password, sender) {
let self = this;
let deploymentConfig = this.app.sites[site];
this.deploymentProcess = childProcess.fork(__dirname + '/../workers/deploy/deployment', {
stdio: [
null,
fs.openSync(this.app.app.getPath('logs') + "/deployment-process.log", "w"),
fs.openSync(this.app.app.getPath('logs') + "/deployment-errors.log", "w"),
'ipc'
]
});
if(password !== false) {
deploymentConfig.deployment.password = password;
}
this.deploymentProcess.send({
type: 'dependencies',
appDir: this.app.appDir,
sitesDir: this.app.sitesDir,
siteConfig: deploymentConfig,
useFtpAlt: this.app.appConfig.experimentalFeatureAppFtpAlt
});
this.deploymentProcess.on('message', function(data) {
if (data.type === 'web-contents') {
if(data.value) {
self.app.mainWindow.webContents.send(data.message, data.value);
} else {
self.app.mainWindow.webContents.send(data.message);
}
}
if(data.type === 'sender') {
sender.send(data.message, data.value);
}
});
}
async testConnection(deploymentConfig, siteName, uuid) {
let deployment = new Deployment(
this.app.app.getPath('logs'),
this.app.sitesDir,
deploymentConfig,
this.app.appConfig.experimentalFeatureAppFtpAlt
);
await deployment.testConnection(this.app, deploymentConfig, siteName, uuid);
}
}
module.exports = DeployEvents;
================================================
FILE: app/back-end/events/file-manager.js
================================================
const fs = require('fs-extra');
const path = require('path');
const ipcMain = require('electron').ipcMain;
const isBinaryFileSync = require('isbinaryfile').isBinaryFileSync;
/*
* Events for the IPC communication regarding file manager
*/
class FileManagerEvents {
/**
* Creating an events instance
*
* @param appInstance
*/
constructor (appInstance) {
let self = this;
this.app = appInstance;
/*
* List files in a specific directory
*/
ipcMain.on('app-file-manager-list', function(event, config) {
self.listFiles(config, event.sender);
});
/*
* Upload file
*/
ipcMain.on('app-file-manager-upload', function(event, config) {
self.uploadFile(config, event.sender);
});
/*
* Create file
*/
ipcMain.on('app-file-manager-create', function(event, config) {
self.createFile(config, event.sender);
});
/*
* Delete files
*/
ipcMain.on('app-file-manager-delete', function(event, config) {
self.deleteFiles(config, event.sender);
});
/*
* Check filename
*/
ipcMain.on('app-file-manager-check-name', function(event, config) {
self.checkFilename(config, event.sender);
});
}
/**
* Listing files from a specific directory
*
* @param config
* @param sender
*/
listFiles(config, sender) {
let siteName = config.siteName;
let dirPath = config.dirPath;
let basePath = path.join(this.app.sitesDir, siteName, 'input', dirPath);
let files = fs.readdirSync(basePath);
let output = [];
let iterator = 0;
for(let file of files) {
if(file === '.DS_Store' || file === 'Thumbs.db') {
continue;
}
let fullPath = path.join(basePath, file);
let fileStats = fs.statSync(fullPath);
let isDirectory = fileStats.isDirectory();
output.push({
name: file,
fullPath: fullPath,
icon: this.getIcon(path.parse(file).ext, isDirectory),
size: fileStats.size,
isBinary: false,
isCatalog: isDirectory,
createdAt: fileStats.ctime,
modifiedAt: fileStats.mtime
});
}
this.checkIfIsBinaryFile(output, 0, sender);
}
/**
* Checks if files are binary
*
* @param output
* @param iterator
* @param sender
*/
checkIfIsBinaryFile(output, iterator, sender) {
if(!output.length || iterator >= output.length) {
sender.send('app-file-manager-listed', output);
return;
}
if (output[iterator] && output[iterator].fullPath && fs.lstatSync(output[iterator].fullPath).isFile()) {
output[iterator].isBinary = isBinaryFileSync(output[iterator].fullPath);
}
iterator++;
this.checkIfIsBinaryFile(output, iterator, sender);
}
/**
* Returns icon file string according to given extension
*
* @param extension
* @return icon string
*/
getIcon(extension, isDirectory = false) {
if (isDirectory) {
return 'catalog';
}
extension = extension.replace('.', '');
switch(extension) {
case '':
case 'txt':
case 'rdf':
return 'txt';
case 'doc':
return 'doc';
case 'docx':
return 'docx';
case 'xls':
return 'xls';
case 'xlsx':
return 'xlsx';
case 'pdf':
return 'pdf';
case 'asp':
case 'aspx':
case 'cfm':
case 'cgi':
case 'pl':
case 'jsp':
case 'php':
case 'py':
case 'rss':
case 'xhtml':
case 'vue':
case 'scss':
return 'code';
case 'js':
return 'js';
case 'css':
return 'css';
case 'html':
return 'html';
case 'htm':
return 'htm';
case 'xml':
return 'xml';
case 'webp':
return 'webp';
case 'bmp':
return 'img';
case 'tiff':
return 'tiff';
case 'avif':
return 'avif';
case 'jpg':
return 'jpg';
case 'jpeg':
return 'jpeg';
case 'png':
return 'png';
case 'svg':
return 'svg';
case 'gif':
return 'gif';
case 'webm':
case 'ogg':
case 'flv':
case 'wmv':
case 'm4v':
case '3gp':
case '3g2':
case 'mkv':
case 'mpg':
case 'mpeg':
case 'rm':
case 'swf':
case 'vob':
return 'video';
case 'avi':
return 'avi';
case 'mov':
return 'mov';
case 'mp4':
return 'mp4';
case 'tar':
case 'zip':
case 'gz':
case 'iso':
case 'dmg':
case 'bz2':
case 'lz':
case 'ace':
case 'apk':
case 'jar':
return 'zip';
case '7z':
return '7z';
case 'rar':
return 'rar';
case 'mp3':
case '3gp':
case 'aac':
case 'aax':
case 'flac':
case 'm4p':
case 'ogg':
case 'wav':
case 'wma':
case 'vox':
return 'music';
default:
return 'unknown';
}
}
/**
* Move file from a given location to specified catalog
*
* @param config
* @param sender
*/
uploadFile(config, sender) {
let siteName = config.siteName;
let dirPath = config.dirPath;
let fileToMove = config.fileToMove;
let fileName = path.parse(fileToMove).base;
let destinationPath = path.join(this.app.sitesDir, siteName, 'input', dirPath);
let fullPath = path.join(destinationPath, fileName);
if(fs.existsSync(fullPath)) {
sender.send('app-file-manager-uploaded', false);
}
fs.copySync(fileToMove, fullPath);
sender.send('app-file-manager-uploaded', true);
}
/**
* Create new file
*
* @param config
* @param sender
*/
createFile(config, sender) {
let siteName = config.siteName;
let dirPath = config.dirPath;
let fileToSave = config.fileToSave;
let filePath = path.join(this.app.sitesDir, siteName, 'input', dirPath, fileToSave);
if(fs.existsSync(filePath)) {
sender.send('app-file-manager-created', false);
return;
}
fs.writeFileSync(filePath, '', {'encoding': 'utf8'})
sender.send('app-file-manager-created', true);
}
/**
* Delete files
*
* @param config
* @param sender
*/
deleteFiles(config, sender) {
let siteName = config.siteName;
let dirPath = config.dirPath;
let filesToDelete = config.filesToDelete;
for(let file of filesToDelete) {
let fullPath = path.join(this.app.sitesDir, siteName, 'input', dirPath, file);
if(fs.existsSync(fullPath)) {
fs.unlinkSync(fullPath);
}
}
sender.send('app-file-manager-deleted', true);
}
/**
* Check if filename exists
*
* @param config
* @param sender
*/
checkFilename(config, sender) {
let siteName = config.siteName;
let dirPath = config.dirPath;
let filenameToCheck = config.filenameToCheck;
let fullPath = path.join(this.app.sitesDir, siteName, 'input', dirPath, filenameToCheck);
let result = fs.existsSync(fullPath);
sender.send('app-file-manager-checked-name', result);
}
}
module.exports = FileManagerEvents;
================================================
FILE: app/back-end/events/image-uploader.js
================================================
const fs = require('fs');
const path = require('path');
const ipcMain = require('electron').ipcMain;
const Image = require('../image.js');
const childProcess = require('child_process');
/*
* Events for the IPC communication regarding post images
*/
class ImageUploaderEvents {
constructor(appInstance) {
// Upload
ipcMain.on('app-image-upload', function (event, imageData) {
let imageProcess = childProcess.fork(__dirname + '/../workers/thumbnails/post-images');
imageProcess.send({
type: 'dependencies',
appInstance: {
appConfig: appInstance.appConfig,
appDir: appInstance.appDir,
sitesDir: appInstance.sitesDir,
db: appInstance.db
},
imageData: imageData
});
imageProcess.on('message', function(data) {
if(data.type === 'image-copied') {
imageProcess.send({
type: 'start-regenerating'
});
} else if(data.type === 'finished') {
event.sender.send('app-image-uploaded', data.result);
}
});
});
// Remove
ipcMain.on('app-image-upload-remove', function (event, filePath, siteName) {
let sitePath = path.join(appInstance.sitesDir, siteName);
if (filePath.indexOf('media/plugins/') === 0) {
filePath = path.join(sitePath, 'input', filePath);
}
if (filePath.indexOf(sitePath) !== 0) {
return;
}
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
}
});
}
}
module.exports = ImageUploaderEvents;
================================================
FILE: app/back-end/events/import.js
================================================
const fs = require('fs-extra');
const path = require('path');
const ipcMain = require('electron').ipcMain;
const Import = require('../modules/import/import.js');
const childProcess = require('child_process');
/*
* Events for the IPC communication regarding imports
*/
class ImportEvents {
/**
* Creating an events instance
*
* @param appInstance
*/
constructor(appInstance) {
let self = this;
this.app = appInstance;
/*
* Import WXR file
*/
ipcMain.on('app-wxr-check', function(event, config) {
self.checkFile(config.siteName, config.filePath, event.sender);
});
ipcMain.on('app-wxr-import', function(event, config) {
self.importFile(appInstance, config, event.sender);
});
}
/**
* Checking the WXR file
*
* @param siteName
* @param filePath
*/
checkFile(siteName, filePath, sender) {
let importProcess = childProcess.fork(__dirname + '/../workers/import/check', {
stdio: [
null,
fs.openSync(this.app.app.getPath('logs') + "/import-check-process.log", "w"),
fs.openSync(this.app.app.getPath('logs') + "/import-check-errors.log", "w"),
'ipc'
]
});
importProcess.send({
type: 'dependencies',
siteName: siteName,
filePath: filePath
});
importProcess.on('message', function(data) {
sender.send('app-wxr-checked', data);
});
}
/**
* Imports data from the WXR file
*
* @param appInstance
* @param config
*/
importFile(appInstance, config, sender) {
let importProcess = childProcess.fork(__dirname + '/../workers/import/import', {
stdio: [
null,
fs.openSync(this.app.app.getPath('logs') + "/import-process.log", "w"),
fs.openSync(this.app.app.getPath('logs') + "/import-errors.log", "w"),
'ipc'
]
});
importProcess.send({
type: 'dependencies',
appInstance: {
appDir: appInstance.appDir,
sitesDir: appInstance.sitesDir,
sites: appInstance.sites
},
siteName: config.siteName,
filePath: config.filePath,
importAuthors: config.importAuthors,
usedTaxonomy: config.usedTaxonomy,
autop: config.autop,
postTypes: config.postTypes
});
importProcess.on('message', function(data) {
if(data.type === 'result') {
sender.send('app-wxr-imported', data);
} else {
sender.send('app-wxr-import-progress', data);
}
});
}
}
module.exports = ImportEvents;
================================================
FILE: app/back-end/events/menu.js
================================================
const fs = require('fs-extra');
const path = require('path');
const ipcMain = require('electron').ipcMain;
/*
* Events for the IPC communication regarding menu events
*/
class MenuEvents {
constructor(appInstance) {
let self = this;
this.app = appInstance;
/*
* Save information about menu
*/
ipcMain.on('app-menu-update', function (event, data) {
self.saveNewMenuStructure(data.menuStructure, data.siteName);
event.sender.send('app-menu-updated', true);
});
}
saveNewMenuStructure(menuStructure, siteName) {
let menuFile = path.join(this.app.sitesDir, siteName, 'input', 'config', 'menu.config.json');
fs.writeFileSync(menuFile, JSON.stringify(menuStructure, null, 4), { encoding: 'utf8' });
}
}
module.exports = MenuEvents;
================================================
FILE: app/back-end/events/notifications.js
================================================
const ipcMain = require('electron').ipcMain;
const path = require('path');
const UpdatesHelper = require('../helpers/updates.helper.js');
/*
* Events for the IPC communication regarding notifications
*/
class NotificationsEvents {
constructor(appInstance) {
// Save
ipcMain.on('app-notifications-retrieve', function(event, downloadNotifications) {
let platform;
if (process.platform === 'darwin') {
platform = process.arch === 'arm64' ? 'mac-arm64' : 'mac-x86';
} else if (process.platform === 'win32') {
platform = 'win';
} else {
platform = 'linux';
}
let updatesHelper = new UpdatesHelper({
event: event,
filePath: path.join(appInstance.app.getPath('logs'), 'updates.json'),
url: 'https://notifications.getpublii.com/updates-' + platform + '.json',
forceDownload: downloadNotifications
});
updatesHelper.retrieve();
});
// Get notifications file
ipcMain.handle('app-get-notifications-file', async (event, fileName) => {
let filePath = path.join(appInstance.app.getPath('logs'), fileName);
try {
let data = await appInstance.app.readFile(filePath, 'utf8');
return JSON.parse(data);
} catch (error) {
console.error(`Error reading notifications file: ${error.message}`);
return false;
}
});
}
}
module.exports = NotificationsEvents;
================================================
FILE: app/back-end/events/page.js
================================================
const fs = require('fs');
const path = require('path');
const FileHelper = require('../helpers/file.js');
const ipcMain = require('electron').ipcMain;
const Page = require('../page.js');
/*
* Events for the IPC communication regarding pages
*/
class PageEvents {
constructor(appInstance) {
this.app = appInstance;
// Load
ipcMain.on('app-page-load', function (event, pageData) {
let page = new Page(appInstance, pageData);
let result = page.load();
event.sender.send('app-page-loaded', result);
});
// Save
ipcMain.on('app-page-save', function (event, pageData) {
let page = new Page(appInstance, pageData);
let result = page.save();
event.sender.send('app-page-saved', result);
});
// Delete
ipcMain.on('app-page-delete', function (event, pageData) {
let result = false;
for(let i = 0; i < pageData.ids.length; i++) {
let page = new Page(appInstance, {
site: pageData.site,
id: pageData.ids[i]
});
result = page.delete();
}
event.sender.send('app-page-deleted', result);
});
// Delete
ipcMain.on('app-page-duplicate', function (event, pageData) {
let result = false;
for(let i = 0; i < pageData.ids.length; i++) {
let page = new Page(appInstance, {
site: pageData.site,
id: pageData.ids[i]
});
result = page.duplicate();
}
event.sender.send('app-page-duplicated', result);
});
// Status change
ipcMain.on('app-page-status-change', function (event, pageData) {
let result = false;
for(let i = 0; i < pageData.ids.length; i++) {
let page = new Page(appInstance, {
site: pageData.site,
id: pageData.ids[i]
});
result = page.changeStatus(pageData.status, pageData.inverse);
}
event.sender.send('app-page-status-changed', result);
});
// Cancelled edition
ipcMain.on('app-page-cancel', function(event, pageData) {
let page = new Page(appInstance, pageData);
let result = page.checkAndCleanImages(true);
event.sender.send('app-page-cancelled', result);
});
// Load pages hierarchy
ipcMain.on('app-pages-hierarchy-load', (event, siteName) => {
let pagesFile = path.join(this.app.sitesDir, siteName, 'input', 'config', 'pages.config.json');
if (fs.existsSync(pagesFile)) {
let pagesHierarchy = JSON.parse(FileHelper.readFileSync(pagesFile, { encoding: 'utf8' }));
pagesHierarchy = this.removeDuplicatedDataFromHierarchy(pagesHierarchy);
event.sender.send('app-pages-hierarchy-loaded', pagesHierarchy);
} else {
event.sender.send('app-pages-hierarchy-loaded', null);
}
});
// Save pages hierarchy
ipcMain.on('app-pages-hierarchy-save', (event, pagesData) => {
let pagesFile = path.join(this.app.sitesDir, pagesData.siteName, 'input', 'config', 'pages.config.json');
pagesData.hierarchy = this.removeNullDataFromHierarchy(pagesData.hierarchy);
pagesData.hierarchy = this.removeDuplicatedDataFromHierarchy(pagesData.hierarchy);
fs.writeFileSync(pagesFile, JSON.stringify(pagesData.hierarchy, null, 4), { encoding: 'utf8' });
});
// Update pages hierarchy during post conversion
ipcMain.on('app-pages-hierarchy-update', (event, conversionData) => {
let pagesFile = path.join(this.app.sitesDir, conversionData.siteName, 'input', 'config', 'pages.config.json');
let pagesHierarchy = JSON.parse(FileHelper.readFileSync(pagesFile, { encoding: 'utf8' }));
for (let i = 0; i < conversionData.postIDs.length; i++) {
pagesHierarchy.push({
id: conversionData.postIDs[i],
subpages: []
});
}
pagesHierarchy = this.removeNullDataFromHierarchy(pagesHierarchy);
pagesHierarchy = this.removeDuplicatedDataFromHierarchy(pagesHierarchy);
fs.writeFileSync(pagesFile, JSON.stringify(pagesHierarchy, null, 4), { encoding: 'utf8' });
});
}
removeNullDataFromHierarchy (data) {
return data
.filter(item => item !== null)
.map(item => ({
...item,
subpages: item.subpages ? this.removeNullDataFromHierarchy(item.subpages) : []
}));
}
removeDuplicatedDataFromHierarchy (data) {
let existingIds = new Set();
return data.filter(item => {
if (existingIds.has(item.id)) {
return false;
}
existingIds.add(item.id);
return true;
});
}
}
module.exports = PageEvents;
================================================
FILE: app/back-end/events/plugin.js
================================================
const ipcMain = require('electron').ipcMain;
const Plugins = require('../plugins.js');
/*
* Events for the IPC communication regarding plugins
*/
class PluginEvents {
constructor(appInstance) {
// Get plugins status
ipcMain.on('app-site-get-plugins-state', function (event, data) {
let pluginsInstance = new Plugins(appInstance.appDir, appInstance.sitesDir);
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let pluginsStatus = pluginsInstance.getSiteSpecificPluginsState(siteName);
event.sender.send('app-site-plugins-state-loaded', pluginsStatus);
});
// Activate
ipcMain.on('app-site-plugin-activate', function (event, data) {
let pluginsInstance = new Plugins(appInstance.appDir, appInstance.sitesDir);
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let pluginName = data.pluginName.replace(/[\/\\]/gmi, '');
let result = pluginsInstance.activatePlugin(siteName, pluginName);
event.sender.send('app-site-plugin-activated', result);
});
// Deactivate
ipcMain.on('app-site-plugin-deactivate', function (event, data) {
let pluginsInstance = new Plugins(appInstance.appDir, appInstance.sitesDir);
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let pluginName = data.pluginName.replace(/[\/\\]/gmi, '');
let result = pluginsInstance.deactivatePlugin(siteName, pluginName);
event.sender.send('app-site-plugin-deactivated', result);
});
// Get plugin info and config
ipcMain.on('app-site-get-plugin-config', function (event, data) {
let pluginsInstance = new Plugins(appInstance.appDir, appInstance.sitesDir);
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let pluginName = data.pluginName.replace(/[\/\\]/gmi, '');
let result = pluginsInstance.getPluginConfig(siteName, pluginName);
event.sender.send('app-site-get-plugin-config-retrieved', result);
});
// Save plugin config
ipcMain.on('app-site-save-plugin-config', function (event, data) {
let pluginsInstance = new Plugins(appInstance.appDir, appInstance.sitesDir);
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let pluginName = data.pluginName.replace(/[\/\\]/gmi, '');
let result = pluginsInstance.savePluginConfig(siteName, pluginName, data.newConfig);
event.sender.send('app-site-plugin-config-saved', result);
});
}
}
module.exports = PluginEvents;
================================================
FILE: app/back-end/events/plugins-api.js
================================================
const ipcMain = require('electron').ipcMain;
const fs = require('fs');
const path = require('path');
const FileHelper = require('../helpers/file.js');
/*
* Events for the IPC communication regarding plugins
*/
class PluginsApiEvents {
constructor (appInstance) {
// Read file in site
ipcMain.handle('app-plugins-api:read-config-file', function (event, data) {
let fileName = data.fileName.replace(/a-zA-Z0-9\-\_\.\*\@\+/gmi, '');
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let pluginName = data.pluginName.replace(/[\/\\]/gmi, '');
let filePath = path.join(appInstance.sitesDir, siteName, 'input', 'config', 'plugins', pluginName, fileName);
if (!fs.existsSync(filePath)) {
return false;
}
let fileContent = FileHelper.readFileSync(filePath);
fileContent = fileContent.toString();
return fileContent;
});
// Read file in the languages
ipcMain.handle('app-plugins-api:read-language-file', function (event, data) {
let fileName = data.fileName.replace(/a-zA-Z0-9\-\_\.\*\@\+/gmi, '');
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let filePath = path.join(appInstance.sitesDir, siteName, 'input', 'languages', fileName);
if (!fs.existsSync(filePath)) {
return false;
}
let fileContent = FileHelper.readFileSync(filePath);
fileContent = fileContent.toString();
return fileContent;
});
// Read file in the themes
ipcMain.handle('app-plugins-api:read-theme-file', function (event, data) {
let fileName = data.fileName.replace(/a-zA-Z0-9\-\_\.\*\@\+/gmi, '');
let themeName = data.themeName.replace(/a-zA-Z0-9\-\_\.\*\@\+/gmi, '');
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let filePath = path.join(appInstance.sitesDir, siteName, 'input', 'themes', themeName, fileName);
if (!fs.existsSync(filePath)) {
return false;
}
let fileContent = FileHelper.readFileSync(filePath);
fileContent = fileContent.toString();
return fileContent;
});
// Save file in site
ipcMain.handle('app-plugins-api:save-config-file', function (event, data) {
let fileName = data.fileName.replace(/a-zA-Z0-9\-\_\.\*\@\+/gmi, '');
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let pluginName = data.pluginName.replace(/[\/\\]/gmi, '');
let filePath = path.join(appInstance.sitesDir, siteName, 'input', 'config', 'plugins', pluginName, fileName);
if (!fs.existsSync(path.join(appInstance.sitesDir, siteName, 'input', 'config', 'plugins', pluginName))) {
fs.mkdirSync(path.join(appInstance.sitesDir, siteName, 'input', 'config', 'plugins', pluginName), { recursive: true });
}
try {
fs.writeFileSync(filePath, data.fileContent);
return { status: 'FILE_SAVED' };
} catch (e) {
return { status: 'FILE_NOT_SAVED' };
}
});
// Save file in languages
ipcMain.handle('app-plugins-api:save-language-file', function (event, data) {
let fileName = data.fileName.replace(/a-zA-Z0-9\-\_\.\*\@\+/gmi, '');
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let dirPath = path.join(appInstance.sitesDir, siteName, 'input', 'languages');
let filePath = path.join(appInstance.sitesDir, siteName, 'input', 'languages', fileName);
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
try {
fs.writeFileSync(filePath, data.fileContent);
return { status: 'FILE_SAVED' };
} catch (e) {
return { status: 'FILE_NOT_SAVED' };
}
});
// Delete file in site
ipcMain.handle('app-plugins-api:delete-config-file', function (event, data) {
let fileName = data.fileName.replace(/a-zA-Z0-9\-\_\.\*\@\+/gmi, '');
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let pluginName = data.pluginName.replace(/[\/\\]/gmi, '');
let filePath = path.join(appInstance.sitesDir, siteName, 'input', 'config', 'plugins', pluginName, fileName);
if (!fs.existsSync(filePath)) {
return { status: 'FILE_TO_REMOVE_NOT_EXISTS' };
}
try {
fs.unlinkSync(filePath);
return { status: 'FILE_REMOVED' };
} catch (e) {
return { status: 'FILE_NOT_REMOVED' };
}
});
// Delete file in site
ipcMain.handle('app-plugins-api:delete-language-file', function (event, data) {
let fileName = data.fileName.replace(/a-zA-Z0-9\-\_\.\*\@\+/gmi, '');
let siteName = data.siteName.replace(/[\/\\]/gmi, '');
let filePath = path.join(appInstance.sitesDir, siteName, 'input', 'languages', fileName);
if (!fs.existsSync(filePath)) {
return { status: 'FILE_TO_REMOVE_NOT_EXISTS' };
}
try {
fs.unlinkSync(filePath);
return { status: 'FILE_REMOVED' };
} catch (e) {
return { status: 'FILE_NOT_REMOVED' };
}
});
}
}
module.exports = PluginsApiEvents;
================================================
FILE: app/back-end/events/post.js
================================================
const ipcMain = require('electron').ipcMain;
const Post = require('../post.js');
/*
* Events for the IPC communication regarding single tags
*/
class PostEvents {
constructor(appInstance) {
// Load
ipcMain.on('app-post-load', function (event, postData) {
let post = new Post(appInstance, postData);
let result = post.load();
event.sender.send('app-post-loaded', result);
});
// Save
ipcMain.on('app-post-save', function (event, postData) {
let post = new Post(appInstance, postData);
let result = post.save();
event.sender.send('app-post-saved', result);
});
// Delete
ipcMain.on('app-post-delete', function (event, postData) {
let result = false;
for(let i = 0; i < postData.ids.length; i++) {
let post = new Post(appInstance, {
site: postData.site,
id: postData.ids[i]
});
result = post.delete();
}
event.sender.send('app-post-deleted', result);
});
// Delete
ipcMain.on('app-post-duplicate', function (event, postData) {
let result = false;
for(let i = 0; i < postData.ids.length; i++) {
let post = new Post(appInstance, {
site: postData.site,
id: postData.ids[i]
});
result = post.duplicate();
}
event.sender.send('app-post-duplicated', result);
});
// Status change
ipcMain.on('app-post-status-change', function (event, postData) {
let result = false;
for(let i = 0; i < postData.ids.length; i++) {
let post = new Post(appInstance, {
site: postData.site,
id: postData.ids[i]
});
result = post.changeStatus(postData.status, postData.inverse);
}
event.sender.send('app-post-status-changed', result);
});
// Cancelled edition
ipcMain.on('app-post-cancel', function(event, postData) {
let post = new Post(appInstance, postData);
let result = post.checkAndCleanImages(true);
event.sender.send('app-post-cancelled', result);
});
}
}
module.exports = PostEvents;
================================================
FILE: app/back-end/events/preview.js
================================================
const fs = require('fs');
const path = require('path');
const electron = require('electron');
const shell = electron.shell;
const ipcMain = electron.ipcMain;
const childProcess = require('child_process');
const UtilsHelper = require('../helpers/utils.js');
const stripTags = require('striptags');
class PreviewEvents {
/**
* Creates preview events
*
* @param appInstance
*/
constructor(appInstance) {
let self = this;
this.app = appInstance;
ipcMain.on('app-preview-render', function (event, siteData) {
if (siteData.site && siteData.theme) {
let itemID = false;
let mode = false;
let postData = false;
let showPreview = true;
if (siteData.itemID !== false && typeof siteData.itemID !== 'undefined') {
itemID = siteData.itemID;
}
if (siteData.mode !== false && typeof siteData.mode !== 'undefined') {
mode = siteData.mode;
}
if (siteData.postData) {
postData = siteData.postData;
}
if (typeof siteData.showPreview !== 'undefined') {
showPreview = siteData.showPreview;
}
self.renderSite(siteData.site, itemID, postData, mode, event, showPreview);
} else {
event.sender.send('app-preview-rendered', {
status: false
});
}
});
}
/**
* Renders website
*
* @param site
* @param pageToRender
* @param postData
* @param event
*/
renderSite(site, itemID, postData, mode, event, showPreview) {
let self = this;
let previewMode = true;
let resultsRetrieved = false;
let rendererProcess = childProcess.fork(__dirname + '/../workers/renderer/preview', {
stdio: [
null,
fs.openSync(this.app.app.getPath('logs') + "/rendering-process.log", "w"),
fs.openSync(this.app.app.getPath('logs') + "/rendering-errors.log", "w"),
'ipc'
]
});
rendererProcess.on('disconnect', function(data) {
setTimeout(function() {
if(!resultsRetrieved) {
let errorDesc = {
translation: 'core.rendering.renderingProcessCrashedMsg'
};
let errorTitle = {
translation: 'core.rendering.renderingProcessCrashed'
};
if (data && data.result && data.result[0] && data.result[0].message) {
errorTitle = {
translation: 'core.rendering.renderingProcessFailed'
};
errorDesc = stripTags((data.result[0].message + "\n\n" + data.result[0].desc).toString());
}
event.sender.send('app-preview-render-error', {
message: [{
message: errorTitle,
desc: errorDesc
}]
});
}
}, 1000);
});
rendererProcess.send({
type: 'dependencies',
appDir: this.app.appDir,
sitesDir: this.app.sitesDir,
siteConfig: this.app.sites[site],
itemID: itemID,
postData: postData,
previewMode: previewMode,
mode: mode,
previewLocation: this.app.appConfig.previewLocation
});
rendererProcess.on('message', function(data) {
resultsRetrieved = true;
if(data.type === 'app-rendering-results') {
if(data.result === true) {
event.sender.send('app-preview-rendered', {
status: true
});
if (showPreview) {
self.showPreview(site, mode);
}
} else {
let errorDesc = 'core.rendering.renderingProcessCrashedMsg';
let errorTitle = 'core.rendering.renderingProcessCrashed';
if (data.result && data.result[0] && data.result[0].message) {
errorTitle = {
translation: 'core.rendering.renderingProcessFailed'
};
errorDesc = stripTags((data.result[0].message + "\n\n" + data.result[0].desc).toString());
}
event.sender.send('app-preview-render-error', {
message: [{
message: errorTitle,
desc: errorDesc
}]
});
}
} else {
event.sender.send(data.type, {
progress: data.progress,
message: stripTags((data.message).toString())
});
}
});
}
/**
* Displays preview
*
* @param siteData
*/
showPreview (siteName, mode) {
let basePath = path.join(this.app.sitesDir, siteName, 'preview');
let previewLocation = '';
if(this.app.appConfig.previewLocation) {
previewLocation = this.app.appConfig.previewLocation.trim();
}
let url = '';
if(previewLocation !== '' && UtilsHelper.dirExists(previewLocation)) {
basePath = previewLocation;
}
url = path.join(basePath, 'index.html');
if (mode === 'tag' || mode === 'post' || mode === 'page' || mode === 'author') {
url = path.join(basePath, 'preview.html');
}
setTimeout(function() {
shell.openExternal('file:///' + url);
}, 1000);
}
}
module.exports = PreviewEvents;
================================================
FILE: app/back-end/events/site.js
================================================
const fs = require('fs-extra');
const os = require('os');
const path = require('path');
const FileHelper = require('../helpers/file.js');
const slug = require('./../helpers/slug');
const passwordSafeStorage = require('keytar');
const ipcMain = require('electron').ipcMain;
const Site = require('../site.js');
const Themes = require('../themes.js');
const Database = os.platform() === 'linux' ? require('node-sqlite3-wasm').Database : require('better-sqlite3');
const DBUtils = require('../helpers/db.utils.js');
const UtilsHelper = require('../helpers/utils.js');
const normalizePath = require('normalize-path');
const URLHelper = require('../modules/render-html/helpers/url.js');
/*
* Events for the IPC communication regarding single sites
*/
class SiteEvents {
constructor(appInstance) {
let self = this;
this.regenerateProcess = false;
/*
* Reload site config and data
*/
ipcMain.on('app-site-reload', (event, config) => {
let result = appInstance.reloadSite(config.siteName);
let language = this.getSiteLanguage(appInstance, config.siteName);
this.setSpellcheckerLanguage (appInstance, language);
event.sender.send('app-site-reloaded', result);
});
/*
* Save site config
*/
ipcMain.on('app-site-config-save', async function (event, config) {
let siteName = '';
let siteNames = Object.keys(appInstance.sites);
let thumbnailsRegenerateRequired = false;
if (siteNames.indexOf(config.site) !== -1) {
siteName = config.site;
} else {
event.sender.send('app-site-config-saved', {
status: false,
message: 'site-not-exists'
});
}
if (config.source === 'server') {
self.removeGitConfigDirectory(appInstance, config.site);
}
// Prepare settings
config.settings.name = slug(config.settings.name);
config.settings.advanced.urls.postsPrefix = slug(config.settings.advanced.urls.postsPrefix);
config.settings.advanced.urls.tagsPrefix = slug(config.settings.advanced.urls.tagsPrefix);
config.settings.advanced.urls.authorsPrefix = slug(config.settings.advanced.urls.authorsPrefix);
config.settings.advanced.urls.pageName = slug(config.settings.advanced.urls.pageName);
config.settings.advanced.urls.errorPage = slug(config.settings.advanced.urls.errorPage, true);
config.settings.advanced.urls.searchPage = slug(config.settings.advanced.urls.searchPage, true);
// If user changed the site name
if (
config.settings.name !== '' &&
siteName !== '' &&
slug(config.settings.name) !== slug(config.site)
) {
// Check if new site name is unique
if (
!fs.existsSync(path.join(appInstance.sitesDir, config.settings.name)) &&
slug(config.settings.displayName) === config.settings.name
) {
if (appInstance.db) {
try {
appInstance.db.close();
} catch (e) {
console.log('[SITE NAME CHANGE] DB already closed');
}
}
// If yes - rename the dir
delete appInstance.sites[siteName];
siteName = config.settings.name;
fs.renameSync(
path.join(appInstance.sitesDir, config.site),
path.join(appInstance.sitesDir, config.settings.name)
);
let dbPath = path.join(appInstance.sitesDir, config.settings.name, 'input', 'db.sqlite');
appInstance.db = new DBUtils(new Database(dbPath));
// Rename also the backups directory
let backupsDir = appInstance.appConfig.backupsLocation;
if(backupsDir) {
let backupsLocation = path.join(backupsDir, config.site);
let newBackupsLocation = path.join(backupsDir, config.settings.name);
if (UtilsHelper.dirExists(backupsLocation)) {
fs.renameSync(
backupsLocation,
newBackupsLocation
);
}
}
} else {
// If no - return error
event.sender.send('app-site-config-saved', {
status: false,
message: 'duplicated-name'
});
return;
}
}
// Check for empty names
if (
siteName === '' ||
config.settings.name === ''
) {
event.sender.send('app-site-config-saved', {
status: false,
message: 'empty-name'
});
return;
}
let configFile = path.join(appInstance.sitesDir, siteName, 'input', 'config', 'site.config.json');
let oldConfig = FileHelper.readFileSync(configFile, 'utf8');
let themesPath = path.join(appInstance.sitesDir, siteName, 'input', 'themes');
let newThemeConfig = {};
oldConfig = JSON.parse(oldConfig);
if (config.settings.theme === '' && oldConfig.theme) {
config.settings.theme = oldConfig.theme;
} else {
let themes = new Themes(appInstance, {
site: siteName
});
if(self.prepareThemeName(config.settings.theme) !== oldConfig.theme) {
thumbnailsRegenerateRequired = true;
}
config.settings.theme = themes.changeTheme(config.settings.theme, oldConfig.theme);
let themeConfigPath = path.join(appInstance.sitesDir, siteName, 'input', 'config', 'theme.config.json');
let themePath = path.join(themesPath, config.settings.theme);
newThemeConfig = Themes.loadThemeConfig(themeConfigPath, themePath);
}
if (
oldConfig.advanced && (
(oldConfig.advanced.responsiveImages !== config.settings.advanced.responsiveImages) ||
(oldConfig.advanced.imagesQuality !== config.settings.advanced.imagesQuality) ||
(oldConfig.advanced.alphaQuality !== config.settings.advanced.alphaQuality) ||
(oldConfig.advanced.forceWebp !== config.settings.advanced.forceWebp) ||
(oldConfig.advanced.webpLossless !== config.settings.advanced.webpLossless)
)
) {
thumbnailsRegenerateRequired = true;
}
if(
config.settings.advanced &&
config.settings.advanced.openGraphImage &&
config.settings.advanced.openGraphImage !== ''
) {
let filename = path.parse(config.settings.advanced.openGraphImage);
config.settings.advanced.openGraphImage = filename.base;
}
let passwordData = false;
let passwordGitData = false;
let passphraseData = false;
let s3IdData = false;
let s3KeyData = false;
let ghTokenData = false;
let glTokenData = false;
let netlifyIdData = false;
let netlifyTokenData = false;
let siteID = slug(config.settings.name);
if (config.settings.uuid) {
siteID = config.settings.uuid;
}
// Save the password in the keychain
if (passwordSafeStorage) {
try {
if (
config.settings.deployment.password !== '' &&
config.settings.deployment.password !== 'publii ' + siteID
) {
passwordData = await self.loadPassword(
config.settings,
'publii',
config.settings.deployment.password
);
config.settings.deployment.password = passwordData.toSave;
}
if (
config.settings.deployment.git.password !== '' &&
config.settings.deployment.git.password !== 'publii-git-password ' + siteID
) {
passwordGitData = await self.loadPassword(
config.settings,
'publii-git-password',
config.settings.deployment.git.password
);
config.settings.deployment.git.password = passwordGitData.toSave;
}
if (
config.settings.deployment.passphrase !== '' &&
config.settings.deployment.passphrase !== 'publii-passphrase ' + siteID
) {
passphraseData = await self.loadPassword(
config.settings,
'publii-passphrase',
config.settings.deployment.passphrase
);
config.settings.deployment.passphrase = passphraseData.toSave;
}
if (
config.settings.deployment.s3.id !== '' &&
config.settings.deployment.s3.key !== '' &&
config.settings.deployment.s3.id !== 'publii-s3-id ' + siteID
) {
s3IdData = await self.loadPassword(
config.settings,
'publii-s3-id',
config.settings.deployment.s3.id
);
s3KeyData = await self.loadPassword(
config.settings,
'publii-s3-key',
config.settings.deployment.s3.key
);
config.settings.deployment.s3.id = s3IdData.toSave;
config.settings.deployment.s3.key = s3KeyData.toSave;
}
if (
config.settings.deployment.github.token !== '' &&
config.settings.deployment.github.token !== 'publii-gh-token ' + siteID
) {
ghTokenData = await self.loadPassword(
config.settings,
'publii-gh-token',
config.settings.deployment.github.token
);
config.settings.deployment.github.token = ghTokenData.toSave;
}
if (
config.settings.deployment.gitlab.token !== '' &&
config.settings.deployment.gitlab.token !== 'publii-gl-token ' + siteID
) {
glTokenData = await self.loadPassword(
config.settings,
'publii-gl-token',
config.settings.deployment.gitlab.token
);
config.settings.deployment.gitlab.token = glTokenData.toSave;
}
if (
config.settings.deployment.netlify.id !== '' &&
config.settings.deployment.netlify.token !== '' &&
config.settings.deployment.netlify.token !== 'publii-netlify-token ' + siteID
) {
netlifyIdData = await self.loadPassword(
config.settings,
'publii-netlify-id',
config.settings.deployment.netlify.id
);
netlifyTokenData = await self.loadPassword(
config.settings,
'publii-netlify-token',
config.settings.deployment.netlify.token
);
config.settings.deployment.netlify.id = netlifyIdData.toSave;
config.settings.deployment.netlify.token = netlifyTokenData.toSave;
}
} catch (error) {
event.sender.send('app-site-config-saved', {
status: false,
message: 'no-keyring'
});
return;
}
}
// Save config
fs.writeFileSync(configFile, JSON.stringify(config.settings, null, 4));
if(passwordData && passwordData.newPassword) {
config.settings.deployment.password = passwordData.newPassword;
}
if(passwordGitData && passwordGitData.newPassword) {
config.settings.deployment.git.password = passwordGitData.newPassword;
}
if(passphraseData && passphraseData.newPassword) {
config.settings.deployment.passphrase = passphraseData.newPassword;
}
if(s3IdData && s3IdData.newPassword) {
config.settings.deployment.s3.id = s3IdData.newPassword;
}
if(s3KeyData && s3KeyData.newPassword) {
config.settings.deployment.s3.key = s3KeyData.newPassword;
}
if(ghTokenData && ghTokenData.newPassword) {
config.settings.deployment.github.token = ghTokenData.newPassword;
}
if(netlifyIdData && netlifyIdData.newPassword) {
config.settings.deployment.netlify.id = netlifyIdData.newPassword;
}
if(netlifyTokenData && netlifyTokenData.newPassword) {
config.settings.deployment.netlify.token = netlifyTokenData.newPassword;
}
appInstance.sites[config.settings.name] = config.settings;
let themesHelper = new Themes(appInstance, { site: siteName });
let themeConfigPath = path.join(appInstance.sitesDir, siteName, 'input', 'config', 'theme.config.json');
if (fs.existsSync(themeConfigPath)) {
let themeConfigString = FileHelper.readFileSync(themeConfigPath, 'utf8');
themesHelper.checkAndCleanImages(themeConfigString);
}
// Send success message
event.sender.send('app-site-config-saved', {
status: true,
siteName: siteName,
message: 'success-save',
themeName: config.settings.theme,
newThemeConfig: newThemeConfig,
thumbnailsRegenerateRequired: thumbnailsRegenerateRequired
});
});
/*
* Switch website
*/
ipcMain.on('app-site-switch', (event, config) => {
let result = appInstance.switchSite(config.site);
let language = this.getSiteLanguage(appInstance, config.site);
this.setSpellcheckerLanguage (appInstance, language);
event.sender.send('app-site-switched', result);
});
/*
* Refresh website data
*/
ipcMain.on('app-site-refresh', function (event, config) {
let result = appInstance.switchSite(config.site);
event.sender.send('app-site-refreshed', result);
});
/*
* Save site theme config
*/
ipcMain.on('app-site-theme-config-save', function (event, data) {
let siteData = {
site: data.site
};
let newConfig = data.config;
let themeName = data.theme;
let themePath = path.join(appInstance.sitesDir, data.site, 'input', 'themes', themeName);
let themeConfigPath = path.join(appInstance.sitesDir, data.site, 'input', 'config', 'theme.config.json');
let themesHelper = new Themes(appInstance, siteData);
themesHelper.updateThemeConfig(newConfig);
let themeConfig = Themes.loadThemeConfig(themeConfigPath, themePath);
event.sender.send('app-site-theme-config-saved', {
status: true,
newConfig: {
config: themeConfig.config,
customConfig: themeConfig.customConfig,
pageConfig: themeConfig.pageConfig,
postConfig: themeConfig.postConfig,
tagConfig: themeConfig.tagConfig,
authorConfig: themeConfig.authorConfig,
defaultTemplates: themeConfig.defaultTemplates
}
});
});
/*
* Create new website
*/
ipcMain.on('app-site-create', function (event, config, authorName) {
config.name = slug(config.name);
if (config.name.trim() === '') {
event.sender.send('app-site-creation-error', {
name: config.name.trim() === '',
author: slug(authorName).trim() === ''
});
return;
}
let site = new Site(appInstance, config);
let result = site.create(authorName);
if (result === 'db-error') {
event.sender.send('app-site-creation-db-error');
return;
}
if (result === 'duplicate') {
event.sender.send('app-site-creation-duplicate');
return;
}
config.uuid = site.uuid;
config.theme = 'simple';
appInstance.sites[config.name] = config;
// Load newly created db
let siteDir = path.join(appInstance.sitesDir, config.name);
let dbPath = path.join(siteDir, 'input', 'db.sqlite');
if (appInstance.db) {
try {
appInstance.db.close();
} catch (e) {
console.log('[SITE CREATION] DB already closed');
}
}
appInstance.db = new DBUtils(new Database(dbPath));
result = {
siteConfig: appInstance.sites[config.name],
siteDir: siteDir,
authorName: authorName
};
event.sender.send('app-site-created', result);
});
/*
* Regenerate thumbnails
*/
ipcMain.on('app-site-regenerate-thumbnails', function(event, config) {
let site = new Site(appInstance, config, true);
self.regenerateProcess = site.regenerateThumbnails(event.sender);
});
ipcMain.on('app-site-abort-regenerate-thumbnails', function(event, config) {
if (self.regenerateProcess) {
self.regenerateProcess.send({
type: 'abort'
});
self.regenerateProcess = false;
}
});
/*
* Regenerate thumbnails stauts
*/
ipcMain.on('app-site-regenerate-thumbnails-required', function(event, config) {
let site = new Site(appInstance, config, true);
site.regenerateThumbnailsIsRequired(event.sender);
});
/*
* Delete website
*/
ipcMain.on('app-site-delete', function (event, config) {
Site.delete(appInstance, config.site);
delete appInstance.sites[config.site];
event.sender.send('app-site-deleted', true);
});
/*
* Clone website
*/
ipcMain.on('app-site-clone', function (event, config) {
let clonedWebsiteData = Site.clone(appInstance, config.catalogName, config.siteName);
event.sender.send('app-site-cloned', clonedWebsiteData);
});
/*
* Save custom CSS
*/
ipcMain.on('app-site-css-save', function (event, config) {
Site.saveCustomCSS(appInstance, config.site, config.code);
event.sender.send('app-site-css-saved', true);
});
/*
* Load custom CSS
*/
ipcMain.on('app-site-css-load', function (event, config) {
let customCSS = Site.loadCustomCSS(appInstance, config.site);
event.sender.send('app-site-css-loaded', customCSS);
});
/*
* Check website catalog name
*/
ipcMain.on('app-site-check-website-to-restore', async function (event, config) {
let result = await Site.checkWebsiteBackup(appInstance, config.backupPath);
event.sender.send('app-site-backup-checked', result);
});
/*
* Check website catalog availability
*/
ipcMain.on('app-site-check-website-catalog-availability', function (event, config) {
let result = Site.checkWebsiteCatalogAvailability(appInstance, config.siteName);
event.sender.send('app-site-website-catalog-availability-checked', result);
});
/*
* Remove temp backup files
*/
ipcMain.on('app-site-remove-temporary-backup-files', function (event, config) {
let tempBackupDir = path.join(appInstance.appDir, 'temp', 'backup-to-restore');
if (fs.existsSync(tempBackupDir)) {
fs.emptyDirSync(tempBackupDir);
}
});
/*
* Restore website from backup
*/
ipcMain.on('app-site-restore-from-backup', function (event, config) {
let result = Site.restoreFromBackup(appInstance, config.siteName);
event.sender.send('app-site-restored-from-backup', result);
});
}
prepareThemeName(themeName) {
if(!themeName) {
return false;
}
return themeName.replace('install-use-', '')
.replace('uninstall-', '')
.replac
gitextract__icctd57/ ├── .editorconfig ├── .github/ │ ├── DISCUSSION_TEMPLATE/ │ │ └── bug-report.yml │ ├── FUNDING.yml │ └── ISSUE_TEMPLATE/ │ ├── bug.yml │ ├── config.yml │ └── feature.yml ├── .gitignore ├── .nvmrc ├── LICENSE ├── README.md ├── app/ │ ├── back-end/ │ │ ├── app-preload.js │ │ ├── app.js │ │ ├── author.js │ │ ├── authors.js │ │ ├── builddata.json │ │ ├── events/ │ │ │ ├── _modules.js │ │ │ ├── app.js │ │ │ ├── author.js │ │ │ ├── authors.js │ │ │ ├── backup.js │ │ │ ├── content.js │ │ │ ├── credits.js │ │ │ ├── deploy.js │ │ │ ├── file-manager.js │ │ │ ├── image-uploader.js │ │ │ ├── import.js │ │ │ ├── menu.js │ │ │ ├── notifications.js │ │ │ ├── page.js │ │ │ ├── plugin.js │ │ │ ├── plugins-api.js │ │ │ ├── post.js │ │ │ ├── preview.js │ │ │ ├── site.js │ │ │ ├── sync.js │ │ │ ├── tag.js │ │ │ └── tags.js │ │ ├── helpers/ │ │ │ ├── app-files.js │ │ │ ├── avatar.js │ │ │ ├── context-menu-builder.js │ │ │ ├── db.utils.js │ │ │ ├── file.js │ │ │ ├── image.helper.js │ │ │ ├── slug.js │ │ │ ├── specs/ │ │ │ │ ├── avatar.spec.js │ │ │ │ └── slug.spec.js │ │ │ ├── updates.helper.js │ │ │ ├── utils.js │ │ │ └── validators/ │ │ │ ├── language-config.js │ │ │ └── plugin-config.js │ │ ├── image.js │ │ ├── languages.js │ │ ├── migrators/ │ │ │ └── site-config.js │ │ ├── model.js │ │ ├── modules/ │ │ │ ├── backup/ │ │ │ │ ├── backup.js │ │ │ │ └── create-from-backup.js │ │ │ ├── custom-changes/ │ │ │ │ └── ftp/ │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ ├── TODO │ │ │ │ ├── lib/ │ │ │ │ │ ├── connection.js │ │ │ │ │ └── parser.js │ │ │ │ └── package.json │ │ │ ├── deploy/ │ │ │ │ ├── deployment.js │ │ │ │ ├── ftp-alt.js │ │ │ │ ├── ftp.js │ │ │ │ ├── git.js │ │ │ │ ├── github-pages.js │ │ │ │ ├── gitlab-pages.js │ │ │ │ ├── google-cloud.js │ │ │ │ ├── libraries/ │ │ │ │ │ └── netlify-api.js │ │ │ │ ├── manual.js │ │ │ │ ├── netlify.js │ │ │ │ ├── s3.js │ │ │ │ └── sftp.js │ │ │ ├── import/ │ │ │ │ ├── automatic-paragraphs.js │ │ │ │ ├── import.js │ │ │ │ └── wxr-parser.js │ │ │ ├── plugins/ │ │ │ │ ├── plugins-api.js │ │ │ │ └── plugins-helpers.js │ │ │ └── render-html/ │ │ │ ├── contexts/ │ │ │ │ ├── 404.js │ │ │ │ ├── author.js │ │ │ │ ├── feed.js │ │ │ │ ├── home.js │ │ │ │ ├── page-preview.js │ │ │ │ ├── page.js │ │ │ │ ├── post-preview.js │ │ │ │ ├── post.js │ │ │ │ ├── search.js │ │ │ │ ├── tag.js │ │ │ │ └── tags.js │ │ │ ├── handlebars/ │ │ │ │ └── helpers/ │ │ │ │ ├── _modules.js │ │ │ │ ├── asset.js │ │ │ │ ├── canonical-link.js │ │ │ │ ├── check-if-all.js │ │ │ │ ├── check-if-any.js │ │ │ │ ├── check-if-none.js │ │ │ │ ├── check-if.js │ │ │ │ ├── concatenate.js │ │ │ │ ├── contains.js │ │ │ │ ├── css.js │ │ │ │ ├── date.js │ │ │ │ ├── encode-url-fragment.js │ │ │ │ ├── encode-url.js │ │ │ │ ├── feed-link.js │ │ │ │ ├── font.js │ │ │ │ ├── gdpr-script-blocker.js │ │ │ │ ├── get-author.js │ │ │ │ ├── get-authors.js │ │ │ │ ├── get-page.js │ │ │ │ ├── get-pages-by-custom-field.js │ │ │ │ ├── get-pages.js │ │ │ │ ├── get-post-by-tags.js │ │ │ │ ├── get-post.js │ │ │ │ ├── get-posts-by-custom-field.js │ │ │ │ ├── get-posts-by-tags.js │ │ │ │ ├── get-posts.js │ │ │ │ ├── get-tag.js │ │ │ │ ├── get-tags.js │ │ │ │ ├── image-dimensions.js │ │ │ │ ├── is-current-page.js │ │ │ │ ├── is-empty.js │ │ │ │ ├── is-not-empty.js │ │ │ │ ├── is-not.js │ │ │ │ ├── is.js │ │ │ │ ├── join.js │ │ │ │ ├── js.js │ │ │ │ ├── json-ld.js │ │ │ │ ├── jsonify.js │ │ │ │ ├── lazyload.js │ │ │ │ ├── math.js │ │ │ │ ├── menu-item-classes.js │ │ │ │ ├── menu-url.js │ │ │ │ ├── meta-description.js │ │ │ │ ├── meta-robots.js │ │ │ │ ├── not-contains.js │ │ │ │ ├── orderby.js │ │ │ │ ├── page-url.js │ │ │ │ ├── publii-footer.js │ │ │ │ ├── publii-head.js │ │ │ │ ├── responsive-image-attributes.js │ │ │ │ ├── responsive-sizes.js │ │ │ │ ├── responsive-srcset.js │ │ │ │ ├── reverse.js │ │ │ │ ├── social-meta-tags.js │ │ │ │ ├── specs/ │ │ │ │ │ ├── check-if-all.spec.js │ │ │ │ │ ├── check-if-any.spec.js │ │ │ │ │ ├── check-if-none.spec.js │ │ │ │ │ ├── check-if.spec.js │ │ │ │ │ ├── feed-link.spec.js │ │ │ │ │ ├── font.spec.js │ │ │ │ │ ├── is-empty.spec.js │ │ │ │ │ ├── is-not-empty.spec.js │ │ │ │ │ ├── jsonify.spec.js │ │ │ │ │ └── translate.spec.js │ │ │ │ └── translate.js │ │ │ ├── helpers/ │ │ │ │ ├── content.js │ │ │ │ ├── deleteEmpty.js │ │ │ │ ├── diffCopy.js │ │ │ │ ├── files.js │ │ │ │ ├── gdpr.js │ │ │ │ ├── helpers.js │ │ │ │ ├── sitemap.js │ │ │ │ ├── specs/ │ │ │ │ │ └── url.spec.js │ │ │ │ ├── template.js │ │ │ │ ├── url.js │ │ │ │ └── view-settings.js │ │ │ ├── items/ │ │ │ │ ├── author.js │ │ │ │ ├── featured-image.js │ │ │ │ ├── page.js │ │ │ │ ├── post.js │ │ │ │ └── tag.js │ │ │ ├── renderer-cache.js │ │ │ ├── renderer-context.js │ │ │ ├── renderer-plugins.js │ │ │ ├── renderer.js │ │ │ ├── text-renderers/ │ │ │ │ ├── blockeditor.js │ │ │ │ └── markdown.js │ │ │ └── validators/ │ │ │ └── theme-config.js │ │ ├── page.js │ │ ├── pages.js │ │ ├── plugins.js │ │ ├── post.js │ │ ├── posts.js │ │ ├── site.js │ │ ├── sites.js │ │ ├── sql/ │ │ │ └── 1.0.0.sql │ │ ├── tag.js │ │ ├── tags.js │ │ ├── themes.js │ │ ├── vendor/ │ │ │ └── locutus/ │ │ │ └── htmlspecialchars.js │ │ ├── window-manager.js │ │ └── workers/ │ │ ├── backup/ │ │ │ ├── create.js │ │ │ └── restore.js │ │ ├── deploy/ │ │ │ └── deployment.js │ │ ├── import/ │ │ │ ├── check.js │ │ │ └── import.js │ │ ├── renderer/ │ │ │ └── preview.js │ │ └── thumbnails/ │ │ ├── post-images.js │ │ └── regenerate.js │ ├── build/ │ │ └── config.gypi │ ├── config/ │ │ ├── AST.app.config.js │ │ └── AST.currentSite.config.js │ ├── default-files/ │ │ ├── default-languages/ │ │ │ ├── en-gb/ │ │ │ │ ├── config.json │ │ │ │ ├── translations.json │ │ │ │ └── wysiwyg.json │ │ │ └── pl/ │ │ │ ├── config.json │ │ │ ├── translations.json │ │ │ └── wysiwyg.json │ │ ├── default-themes/ │ │ │ └── simple/ │ │ │ ├── 404.hbs │ │ │ ├── CHANGELOG.md │ │ │ ├── assets/ │ │ │ │ ├── css/ │ │ │ │ │ ├── editor.css │ │ │ │ │ ├── main.css │ │ │ │ │ └── style.css │ │ │ │ ├── dynamic/ │ │ │ │ │ └── fonts/ │ │ │ │ │ ├── adventpro/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── albertsans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── aleo/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── andadapro/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── antonio/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── archivonarrow/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── asap/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── assistant/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── besley/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── bigshouldersdisplay/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── bitcount/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── bitter/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── bodonimoda/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── brygada1918/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── cabin/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── cairo/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── cinzel/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── comfortaa/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── comme/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── dancingscript/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── danfo/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── dmsans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── domine/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── dosis/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── doto/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── dynapuff/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── exo/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── familjengrotesk/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── faustina/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── figtree/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── finlandica/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── frankruhllibre/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── fredoka/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── funneldisplay/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── gantari/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── geistmono/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── glory/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── gluten/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── googlesanscode/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── grenzegotisch/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── handjet/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── heebo/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── hostgrotesk/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── imbue/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── inclusivesans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── instrumentsans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── jetbrainsmono/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── jura/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── kalnia/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── karla/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── kreon/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── kumbhsans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── labrada/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── leaguespartan/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── lemonada/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── lexend/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── lexenddeca/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── librefranklin/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── lora/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── manrope/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── manuale/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── mavenpro/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── merriweathersans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── montserrat/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── mulish/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── nunito/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── orbitron/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── oswald/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── outfit/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── oxanium/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── parkinsans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── petrona/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── playfairdisplay/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── playwriteusmodern/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── playwriteustrad/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── plusjakartasans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── pontanosans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── publicsans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── quicksand/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── radiocanadabig/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── raleway/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── redhatdisplay/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── redhatmono/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── redhattext/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── redrose/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── rem/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── robotoflex/ │ │ │ │ │ │ └── LICENSE.txt │ │ │ │ │ ├── robotoslab/ │ │ │ │ │ │ └── LICENSE.txt │ │ │ │ │ ├── rokkitt/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── rubik/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── ruda/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── smoochsans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── sora/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── sourcecodepro/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── spartan/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── sticknobills/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── susemono/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── teachers/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── tektur/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── tourney/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── urbanist/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── varta/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── victormono/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── wixmadefortext/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── workbench/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── worksans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── yanonekaffeesatz/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── yrsa/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ ├── zalandosans/ │ │ │ │ │ │ └── OFL.txt │ │ │ │ │ └── zalandosansexpanded/ │ │ │ │ │ └── OFL.txt │ │ │ │ └── js/ │ │ │ │ ├── scripts.js │ │ │ │ ├── svg-fix.js │ │ │ │ └── svg-map.js │ │ │ ├── author.hbs │ │ │ ├── computed-options.js │ │ │ ├── config.json │ │ │ ├── dynamic-assets-mapping.js │ │ │ ├── index.hbs │ │ │ ├── page-empty.hbs │ │ │ ├── page.hbs │ │ │ ├── partials/ │ │ │ │ ├── fonts.hbs │ │ │ │ ├── footer.hbs │ │ │ │ ├── head.hbs │ │ │ │ ├── menu.hbs │ │ │ │ ├── navbar.hbs │ │ │ │ ├── pagination.hbs │ │ │ │ ├── share-buttons.hbs │ │ │ │ ├── simple-menu.hbs │ │ │ │ └── subpages-list.hbs │ │ │ ├── post.hbs │ │ │ ├── posts.hbs │ │ │ ├── search.hbs │ │ │ ├── simple.lang.json │ │ │ ├── tag.hbs │ │ │ ├── tags.hbs │ │ │ ├── theme-variables.js │ │ │ └── visual-override.js │ │ ├── gdpr-assets/ │ │ │ ├── gdpr.css │ │ │ ├── gdpr.js │ │ │ └── template.html │ │ ├── theme-files/ │ │ │ ├── config.json │ │ │ ├── feed-json.hbs │ │ │ ├── feed-xml.hbs │ │ │ ├── menu.hbs │ │ │ ├── pagination.hbs │ │ │ └── sitemap.xsl │ │ └── vendor/ │ │ └── prism.js │ ├── dist/ │ │ └── index.html │ ├── license.txt │ ├── licenses/ │ │ ├── LICENSES.chromium.html │ │ ├── agent-base/ │ │ │ └── license.txt │ │ ├── all-licenses.json │ │ ├── assert-plus/ │ │ │ └── license.txt │ │ ├── base64url/ │ │ │ └── license.txt │ │ ├── bindings/ │ │ │ └── license.txt │ │ ├── brace-expansion/ │ │ │ └── license.txt │ │ ├── buffer-alloc/ │ │ │ └── license.txt │ │ ├── buffer-alloc-unsafe/ │ │ │ └── license.txt │ │ ├── buffer-equal/ │ │ │ └── license.txt │ │ ├── buffer-fill/ │ │ │ └── license.txt │ │ ├── buffer-from/ │ │ │ └── license.txt │ │ ├── bufferjs/ │ │ │ └── license.txt │ │ ├── capture-stack-trace/ │ │ │ └── license.txt │ │ ├── chainsaw/ │ │ │ └── license.txt │ │ ├── cli/ │ │ │ └── license.txt │ │ ├── clipboard/ │ │ │ └── license.txt │ │ ├── codemirror/ │ │ │ └── license.txt │ │ ├── colors/ │ │ │ └── license.txt │ │ ├── commander/ │ │ │ └── license.txt │ │ ├── deep-equal/ │ │ │ └── license.txt │ │ ├── devtron/ │ │ │ └── license.txt │ │ ├── diff/ │ │ │ └── license.txt │ │ ├── electron/ │ │ │ └── license.txt │ │ ├── end-of-stream/ │ │ │ └── license.txt │ │ ├── es6-promisify/ │ │ │ └── license.txt │ │ ├── feathericons/ │ │ │ └── license.txt │ │ ├── follow-redirects/ │ │ │ └── license.txt │ │ ├── fresh/ │ │ │ └── license.txt │ │ ├── generate-function/ │ │ │ └── license.txt │ │ ├── get-stdin/ │ │ │ └── license.txt │ │ ├── growl/ │ │ │ └── license.txt │ │ ├── handlebars/ │ │ │ └── license.txt │ │ ├── has/ │ │ │ └── license.txt │ │ ├── he/ │ │ │ └── license.txt │ │ ├── https-proxy-agent/ │ │ │ └── license.txt │ │ ├── humps/ │ │ │ └── license.txt │ │ ├── ignore/ │ │ │ └── license.txt │ │ ├── imurmurhash/ │ │ │ └── license.txt │ │ ├── invert-kv/ │ │ │ └── license.txt │ │ ├── isarray/ │ │ │ └── license.txt │ │ ├── jquery/ │ │ │ └── license.txt │ │ ├── jquery-ui/ │ │ │ └── license.txt │ │ ├── json-schema/ │ │ │ └── license.txt │ │ ├── lazystream/ │ │ │ └── license.txt │ │ ├── libvips/ │ │ │ └── license.txt │ │ ├── licenses.json │ │ ├── locutus/ │ │ │ └── license.txt │ │ ├── log-driver/ │ │ │ └── license.txt │ │ ├── lucide/ │ │ │ └── license.txt │ │ ├── mocha/ │ │ │ └── license.txt │ │ ├── ncname/ │ │ │ └── license.txt │ │ ├── nested-sortable/ │ │ │ └── license.txt │ │ ├── node-slug/ │ │ │ └── license.txt │ │ ├── normalize.css/ │ │ │ └── license.txt │ │ ├── parse-bmfont-ascii/ │ │ │ └── license.txt │ │ ├── parse-bmfont-xml/ │ │ │ └── license.txt │ │ ├── punycode/ │ │ │ └── license.txt │ │ ├── range-parser/ │ │ │ └── license.txt │ │ ├── read-chunk/ │ │ │ └── license.txt │ │ ├── select2/ │ │ │ └── license.txt │ │ ├── send/ │ │ │ └── license.txt │ │ ├── slash/ │ │ │ └── license.txt │ │ ├── sortablejs/ │ │ │ └── license.txt │ │ ├── source-map/ │ │ │ └── license.txt │ │ ├── stream-consume/ │ │ │ └── license.txt │ │ ├── stream-events/ │ │ │ └── license.txt │ │ ├── stream-to/ │ │ │ └── license.txt │ │ ├── stream-to-buffer/ │ │ │ └── license.txt │ │ ├── stubs/ │ │ │ └── license.txt │ │ ├── tabler-icons/ │ │ │ └── license.txt │ │ ├── tinycolorpicker/ │ │ │ └── license.txt │ │ ├── tinymce/ │ │ │ └── license.txt │ │ ├── tootallnate/ │ │ │ └── once/ │ │ │ └── license.txt │ │ ├── topo/ │ │ │ └── license.txt │ │ ├── tr46/ │ │ │ └── license.txt │ │ ├── trim/ │ │ │ └── license.txt │ │ ├── typo-js/ │ │ │ └── license.txt │ │ ├── uri-js/ │ │ │ └── license.txt │ │ ├── vendor-licenses.json │ │ ├── window-size/ │ │ │ └── license.txt │ │ ├── wordwrap/ │ │ │ └── license.txt │ │ ├── xml-char-classes/ │ │ │ └── license.txt │ │ ├── xml-parse-from-string/ │ │ │ └── license.txt │ │ ├── xml2json/ │ │ │ └── license.txt │ │ ├── xmlbuilder/ │ │ │ └── license.txt │ │ └── xregexp/ │ │ └── license.txt │ ├── main.js │ ├── package.json │ └── src/ │ ├── assets/ │ │ └── vendor/ │ │ ├── css/ │ │ │ ├── codemirror.css │ │ │ └── normalize.css │ │ └── js/ │ │ └── codemirror/ │ │ ├── addon/ │ │ │ ├── display/ │ │ │ │ ├── autorefresh.js │ │ │ │ ├── fullscreen.css │ │ │ │ ├── fullscreen.js │ │ │ │ ├── panel.js │ │ │ │ ├── placeholder.js │ │ │ │ └── rulers.js │ │ │ ├── scroll/ │ │ │ │ ├── annotatescrollbar.js │ │ │ │ ├── scrollpastend.js │ │ │ │ ├── simplescrollbars.css │ │ │ │ └── simplescrollbars.js │ │ │ └── search/ │ │ │ ├── jump-to-line.js │ │ │ ├── match-highlighter.js │ │ │ ├── matchesonscrollbar.css │ │ │ ├── matchesonscrollbar.js │ │ │ ├── search.js │ │ │ └── searchcursor.js │ │ ├── autorefresh.js │ │ ├── codemirror.js │ │ ├── css.js │ │ └── xml.js │ ├── components/ │ │ ├── About.vue │ │ ├── AboutCredits.vue │ │ ├── AboutCreditsList.vue │ │ ├── App.vue │ │ ├── AppLanguages.vue │ │ ├── AppPlugins.vue │ │ ├── AppSettings.vue │ │ ├── AppThemes.vue │ │ ├── AuthorForm.vue │ │ ├── Authors.vue │ │ ├── Backups.vue │ │ ├── CustomCss.vue │ │ ├── CustomHtml.vue │ │ ├── ErrorPopup.vue │ │ ├── FileManager.vue │ │ ├── LanguagesList.vue │ │ ├── LanguagesListItem.vue │ │ ├── LogViewer.vue │ │ ├── MenuItem.vue │ │ ├── MenuItemEditor.vue │ │ ├── MenuPositionPopup.vue │ │ ├── Menus.vue │ │ ├── Message.vue │ │ ├── NotificationsCenter.vue │ │ ├── Pages.vue │ │ ├── PluginsList.vue │ │ ├── PluginsListItem.vue │ │ ├── PostEditorBlockEditor.vue │ │ ├── PostEditorMarkdown.vue │ │ ├── PostEditorTinyMCE.vue │ │ ├── Posts.vue │ │ ├── RegenerateThumbnails.vue │ │ ├── RegenerateThumbnailsPopup.vue │ │ ├── RenderingPopup.vue │ │ ├── ServerSettings.vue │ │ ├── Settings.vue │ │ ├── Sidebar.vue │ │ ├── SidebarMenu.vue │ │ ├── SidebarSites.vue │ │ ├── SidebarSyncButton.vue │ │ ├── Site.vue │ │ ├── SiteAddForm.vue │ │ ├── SiteLogo.vue │ │ ├── SitesList.vue │ │ ├── SitesListItem.vue │ │ ├── SitesPopup.vue │ │ ├── SitesSearch.vue │ │ ├── Splashscreen.vue │ │ ├── SyncPopup.vue │ │ ├── TagForm.vue │ │ ├── Tags.vue │ │ ├── ThemeSettings.vue │ │ ├── ThemesList.vue │ │ ├── ThemesListItem.vue │ │ ├── Tools.vue │ │ ├── ToolsPlugin.vue │ │ ├── TopBar.vue │ │ ├── TopBarAppBar.vue │ │ ├── TopBarDropDown.vue │ │ ├── TopBarDropDownItem.vue │ │ ├── WPImport.vue │ │ ├── WPImportStats.vue │ │ ├── basic-elements/ │ │ │ ├── Alert.vue │ │ │ ├── AuthorsDropDown.vue │ │ │ ├── Button.vue │ │ │ ├── ButtonDropdown.vue │ │ │ ├── CharCounter.vue │ │ │ ├── Checkbox.vue │ │ │ ├── CodeMirrorEditor.vue │ │ │ ├── Collection.vue │ │ │ ├── CollectionCell.vue │ │ │ ├── CollectionHeader.vue │ │ │ ├── CollectionRow.vue │ │ │ ├── ColorPicker.vue │ │ │ ├── Confirm.vue │ │ │ ├── DirSelect.vue │ │ │ ├── Dropdown.vue │ │ │ ├── EmbedConsentsGroups.vue │ │ │ ├── EmptyState.vue │ │ │ ├── Field.vue │ │ │ ├── FieldsGroup.vue │ │ │ ├── FileSelect.vue │ │ │ ├── Footer.vue │ │ │ ├── GConsentModeGroups.vue │ │ │ ├── GdprGroups.vue │ │ │ ├── Header.vue │ │ │ ├── HeaderSearch.vue │ │ │ ├── Icon.vue │ │ │ ├── ImageUpload.vue │ │ │ ├── LogoCreator.vue │ │ │ ├── Overlay.vue │ │ │ ├── PagesDropDown.vue │ │ │ ├── PostsDropDown.vue │ │ │ ├── ProgressBar.vue │ │ │ ├── RadioButton.vue │ │ │ ├── RangeSlider.vue │ │ │ ├── Repeater.vue │ │ │ ├── Separator.vue │ │ │ ├── SmallImageUpload.vue │ │ │ ├── SupportedFeaturesCheck.vue │ │ │ ├── Switcher.vue │ │ │ ├── Tabs.vue │ │ │ ├── TagsDropDown.vue │ │ │ ├── TextArea.vue │ │ │ ├── TextInput.vue │ │ │ └── ThemesDropdown.vue │ │ ├── block-editor/ │ │ │ ├── PubliiBlockEditor.vue │ │ │ ├── assets/ │ │ │ │ ├── prism-theme.scss │ │ │ │ └── typography.scss │ │ │ ├── available-blocks.json │ │ │ ├── blocks-mapping.js │ │ │ ├── components/ │ │ │ │ ├── Block.vue │ │ │ │ ├── BlockAdvancedConfig.vue │ │ │ │ ├── BlockEditor.vue │ │ │ │ ├── BlockLinkPopup.vue │ │ │ │ ├── BlockWrapper.vue │ │ │ │ ├── BlocksList.vue │ │ │ │ ├── default-blocks/ │ │ │ │ │ ├── publii-code/ │ │ │ │ │ │ ├── block.vue │ │ │ │ │ │ ├── config-form.json │ │ │ │ │ │ ├── conversions.js │ │ │ │ │ │ └── render.js │ │ │ │ │ ├── publii-embed/ │ │ │ │ │ │ ├── block.vue │ │ │ │ │ │ ├── config-form.json │ │ │ │ │ │ ├── embed.js │ │ │ │ │ │ └── render.js │ │ │ │ │ ├── publii-gallery/ │ │ │ │ │ │ ├── block.vue │ │ │ │ │ │ ├── config-form.json │ │ │ │ │ │ └── render.js │ │ │ │ │ ├── publii-header/ │ │ │ │ │ │ ├── block.vue │ │ │ │ │ │ ├── config-form.json │ │ │ │ │ │ ├── conversions.js │ │ │ │ │ │ └── render.js │ │ │ │ │ ├── publii-html/ │ │ │ │ │ │ ├── aspect-ratio.js │ │ │ │ │ │ ├── block.vue │ │ │ │ │ │ ├── config-form.json │ │ │ │ │ │ ├── content-filter.js │ │ │ │ │ │ ├── conversions.js │ │ │ │ │ │ └── render.js │ │ │ │ │ ├── publii-image/ │ │ │ │ │ │ ├── block.vue │ │ │ │ │ │ ├── config-form.json │ │ │ │ │ │ └── render.js │ │ │ │ │ ├── publii-list/ │ │ │ │ │ │ ├── block.vue │ │ │ │ │ │ ├── config-form.json │ │ │ │ │ │ ├── conversions.js │ │ │ │ │ │ └── render.js │ │ │ │ │ ├── publii-paragraph/ │ │ │ │ │ │ ├── block.vue │ │ │ │ │ │ ├── config-form.json │ │ │ │ │ │ ├── conversions.js │ │ │ │ │ │ └── render.js │ │ │ │ │ ├── publii-quote/ │ │ │ │ │ │ ├── block.vue │ │ │ │ │ │ ├── config-form.json │ │ │ │ │ │ ├── conversions.js │ │ │ │ │ │ └── render.js │ │ │ │ │ ├── publii-readmore/ │ │ │ │ │ │ ├── block.vue │ │ │ │ │ │ ├── config-form.json │ │ │ │ │ │ └── render.js │ │ │ │ │ ├── publii-separator/ │ │ │ │ │ │ ├── block.vue │ │ │ │ │ │ ├── config-form.json │ │ │ │ │ │ ├── conversions.js │ │ │ │ │ │ └── render.js │ │ │ │ │ └── publii-toc/ │ │ │ │ │ ├── block.vue │ │ │ │ │ ├── config-form.json │ │ │ │ │ └── render.js │ │ │ │ ├── elements/ │ │ │ │ │ ├── EditorIcon.vue │ │ │ │ │ └── Switcher.vue │ │ │ │ ├── extensions/ │ │ │ │ │ ├── ConversionHelpers.js │ │ │ │ │ ├── ShortcutManager.js │ │ │ │ │ └── UndoManager.js │ │ │ │ ├── helpers/ │ │ │ │ │ ├── ContentEditableImprovements.vue │ │ │ │ │ ├── InlineMenuUI.vue │ │ │ │ │ └── TopMenuUI.vue │ │ │ │ ├── mixins/ │ │ │ │ │ ├── AdvancedConfig.vue │ │ │ │ │ ├── HasPreview.vue │ │ │ │ │ ├── InlineMenu.vue │ │ │ │ │ ├── LinkConfig.vue │ │ │ │ │ └── LinkHelpers.vue │ │ │ │ └── utils/ │ │ │ │ ├── SelectedText.js │ │ │ │ └── Utils.js │ │ │ └── vendors/ │ │ │ ├── _modularscale.scss │ │ │ └── modularscale/ │ │ │ ├── _function.scss │ │ │ ├── _pow.scss │ │ │ ├── _respond.scss │ │ │ ├── _round-px.scss │ │ │ ├── _settings.scss │ │ │ ├── _sort.scss │ │ │ ├── _strip-units.scss │ │ │ ├── _sugar.scss │ │ │ ├── _target.scss │ │ │ └── _vars.scss │ │ ├── configs/ │ │ │ ├── defaultDeploymentSettings.js │ │ │ ├── postEditor.config.js │ │ │ ├── preloaderImages.js │ │ │ ├── s3ACLs.js │ │ │ ├── s3Regions.js │ │ │ └── sidebar-icons.js │ │ ├── mixins/ │ │ │ ├── BackToTools.js │ │ │ ├── CollectionCheckboxes.js │ │ │ ├── GoToLastOpenedWebsite.vue │ │ │ └── PostEditorsCommon.vue │ │ └── post-editor/ │ │ ├── AuthorPopup.vue │ │ ├── CodeMirror/ │ │ │ ├── codemirror-4.inline-attachment.js │ │ │ └── inline-attachment.js │ │ ├── DatePopup.vue │ │ ├── EasyMde.vue │ │ ├── Editor.vue │ │ ├── EditorBridge.js │ │ ├── GalleryPopup.vue │ │ ├── HelpPanelBlockEditor.vue │ │ ├── HelpPanelMarkdown.vue │ │ ├── InlineEditor.vue │ │ ├── ItemHelper.js │ │ ├── LinkPopup.vue │ │ ├── LinkToolbar.vue │ │ ├── SearchPopup.vue │ │ ├── Sidebar.vue │ │ ├── SourceCodeEditor.vue │ │ ├── TopBar.vue │ │ └── WritersPanel.vue │ ├── config/ │ │ └── langs.js │ ├── helpers/ │ │ ├── sass-colors.js │ │ ├── utils.js │ │ ├── vendor/ │ │ │ ├── locutus/ │ │ │ │ ├── strings/ │ │ │ │ │ └── strip_tags.js │ │ │ │ └── xml/ │ │ │ │ ├── index.js │ │ │ │ ├── utf8_decode.js │ │ │ │ └── utf8_encode.js │ │ │ └── tinymce/ │ │ │ ├── icons/ │ │ │ │ └── publii/ │ │ │ │ └── icons.js │ │ │ ├── langs/ │ │ │ │ └── readme.md │ │ │ ├── license.txt │ │ │ ├── plugins/ │ │ │ │ └── emoticons/ │ │ │ │ └── js/ │ │ │ │ ├── emojiimages.js │ │ │ │ └── emojis.js │ │ │ └── tinymce.d.ts │ │ └── version-comparator.js │ ├── main.js │ ├── router/ │ │ └── index.js │ ├── scss/ │ │ ├── codemirror.scss │ │ ├── css-variables.scss │ │ ├── editor/ │ │ │ ├── editor-markdown.scss │ │ │ ├── editor-options.scss │ │ │ ├── editor-overrides.scss │ │ │ ├── editor.scss │ │ │ ├── post-editors-common.scss │ │ │ └── scrollbar.scss │ │ ├── empty-states.scss │ │ ├── forms.scss │ │ ├── global.scss │ │ ├── help-panel-common.scss │ │ ├── mixins.scss │ │ ├── notifications.scss │ │ ├── options-sidebar.scss │ │ ├── popup-common.scss │ │ ├── scope-fix.scss │ │ ├── variables.scss │ │ └── vendor/ │ │ ├── _modularscale.scss │ │ ├── codemirror.css │ │ ├── modularscale/ │ │ │ ├── _function.scss │ │ │ ├── _pow.scss │ │ │ ├── _respond.scss │ │ │ ├── _round-px.scss │ │ │ ├── _settings.scss │ │ │ ├── _sort.scss │ │ │ ├── _strip-units.scss │ │ │ ├── _sugar.scss │ │ │ ├── _target.scss │ │ │ └── _vars.scss │ │ ├── normalize.css │ │ └── vue-multiselect.scss │ └── store/ │ ├── default.state.js │ ├── getters/ │ │ ├── app-version.js │ │ ├── author-templates.js │ │ ├── languages.js │ │ ├── notifications-count.js │ │ ├── notifications-status.js │ │ ├── notifications.js │ │ ├── plugins.js │ │ ├── site-authors.js │ │ ├── site-display-names.js │ │ ├── site-names.js │ │ ├── site-pages.js │ │ ├── site-plugins.js │ │ ├── site-posts.js │ │ ├── site-tags.js │ │ ├── tag-templates.js │ │ ├── theme-select.js │ │ └── themes.js │ ├── helpers/ │ │ ├── mutations.js │ │ ├── page-filter.js │ │ ├── page-get-author.js │ │ ├── post-filter.js │ │ ├── post-get-author.js │ │ └── post-get-tags.js │ └── index.js ├── build/ │ ├── config.gypi │ ├── entitlements.mac.plist │ ├── installation/ │ │ ├── icon.icns │ │ ├── volume-prerelease.icns │ │ └── volume.icns │ ├── installer.nsh │ ├── license_en.txt │ └── scripts/ │ ├── afterPack.js │ └── update-build-number.js ├── gulpfile.js ├── internal-tools/ │ └── loc.js ├── package.json └── webpack.config.js
SYMBOL INDEX (2210 symbols across 209 files)
FILE: app/back-end/app.js
class App (line 41) | class App {
method constructor (line 47) | constructor(startupSettings) {
method checkDirs (line 98) | checkDirs() {
method checkThemes (line 134) | checkThemes() {
method reloadSite (line 194) | reloadSite (siteName) {
method switchSite (line 205) | switchSite (site) {
method loadSite (line 267) | loadSite (siteName) {
method loadSites (line 323) | loadSites() {
method loadThemes (line 340) | loadThemes() {
method loadLanguages (line 352) | loadLanguages() {
method loadPlugins (line 375) | loadPlugins() {
method loadDefaultLanguage (line 382) | loadDefaultLanguage (languagesLoader, errorOccurred = false) {
method loadLanguage (line 396) | loadLanguage (lang, type) {
method setLanguage (line 424) | setLanguage (lang, type) {
method loadConfig (line 445) | loadConfig () {
method loadAdditionalConfig (line 526) | loadAdditionalConfig () {
method hasPermissionsErrors (line 545) | hasPermissionsErrors (error) {
method initWindow (line 560) | initWindow() {
method initWindowEvents (line 725) | initWindowEvents() {
method initializeCustomIpcMainEvents (line 739) | initializeCustomIpcMainEvents () {
method getMainWindow (line 749) | getMainWindow() {
method skipSystemFiles (line 754) | skipSystemFiles (src, dest) {
method addSite (line 759) | addSite (siteCatalog, siteData) {
method setCurrentZoomLevel (line 764) | setCurrentZoomLevel () {
FILE: app/back-end/author.js
class Author (line 16) | class Author extends Model {
method constructor (line 23) | constructor(appInstance, authorData, storeMode = true) {
method save (line 61) | save () {
method addAuthor (line 108) | addAuthor() {
method updateAuthor (line 155) | updateAuthor() {
method prepareAuthorName (line 186) | prepareAuthorName() {
method isAuthorNameUnique (line 201) | isAuthorNameUnique() {
method isAuthorUsernameUnique (line 225) | isAuthorUsernameUnique() {
method delete (line 248) | delete() {
method checkAndCleanImages (line 272) | checkAndCleanImages (cancelEvent = false) {
method cleanImages (line 299) | cleanImages(images, imagesDir, cancelEvent) {
method removeResponsiveImages (line 380) | removeResponsiveImages(originalPath) {
FILE: app/back-end/authors.js
class Authors (line 7) | class Authors extends Model {
method constructor (line 14) | constructor(appInstance, authorsData) {
method load (line 21) | load() {
FILE: app/back-end/events/app.js
class AppEvents (line 15) | class AppEvents {
method constructor (line 16) | constructor(appInstance) {
FILE: app/back-end/events/author.js
class AuthorEvents (line 8) | class AuthorEvents {
method constructor (line 9) | constructor(appInstance) {
FILE: app/back-end/events/authors.js
class AuthorsEvents (line 9) | class AuthorsEvents {
method constructor (line 10) | constructor(appInstance) {
FILE: app/back-end/events/backup.js
class BackupEvents (line 6) | class BackupEvents {
method constructor (line 7) | constructor(appInstance) {
method loadBackupsList (line 75) | loadBackupsList(siteName, event) {
method removeBackups (line 84) | async removeBackups(siteName, backupsNames, event) {
method renameBackup (line 93) | renameBackup(siteName, oldBackupName, newBackupName, event) {
method createBackup (line 102) | async createBackup(siteName, filename, event) {
method restoreBackup (line 120) | async restoreBackup(siteName, backupName, event) {
FILE: app/back-end/events/content.js
class ContentEvents (line 8) | class ContentEvents {
method constructor (line 9) | constructor(appInstance) {
FILE: app/back-end/events/credits.js
class CreditsEvents (line 10) | class CreditsEvents {
method constructor (line 11) | constructor(appInstance) {
FILE: app/back-end/events/deploy.js
class DeployEvents (line 7) | class DeployEvents {
method constructor (line 8) | constructor(appInstance) {
method renderSite (line 92) | renderSite(site, event) {
method deploySite (line 155) | deploySite(site, password, sender) {
method testConnection (line 194) | async testConnection(deploymentConfig, siteName, uuid) {
FILE: app/back-end/events/file-manager.js
class FileManagerEvents (line 10) | class FileManagerEvents {
method constructor (line 16) | constructor (appInstance) {
method listFiles (line 62) | listFiles(config, sender) {
method checkIfIsBinaryFile (line 101) | checkIfIsBinaryFile(output, iterator, sender) {
method getIcon (line 121) | getIcon(extension, isDirectory = false) {
method uploadFile (line 241) | uploadFile(config, sender) {
method createFile (line 263) | createFile(config, sender) {
method deleteFiles (line 284) | deleteFiles(config, sender) {
method checkFilename (line 306) | checkFilename(config, sender) {
FILE: app/back-end/events/image-uploader.js
class ImageUploaderEvents (line 11) | class ImageUploaderEvents {
method constructor (line 12) | constructor(appInstance) {
FILE: app/back-end/events/import.js
class ImportEvents (line 11) | class ImportEvents {
method constructor (line 17) | constructor(appInstance) {
method checkFile (line 39) | checkFile(siteName, filePath, sender) {
method importFile (line 66) | importFile(appInstance, config, sender) {
FILE: app/back-end/events/menu.js
class MenuEvents (line 9) | class MenuEvents {
method constructor (line 10) | constructor(appInstance) {
method saveNewMenuStructure (line 23) | saveNewMenuStructure(menuStructure, siteName) {
FILE: app/back-end/events/notifications.js
class NotificationsEvents (line 9) | class NotificationsEvents {
method constructor (line 10) | constructor(appInstance) {
FILE: app/back-end/events/page.js
class PageEvents (line 11) | class PageEvents {
method constructor (line 12) | constructor(appInstance) {
method removeNullDataFromHierarchy (line 123) | removeNullDataFromHierarchy (data) {
method removeDuplicatedDataFromHierarchy (line 132) | removeDuplicatedDataFromHierarchy (data) {
FILE: app/back-end/events/plugin.js
class PluginEvents (line 8) | class PluginEvents {
method constructor (line 9) | constructor(appInstance) {
FILE: app/back-end/events/plugins-api.js
class PluginsApiEvents (line 10) | class PluginsApiEvents {
method constructor (line 11) | constructor (appInstance) {
FILE: app/back-end/events/post.js
class PostEvents (line 8) | class PostEvents {
method constructor (line 9) | constructor(appInstance) {
FILE: app/back-end/events/preview.js
class PreviewEvents (line 10) | class PreviewEvents {
method constructor (line 16) | constructor(appInstance) {
method renderSite (line 60) | renderSite(site, itemID, postData, mode, event, showPreview) {
method showPreview (line 157) | showPreview (siteName, mode) {
FILE: app/back-end/events/site.js
class SiteEvents (line 20) | class SiteEvents {
method constructor (line 21) | constructor(appInstance) {
method prepareThemeName (line 556) | prepareThemeName(themeName) {
method loadPassword (line 566) | async loadPassword(settings, type, newPassword) {
method getSiteLanguage (line 602) | getSiteLanguage (appInstance, siteName) {
method setSpellcheckerLanguage (line 627) | setSpellcheckerLanguage (appInstance, language) {
method removeGitConfigDirectory (line 660) | removeGitConfigDirectory (appInstance, siteName) {
FILE: app/back-end/events/sync.js
class SyncEvents (line 10) | class SyncEvents {
method constructor (line 11) | constructor(appInstance) {
method saveSyncStatus (line 25) | saveSyncStatus(status, siteName) {
FILE: app/back-end/events/tag.js
class TagEvents (line 8) | class TagEvents {
method constructor (line 9) | constructor(appInstance) {
FILE: app/back-end/events/tags.js
class TagsEvents (line 9) | class TagsEvents {
method constructor (line 10) | constructor(appInstance) {
FILE: app/back-end/helpers/app-files.js
class AppFilesHelper (line 8) | class AppFilesHelper {
method constructor (line 14) | constructor(appInstance) {
method relocateSites (line 26) | relocateSites(oldLocation, newLocation, event) {
method relocateSite (line 80) | relocateSite(oldLocation, newLocation, site) {
method checkIfDirectoryIsSite (line 112) | checkIfDirectoryIsSite(siteLocation) {
method removeCatalogs (line 127) | removeCatalogs(location, catalogsToRemove) {
FILE: app/back-end/helpers/avatar.js
class AvatarHelper (line 3) | class AvatarHelper {
method isLocalAvatar (line 11) | static isLocalAvatar(pathToCheck) {
method isGravatar (line 26) | static isGravatar(pathToCheck) {
method getAvatarData (line 42) | static getAvatarData(authorObject, avatarPath) {
FILE: app/back-end/helpers/context-menu-builder.js
method constructor (line 6) | constructor (webContents) {
method showPopupMenu (line 17) | async showPopupMenu(context) {
method buildMenuForElement (line 31) | async buildMenuForElement(info) {
method buildMenuForTextInput (line 37) | async buildMenuForTextInput(menuInfo) {
method addSpellingItems (line 49) | async addSpellingItems(menu, menuInfo) {
method addSearchItems (line 72) | addSearchItems(menu, menuInfo) {
method addCut (line 91) | addCut(menu, menuInfo) {
method addCopy (line 102) | addCopy(menu, menuInfo) {
method addPaste (line 113) | addPaste(menu, menuInfo) {
method addSeparator (line 124) | addSeparator(menu) {
FILE: app/back-end/helpers/db.utils.js
class DBUtils (line 6) | class DBUtils {
method constructor (line 7) | constructor (dbInstance) {
method prepare (line 13) | prepare (sqlStatement) {
method get (line 18) | get (paramsObject = null) {
method run (line 35) | run (paramsObject = null) {
method all (line 52) | all (paramsObject = null) {
method exec (line 69) | exec (sqlQueries) {
method close (line 73) | close () {
method transformParams (line 80) | transformParams (paramsObject) {
FILE: app/back-end/helpers/file.js
class FileHelper (line 6) | class FileHelper {
method readFileSync (line 13) | static readFileSync(path, options) {
FILE: app/back-end/helpers/image.helper.js
class ImageHelper (line 11) | class ImageHelper {
method constructor (line 12) | constructor(postInstance) {
method save (line 26) | save() {
method delete (line 61) | delete() {
method store (line 71) | store() {
method storeImageAdditionalData (line 102) | storeImageAdditionalData() {
method getMediaPath (line 115) | getMediaPath() {
method deleteImagesDirectory (line 125) | static deleteImagesDirectory(siteDir, itemType, itemID) {
method copyImagesDirectory (line 148) | static copyImagesDirectory(siteDir, postID, newPostID) {
FILE: app/back-end/helpers/slug.js
function createSlug (line 49) | function createSlug(textToSlugify, filenameMode = false, saveLowerChars ...
FILE: app/back-end/helpers/updates.helper.js
class UpdatesHelper (line 5) | class UpdatesHelper {
method constructor (line 6) | constructor (config) {
method retrieve (line 13) | retrieve () {
method download (line 21) | download () {
method sendError (line 38) | sendError (err) {
method readExistingData (line 45) | readExistingData () {
method handleResponse (line 52) | handleResponse (body, downloaded) {
FILE: app/back-end/helpers/utils.js
class UtilsHelper (line 9) | class UtilsHelper {
method mergeObjects (line 19) | static mergeObjects(target, source) {
method dirExists (line 56) | static dirExists(dirPath) {
method fileExists (line 73) | static fileExists(filePath) {
method responsiveImagesConfigExists (line 98) | static responsiveImagesConfigExists(themeConfig, type = false) {
method responsiveImagesDimensions (line 118) | static responsiveImagesDimensions(themeConfig, type, group = false) {
method responsiveImagesData (line 145) | static responsiveImagesData(themeConfig, type, group = false) {
method responsiveImagesGroups (line 186) | static responsiveImagesGroups(themeConfig, type) {
method responsiveImagesDimensionNames (line 228) | static responsiveImagesDimensionNames(dimensions, group = false) {
method fileIsOverrided (line 255) | static fileIsOverrided(inputDir, themeName, filePath) {
method loadThemeConfig (line 284) | static loadThemeConfig(inputDir, themeName) {
method requireWithNoCache (line 315) | static requireWithNoCache(module, params = false) {
method arraysHaveTheSameContent (line 328) | static arraysHaveTheSameContent (arrayA, arrayB) {
FILE: app/back-end/helpers/validators/language-config.js
function languageConfigValidator (line 9) | function languageConfigValidator(configPath) {
FILE: app/back-end/helpers/validators/plugin-config.js
function pluginConfigValidator (line 9) | function pluginConfigValidator(configPath) {
FILE: app/back-end/image.js
class Image (line 24) | class Image extends Model {
method constructor (line 25) | constructor(appInstance, imageData) {
method generateFileName (line 53) | generateFileName (fileName, suffix, dirPath, galleryDirPath) {
method save (line 79) | save (generateResponsiveImages = true) {
method createResponsiveImages (line 211) | createResponsiveImages(originalPath, imageType = 'contentImages') {
method getSvgImageDimensions (line 549) | getSvgImageDimensions(imagePath) {
method allowedImageExtension (line 580) | allowedImageExtension(extension) {
method shouldUseJimp (line 593) | shouldUseJimp() {
FILE: app/back-end/languages.js
class Languages (line 12) | class Languages {
method constructor (line 13) | constructor(appInstance) {
method loadLanguages (line 22) | loadLanguages () {
method removeLanguage (line 103) | removeLanguage(directory) {
method normalizeLanguageImagePath (line 110) | normalizeLanguageImagePath(imagePath) {
method loadTranslations (line 121) | loadTranslations (languageName = 'en-gb', type = 'default') {
method loadWysiwygTranslation (line 140) | loadWysiwygTranslation (languageName = 'en-gb', type = 'default') {
method loadLanguageConfig (line 159) | loadLanguageConfig (languageName = 'en-gb', type = 'default') {
FILE: app/back-end/migrators/site-config.js
class SiteConfigMigrator (line 8) | class SiteConfigMigrator {
method moveOldAuthorData (line 9) | static moveOldAuthorData(appInstance, siteConfig) {
FILE: app/back-end/model.js
class Model (line 8) | class Model {
method constructor (line 15) | constructor(appInstance, data) {
method escape (line 30) | escape(stringToEscape) {
method updateField (line 64) | updateField (table, itemID, fieldsToUpdate) {
FILE: app/back-end/modules/backup/backup.js
class Backup (line 14) | class Backup {
method loadList (line 22) | static loadList(siteName, backupsDir) {
method create (line 78) | static async create(siteName, backupFilename, backupsDir, sourceDir) {
method remove (line 149) | static async remove(siteName, backupsNames, backupsDir) {
method rename (line 186) | static rename(siteName, oldBackupName, newBackupName, backupsDir) {
method restore (line 221) | static async restore(siteName, backupName, backupsDir, destinationDir,...
method verify (line 319) | static verify(backupDir, siteName) {
method checkSiteName (line 371) | static checkSiteName(siteName, configFilePath) {
method convertToMegabytes (line 392) | static convertToMegabytes(fileSizeInBytes) {
FILE: app/back-end/modules/backup/create-from-backup.js
class CreateFromBackup (line 7) | class CreateFromBackup {
method constructor (line 8) | constructor (appInstance, backupPath) {
method prepareBackupToRestore (line 15) | async prepareBackupToRestore () {
method checkExtension (line 26) | checkExtension () {
method unpackBackup (line 34) | async unpackBackup () {
method verifyBackup (line 87) | verifyBackup(backupDir) {
method getSiteName (line 121) | getSiteName () {
method removeBackupFilesIfNecessary (line 139) | removeBackupFilesIfNecessary () {
FILE: app/back-end/modules/custom-changes/ftp/lib/connection.js
function donoop (line 156) | function donoop() {
function onconnect (line 167) | function onconnect() {
function ondata (line 270) | function ondata(chunk) {
function onerror (line 277) | function onerror(err) {
function onend (line 284) | function onend() {
function ondone (line 295) | function ondone() {
function ondone (line 449) | function ondone() {
function final (line 453) | function final() {
function sendList (line 491) | function sendList() {
function ondone (line 571) | function ondone() {
function sendRetr (line 593) | function sendRetr() {
function onerror (line 921) | function onerror(err) {
function sendStore (line 983) | function sendStore() {
function makeError (line 1066) | function makeError(code, text) {
FILE: app/back-end/modules/custom-changes/ftp/lib/parser.js
function Parser (line 20) | function Parser(options) {
FILE: app/back-end/modules/deploy/deployment.js
constant FTP (line 9) | const FTP = require('./ftp.js');
constant SFTP (line 11) | const SFTP = require('./sftp.js');
class Deployment (line 34) | class Deployment {
method constructor (line 42) | constructor (appDir, sitesDir, siteConfig, useAltFtp) {
method testConnection (line 64) | async testConnection (app, deploymentConfig, siteName, uuid) {
method initSession (line 93) | async initSession () {
method setInput (line 119) | setInput () {
method setOutput (line 129) | setOutput (useEmpty = false) {
method prepareLocalFilesList (line 140) | prepareLocalFilesList () {
method checkLocalListWithRemoteList (line 216) | checkLocalListWithRemoteList (fileContent) {
method compareFilesList (line 257) | compareFilesList (remoteFileListExists = false) {
method continueSync (line 295) | continueSync (remoteFiles) {
method sortFiles (line 398) | sortFiles () {
method removeFile (line 461) | removeFile () {
method uploadFile (line 501) | uploadFile () {
method readDirRecursiveSync (line 544) | readDirRecursiveSync (dir, filelist) {
method saveConnectionFilesLog (line 573) | saveConnectionFilesLog (files, suffix = '') {
FILE: app/back-end/modules/deploy/ftp-alt.js
class FTPAlt (line 14) | class FTPAlt {
method constructor (line 15) | constructor(deploymentInstance = false) {
method initConnection (line 22) | async initConnection() {
method downloadFilesList (line 113) | async downloadFilesList() {
method uploadNewFileList (line 137) | async uploadNewFileList() {
method uploadFile (line 184) | async uploadFile(input, output) {
method uploadDirectory (line 220) | async uploadDirectory(input, output) {
method removeFile (line 268) | async removeFile(input) {
method removeDirectory (line 283) | async removeDirectory(input) {
method updateProgress (line 298) | updateProgress (progressType) {
method testConnection (line 309) | async testConnection(app, deploymentConfig, siteName, uuid) {
method connectionDebugger (line 401) | connectionDebugger(message) {
FILE: app/back-end/modules/deploy/ftp.js
class FTP (line 13) | class FTP {
method constructor (line 14) | constructor(deploymentInstance = false) {
method initConnection (line 22) | async initConnection() {
method downloadFilesList (line 155) | downloadFilesList() {
method uploadNewFileList (line 192) | uploadNewFileList() {
method uploadFile (line 248) | uploadFile(input, output) {
method uploadDirectory (line 307) | uploadDirectory(input, output) {
method removeFile (line 366) | removeFile(input) {
method removeDirectory (line 396) | removeDirectory(input) {
method testConnection (line 427) | async testConnection(app, deploymentConfig, siteName, uuid) {
method connectionDebugger (line 534) | connectionDebugger(message) {
FILE: app/back-end/modules/deploy/git.js
class Git (line 12) | class Git {
method constructor (line 13) | constructor(deploymentInstance = false) {
method initConnection (line 24) | async initConnection() {
method testConnection (line 60) | async testConnection(app, deploymentConfig, siteName, uuid) {
method prepareToSync (line 128) | async prepareToSync (siteConfig, siteName, dir, sendProgressCallback) {
method deploy (line 250) | async deploy() {
method hasCorrectOrigin (line 375) | async hasCorrectOrigin (repo, originToCheck) {
FILE: app/back-end/modules/deploy/github-pages.js
class GithubPages (line 18) | class GithubPages {
method constructor (line 19) | constructor(deploymentInstance = false) {
method initConnection (line 47) | async initConnection() {
method testConnection (line 189) | async testConnection(app, deploymentConfig, siteName, uuid) {
method deploy (line 263) | async deploy() {
method apiRequest (line 326) | async apiRequest(requestData, method, extractor) {
method getAPIRateLimit (line 345) | getAPIRateLimit() {
method getLatestSHA (line 353) | getLatestSHA() {
method getTreeSHA (line 382) | getTreeSHA(latestCommitSHA) {
method getTreeData (line 403) | getTreeData(treeSHA) {
method getNewTreeBasedOnDiffs (line 427) | async getNewTreeBasedOnDiffs(remoteTree, localTree) {
method findRemoteFile (line 472) | findRemoteFile(filePath, remoteTree) {
method listFolderFiles (line 482) | async listFolderFiles(remoteTree) {
method createBlob (line 519) | createBlob(filePath) {
method updateBlobsList (line 552) | updateBlobsList(files) {
method createBlobs (line 570) | async createBlobs(files, reuploadSession = false) {
method createTree (line 626) | createTree(tree) {
method createCommit (line 665) | createCommit(tree, parentSHA) {
method createReference (line 694) | createReference(sha) {
method isBinaryFile (line 721) | isBinaryFile(fullPath) {
method isNecessaryFile (line 741) | isNecessaryFile(filePath) {
FILE: app/back-end/modules/deploy/gitlab-pages.js
class GitlabPages (line 12) | class GitlabPages {
method constructor (line 13) | constructor (deploymentInstance = false) {
method testConnection (line 36) | async testConnection (app, deploymentConfig, siteName, uuid) {
method initConnection (line 145) | async initConnection () {
method downloadFilesList (line 186) | downloadFilesList () {
method startSync (line 235) | startSync () {
method removeFiles (line 240) | removeFiles () {
method updateTextFiles (line 262) | updateTextFiles () {
method uploadTextFiles (line 303) | uploadTextFiles () {
method createBinaryFilesList (line 344) | createBinaryFilesList () {
method updateBinaryFiles (line 386) | updateBinaryFiles () {
method uploadBinaryFiles (line 412) | uploadBinaryFiles () {
method updateFilesListFile (line 436) | updateFilesListFile () {
method finishSync (line 459) | finishSync () {
method makeCommit (line 471) | makeCommit (operations, nextOperationCallback, commitMessage = 'Publii...
method setUploadProgress (line 486) | setUploadProgress (progress, operations = false) {
method readFile (line 499) | readFile (filePath) {
method isBinaryFile (line 503) | isBinaryFile (fullPath) {
method getPrefix (line 523) | getPrefix (fileNameToBePrefixed) {
method isNecessaryFile (line 533) | isNecessaryFile (filePath) {
FILE: app/back-end/modules/deploy/google-cloud.js
class GoogleCloud (line 12) | class GoogleCloud {
method constructor (line 13) | constructor(deploymentInstance = false) {
method initConnection (line 22) | async initConnection() {
method downloadFilesList (line 90) | downloadFilesList() {
method uploadNewFileList (line 111) | uploadNewFileList() {
method uploadFile (line 161) | uploadFile(input, output) {
method uploadDirectory (line 227) | uploadDirectory(input, output) {
method removeFile (line 231) | removeFile(input) {
method removeDirectory (line 266) | removeDirectory(input) {
method testConnection (line 270) | async testConnection(app, deploymentConfig, siteName) {
FILE: app/back-end/modules/deploy/libraries/netlify-api.js
class NetlifyAPI (line 8) | class NetlifyAPI {
method constructor (line 9) | constructor (settings, events = {}) {
method deploy (line 23) | async deploy () {
method prepareLocalFilesList (line 59) | async prepareLocalFilesList () {
method makeApiRequest (line 78) | async makeApiRequest (method, endpoint, data) {
method uploadFile (line 118) | async uploadFile (filePath, deployID) {
method getFilesToUpload (line 159) | getFilesToUpload (filesList, hashesToUpload) {
method getFileHash (line 176) | getFileHash (fileName) {
method readDirRecursiveSync (line 190) | readDirRecursiveSync(dir, fileList) {
method fileIsDirectory (line 208) | fileIsDirectory (dir, file) {
method fileIsNotExcluded (line 212) | fileIsNotExcluded (file) {
method getFilePath (line 216) | getFilePath (dir, file, includeInputDir = false) {
method noop (line 224) | noop () {
method testConnection (line 228) | async testConnection () {
FILE: app/back-end/modules/deploy/manual.js
class ManualDeployment (line 11) | class ManualDeployment {
method constructor (line 12) | constructor(deploymentInstance = false) {
method initConnection (line 16) | async initConnection() {
method returnCatalog (line 32) | returnCatalog() {
method returnZipArchive (line 77) | returnZipArchive() {
method returnTarArchive (line 133) | returnTarArchive() {
method endDeployment (line 189) | endDeployment(type, pathToOutput) {
FILE: app/back-end/modules/deploy/netlify.js
class Netlify (line 12) | class Netlify {
method constructor (line 13) | constructor(deploymentInstance = false) {
method initConnection (line 19) | async initConnection() {
method onStart (line 98) | onStart (totalFiles) {
method onError (line 105) | onError (apiResponse = false) {
method onProgress (line 126) | onProgress(currentFile) {
method testConnection (line 144) | async testConnection(app, deploymentConfig, siteName, uuid) {
FILE: app/back-end/modules/deploy/s3.js
class S3 (line 19) | class S3 {
method constructor (line 20) | constructor(deploymentInstance = false) {
method initConnection (line 29) | async initConnection() {
method downloadFilesList (line 125) | async downloadFilesList() {
method uploadNewFileList (line 156) | async uploadNewFileList() {
method uploadFile (line 209) | async uploadFile() {
method uploadFileObject (line 225) | async uploadFileObject(input) {
method removeFile (line 286) | async removeFile() {
method removeFileObject (line 302) | async removeFileObject(input) {
method onError (line 331) | onError(err, silentMode = false) {
method prepareFilePath (line 348) | prepareFilePath(filePath) {
method testConnection (line 356) | async testConnection(app, deploymentConfig, siteName, uuid) {
method sendProgress (line 434) | sendProgress (progress, showOperations = true) {
method s3streamToString (line 451) | async s3streamToString (stream) {
FILE: app/back-end/modules/deploy/sftp.js
class SFTP (line 13) | class SFTP {
method constructor (line 14) | constructor(deploymentInstance = false) {
method initConnection (line 19) | async initConnection() {
method downloadFilesList (line 122) | downloadFilesList() {
method uploadNewFileList (line 149) | uploadNewFileList() {
method uploadFile (line 207) | uploadFile(input, output) {
method uploadDirectory (line 239) | uploadDirectory(input, output) {
method removeFile (line 298) | removeFile(input) {
method removeDirectory (line 323) | removeDirectory(input) {
method testConnection (line 348) | async testConnection(app, deploymentConfig, siteName, siteConfig) {
FILE: app/back-end/modules/import/automatic-paragraphs.js
function automaticParagraphs (line 1) | function automaticParagraphs (inputText) {
FILE: app/back-end/modules/import/import.js
class Import (line 12) | class Import {
method constructor (line 20) | constructor(appInstance, siteName, filePath) {
method connectWithDB (line 33) | connectWithDB() {
method checkFile (line 56) | checkFile() {
method importFile (line 93) | importFile(importAuthors, usedTaxonomy, autop, postTypes) {
FILE: app/back-end/modules/import/wxr-parser.js
class WxrParser (line 19) | class WxrParser {
method constructor (line 26) | constructor(appInstance, siteName) {
method loadFile (line 55) | loadFile(filePath) {
method isWXR (line 67) | isWXR() {
method parseFile (line 87) | parseFile() {
method getWxrStats (line 110) | getWxrStats() {
method getItemsCount (line 147) | getItemsCount(items, filterType = false) {
method getPostTypes (line 169) | getPostTypes(items) {
method setConfig (line 196) | setConfig(authors, taxonomy, autop, postTypes) {
method importAuthorsData (line 216) | importAuthorsData() {
method createAuthor (line 242) | createAuthor(authorData, index, totalNumber) {
method importTagsData (line 288) | importTagsData() {
method createTag (line 315) | createTag(tagData, index, totalNumber) {
method importPostsData (line 379) | importPostsData() {
method importPagesData (line 502) | importPagesData() {
method getImageURLs (line 614) | getImageURLs() {
method getPostImages (line 632) | getPostImages(postText) {
method getFeaturedPostImage (line 656) | getFeaturedPostImage(postObject) {
method importImages (line 680) | importImages() {
method downloadImages (line 715) | downloadImages(imagesQueue, destinationPath) {
method countImages (line 791) | countImages() {
method preparePostText (line 807) | preparePostText(text, images) {
method finishImport (line 843) | finishImport() {
FILE: app/back-end/modules/plugins/plugins-api.js
class PluginsAPI (line 1) | class PluginsAPI {
method constructor (line 2) | constructor () {
method _add (line 12) | _add (scope, place, callback, priority) {
method addSiteEvent (line 22) | addSiteEvent (event, callback, priority) {
method addAppEvent (line 26) | addAppEvent (event, callback, priority) {
method _get (line 33) | _get (scope, place) {
method getSiteEvents (line 41) | getSiteEvents (event) {
method getAppEvents (line 45) | getAppEvents (event) {
method _remove (line 52) | _remove (scope, place, callback, priority) {
method removeSiteEvent (line 60) | removeSiteEvent (event, callback, priority) {
method removeAppEvent (line 64) | removeAppEvent (event, callback, priority) {
method _reset (line 71) | _reset (scope) {
method resetSiteEvents (line 75) | resetSiteEvents () {
method resetAppEvents (line 79) | resetAppEvents () {
method sortByPriority (line 86) | sortByPriority (itemA, itemB) {
FILE: app/back-end/modules/plugins/plugins-helpers.js
class PluginsHelpers (line 4) | class PluginsHelpers {
method getActivePluginsList (line 6) | static getActivePluginsList (sitePluginsConfigPath) {
method getPluginFrontEndFiles (line 34) | static getPluginFrontEndFiles (pluginName, pluginsDir) {
FILE: app/back-end/modules/render-html/contexts/404.js
class RendererContext404 (line 9) | class RendererContext404 extends RendererContext {
method loadData (line 13) | loadData() {
method prepareData (line 50) | prepareData() {
method setContext (line 63) | setContext() {
method getContext (line 95) | getContext() {
FILE: app/back-end/modules/render-html/contexts/author.js
class RendererContextAuthor (line 12) | class RendererContextAuthor extends RendererContext {
method loadData (line 13) | loadData() {
method prepareData (line 79) | prepareData() {
method setContext (line 145) | setContext() {
method getContext (line 180) | getContext(authorID, offset = 0, postsNumber = 999) {
FILE: app/back-end/modules/render-html/contexts/feed.js
class RendererContextFeed (line 12) | class RendererContextFeed extends RendererContext {
method loadData (line 13) | loadData() {
method prepareData (line 51) | prepareData() {
method setContext (line 73) | setContext() {
method getContext (line 105) | getContext(postsNumber = 10) {
method getLastUpdateDate (line 113) | getLastUpdateDate() {
method getPostCategories (line 126) | getPostCategories(postID) {
method getPostThumbnail (line 152) | getPostThumbnail(postID) {
method getAuthor (line 202) | getAuthor(dataType, id) {
FILE: app/back-end/modules/render-html/contexts/home.js
class RendererContextHome (line 10) | class RendererContextHome extends RendererContext {
method loadData (line 11) | loadData() {
method prepareData (line 90) | prepareData() {
method setContext (line 110) | setContext() {
method getContext (line 138) | getContext(offset = 0, postsNumber = 999) {
method getPostsNumber (line 146) | getPostsNumber() {
FILE: app/back-end/modules/render-html/contexts/page-preview.js
class RendererContextPagePreview (line 18) | class RendererContextPagePreview extends RendererContext {
method loadData (line 19) | loadData() {
method prepareData (line 31) | prepareData() {
method setContext (line 71) | setContext() {
method getContext (line 93) | getContext(pageID) {
method getPageFeaturedImages (line 100) | getPageFeaturedImages(pageID, mainPage = false) {
method prepareContent (line 238) | prepareContent(originalText, pageID) {
method isGifOrSvg (line 364) | isGifOrSvg(url) {
FILE: app/back-end/modules/render-html/contexts/page.js
class RendererContextPage (line 9) | class RendererContextPage extends RendererContext {
method loadData (line 10) | loadData() {
method prepareData (line 31) | prepareData() {
method setContext (line 86) | setContext() {
method getContext (line 142) | getContext(pageID) {
FILE: app/back-end/modules/render-html/contexts/post-preview.js
class RendererContextPostPreview (line 18) | class RendererContextPostPreview extends RendererContext {
method loadData (line 19) | loadData() {
method prepareData (line 40) | prepareData() {
method loadPost (line 128) | loadPost(type, similarPost = false) {
method loadRelatedPosts (line 210) | loadRelatedPosts() {
method setContext (line 294) | setContext() {
method getContext (line 318) | getContext(postID) {
method getPostFeaturedImages (line 325) | getPostFeaturedImages(postID, mainPost = false) {
method prepareContent (line 462) | prepareContent(originalText, postID) {
method isGifOrSvg (line 588) | isGifOrSvg(url) {
FILE: app/back-end/modules/render-html/contexts/post.js
class RendererContextPost (line 11) | class RendererContextPost extends RendererContext {
method loadData (line 12) | loadData() {
method prepareData (line 33) | prepareData() {
method loadPost (line 114) | loadPost(type, similarPost = false) {
method loadRelatedPosts (line 234) | loadRelatedPosts() {
method setContext (line 382) | setContext() {
method getContext (line 443) | getContext(postID) {
FILE: app/back-end/modules/render-html/contexts/search.js
class RendererContextSearch (line 9) | class RendererContextSearch extends RendererContext {
method loadData (line 13) | loadData() {
method prepareData (line 51) | prepareData() {
method setContext (line 64) | setContext() {
method getContext (line 96) | getContext() {
FILE: app/back-end/modules/render-html/contexts/tag.js
class RendererContextTag (line 10) | class RendererContextTag extends RendererContext {
method loadData (line 11) | loadData() {
method prepareData (line 79) | prepareData() {
method setContext (line 147) | setContext() {
method getContext (line 182) | getContext(tagID, offset = 0, postsNumber = 999) {
FILE: app/back-end/modules/render-html/contexts/tags.js
class RendererContextTags (line 8) | class RendererContextTags extends RendererContext {
method loadData (line 9) | loadData() {
method prepareData (line 27) | prepareData() {
method setContext (line 55) | setContext() {
method getContext (line 83) | getContext () {
FILE: app/back-end/modules/render-html/handlebars/helpers/asset.js
function asset (line 11) | function asset(filePath) {
function assetHelper (line 28) | function assetHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/canonical-link.js
function canonicalLinkHelper (line 10) | function canonicalLinkHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/check-if-all.js
function checkIfAll (line 11) | function checkIfAll() {
FILE: app/back-end/modules/render-html/handlebars/helpers/check-if-any.js
function checkIfAny (line 11) | function checkIfAny() {
FILE: app/back-end/modules/render-html/handlebars/helpers/check-if-none.js
function checkIfNone (line 12) | function checkIfNone() {
FILE: app/back-end/modules/render-html/handlebars/helpers/check-if.js
function checkIf (line 14) | function checkIf(v1, operator, v2, options) {
FILE: app/back-end/modules/render-html/handlebars/helpers/concatenate.js
function concatenate (line 10) | function concatenate () {
FILE: app/back-end/modules/render-html/handlebars/helpers/contains.js
function contains (line 8) | function contains (needle, haystack, options) {
FILE: app/back-end/modules/render-html/handlebars/helpers/css.js
function getMD5 (line 16) | function getMD5(localPath, overridedLocalPath) {
function CSSHelper (line 39) | function CSSHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/date.js
function dateHelper (line 20) | function dateHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/encode-url-fragment.js
function encodeUrlFragment (line 10) | function encodeUrlFragment(text) {
FILE: app/back-end/modules/render-html/handlebars/helpers/encode-url.js
function encodeUrl (line 13) | function encodeUrl(text) {
FILE: app/back-end/modules/render-html/handlebars/helpers/feed-link.js
function feedLink (line 10) | function feedLink() {
function feedLinkHelper (line 46) | function feedLinkHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/font.js
function font (line 11) | function font(path) {
function fontHelper (line 25) | function fontHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/gdpr-script-blocker.js
function gdprScriptBlockerHelper (line 10) | function gdprScriptBlockerHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-author.js
function getAuthorHelper (line 14) | function getAuthorHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-authors.js
function getAuthorsHelper (line 14) | function getAuthorsHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-page.js
function getPageHelper (line 11) | function getPageHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-pages-by-custom-field.js
function getPagesByCustomFieldsHelper (line 22) | function getPagesByCustomFieldsHelper (rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-pages.js
function getPagesHelper (line 17) | function getPagesHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-post-by-tags.js
function getPostByTagsHelper (line 27) | function getPostByTagsHelper (rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-post.js
function getPostHelper (line 11) | function getPostHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-posts-by-custom-field.js
function getPostsByCustomFieldsHelper (line 24) | function getPostsByCustomFieldsHelper (rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-posts-by-tags.js
function getPostsByTagsHelper (line 46) | function getPostsByTagsHelper (rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-posts.js
function getPostsHelper (line 17) | function getPostsHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-tag.js
function getTagHelper (line 14) | function getTagHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/get-tags.js
function getTagsHelper (line 14) | function getTagsHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/image-dimensions.js
function imageDimensionsHelper (line 13) | function imageDimensionsHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/is-current-page.js
function isCurrentPage (line 10) | function isCurrentPage(current, iteration, options) {
FILE: app/back-end/modules/render-html/handlebars/helpers/is-empty.js
function isEmpty (line 10) | function isEmpty(obj, options) {
FILE: app/back-end/modules/render-html/handlebars/helpers/is-not-empty.js
function isNotEmpty (line 11) | function isNotEmpty(obj, options) {
FILE: app/back-end/modules/render-html/handlebars/helpers/is-not.js
function isNot (line 12) | function isNot (conditional, options) {
FILE: app/back-end/modules/render-html/handlebars/helpers/is.js
function is (line 12) | function is(conditional, options) {
FILE: app/back-end/modules/render-html/handlebars/helpers/join.js
function join (line 10) | function join () {
FILE: app/back-end/modules/render-html/handlebars/helpers/js.js
function getMD5 (line 16) | function getMD5(localPath, overridedLocalPath) {
function JSHelper (line 39) | function JSHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/json-ld.js
function jsonLDHelper (line 14) | function jsonLDHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/jsonify.js
function jsonify (line 8) | function jsonify(content) {
FILE: app/back-end/modules/render-html/handlebars/helpers/lazyload.js
function lazyloadHelper (line 10) | function lazyloadHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/math.js
function math (line 12) | function math(a, operator, b) {
FILE: app/back-end/modules/render-html/handlebars/helpers/menu-item-classes.js
function menuItemClassesHelper (line 18) | function menuItemClassesHelper(rendererInstance, Handlebars) {
function hasActiveChild (line 125) | function hasActiveChild(items, context) {
FILE: app/back-end/modules/render-html/handlebars/helpers/menu-url.js
function menuURLHelper (line 21) | function menuURLHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/meta-description.js
function metaDescription (line 10) | function metaDescription(options) {
FILE: app/back-end/modules/render-html/handlebars/helpers/meta-robots.js
function metaRobotsHelper (line 10) | function metaRobotsHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/not-contains.js
function notContains (line 8) | function notContains (needle, haystack, options) {
FILE: app/back-end/modules/render-html/handlebars/helpers/orderby.js
function orderby (line 10) | function orderby (collection, field, direction, langForLocaleCompare = f...
FILE: app/back-end/modules/render-html/handlebars/helpers/page-url.js
function pageURLHelper (line 8) | function pageURLHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/publii-footer.js
function publiiFooterHelper (line 11) | function publiiFooterHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/publii-head.js
function publiiHeadHelper (line 10) | function publiiHeadHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/responsive-image-attributes.js
function responsiveImageAttributesHelper (line 16) | function responsiveImageAttributesHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/responsive-sizes.js
function responsiveSizesHelper (line 11) | function responsiveSizesHelper(rendererInstance, Handlebars) {
function returnSizesAttribute (line 15) | function returnSizesAttribute (type, group) {
FILE: app/back-end/modules/render-html/handlebars/helpers/responsive-srcset.js
function responsiveSrcSetHelper (line 14) | function responsiveSrcSetHelper(rendererInstance, Handlebars) {
function returnSrcSetAttribute (line 18) | function returnSrcSetAttribute (url, type, group) {
FILE: app/back-end/modules/render-html/handlebars/helpers/reverse.js
function reverse (line 7) | function reverse (collection) {
FILE: app/back-end/modules/render-html/handlebars/helpers/social-meta-tags.js
function socialMetaTagsHelper (line 13) | function socialMetaTagsHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/handlebars/helpers/translate.js
function translate (line 10) | function translate(key) {
function resolveObject (line 86) | function resolveObject(obj, path) {
function translateHelper (line 101) | function translateHelper(rendererInstance, Handlebars) {
FILE: app/back-end/modules/render-html/helpers/content.js
class ContentHelper (line 17) | class ContentHelper {
method prepareContent (line 28) | static prepareContent(postID, originalText, siteDomain, themeConfig, r...
method parseText (line 181) | static parseText (inputText, editor = 'tinymce') {
method prepareMarkdown (line 200) | static prepareMarkdown (input) {
method prepareExcerpt (line 212) | static prepareExcerpt(length, text) {
method getFeaturedImageSrcset (line 255) | static getFeaturedImageSrcset(baseUrl, themeConfig, useWebp, type = 'p...
method getFeaturedImageSizes (line 322) | static getFeaturedImageSizes(themeConfig, type = 'post') {
method getContentImageSrcset (line 347) | static getContentImageSrcset(baseUrl, themeConfig, useWebp) {
method getContentImageSizes (line 375) | static getContentImageSizes(themeConfig) {
method _getSrcSet (line 395) | static _getSrcSet(url, dimension, useWebp) {
method _isImage (line 419) | static _isImage(url) {
method _addResponsiveAttributes (line 442) | static _addResponsiveAttributes(matches, url, themeConfig, useWebp, do...
method _imageIsLocal (line 489) | static _imageIsLocal (url, domain) {
method setInternalLinks (line 512) | static setInternalLinks(text, renderer) {
method prepareInternalLinks (line 534) | static prepareInternalLinks(text, renderer, type) {
method addEmbedConsents (line 668) | static addEmbedConsents (text, embedConsents) {
method setWebpCompatibility (line 718) | static setWebpCompatibility (forceWebp, text) {
method isWebpImage (line 751) | static isWebpImage (url) {
method getImageType (line 764) | static getImageType (url) {
method getImageExtension (line 785) | static getImageExtension (url) {
FILE: app/back-end/modules/render-html/helpers/deleteEmpty.js
function isSystemFile (line 9) | function isSystemFile (file) {
function deleteEmpty (line 13) | function deleteEmpty (dirPath) {
FILE: app/back-end/modules/render-html/helpers/diffCopy.js
class DiffCopy (line 5) | class DiffCopy {
method copy (line 6) | static async copy (input, output) {
method listAllFiles (line 18) | static async listAllFiles (dir) {
method compareExistingFiles (line 22) | static compareExistingFiles (inputFiles, inputDir, outputDir) {
method inputFilesCopy (line 43) | static inputFilesCopy (inputFiles, outputFiles, inputDir, outputDir) {
method outputFilesDelete (line 80) | static outputFilesDelete (inputFiles, outputFiles, inputDir, outputDir) {
method removeUnusedItemFolders (line 114) | static removeUnusedItemFolders (postIDs, pageIDs, baseOutputPath) {
method getFileSize (line 136) | static getFileSize(filename) {
FILE: app/back-end/modules/render-html/helpers/files.js
class Files (line 10) | class Files {
method copyRootFiles (line 17) | static copyRootFiles(inputDir, outputDir) {
method copyAssetsFiles (line 43) | static async copyAssetsFiles(themeDir, outputDir, themeConfig) {
method copyDynamicAssetsFiles (line 116) | static copyDynamicAssetsFiles(themeDir, outputDir, themeConfig) {
method copyMediaFiles (line 167) | static async copyMediaFiles (inputDir, outputDir, postIDs, pageIDs) {
method copyPluginFiles (line 225) | static async copyPluginFiles (inputDir, outputDir, pluginsDir) {
method removeEmptyDirectories (line 271) | static async removeEmptyDirectories (outputDir) {
FILE: app/back-end/modules/render-html/helpers/gdpr.js
class Gdpr (line 2) | class Gdpr {
method popupHtmlOutput (line 3) | static popupHtmlOutput (configuration, renderer) {
method prepareCookieGroups (line 9) | static prepareCookieGroups (configuration) {
method parseTemplate (line 64) | static parseTemplate (configuration, template, renderer) {
method popupCssOutput (line 130) | static popupCssOutput () {
method popupJsOutput (line 135) | static popupJsOutput (configuration) {
method getPrivacyPolicyUrl (line 160) | static getPrivacyPolicyUrl (configuration, renderer) {
FILE: app/back-end/modules/render-html/helpers/helpers.js
class RendererHelpers (line 5) | class RendererHelpers {
method getRendererOptionValue (line 6) | static getRendererOptionValue (optionName, themeConfig) {
FILE: app/back-end/modules/render-html/helpers/sitemap.js
class Sitemap (line 19) | class Sitemap {
method constructor (line 27) | constructor (db, directory, siteConfig, themeConfig) {
method create (line 47) | async create () {
method getData (line 59) | getData () {
method getMatches (line 195) | getMatches (string, regex, index = 1) {
method getMediaPath (line 209) | getMediaPath (postObject) {
method getFilesList (line 216) | async getFilesList () {
method getInternalsList (line 319) | getInternalsList () {
method shouldIndexAuthors (line 348) | shouldIndexAuthors () {
method shouldIndexHomepage (line 357) | shouldIndexHomepage () {
method shouldIndexTags (line 366) | shouldIndexTags () {
method getAuthorsFilesList (line 373) | async getAuthorsFilesList () {
method getTagsFilesList (line 443) | async getTagsFilesList (tagName, prefix = '') {
method getHomepagePaginationFilesList (line 571) | async getHomepagePaginationFilesList () {
method getPostsAndPagesFilesList (line 626) | async getPostsAndPagesFilesList (file, cleanUrlsEnabled = false, skipP...
method scanSubpages (line 691) | scanSubpages (subpages, currentPath) {
method renderXML (line 724) | renderXML() {
method saveXML (line 779) | saveXML () {
method isExcluded (line 797) | isExcluded (url) {
FILE: app/back-end/modules/render-html/helpers/template.js
class TemplateHelper (line 11) | class TemplateHelper {
method constructor (line 15) | constructor(themeDir, outputDir, siteConfig) {
method loadThemeConfig (line 27) | loadThemeConfig() {
method loadTemplate (line 42) | loadTemplate(fileName) {
method loadPartialTemplate (line 65) | loadPartialTemplate(fileName) {
method saveOutputFile (line 89) | saveOutputFile(fileName, content) {
method saveOutputPostFile (line 100) | saveOutputPostFile (postSlug, content) {
method saveOutputHomePaginationFile (line 123) | saveOutputHomePaginationFile(pageNumber, content) {
method saveOutputPageFile (line 143) | saveOutputPageFile (pageID, pageSlug, content, renderer) {
method saveOutputTagsListFile (line 186) | saveOutputTagsListFile(content) {
method saveOutputTagFile (line 202) | saveOutputTagFile(tagSlug, content, isTagPreview = false) {
method saveOutputTagPaginationFile (line 231) | saveOutputTagPaginationFile(tagSlug, pageNumber, content) {
method saveOutputAuthorFile (line 273) | saveOutputAuthorFile(authorSlug, content, isAuthorPreview = false) {
method saveOutputAuthorPaginationFile (line 292) | saveOutputAuthorPaginationFile(authorSlug, pageNumber, content) {
method compressHTML (line 312) | compressHTML(content) {
method getUserPartials (line 338) | getUserPartials(requiredPartials, optionalPartials) {
method getHbsFilesRecursively (line 394) | getHbsFilesRecursively (dir) {
FILE: app/back-end/modules/render-html/helpers/url.js
class URLHelper (line 13) | class URLHelper {
method createSlug (line 20) | static createSlug(string) {
method createTagPermalink (line 33) | static createTagPermalink(domain, urlsConfig, tagName, addIndexHtml = ...
method createPaginationPermalink (line 61) | static createPaginationPermalink(siteConfig, themeConfig, pageNumber, ...
method createImageURL (line 134) | static createImageURL(domain, itemID, imageURL, type = 'post') {
method transformAssetURLIntoPath (line 150) | static transformAssetURLIntoPath(inputDir, assetUrl, websiteUrl) {
method fixProtocols (line 166) | static fixProtocols(input) {
method prepareSettingsImages (line 213) | static prepareSettingsImages(domain, settings) {
FILE: app/back-end/modules/render-html/helpers/view-settings.js
class ViewSettings (line 1) | class ViewSettings {
method override (line 2) | static override(viewSettings, defaultViewConfig, itemData, rendererIns...
FILE: app/back-end/modules/render-html/items/author.js
class AuthorItem (line 11) | class AuthorItem {
method constructor (line 18) | constructor(author, rendererInstance) {
method prepareData (line 33) | prepareData() {
method storeData (line 103) | storeData() {
method getPostsNumber (line 117) | getPostsNumber() {
method setAuthorViewConfig (line 132) | setAuthorViewConfig(config) {
FILE: app/back-end/modules/render-html/items/featured-image.js
class FeaturedImageItem (line 10) | class FeaturedImageItem {
method constructor (line 11) | constructor(image, rendererInstance, type = 'featuredImages', cacheIte...
method prepareData (line 35) | prepareData() {
method storeData (line 150) | storeData() {
method isGifOrSvg (line 162) | isGifOrSvg(url) {
FILE: app/back-end/modules/render-html/items/page.js
class PageItem (line 7) | class PageItem {
method constructor (line 8) | constructor(page, rendererInstance) {
method getMetaData (line 25) | getMetaData () {
method prepareData (line 46) | prepareData() {
method storeData (line 105) | storeData() {
method setInternalLinks (line 113) | setInternalLinks() {
method setHierarchyLinks (line 120) | setHierarchyLinks() {
method setPageViewConfig (line 158) | setPageViewConfig(config) {
FILE: app/back-end/modules/render-html/items/post.js
class PostItem (line 7) | class PostItem {
method constructor (line 8) | constructor(post, rendererInstance) {
method getMetaData (line 24) | getMetaData () {
method prepareData (line 45) | prepareData() {
method storeData (line 159) | storeData() {
method setInternalLinks (line 167) | setInternalLinks() {
method setPostViewConfig (line 174) | setPostViewConfig(config) {
FILE: app/back-end/modules/render-html/items/tag.js
class TagItem (line 6) | class TagItem {
method constructor (line 13) | constructor(tag, rendererInstance, mainTagIDs = []) {
method prepareData (line 29) | prepareData() {
method storeData (line 58) | storeData() {
method getPostsNumber (line 76) | getPostsNumber() {
method setTagViewConfig (line 91) | setTagViewConfig(config) {
FILE: app/back-end/modules/render-html/renderer-cache.js
class RendererCache (line 13) | class RendererCache {
method constructor (line 19) | constructor(rendererInstance, themeConfig) {
method create (line 28) | create() {
method getTags (line 55) | getTags() {
method getTagPostCounts (line 105) | getTagPostCounts() {
method getFeaturedAuthorImages (line 145) | getFeaturedAuthorImages() {
method getAuthors (line 185) | getAuthors() {
method getAuthorPostCounts (line 219) | getAuthorPostCounts() {
method getFeaturedPostImages (line 259) | getFeaturedPostImages() {
method getFeaturedPageImages (line 290) | getFeaturedPageImages() {
method getFeaturedTagImages (line 321) | getFeaturedTagImages() {
method getPostTags (line 361) | getPostTags() {
method getPagesStructure (line 394) | getPagesStructure () {
method getPosts (line 442) | getPosts() {
method getPages (line 475) | getPages() {
method getPostViewSettings (line 513) | getPostViewSettings(defaultPostViewConfig, postID) {
method getPageViewSettings (line 548) | getPageViewSettings(defaultPageViewConfig, pageID) {
method getViewSettings (line 583) | getViewSettings(defaultViewConfig, itemData, itemConfig) {
method setInternalLinks (line 604) | setInternalLinks (posts, pages) {
FILE: app/back-end/modules/render-html/renderer-context.js
class RendererContext (line 16) | class RendererContext {
method constructor (line 17) | constructor(rendererInstance) {
method getMenus (line 53) | getMenus() {
method prepareMenuItems (line 122) | prepareMenuItems(items, tagsData, postsData, pagesData, level = 2, max...
method getTagsMenuData (line 176) | getTagsMenuData() {
method getPostsMenuData (line 191) | getPostsMenuData () {
method getPagesMenuData (line 209) | getPagesMenuData () {
method getAllTags (line 227) | getAllTags() {
method getAllMainTags (line 249) | getAllMainTags() {
method getAuthors (line 279) | getAuthors() {
method setGlobalContext (line 296) | setGlobalContext(context, additionalContexts, paginationData, itemSlug...
method getCustomHTMLCode (line 435) | getCustomHTMLCode (optionName, context) {
method getCustomHTMLCodeObject (line 446) | getCustomHTMLCodeObject (object, context) {
method getGlobalContext (line 474) | getGlobalContext(context, additionalContexts, paginationData, itemSlug...
method getContentStructure (line 479) | getContentStructure() {
method getContentStructureTagPosts (line 548) | getContentStructureTagPosts(tagID) {
method getContentStructureAuthorPosts (line 583) | getContentStructureAuthorPosts(authorID) {
method getCachedItems (line 615) | getCachedItems() {
method getFeaturedPosts (line 620) | getFeaturedPosts(type) {
method getHiddenPosts (line 656) | getHiddenPosts() {
method getPages (line 674) | getPages() {
method getPageUrl (line 688) | getPageUrl (context, paginationData, itemSlug, itemContext) {
method getPaginationContextData (line 796) | getPaginationContextData (paginationData) {
method getFirstPageContextData (line 804) | getFirstPageContextData (paginationData) {
method getLastPageContextData (line 812) | getLastPageContextData (paginationData) {
method getTagsUrl (line 820) | getTagsUrl () {
FILE: app/back-end/modules/render-html/renderer-plugins.js
class RendererPlugins (line 5) | class RendererPlugins {
method constructor (line 6) | constructor (sitePath) {
method _add (line 16) | _add (type, key, callback, priority, pluginInstance) {
method addInsertion (line 26) | addInsertion (place, callback, priority, pluginInstance) {
method addModifier (line 30) | addModifier (value, callback, priority, pluginInstance) {
method addEvent (line 34) | addEvent (value, callback, priority, pluginInstance) {
method _get (line 41) | _get (type, key) {
method getInsertions (line 49) | getInsertions (place) {
method getModifiers (line 53) | getModifiers (value) {
method getEvents (line 57) | getEvents (value) {
method _has (line 64) | _has (type, key) {
method hasInsertions (line 72) | hasInsertions (place) {
method hasModifiers (line 76) | hasModifiers (value) {
method hasEvents (line 80) | hasEvents (value) {
method _remove (line 87) | _remove (type, key, callback, priority) {
method removeInsertion (line 95) | removeInsertion (place, callback, priority) {
method removeModifier (line 99) | removeModifier (value, callback, priority) {
method removeEvent (line 103) | removeEvent (value, callback, priority) {
method _reset (line 110) | _reset (type) {
method resetInsertions (line 114) | resetInsertions () {
method resetModifiers (line 118) | resetModifiers () {
method resetEvents (line 122) | resetEvents () {
method runInsertions (line 129) | runInsertions (place, rendererInstance, params = false) {
method runModifiers (line 144) | runModifiers (value, rendererInstance, originalValue, params = false) {
method runEvents (line 159) | runEvents (value, rendererInstance, params = false) {
method sortByPriority (line 172) | sortByPriority (itemA, itemB) {
method readFile (line 179) | readFile (fileName, pluginInstance) {
method createFile (line 219) | createFile (fileName, fileContent, pluginInstance) {
FILE: app/back-end/modules/render-html/renderer.js
class Renderer (line 48) | class Renderer {
method constructor (line 49) | constructor(appDir, sitesDir, siteConfig, itemID = false, postData = f...
method render (line 108) | async render(previewMode = false, previewLocation = '', mode = 'full') {
method themeIsValid (line 141) | themeIsValid() {
method renderSite (line 161) | async renderSite() {
method renderFullPreview (line 191) | async renderFullPreview() {
method preparePageToRender (line 211) | preparePageToRender() {
method generateWWW (line 237) | async generateWWW() {
method preparePreview (line 289) | preparePreview (type) {
method renderPostPreview (line 320) | async renderPostPreview () {
method renderPagePreview (line 334) | async renderPagePreview () {
method renderHomepagePreview (line 348) | async renderHomepagePreview () {
method renderTagPreview (line 364) | async renderTagPreview () {
method renderAuthorPreview (line 391) | async renderAuthorPreview () {
method sendProgress (line 421) | sendProgress(progress, message = '') {
method emptyOutputDir (line 432) | async emptyOutputDir() {
method setIO (line 467) | setIO() {
method registerHelpers (line 485) | registerHelpers() {
method registerThemeHelpers (line 507) | registerThemeHelpers() {
method loadSiteConfig (line 546) | loadSiteConfig() {
method loadSiteTranslations (line 584) | loadSiteTranslations() {
method parseTranslations (line 614) | parseTranslations(path) {
method loadDataFromDB (line 629) | loadDataFromDB() {
method loadThemeConfig (line 637) | loadThemeConfig() {
method loadThemeFiles (line 666) | loadThemeFiles() {
method generatePartials (line 673) | generatePartials() {
method generateFrontpage (line 711) | generateFrontpage() {
method generatePosts (line 944) | generatePosts() {
method generatePost (line 1040) | generatePost() {
method generatePage (line 1104) | generatePage() {
method overrideItemViewSettings (line 1178) | overrideItemViewSettings(defaultViewConfig, itemID, itemType, itemPrev...
method generatePages (line 1213) | generatePages() {
method generateTagsList (line 1340) | generateTagsList() {
method generateTags (line 1379) | generateTags(tagID = false) {
method generateAuthors (line 1595) | generateAuthors(authorID = false) {
method generate404s (line 1822) | generate404s() {
method generateSearch (line 1860) | generateSearch() {
method generateCSS (line 1897) | generateCSS() {
method getThemeVariablesCSS (line 1928) | getThemeVariablesCSS() {
method getMainCSS (line 1959) | getMainCSS () {
method getGdprPopupCSS (line 1973) | getGdprPopupCSS () {
method getOverrideCSS (line 1984) | getOverrideCSS () {
method getCustomCSS (line 2015) | getCustomCSS () {
method generateFeeds (line 2028) | generateFeeds() {
method generateFeed (line 2049) | generateFeed(format = 'xml') {
method generateSitemap (line 2078) | async generateSitemap() {
method copyFiles (line 2092) | async copyFiles() {
method loadContentStructure (line 2106) | loadContentStructure() {
method loadCommonData (line 2132) | loadCommonData() {
method createGlobalContext (line 2156) | createGlobalContext(context, additionalContexts = [], paginationData =...
method compileTemplate (line 2161) | compileTemplate(inputFile) {
method renderTemplate (line 2192) | renderTemplate(compiledTemplate, context, globalContext, inputFile) {
method createRobotsTxt (line 2218) | createRobotsTxt () {
method relativizeUrls (line 2257) | async relativizeUrls () {
method relativizeUrlsInFile (line 2275) | relativizeUrlsInFile (file, outputDir) {
method loadPlugins (line 2292) | loadPlugins () {
method loadPluginConfig (line 2337) | loadPluginConfig (pluginName, siteName) {
method getPluginsConfig (line 2393) | getPluginsConfig () {
method triggerEvent (line 2418) | triggerEvent (eventName) {
FILE: app/back-end/modules/render-html/text-renderers/blockeditor.js
class BlocksToHtml (line 3) | class BlocksToHtml {
method parse (line 4) | static parse (inputJson) {
FILE: app/back-end/modules/render-html/text-renderers/markdown.js
class MarkdownToHtml (line 3) | class MarkdownToHtml {
method parse (line 4) | static parse (inputText) {
FILE: app/back-end/modules/render-html/validators/theme-config.js
function themeConfigValidator (line 9) | function themeConfigValidator(configPath) {
FILE: app/back-end/page.js
class Page (line 16) | class Page extends Model {
method constructor (line 17) | constructor(appInstance, pageData, storeMode = true) {
method load (line 46) | load() {
method save (line 141) | save() {
method delete (line 254) | delete() {
method duplicate (line 267) | duplicate() {
method changeStatus (line 371) | changeStatus(status, inverse = false) {
method checkAndPrepareSlug (line 406) | checkAndPrepareSlug(suffix = 0) {
method checkAndCleanImages (line 456) | checkAndCleanImages(cancelEvent = false) {
method cleanImages (line 512) | cleanImages(images, imagesDir, cancelEvent) {
method removeResponsiveImages (line 580) | removeResponsiveImages(originalPath) {
method saveAdditionalData (line 635) | saveAdditionalData() {
method savePageViewSettings (line 657) | savePageViewSettings() {
method cleanUpContent (line 679) | cleanUpContent (content) {
FILE: app/back-end/pages.js
class Pages (line 7) | class Pages extends Model {
method constructor (line 8) | constructor(appInstance, pagesData) {
method load (line 15) | load () {
method loadAuthorsXRef (line 47) | loadAuthorsXRef() {
FILE: app/back-end/plugins.js
class Plugins (line 11) | class Plugins {
method constructor (line 12) | constructor(appDir, sitesDir) {
method loadPlugins (line 21) | loadPlugins () {
method getExistingPluginsDirs (line 64) | getExistingPluginsDirs () {
method getSiteSpecificPluginsState (line 83) | getSiteSpecificPluginsState (siteName) {
method loadSitePluginsConfig (line 99) | loadSitePluginsConfig (siteName) {
method validateLoadedPlugins (line 129) | validateLoadedPlugins (siteName, configToCheck, existingPlugins) {
method saveSitePluginsConfig (line 157) | saveSitePluginsConfig (siteName, config) {
method activatePlugin (line 173) | activatePlugin (siteName, pluginName) {
method deactivatePlugin (line 182) | deactivatePlugin (siteName, pluginName) {
method removePlugin (line 191) | removePlugin (directory) {
method getPluginConfig (line 195) | getPluginConfig (siteName, pluginName) {
method savePluginConfig (line 227) | savePluginConfig (siteName, pluginName, newConfig) {
method loadPluginConfig (line 241) | loadPluginConfig (pluginName, siteName) {
method checkAndCleanImages (line 297) | checkAndCleanImages (siteName, pluginName, newConfig) {
FILE: app/back-end/post.js
class Post (line 17) | class Post extends Model {
method constructor (line 18) | constructor(appInstance, postData, storeMode = true) {
method load (line 49) | load() {
method save (line 167) | save() {
method delete (line 283) | delete() {
method duplicate (line 296) | duplicate() {
method changeStatus (line 414) | changeStatus(status, inverse = false) {
method saveTags (line 456) | saveTags() {
method saveTag (line 483) | saveTag(tagName) {
method checkAndPrepareSlug (line 513) | checkAndPrepareSlug(suffix = 0) {
method checkAndCleanImages (line 559) | checkAndCleanImages(cancelEvent = false) {
method cleanImages (line 615) | cleanImages(images, imagesDir, cancelEvent) {
method removeResponsiveImages (line 683) | removeResponsiveImages(originalPath) {
method saveAdditionalData (line 738) | saveAdditionalData() {
method savePostViewSettings (line 777) | savePostViewSettings() {
method cleanUpContent (line 799) | cleanUpContent (content) {
FILE: app/back-end/posts.js
class Posts (line 7) | class Posts extends Model {
method constructor (line 8) | constructor(appInstance, postsData) {
method load (line 15) | load() {
method loadTagsXRef (line 47) | loadTagsXRef() {
method loadAuthorsXRef (line 69) | loadAuthorsXRef() {
FILE: app/back-end/site.js
class Site (line 20) | class Site {
method constructor (line 21) | constructor(appInstance, config, maintenanceMode = false) {
method siteExists (line 40) | siteExists() {
method create (line 47) | create(authorName) {
method createDirectories (line 69) | createDirectories() {
method copyDefaultTheme (line 94) | copyDefaultTheme () {
method createConfigFiles (line 104) | createConfigFiles() {
method createDB (line 125) | createDB() {
method createAuthor (line 143) | createAuthor(authorName) {
method regenerateThumbnailsIsRequired (line 157) | regenerateThumbnailsIsRequired(sender) {
method regenerateThumbnails (line 224) | regenerateThumbnails(sender) {
method removeGalleryThumbnails (line 386) | removeGalleryThumbnails(galleryCatalog) {
method getNumberOfImagesToRegenerate (line 403) | getNumberOfImagesToRegenerate(mediaPath, catalogs) {
method delete (line 437) | static delete(appInstance, name) {
method clone (line 456) | static clone(appInstance, catalogName, siteName) {
method findFreeName (line 484) | static findFreeName (name, basePath) {
method updateNameAndUUIDInSiteConfig (line 503) | static updateNameAndUUIDInSiteConfig (sitePath, newSiteSlug, newSiteNa...
method loadCustomCSS (line 518) | static loadCustomCSS(appInstance, name) {
method saveCustomCSS (line 534) | static saveCustomCSS(appInstance, name, code) {
method checkFilesConsistency (line 555) | static checkFilesConsistency(appInstance, siteName) {
method checkWebsiteBackup (line 613) | static async checkWebsiteBackup (appInstance, backupPath) {
method checkWebsiteCatalogAvailability (line 619) | static checkWebsiteCatalogAvailability (appInstance, siteName) {
method restoreFromBackup (line 633) | static restoreFromBackup (appInstance, siteName) {
FILE: app/back-end/sites.js
class Sites (line 5) | class Sites {
method constructor (line 6) | constructor() {
FILE: app/back-end/sql/1.0.0.sql
type AUTOINCREMENT (line 6) | CREATE TABLE 'authors' ('id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,...
type AUTOINCREMENT (line 8) | CREATE TABLE 'posts_additional_data' ('id' INTEGER PRIMARY KEY AUTOINCRE...
FILE: app/back-end/tag.js
class Tag (line 14) | class Tag extends Model {
method constructor (line 15) | constructor(appInstance, tagData, storeMode = true) {
method save (line 41) | save() {
method addTag (line 86) | addTag() {
method updateTag (line 127) | updateTag() {
method prepareTagName (line 154) | prepareTagName() {
method isTagNameUnique (line 167) | isTagNameUnique() {
method isTagSlugUnique (line 186) | isTagSlugUnique() {
method isTagRestrictedSlug (line 207) | isTagRestrictedSlug() {
method delete (line 227) | delete() {
method createSlug (line 241) | createSlug(string) {
method checkAndCleanImages (line 248) | checkAndCleanImages (cancelEvent = false) {
method cleanImages (line 275) | cleanImages(images, imagesDir, cancelEvent) {
method removeResponsiveImages (line 347) | removeResponsiveImages(originalPath) {
method changeStatus (line 402) | changeStatus(status, inverse = false) {
FILE: app/back-end/tags.js
class Tags (line 7) | class Tags extends Model {
method constructor (line 8) | constructor(appInstance, tagsData) {
method load (line 15) | load() {
FILE: app/back-end/themes.js
class Themes (line 14) | class Themes {
method constructor (line 15) | constructor(appInstance, siteData = false) {
method loadThemes (line 34) | loadThemes(pathToThemes = false) {
method currentTheme (line 87) | currentTheme(returnDir = false) {
method load (line 110) | load() {
method changeTheme (line 120) | changeTheme(newTheme, oldTheme) {
method loadPostTemplates (line 240) | loadPostTemplates() {
method loadPageTemplates (line 268) | loadPageTemplates() {
method loadTagTemplates (line 296) | loadTagTemplates() {
method loadAuthorTemplates (line 324) | loadAuthorTemplates() {
method removeTheme (line 352) | removeTheme(directory) {
method updateThemeConfig (line 356) | updateThemeConfig(newConfig) {
method normalizeThemeImagePath (line 411) | normalizeThemeImagePath(imagePath) {
method loadThemeConfig (line 422) | static loadThemeConfig(themeConfigPath, themeDir) {
method checkAndCleanImages (line 485) | checkAndCleanImages(configString) {
method removeResponsiveImages (line 614) | removeResponsiveImages(originalPath) {
method loadComputedOptions (line 663) | static loadComputedOptions(inputDir, themeConfig) {
FILE: app/back-end/window-manager.js
class PubliiWindowManager (line 1) | class PubliiWindowManager {
method constructor (line 2) | constructor () {
method initEvents (line 7) | initEvents () {
method createMainWindow (line 11) | createMainWindow () {
method createEditorWindow (line 15) | createEditorWindow () {
method getMainWindow (line 19) | getMainWindow () {
method getEditorWindow (line 23) | getEditorWindow () {
method removeMainWindow (line 27) | removeMainWindow () {
method removeEditorWindow (line 31) | removeEditorWindow () {
FILE: app/back-end/workers/thumbnails/regenerate.js
function regenerateImages (line 40) | function regenerateImages(mediaPath, catalog) {
function regenerateImage (line 67) | function regenerateImage (images, fullPath, catalog) {
function isImage (line 153) | function isImage(image, fullImagePath) {
function getImageType (line 186) | function getImageType(context, image, catalog) {
function finishProcess (line 222) | function finishProcess() {
FILE: app/default-files/default-themes/simple/assets/js/scripts.js
function init (line 80) | function init() {
function initSubmenuPositions (line 103) | function initSubmenuPositions() {
function initMobileMenuOverlay (line 180) | function initMobileMenuOverlay() {
function initMobileMenuSidebar (line 224) | function initMobileMenuSidebar() {
function setAriaForSubmenus (line 283) | function setAriaForSubmenus(menuWrapper) {
function wrapSubmenusIntoContainer (line 294) | function wrapSubmenusIntoContainer(menuWrapper) {
function initToggleSubmenu (line 308) | function initToggleSubmenu(menuWrapper) {
function initAriaAttributes (line 380) | function initAriaAttributes() {
function initClosingMenuOnClickLink (line 402) | function initClosingMenuOnClickLink() {
function closeMenu (line 419) | function closeMenu(clickedLink, forceClose) {
function PopupHandler (line 521) | function PopupHandler(e) {
FILE: app/default-files/gdpr-assets/gdpr.js
function initUI (line 39) | function initUI () {
function initState (line 70) | function initState () {
function checkIfConfigIsFresh (line 167) | function checkIfConfigIsFresh () {
function getDefaultConsentState (line 187) | function getDefaultConsentState (currentConfig, consentGroup) {
function initBannerEvents (line 206) | function initBannerEvents () {
function initPopupEvents (line 231) | function initPopupEvents () {
function initBadgeEvents (line 265) | function initBadgeEvents () {
function addScript (line 284) | function addScript (src, inline) {
function allowCookieGroup (line 298) | function allowCookieGroup (allowedGroup) {
function showBannerOrPopup (line 339) | function showBannerOrPopup () {
function showAdvancedPopup (line 347) | function showAdvancedPopup () {
function hideAdvancedPopup (line 354) | function hideAdvancedPopup () {
function showBanner (line 361) | function showBanner () {
function hideBanner (line 366) | function hideBanner () {
function showBadge (line 371) | function showBadge () {
function getConfigName (line 380) | function getConfigName () {
function storeConfiguration (line 390) | function storeConfiguration (allowedGroups) {
function getInitialStateOfConsents (line 406) | function getInitialStateOfConsents () {
function getCurrentStateOfConsents (line 429) | function getCurrentStateOfConsents () {
function getAllGroups (line 452) | function getAllGroups () {
function acceptAllCookies (line 471) | function acceptAllCookies (source) {
function rejectAllCookies (line 508) | function rejectAllCookies () {
function saveConfiguration (line 519) | function saveConfiguration () {
function reloadIsNeeded (line 551) | function reloadIsNeeded (groupsToAccept) {
function unlockEmbeds (line 572) | function unlockEmbeds (cookieGroup) {
FILE: app/default-files/vendor/prism.js
function u (line 3) | function u(e){s.highlightedCode=e,a.hooks.run("before-insert",s),s.eleme...
function i (line 3) | function i(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=...
function l (line 3) | function l(e,n,t,r){e.lastIndex=n;var a=e.exec(t);if(a&&r&&a[1]){var i=a...
function o (line 3) | function o(e,n,t,r,s,g){for(var f in t)if(t.hasOwnProperty(f)&&t[f]){var...
function s (line 3) | function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e...
function u (line 3) | function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a...
function c (line 3) | function c(e,n,t){for(var r=n.next,a=0;a<t&&r!==e.tail;a++)r=r.next;n.ne...
function f (line 3) | function f(){a.manual||a.highlightAll()}
function n (line 9) | function n(e,n){return e.replace(/<<(\d+)>>/g,(function(e,s){return"(?:"...
function s (line 9) | function s(e,s,a){return RegExp(n(e,s),a||"")}
function a (line 9) | function a(e,n){for(var s=0;s<n;s++)e=e.replace(/<<self>>/g,(function(){...
function l (line 9) | function l(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}
function q (line 9) | function q(n,a){return{interpolation:{pattern:s("((?:^|[^{])(?:\\{\\{)*)...
function a (line 19) | function a(e,r){return e=e.replace(/<OPT>/g,(function(){return t})).repl...
function l (line 26) | function l(n){return t[e+n]}
function c (line 26) | function c(n,t){t=t||0;for(var e=0;e<n.length;e++){var a=l(e+t);if(!a||a...
function f (line 26) | function f(n,a){for(var r=1,i=e;i<t.length;i++){var o=t[i],s=o.content;i...
function b (line 26) | function b(n,t){var e=n.alias;e?Array.isArray(e)||(n.alias=e=[e]):n.alia...
function n (line 29) | function n(e,n){return"___"+e.toUpperCase()+n+"___"}
function a (line 32) | function a(t){return RegExp("(^(?:"+t+"):[ \t]*(?![ \t]))[^]+","i")}
function r (line 32) | function r(t){var a=t.replace(/^[a-z]+\//,"");return"(?:"+t+"|\\w+/(?:[\...
function e (line 35) | function e(a,e){return RegExp(a.replace(/<ID>/g,(function(){return"(?!\\...
function n (line 41) | function n(e){return RegExp("(\\()(?:"+e+")(?=[\\s\\)])")}
function a (line 41) | function a(e){return RegExp("([\\s([])(?:"+e+")(?=[\\s)])")}
function e (line 44) | function e(n){return n=n.replace(/<inner>/g,(function(){return"(?:\\\\.|...
function a (line 56) | function a(t,n){return t=t.replace(/<S>/g,(function(){return"(?:\\s|//.*...
function o (line 69) | function o(e,n){n=(n||"").replace(/m/g,"")+"m";var r="([:\\-,[{]\\s*(?:\...
FILE: app/src/assets/vendor/js/codemirror/addon/display/autorefresh.js
function startListening (line 23) | function startListening(cm, state) {
function stopListening (line 42) | function stopListening(_cm, state) {
FILE: app/src/assets/vendor/js/codemirror/addon/display/fullscreen.js
function setFullscreen (line 21) | function setFullscreen(cm) {
function setNormal (line 32) | function setNormal(cm) {
FILE: app/src/assets/vendor/js/codemirror/addon/display/panel.js
function Panel (line 47) | function Panel(cm, node, options, height) {
function initPanels (line 73) | function initPanels(cm) {
function removePanels (line 107) | function removePanels(cm) {
function isAtTop (line 118) | function isAtTop(cm, dom) {
FILE: app/src/assets/vendor/js/codemirror/addon/display/placeholder.js
function clearPlaceholder (line 31) | function clearPlaceholder(cm) {
function setPlaceholder (line 37) | function setPlaceholder(cm) {
function onBlur (line 48) | function onBlur(cm) {
function onChange (line 51) | function onChange(cm) {
function isEmpty (line 59) | function isEmpty(cm) {
FILE: app/src/assets/vendor/js/codemirror/addon/display/rulers.js
function drawRulers (line 28) | function drawRulers(cm) {
FILE: app/src/assets/vendor/js/codemirror/addon/scroll/annotatescrollbar.js
function Annotation (line 21) | function Annotation(cm, options) {
function getY (line 75) | function getY(pos, top) {
FILE: app/src/assets/vendor/js/codemirror/addon/scroll/scrollpastend.js
function onChange (line 28) | function onChange(cm, change) {
function updateBottomMargin (line 33) | function updateBottomMargin(cm) {
FILE: app/src/assets/vendor/js/codemirror/addon/scroll/simplescrollbars.js
function Bar (line 14) | function Bar(cls, orientation, scroll) {
function SimpleScrollbars (line 96) | function SimpleScrollbars(cls, place, scroll) {
FILE: app/src/assets/vendor/js/codemirror/addon/search/jump-to-line.js
function dialog (line 16) | function dialog(cm, text, shortText, deflt, f) {
function interpretLine (line 24) | function interpretLine(cm, string) {
FILE: app/src/assets/vendor/js/codemirror/addon/search/match-highlighter.js
function State (line 42) | function State(options) {
function cursorActivity (line 71) | function cursorActivity(cm) {
function onFocus (line 76) | function onFocus(cm) {
function scheduleHighlight (line 84) | function scheduleHighlight(cm, state) {
function addOverlay (line 89) | function addOverlay(cm, query, hasBoundary, style) {
function removeOverlay (line 99) | function removeOverlay(cm) {
function highlightMatches (line 111) | function highlightMatches(cm) {
function isWord (line 134) | function isWord(cm, from, to) {
function boundariesAround (line 151) | function boundariesAround(stream, re) {
function makeOverlay (line 156) | function makeOverlay(query, hasBoundary, style) {
FILE: app/src/assets/vendor/js/codemirror/addon/search/matchesonscrollbar.js
function SearchAnnotation (line 20) | function SearchAnnotation(cm, query, caseFold, options) {
function offsetLine (line 60) | function offsetLine(line, changeStart, sizeChange) {
FILE: app/src/assets/vendor/js/codemirror/addon/search/search.js
function searchOverlay (line 22) | function searchOverlay(query, caseInsensitive) {
function SearchState (line 42) | function SearchState() {
function getSearchState (line 47) | function getSearchState(cm) {
function queryCaseInsensitive (line 51) | function queryCaseInsensitive(query) {
function getSearchCursor (line 55) | function getSearchCursor(cm, query, pos) {
function persistentDialog (line 60) | function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
function dialog (line 70) | function dialog(cm, text, shortText, deflt, f) {
function confirmDialog (line 75) | function confirmDialog(cm, text, shortText, fs) {
function parseString (line 80) | function parseString(string) {
function parseQuery (line 88) | function parseQuery(query) {
function startSearch (line 104) | function startSearch(cm, state, query) {
function doSearch (line 116) | function doSearch(cm, rev, persistent, immediate) {
function findNext (line 167) | function findNext(cm, rev, callback) {cm.operation(function() {
function clearSearch (line 180) | function clearSearch(cm) {cm.operation(function() {
function replaceAll (line 194) | function replaceAll(cm, query, text) {
function replace (line 205) | function replace(cm, all) {
FILE: app/src/assets/vendor/js/codemirror/addon/search/searchcursor.js
function regexpFlags (line 15) | function regexpFlags(regexp) {
function ensureGlobal (line 22) | function ensureGlobal(regexp) {
function maybeMultiline (line 26) | function maybeMultiline(regexp) {
function searchRegexpForward (line 30) | function searchRegexpForward(doc, regexp, start) {
function searchRegexpForwardMultiline (line 42) | function searchRegexpForwardMultiline(doc, regexp, start) {
function lastMatchIn (line 71) | function lastMatchIn(string, regexp) {
function searchRegexpBackward (line 83) | function searchRegexpBackward(doc, regexp, start) {
function searchRegexpBackwardMultiline (line 96) | function searchRegexpBackwardMultiline(doc, regexp, start) {
function adjustPos (line 129) | function adjustPos(orig, folded, pos, foldFunc) {
function searchStringForward (line 141) | function searchStringForward(doc, query, start, caseFold) {
function searchStringBackward (line 169) | function searchStringBackward(doc, query, start, caseFold) {
function SearchCursor (line 196) | function SearchCursor(doc, query, pos, options) {
FILE: app/src/assets/vendor/js/codemirror/autorefresh.js
function startListening (line 23) | function startListening(cm, state) {
function stopListening (line 42) | function stopListening(_cm, state) {
FILE: app/src/assets/vendor/js/codemirror/codemirror.js
function classTest (line 48) | function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)...
function removeChildren (line 59) | function removeChildren(e) {
function removeChildrenAndAdd (line 65) | function removeChildrenAndAdd(parent, e) {
function elt (line 69) | function elt(tag, content, className, style) {
function contains (line 95) | function contains(parent, child) {
function addClass (line 119) | function addClass(node, cls) {
function joinClasses (line 123) | function joinClasses(a, b) {
function bind (line 136) | function bind(f) {
function copyObj (line 141) | function copyObj(obj, target, overwrite) {
function countColumn (line 151) | function countColumn(string, end, tabSize, startIndex, startValue) {
function Delayed (line 166) | function Delayed() {this.id = null}
function indexOf (line 172) | function indexOf(array, elt) {
function findColumn (line 192) | function findColumn(string, goal, tabSize) {
function spaceStr (line 207) | function spaceStr(n) {
function lst (line 213) | function lst(arr) { return arr[arr.length-1] }
function map (line 215) | function map(array, f) {
function insertSorted (line 221) | function insertSorted(array, value, score) {
function nothing (line 227) | function nothing() {}
function createObj (line 229) | function createObj(base, props) {
function isWordCharBasic (line 242) | function isWordCharBasic(ch) {
function isWordChar (line 246) | function isWordChar(ch, helper) {
function isEmpty (line 252) | function isEmpty(obj) {
function isExtendingChar (line 263) | function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendi...
function Display (line 269) | function Display(place, doc, input) {
function getLine (line 368) | function getLine(doc, n) {
function getBetween (line 384) | function getBetween(doc, start, end) {
function getLines (line 396) | function getLines(doc, from, to) {
function updateLineHeight (line 404) | function updateLineHeight(line, height) {
function lineNo (line 411) | function lineNo(line) {
function lineAtHeight (line 425) | function lineAtHeight(chunk, h) {
function isLine (line 445) | function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
function lineNumberFor (line 447) | function lineNumberFor(options, i) {
function Pos (line 452) | function Pos (line, ch) {
function cmp (line 459) | function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
function copyPos (line 461) | function copyPos(x) {return Pos(x.line, x.ch)}
function maxPos (line 462) | function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
function minPos (line 463) | function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
function clipLine (line 467) | function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.fi...
function clipPos (line 468) | function clipPos(doc, pos) {
function clipToLen (line 474) | function clipToLen(pos, linelen) {
function clipPosArray (line 480) | function clipPosArray(doc, array) {
function seeReadOnlySpans (line 490) | function seeReadOnlySpans() {
function seeCollapsedSpans (line 494) | function seeCollapsedSpans() {
function MarkedSpan (line 500) | function MarkedSpan(marker, from, to) {
function getMarkedSpanFor (line 506) | function getMarkedSpanFor(spans, marker) {
function removeMarkedSpan (line 514) | function removeMarkedSpan(spans, span) {
function addMarkedSpan (line 521) | function addMarkedSpan(line, span) {
function markedSpansBefore (line 530) | function markedSpansBefore(old, startCh, isInsert) {
function markedSpansAfter (line 541) | function markedSpansAfter(old, endCh, isInsert) {
function stretchSpansOverChange (line 560) | function stretchSpansOverChange(doc, change) {
function clearEmptySpans (line 622) | function clearEmptySpans(spans) {
function removeReadOnlyRanges (line 633) | function removeReadOnlyRanges(doc, from, to) {
function detachMarkedSpans (line 662) | function detachMarkedSpans(line) {
function attachMarkedSpans (line 669) | function attachMarkedSpans(line, spans) {
function extraLeft (line 678) | function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
function extraRight (line 679) | function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
function compareCollapsedMarkers (line 684) | function compareCollapsedMarkers(a, b) {
function collapsedSpanAtSide (line 697) | function collapsedSpanAtSide(line, start) {
function collapsedSpanAtStart (line 707) | function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, t...
function collapsedSpanAtEnd (line 708) | function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, fal...
function conflictingCollapsedRange (line 713) | function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {
function visualLine (line 733) | function visualLine(line) {
function visualLineContinued (line 742) | function visualLineContinued(line) {
function visualLineNo (line 753) | function visualLineNo(doc, lineN) {
function visualLineEndNo (line 761) | function visualLineEndNo(doc, lineN) {
function lineIsHidden (line 773) | function lineIsHidden(doc, line) {
function lineIsHiddenInner (line 784) | function lineIsHiddenInner(doc, line, span) {
function heightAtLine (line 801) | function heightAtLine(lineObj) {
function lineLength (line 823) | function lineLength(line) {
function findMaxLine (line 842) | function findMaxLine(cm) {
function iterateBidiSections (line 858) | function iterateBidiSections(order, from, to, f) {
function bidiLeft (line 871) | function bidiLeft(part) { return part.level % 2 ? part.to : part.from }
function bidiRight (line 872) | function bidiRight(part) { return part.level % 2 ? part.from : part.to }
function lineLeft (line 874) | function lineLeft(line) { var order = getOrder(line); return order ? bid...
function lineRight (line 875) | function lineRight(line) {
function compareBidiLevel (line 881) | function compareBidiLevel(order, a, b) {
function getBidiPartAt (line 889) | function getBidiPartAt(order, pos) {
function moveInLine (line 910) | function moveInLine(line, pos, dir, byUnit) {
function moveVisually (line 922) | function moveVisually(line, start, dir, byUnit) {
function moveLogically (line 945) | function moveLogically(line, start, dir, byUnit) {
function charType (line 979) | function charType(code) {
function BidiSpan (line 994) | function BidiSpan(level, from, to) {
function getOrder (line 1126) | function getOrder(line) {
function getHandlers (line 1150) | function getHandlers(emitter, type, copy) {
function off (line 1156) | function off(emitter, type, f) {
function signal (line 1168) | function signal(emitter, type /*, values...*/) {
function signalDOMEvent (line 1178) | function signalDOMEvent(cm, e, override) {
function signalCursorActivity (line 1185) | function signalCursorActivity(cm) {
function hasHandler (line 1193) | function hasHandler(emitter, type) {
function eventMixin (line 1199) | function eventMixin(ctor) {
function e_preventDefault (line 1207) | function e_preventDefault(e) {
function e_stopPropagation (line 1211) | function e_stopPropagation(e) {
function e_defaultPrevented (line 1215) | function e_defaultPrevented(e) {
function e_stop (line 1218) | function e_stop(e) {e_preventDefault(e); e_stopPropagation(e)}
function e_target (line 1220) | function e_target(e) {return e.target || e.srcElement}
function e_button (line 1221) | function e_button(e) {
function zeroWidthElement (line 1242) | function zeroWidthElement(measure) {
function hasBadBidiRects (line 1257) | function hasBadBidiRects(measure) {
function hasBadZoomedRects (line 1306) | function hasBadZoomedRects(measure) {
function defineMode (line 1321) | function defineMode(name, mode) {
function defineMIME (line 1327) | function defineMIME(mime, spec) {
function resolveMode (line 1333) | function resolveMode(spec) {
function getMode (line 1352) | function getMode(options, spec) {
function extendMode (line 1376) | function extendMode(mode, properties) {
function copyState (line 1381) | function copyState(mode, state) {
function innerMode (line 1395) | function innerMode(mode, state) {
function startState (line 1406) | function startState(mode, a1, a2) {
function highlightLine (line 1494) | function highlightLine(cm, line, state, forceToEnd) {
function getLineStyles (line 1533) | function getLineStyles(cm, line, updateFrontier) {
function getStateBefore (line 1546) | function getStateBefore(cm, n, precise) {
function processLine (line 1565) | function processLine(cm, text, state, startAt) {
function callBlankLine (line 1576) | function callBlankLine(mode, state) {
function readToken (line 1583) | function readToken(mode, stream, state, inner) {
function takeToken (line 1593) | function takeToken(cm, pos, precise, asArray) {
function extractLineClasses (line 1614) | function extractLineClasses(type, output) {
function runMode (line 1629) | function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
function findStartLine (line 1673) | function findStartLine(cm, n, precise) {
function Line (line 1693) | function Line(text, markedSpans, estimateHeight) {
function updateLine (line 1704) | function updateLine(line, text, markedSpans, estimateHeight) {
function cleanUpLine (line 1716) | function cleanUpLine(line) {
function interpretTokenStyle (line 1726) | function interpretTokenStyle(style, options) {
function buildLineContent (line 1738) | function buildLineContent(cm, lineView) {
function defaultSpecialCharPlaceholder (line 1796) | function defaultSpecialCharPlaceholder(ch) {
function buildToken (line 1805) | function buildToken(builder, text, style, startStyle, endStyle, title, c...
function splitSpaces (line 1867) | function splitSpaces(text, trailingBefore) {
function buildTokenBadBidi (line 1882) | function buildTokenBadBidi(inner, order) {
function buildCollapsedSpan (line 1902) | function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
function insertLineContent (line 1920) | function insertLineContent(line, builder, styles) {
function LineView (line 1992) | function LineView(doc, line, lineN) {
function buildViewArray (line 2004) | function buildViewArray(cm, from, to) {
function pushOperation (line 2016) | function pushOperation(op) {
function fireCallbacksForOps (line 2027) | function fireCallbacksForOps(group) {
function finishOperation (line 2043) | function finishOperation(op, endCb) {
function signalLater (line 2063) | function signalLater(emitter, type /*, values...*/) {
function fireOrphanDelayed (line 2083) | function fireOrphanDelayed() {
function updateLineForChanges (line 2092) | function updateLineForChanges(cm, lineView, lineN, dims) {
function ensureLineWrapped (line 2105) | function ensureLineWrapped(lineView) {
function updateLineBackground (line 2116) | function updateLineBackground(lineView) {
function getLineContent (line 2130) | function getLineContent(cm, lineView) {
function updateLineText (line 2143) | function updateLineText(cm, lineView) {
function updateLineClasses (line 2158) | function updateLineClasses(lineView) {
function updateLineGutter (line 2168) | function updateLineGutter(cm, lineView, lineN, dims) {
function updateLineWidgets (line 2205) | function updateLineWidgets(cm, lineView, dims) {
function buildLineElement (line 2216) | function buildLineElement(cm, lineView, lineN, dims) {
function insertLineWidgets (line 2230) | function insertLineWidgets(cm, lineView, dims) {
function insertLineWidgetsFor (line 2236) | function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
function positionLineWidget (line 2252) | function positionLineWidget(widget, node, lineView, dims) {
function widgetHeight (line 2270) | function widgetHeight(widget) {
function eventInWidget (line 2286) | function eventInWidget(display, e) {
function paddingTop (line 2296) | function paddingTop(display) {return display.lineSpace.offsetTop}
function paddingVert (line 2297) | function paddingVert(display) {return display.mover.offsetHeight - displ...
function paddingH (line 2298) | function paddingH(display) {
function scrollGap (line 2307) | function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
function displayWidth (line 2308) | function displayWidth(cm) {
function displayHeight (line 2311) | function displayHeight(cm) {
function ensureLineHeights (line 2319) | function ensureLineHeights(cm, lineView, rect) {
function mapFromLineView (line 2340) | function mapFromLineView(lineView, line, lineN) {
function updateExternalMeasurement (line 2353) | function updateExternalMeasurement(cm, line) {
function measureChar (line 2366) | function measureChar(cm, line, ch, bias) {
function findViewForLine (line 2371) | function findViewForLine(cm, lineN) {
function prepareMeasureForLine (line 2384) | function prepareMeasureForLine(cm, line) {
function measureCharPrepared (line 2406) | function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
function nodeAndOffsetInLineMap (line 2428) | function nodeAndOffsetInLineMap(map$$1, ch, bias) {
function getUsefulRect (line 2466) | function getUsefulRect(rects, bias) {
function measureCharInner (line 2476) | function measureCharInner(cm, prepared, ch, bias) {
function maybeUpdateRectForZooming (line 2529) | function maybeUpdateRectForZooming(measure, rect) {
function clearLineMeasurementCacheFor (line 2539) | function clearLineMeasurementCacheFor(lineView) {
function clearLineMeasurementCache (line 2548) | function clearLineMeasurementCache(cm) {
function clearCaches (line 2555) | function clearCaches(cm) {
function pageScrollX (line 2562) | function pageScrollX() { return window.pageXOffset || (document.document...
function pageScrollY (line 2563) | function pageScrollY() { return window.pageYOffset || (document.document...
function intoCoordSystem (line 2569) | function intoCoordSystem(cm, lineObj, rect, context) {
function fromCoordSystem (line 2591) | function fromCoordSystem(cm, coords, context) {
function charCoords (line 2608) | function charCoords(cm, pos, context, lineObj, bias) {
function cursorCoords (line 2616) | function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHei...
function estimateCoords (line 2648) | function estimateCoords(cm, pos) {
function PosWithInfo (line 2663) | function PosWithInfo(line, ch, outside, xRel) {
function coordsChar (line 2672) | function coordsChar(cm, x, y) {
function coordsCharInner (line 2693) | function coordsCharInner(cm, lineObj, lineNo$$1, x, y) {
function textHeight (line 2748) | function textHeight(display) {
function charWidth (line 2768) | function charWidth(display) {
function getDimensions (line 2780) | function getDimensions(cm) {
function compensateForHScroll (line 2797) | function compensateForHScroll(display) {
function estimateHeight (line 2804) | function estimateHeight(cm) {
function estimateLineHeights (line 2822) | function estimateLineHeights(cm) {
function posFromMouse (line 2835) | function posFromMouse(cm, e, liberal, forRect) {
function findViewIndex (line 2853) | function findViewIndex(cm, n) {
function updateSelection (line 2864) | function updateSelection(cm) {
function prepareSelection (line 2868) | function prepareSelection(cm, primary) {
function drawSelectionCursor (line 2887) | function drawSelectionCursor(cm, head, output) {
function drawSelectionRange (line 2906) | function drawSelectionRange(cm, range$$1, output) {
function restartBlink (line 2979) | function restartBlink(cm) {
function ensureFocus (line 2992) | function ensureFocus(cm) {
function delayBlurEvent (line 2996) | function delayBlurEvent(cm) {
function onFocus (line 3004) | function onFocus(cm, e) {
function onBlur (line 3023) | function onBlur(cm, e) {
function alignHorizontally (line 3037) | function alignHorizontally(cm) {
function maybeUpdateLineNumberWidth (line 3060) | function maybeUpdateLineNumberWidth(cm) {
function updateHeightsInViewport (line 3080) | function updateHeightsInViewport(cm) {
function updateWidgetHeight (line 3107) | function updateWidgetHeight(line) {
function visibleLines (line 3115) | function visibleLines(display, doc, viewport) {
function setScrollTop (line 3138) | function setScrollTop(cm, val) {
function setScrollLeft (line 3149) | function setScrollLeft(cm, val, isScroller) {
function wheelEventDelta (line 3180) | function wheelEventDelta(e) {
function wheelEventPixels (line 3187) | function wheelEventPixels(e) {
function onScrollWheel (line 3194) | function onScrollWheel(cm, e) {
function measureForScrollbars (line 3273) | function measureForScrollbars(cm) {
function NativeScrollbars (line 3289) | function NativeScrollbars(place, scroll, cm) {
function maybeDisable (line 3361) | function maybeDisable() {
function NullScrollbars (line 3382) | function NullScrollbars() {}
function updateScrollbars (line 3391) | function updateScrollbars(cm, measure) {
function updateScrollbarsInner (line 3405) | function updateScrollbarsInner(cm, measure) {
function initScrollbars (line 3427) | function initScrollbars(cm) {
function maybeScrollWindow (line 3453) | function maybeScrollWindow(cm, coords) {
function scrollPosIntoView (line 3470) | function scrollPosIntoView(cm, pos, end, margin) {
function scrollIntoView (line 3496) | function scrollIntoView(cm, x1, y1, x2, y2) {
function calculateScrollPos (line 3506) | function calculateScrollPos(cm, x1, y1, x2, y2) {
function addToScrollPos (line 3536) | function addToScrollPos(cm, left, top) {
function ensureCursorVisible (line 3546) | function ensureCursorVisible(cm) {
function resolveScrollToPos (line 3560) | function resolveScrollToPos(cm) {
function startOperation (line 3581) | function startOperation(cm) {
function endOperation (line 3603) | function endOperation(cm) {
function endOperations (line 3614) | function endOperations(group) {
function endOperation_R1 (line 3628) | function endOperation_R1(op) {
function endOperation_W1 (line 3641) | function endOperation_W1(op) {
function endOperation_R2 (line 3645) | function endOperation_R2(op) {
function endOperation_W2 (line 3666) | function endOperation_W2(op) {
function endOperation_finish (line 3691) | function endOperation_finish(op) {
function runInOp (line 3738) | function runInOp(cm, f) {
function operation (line 3745) | function operation(cm, f) {
function methodOp (line 3755) | function methodOp(f) {
function docMethodOp (line 3763) | function docMethodOp(f) {
function regChange (line 3779) | function regChange(cm, from, to, lendiff) {
function regLineChange (line 3844) | function regLineChange(cm, line, type) {
function resetView (line 3858) | function resetView(cm) {
function viewCuttingPoint (line 3864) | function viewCuttingPoint(cm, oldN, newN, dir) {
function adjustView (line 3891) | function adjustView(cm, from, to) {
function countDirtyView (line 3912) | function countDirtyView(cm) {
function startWorker (line 3923) | function startWorker(cm, time) {
function highlightWorker (line 3928) | function highlightWorker(cm) {
function DisplayUpdate (line 3968) | function DisplayUpdate(cm, viewport, force) {
function maybeClipScrollbars (line 3994) | function maybeClipScrollbars(cm) {
function updateDisplayIfNeeded (line 4008) | function updateDisplayIfNeeded(cm, update) {
function postUpdateDisplay (line 4080) | function postUpdateDisplay(cm, update) {
function updateDisplaySimple (line 4109) | function updateDisplaySimple(cm, viewport) {
function patchDisplay (line 4126) | function patchDisplay(cm, updateNumbersFrom, dims) {
function updateGutterSpace (line 4168) | function updateGutterSpace(cm) {
function setDocumentHeight (line 4173) | function setDocumentHeight(cm, measure) {
function updateGutters (line 4181) | function updateGutters(cm) {
function setGuttersForLineNumbers (line 4199) | function setGuttersForLineNumbers(options) {
function Selection (line 4214) | function Selection(ranges, primIndex) {
function Range (line 4260) | function Range(anchor, head) {
function normalizeSelection (line 4275) | function normalizeSelection(ranges, primIndex) {
function simpleSelection (line 4291) | function simpleSelection(anchor, head) {
function changeEnd (line 4297) | function changeEnd(change) {
function adjustForChange (line 4305) | function adjustForChange(pos, change) {
function computeSelAfterChange (line 4314) | function computeSelAfterChange(doc, change) {
function offsetPos (line 4324) | function offsetPos(pos, old, nw) {
function computeReplacedSel (line 4333) | function computeReplacedSel(doc, changes, hint) {
function loadMode (line 4354) | function loadMode(cm) {
function resetModeState (line 4359) | function resetModeState(cm) {
function isWholeLineUpdate (line 4375) | function isWholeLineUpdate(doc, change) {
function updateDoc (line 4381) | function updateDoc(doc, change, markedSpans, estimateHeight$$1) {
function linkedDocs (line 4433) | function linkedDocs(doc, f, sharedHistOnly) {
function attachDoc (line 4448) | function attachDoc(cm, doc) {
function History (line 4459) | function History(startGen) {
function historyChangeFromChange (line 4476) | function historyChangeFromChange(doc, change) {
function clearSelectionEvents (line 4485) | function clearSelectionEvents(array) {
function lastChangeEvent (line 4495) | function lastChangeEvent(hist, force) {
function addChangeToHistory (line 4510) | function addChangeToHistory(doc, change, selAfter, opId) {
function selectionEventCanBeMerged (line 4553) | function selectionEventCanBeMerged(doc, origin, prev, sel) {
function addSelectionToHistory (line 4566) | function addSelectionToHistory(doc, sel, opId, options) {
function pushSelectionToHistory (line 4588) | function pushSelectionToHistory(sel, dest) {
function attachLocalSpans (line 4595) | function attachLocalSpans(doc, change, from, to) {
function removeClearedSpans (line 4606) | function removeClearedSpans(spans) {
function getOldSpans (line 4617) | function getOldSpans(doc, change) {
function mergeOldSpans (line 4630) | function mergeOldSpans(doc, change) {
function copyHistoryArray (line 4654) | function copyHistoryArray(events, newGroup, instantiateSel) {
function extendRange (line 4686) | function extendRange(doc, range, head, other) {
function extendSelection (line 4705) | function extendSelection(doc, head, other, options) {
function extendSelections (line 4711) | function extendSelections(doc, heads, options) {
function replaceOneSelection (line 4720) | function replaceOneSelection(doc, i, range, options) {
function setSimpleSelection (line 4727) | function setSimpleSelection(doc, anchor, head, options) {
function filterSelectionChange (line 4733) | function filterSelectionChange(doc, sel, options) {
function setSelectionReplaceHistory (line 4752) | function setSelectionReplaceHistory(doc, sel, options) {
function setSelection (line 4763) | function setSelection(doc, sel, options) {
function setSelectionNoUndo (line 4768) | function setSelectionNoUndo(doc, sel, options) {
function setSelectionInner (line 4780) | function setSelectionInner(doc, sel) {
function reCheckSelection (line 4794) | function reCheckSelection(doc) {
function skipAtomicInSelection (line 4800) | function skipAtomicInSelection(doc, sel, bias, mayClear) {
function skipAtomicInner (line 4815) | function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
function skipAtomic (line 4848) | function skipAtomic(doc, pos, oldPos, bias, mayClear) {
function movePos (line 4861) | function movePos(doc, pos, dir, line) {
function selectAll (line 4873) | function selectAll(cm) {
function filterChange (line 4880) | function filterChange(doc, change, update) {
function makeChange (line 4904) | function makeChange(doc, change, ignoreReadOnly) {
function makeChangeInner (line 4926) | function makeChangeInner(doc, change) {
function makeChangeFromHistory (line 4944) | function makeChangeFromHistory(doc, type, allowSelectionOnly) {
function shiftDoc (line 5017) | function shiftDoc(doc, distance) {
function makeChangeSingleDoc (line 5033) | function makeChangeSingleDoc(doc, change, selAfter, spans) {
function makeChangeSingleDocInEditor (line 5066) | function makeChangeSingleDocInEditor(cm, change, spans) {
function replaceRange (line 5125) | function replaceRange(doc, code, from, to, origin) {
function rebaseHistSelSingle (line 5134) | function rebaseHistSelSingle(pos, from, to, diff) {
function rebaseHistArray (line 5150) | function rebaseHistArray(array, from, to, diff) {
function rebaseHist (line 5178) | function rebaseHist(hist, change) {
function changeLine (line 5187) | function changeLine(doc, handle, changeType, op) {
function LeafChunk (line 5209) | function LeafChunk(lines) {
function BranchChunk (line 5258) | function BranchChunk(children) {
function LineWidget (line 5371) | function LineWidget(doc, node, options) {
function adjustScrollWhenAboveVisible (line 5381) | function adjustScrollWhenAboveVisible(cm, line, diff) {
function addLineWidget (line 5412) | function addLineWidget(doc, handle, node, options) {
function TextMarker (line 5449) | function TextMarker(doc, type) {
function markText (line 5566) | function markText(doc, from, to, options, type) {
function SharedTextMarker (line 5640) | function SharedTextMarker(markers, primary) {
function markTextShared (line 5663) | function markTextShared(doc, from, to, options, type) {
function findSharedMarkers (line 5678) | function findSharedMarkers(doc) {
function copySharedMarkers (line 5682) | function copySharedMarkers(doc, markers) {
function detachSharedMarkers (line 5694) | function detachSharedMarkers(markers) {
function onDrop (line 6087) | function onDrop(e) {
function onDragStart (line 6147) | function onDragStart(cm, e) {
function onDragOver (line 6170) | function onDragOver(cm, e) {
function clearDragCursor (line 6182) | function clearDragCursor(cm) {
function forEachCodeMirror (line 6193) | function forEachCodeMirror(f) {
function ensureGlobalHandlers (line 6203) | function ensureGlobalHandlers() {
function registerGlobalHandlers (line 6208) | function registerGlobalHandlers() {
function onResize (line 6221) | function onResize(cm) {
function normalizeKeyName (line 6294) | function normalizeKeyName(name) {
function normalizeKeyMap (line 6318) | function normalizeKeyMap(keymap) {
function lookupKey (line 6345) | function lookupKey(key, map$$1, handle, context) {
function isModifierKey (line 6364) | function isModifierKey(value) {
function keyName (line 6370) | function keyName(event, noShift) {
function getKeyMap (line 6381) | function getKeyMap(val) {
function deleteNearSelection (line 6387) | function deleteNearSelection(cm, compute) {
function lineStart (line 6553) | function lineStart(cm, lineN) {
function lineEnd (line 6561) | function lineEnd(cm, lineN) {
function lineStartSmart (line 6571) | function lineStartSmart(cm, pos) {
function doHandleBinding (line 6584) | function doHandleBinding(cm, bound, dropShift) {
function lookupKeyForEditor (line 6604) | function lookupKeyForEditor(cm, name, handle) {
function dispatchKey (line 6614) | function dispatchKey(cm, name, e, handle) {
function handleKeyBinding (line 6646) | function handleKeyBinding(cm, e) {
function handleCharBinding (line 6665) | function handleCharBinding(cm, e, ch) {
function onKeyDown (line 6670) | function onKeyDown(e) {
function showCrossHair (line 6691) | function showCrossHair(cm) {
function onKeyUp (line 6706) | function onKeyUp(e) {
function onKeyPress (line 6711) | function onKeyPress(e) {
function onMouseDown (line 6729) | function onMouseDown(e) {
function leftButtonDown (line 6772) | function leftButtonDown(cm, e, start) {
function leftButtonStartDrag (line 6799) | function leftButtonStartDrag(cm, e, start, modifier) {
function leftButtonSelect (line 6828) | function leftButtonSelect(cm, e, start, type, addNew) {
function gutterEvent (line 6976) | function gutterEvent(cm, e, type, prevent) {
function clickInGutter (line 7000) | function clickInGutter(cm, e) {
function onContextMenu (line 7009) | function onContextMenu(cm, e) {
function contextMenuInGutter (line 7015) | function contextMenuInGutter(cm, e) {
function themeChanged (line 7020) | function themeChanged(cm) {
function defineOptions (line 7031) | function defineOptions(CodeMirror) {
function guttersChanged (line 7164) | function guttersChanged(cm) {
function dragDropChanged (line 7170) | function dragDropChanged(cm, value, old) {
function wrappingChanged (line 7183) | function wrappingChanged(cm) {
function CodeMirror$1 (line 7201) | function CodeMirror$1(place, options) {
function registerEventHandlers (line 7276) | function registerEventHandlers(cm) {
function indentLine (line 7390) | function indentLine(cm, n, how, aggressive) {
function setLastCopied (line 7454) | function setLastCopied(newLastCopied) {
function applyTextInput (line 7458) | function applyTextInput(cm, inserted, deleted, sel, origin) {
function handlePaste (line 7506) | function handlePaste(e, cm) {
function triggerElectric (line 7516) | function triggerElectric(cm, inserted) {
function copyableRanges (line 7540) | function copyableRanges(cm) {
function disableBrowserMagic (line 7551) | function disableBrowserMagic(field, spellcheck) {
function hiddenTextarea (line 7557) | function hiddenTextarea() {
function findPosH (line 8067) | function findPosH(doc, pos, dir, unit, visually) {
function findPosV (line 8119) | function findPosV(cm, pos, dir, unit) {
function ContentEditableInput (line 8141) | function ContentEditableInput(cm) {
function onCopyCut (line 8198) | function onCopyCut(e) {
function poll (line 8340) | function poll() {
function posToDOM (line 8461) | function posToDOM(cm, pos) {
function badPos (line 8477) | function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
function domTextBetween (line 8479) | function domTextBetween(cm, from, to, fromLine, toLine) {
function domToPos (line 8520) | function domToPos(cm, node, offset) {
function locateNodeInLineView (line 8539) | function locateNodeInLineView(lineView, node, offset) {
function TextareaInput (line 8596) | function TextareaInput(cm) {
function prepareCopyCut (line 8643) | function prepareCopyCut(e) {
function p (line 8785) | function p() {
function prepareSelectAllHack (line 8888) | function prepareSelectAllHack() {
function rehide (line 8901) | function rehide() {
function fromTextArea (line 8943) | function fromTextArea(textarea, options) {
function addLegacyProps (line 9000) | function addLegacyProps(CodeMirror) {
FILE: app/src/assets/vendor/js/codemirror/css.js
function ret (line 30) | function ret(style, tp) { type = tp; return style; }
function tokenBase (line 34) | function tokenBase(stream, state) {
function tokenString (line 89) | function tokenString(quote) {
function tokenParenthesized (line 104) | function tokenParenthesized(stream, state) {
function Context (line 115) | function Context(type, indent, prev) {
function pushContext (line 121) | function pushContext(state, stream, type, indent) {
function popContext (line 126) | function popContext(state) {
function pass (line 132) | function pass(type, stream, state) {
function popAndPass (line 135) | function popAndPass(type, stream, state, n) {
function wordAsValue (line 143) | function wordAsValue(stream) {
function keySet (line 410) | function keySet(array) {
function tokenCComment (line 686) | function tokenCComment(stream, state) {
FILE: app/src/assets/vendor/js/codemirror/xml.js
function inText (line 64) | function inText(stream, state) {
function inTag (line 112) | function inTag(stream, state) {
function inAttribute (line 137) | function inAttribute(quote) {
function inBlock (line 151) | function inBlock(style, terminator) {
function doctype (line 163) | function doctype(depth) {
function Context (line 184) | function Context(state, tagName, startOfLine) {
function popContext (line 192) | function popContext(state) {
function maybePopContext (line 195) | function maybePopContext(state, nextTagName) {
function baseState (line 210) | function baseState(type, stream, state) {
function tagNameState (line 220) | function tagNameState(type, stream, state) {
function closeTagNameState (line 230) | function closeTagNameState(type, stream, state) {
function closeState (line 249) | function closeState(type, _stream, state) {
function closeStateErr (line 257) | function closeStateErr(type, stream, state) {
function attrState (line 262) | function attrState(type, _stream, state) {
function attrEqState (line 281) | function attrEqState(type, stream, state) {
function attrValueState (line 286) | function attrValueState(type, stream, state) {
function attrContinuedState (line 292) | function attrContinuedState(type, stream, state) {
FILE: app/src/components/block-editor/components/default-blocks/publii-code/render.js
function render (line 1) | function render (blockData) {
FILE: app/src/components/block-editor/components/default-blocks/publii-embed/embed.js
method isEmbedable (line 2) | isEmbedable (code) {
method embed (line 13) | embed (code) {
method isUrl (line 18) | isUrl (code) {
method getService (line 25) | getService (code) {
method createIframe (line 36) | createIframe (service, code) {
method youtubeIframe (line 46) | youtubeIframe (code) {
method vimeoIframe (line 56) | vimeoIframe (code) {
method rawIframe (line 62) | rawIframe (code) {
FILE: app/src/components/block-editor/components/default-blocks/publii-embed/render.js
function render (line 1) | function render (blockData) {
FILE: app/src/components/block-editor/components/default-blocks/publii-gallery/render.js
function render (line 1) | function render (blockData) {
FILE: app/src/components/block-editor/components/default-blocks/publii-header/render.js
function render (line 1) | function render (blockData) {
FILE: app/src/components/block-editor/components/default-blocks/publii-html/aspect-ratio.js
function findGreatestCommonDivider (line 1) | function findGreatestCommonDivider (a, b) {
function calculateAspectRatio (line 5) | function calculateAspectRatio (width, height) {
function addAspectRatio (line 10) | function addAspectRatio (code) {
FILE: app/src/components/block-editor/components/default-blocks/publii-html/content-filter.js
function contentFilter (line 1) | function contentFilter (code, mode = 'editor') {
FILE: app/src/components/block-editor/components/default-blocks/publii-html/render.js
function render (line 3) | function render (blockData) {
FILE: app/src/components/block-editor/components/default-blocks/publii-image/render.js
function render (line 1) | function render (blockData) {
FILE: app/src/components/block-editor/components/default-blocks/publii-list/render.js
function render (line 1) | function render (blockData) {
FILE: app/src/components/block-editor/components/default-blocks/publii-paragraph/render.js
function render (line 1) | function render (blockData) {
FILE: app/src/components/block-editor/components/default-blocks/publii-quote/render.js
function render (line 1) | function render (blockData) {
FILE: app/src/components/block-editor/components/default-blocks/publii-readmore/render.js
function render (line 1) | function render () {
FILE: app/src/components/block-editor/components/default-blocks/publii-separator/render.js
function render (line 1) | function render (blockData) {
FILE: app/src/components/block-editor/components/default-blocks/publii-toc/render.js
function render (line 1) | function render (blockData) {
FILE: app/src/components/block-editor/components/extensions/ConversionHelpers.js
class ConversionHelpers (line 1) | class ConversionHelpers {
method stripTags (line 2) | stripTags (input, saveLineBreaks = true) {
FILE: app/src/components/block-editor/components/extensions/ShortcutManager.js
class ShortcutManager (line 1) | class ShortcutManager {
method constructor (line 2) | constructor () {
method initDefaultShortcuts (line 8) | initDefaultShortcuts () {
method initMarkdownDefaultShortcuts (line 32) | initMarkdownDefaultShortcuts () {
method checkContentForShortcuts (line 46) | checkContentForShortcuts (text) {
method add (line 54) | add (shortcut, componentName) {
FILE: app/src/components/block-editor/components/extensions/UndoManager.js
class UndoManager (line 1) | class UndoManager {
method constructor (line 2) | constructor () {
method saveHistory (line 7) | saveHistory (blockID, blockContent) {
method undoHistory (line 18) | undoHistory (blockID) {
method redoHistory (line 28) | redoHistory (blockID) {
FILE: app/src/components/block-editor/components/utils/SelectedText.js
class SelectedText (line 3) | class SelectedText {
method constructor (line 4) | constructor (inlineMenuContainer, blockType) {
method isInvalidTextSelection (line 35) | isInvalidTextSelection () {
method analyzeSelectedText (line 40) | analyzeSelectedText () {
method removeStyle (line 77) | removeStyle (tag) {
method checkIfElementCanBeNested (line 130) | checkIfElementCanBeNested () {
method checkIfElementCanBeFlattened (line 154) | checkIfElementCanBeFlattened () {
FILE: app/src/components/block-editor/components/utils/Utils.js
class Utils (line 1) | class Utils {
method deepMerge (line 5) | static deepMerge (target, source) {
method debounce (line 36) | static debounce (func, wait, immediate) {
FILE: app/src/components/mixins/CollectionCheckboxes.js
method anyCheckboxIsSelected (line 3) | anyCheckboxIsSelected () {
method toggleAllCheckboxes (line 8) | toggleAllCheckboxes (useArrayIndexAsID = false) {
method isChecked (line 25) | isChecked (id) {
method toggleSelection (line 28) | toggleSelection (id) {
method getSelectedItems (line 37) | getSelectedItems (itemsCanBeFiltered = true) {
FILE: app/src/components/post-editor/EditorBridge.js
class EditorBridge (line 4) | class EditorBridge {
method constructor (line 5) | constructor(itemID, itemType = 'post') {
method updateItemID (line 17) | updateItemID (newItemID) {
method init (line 23) | init() {
method focus (line 63) | focus () {
method setupEditor (line 67) | setupEditor(customFormats, editor) {
method extensionsPath (line 681) | extensionsPath () {
method galleryPopupUpdated (line 691) | galleryPopupUpdated (response) {
method getTinyMCECSSFiles (line 700) | getTinyMCECSSFiles () {
method getCustomThemeEditorConfig (line 710) | getCustomThemeEditorConfig () {
method loadCustomFormatsFromTheme (line 730) | loadCustomFormatsFromTheme() {
method filePickerCallback (line 788) | filePickerCallback(callback, value, meta) {
method addEditorButtons (line 798) | addEditorButtons() {
method addInlineEditor (line 841) | addInlineEditor(customFormats) {
method checkInlineTrigger (line 861) | checkInlineTrigger (target) {
method checkInlineLinkTrigger (line 885) | checkInlineLinkTrigger (target) {
method addLinkEditor (line 895) | addLinkEditor(iframe) {
method hideToolbarsOnCopyOrScroll (line 899) | hideToolbarsOnCopyOrScroll() {
method initEditorDragNDropImages (line 904) | initEditorDragNDropImages(editor) {
method fileDragOver (line 958) | fileDragOver (e) {
method editorFileSelect (line 966) | async editorFileSelect (e) {
method reloadEditor (line 1012) | reloadEditor () {
FILE: app/src/components/post-editor/ItemHelper.js
class ItemHelper (line 1) | class ItemHelper {
method prepareItemData (line 2) | static async prepareItemData (newStatus, itemID, $store, itemData, ite...
method loadItemData (line 127) | static loadItemData (data, $store, $moment, itemType = 'post') {
method updateViewSettings (line 246) | static updateViewSettings(itemType, data, itemData) {
method getMediaPath (line 264) | static getMediaPath ($store, itemID, itemType = 'post') {
method setWebpCompatibility (line 279) | static setWebpCompatibility ($store, text) {
method isWebpImage (line 309) | static isWebpImage (url) {
method getImageType (line 317) | static getImageType (url) {
method getImageExtension (line 333) | static getImageExtension (url) {
FILE: app/src/helpers/utils.js
class Utils (line 1) | class Utils {
method deepMerge (line 9) | static deepMerge(target, source) {
method generateErrorLog (line 44) | static generateErrorLog(errorData, returnText = false) {
method debouncedFunction (line 77) | static debouncedFunction(fn, wait) {
method throttledFunction (line 98) | static throttledFunction(fn, threshhold, scope) {
method debounce (line 124) | static debounce(func, wait, immediate) {
method once (line 151) | static once(fn, context) {
method normalizePath (line 170) | static normalizePath(str, stripTrailing) {
method getValidUrl (line 184) | static getValidUrl(urlToCheck) {
FILE: app/src/helpers/vendor/tinymce/tinymce.d.ts
type StringPathBookmark (line 1) | interface StringPathBookmark {
type RangeBookmark (line 5) | interface RangeBookmark {
type IdBookmark (line 8) | interface IdBookmark {
type IndexBookmark (line 12) | interface IndexBookmark {
type PathBookmark (line 16) | interface PathBookmark {
type Bookmark (line 21) | type Bookmark = StringPathBookmark | RangeBookmark | IdBookmark | IndexB...
type NormalizedEvent (line 22) | type NormalizedEvent<E, T = any> = E & {
type MappedEvent (line 32) | type MappedEvent<T, K extends string> = K extends keyof T ? T[K] : any;
type NativeEventMap (line 33) | interface NativeEventMap {
type EditorEvent (line 75) | type EditorEvent<T> = NormalizedEvent<T>;
type EventDispatcherSettings (line 76) | interface EventDispatcherSettings {
type EventDispatcherConstructor (line 81) | interface EventDispatcherConstructor<T extends NativeEventMap> {
class EventDispatcher (line 86) | class EventDispatcher<T> {
type UndoLevelType (line 99) | const enum UndoLevelType {
type UndoLevel (line 103) | interface UndoLevel {
type UndoManager (line 110) | interface UndoManager {
type ArrayCallback$1 (line 125) | type ArrayCallback$1<T, R> = (x: T, i: number, xs: ReadonlyArray<T>) => R;
type ObjCallback$1 (line 126) | type ObjCallback$1<T, R> = (value: T, key: string, obj: Record<string, T...
type ArrayCallback (line 127) | type ArrayCallback<T, R> = ArrayCallback$1<T, R>;
type ObjCallback (line 128) | type ObjCallback<T, R> = ObjCallback$1<T, R>;
type Tools (line 129) | interface Tools {
type EventUtilsCallback (line 157) | type EventUtilsCallback<T> = (event: EventUtilsEvent<T>) => void;
type EventUtilsEvent (line 158) | type EventUtilsEvent<T> = NormalizedEvent<T> & {
type EventUtilsConstructor (line 161) | interface EventUtilsConstructor {
class EventUtils (line 166) | class EventUtils {
type DomQuerySelector (line 187) | type DomQuerySelector<T extends Node> = string | T | T[] | DomQuery<T>;
type DomQueryInitSelector (line 188) | type DomQueryInitSelector<T extends Node> = DomQuerySelector<T> | Window;
type Hook (line 189) | interface Hook {
type DomQueryConstructor (line 193) | interface DomQueryConstructor {
type DomQuery (line 232) | interface DomQuery<T extends Node = Node> extends ArrayLike<T> {
type SchemaType (line 304) | type SchemaType = 'html4' | 'html5' | 'html5-strict';
type SchemaSettings (line 305) | interface SchemaSettings {
type Attribute (line 327) | interface Attribute {
type DefaultAttribute (line 333) | interface DefaultAttribute {
type AttributePattern (line 337) | interface AttributePattern {
type ElementRule (line 344) | interface ElementRule {
type SchemaElement (line 355) | interface SchemaElement extends ElementRule {
type SchemaMap (line 360) | interface SchemaMap {
type SchemaRegExpMap (line 363) | interface SchemaRegExpMap {
type Schema (line 366) | interface Schema {
type Attributes$1 (line 391) | type Attributes$1 = Array<{
type AstNodeConstructor (line 397) | interface AstNodeConstructor {
class AstNode (line 402) | class AstNode {
type Content (line 433) | type Content = string | AstNode;
type ContentFormat (line 434) | type ContentFormat = 'raw' | 'text' | 'html' | 'tree';
type GetContentArgs (line 435) | interface GetContentArgs {
type SetContentArgs (line 443) | interface SetContentArgs {
type BlobInfoData (line 450) | interface BlobInfoData {
type BlobInfo (line 459) | interface BlobInfo {
type BlobCache (line 468) | interface BlobCache {
type NotificationManagerImpl (line 478) | interface NotificationManagerImpl {
type NotificationSpec (line 484) | interface NotificationSpec {
type NotificationApi (line 492) | interface NotificationApi {
type NotificationManager (line 503) | interface NotificationManager {
type UploadFailureOptions (line 508) | interface UploadFailureOptions {
type UploadHandler (line 511) | type UploadHandler = (blobInfo: BlobInfo, success: (url: string) => void...
type UploadResult$2 (line 512) | interface UploadResult$2 {
type RangeLikeObject (line 521) | interface RangeLikeObject {
type ApplyFormat (line 527) | type ApplyFormat = BlockFormat | InlineFormat | SelectorFormat;
type RemoveFormat (line 528) | type RemoveFormat = RemoveBlockFormat | RemoveInlineFormat | RemoveSelec...
type Format (line 529) | type Format = ApplyFormat | RemoveFormat;
type Formats (line 530) | type Formats = Record<string, Format | Format[]>;
type FormatAttrOrStyleValue (line 531) | type FormatAttrOrStyleValue = string | ((vars?: FormatVars) => string);
type FormatVars (line 532) | type FormatVars = Record<string, string | null>;
type BaseFormat (line 533) | interface BaseFormat<T> {
type Block (line 549) | interface Block {
type Inline (line 554) | interface Inline {
type Selector (line 557) | interface Selector {
type CommonFormat (line 561) | interface CommonFormat<T> extends BaseFormat<T> {
type BlockFormat (line 572) | interface BlockFormat extends Block, CommonFormat<BlockFormat> {
type InlineFormat (line 574) | interface InlineFormat extends Inline, CommonFormat<InlineFormat> {
type SelectorFormat (line 576) | interface SelectorFormat extends Selector, CommonFormat<SelectorFormat> {
type CommonRemoveFormat (line 578) | interface CommonRemoveFormat<T> extends BaseFormat<T> {
type RemoveBlockFormat (line 582) | interface RemoveBlockFormat extends Block, CommonRemoveFormat<RemoveBloc...
type RemoveInlineFormat (line 584) | interface RemoveInlineFormat extends Inline, CommonRemoveFormat<RemoveIn...
type RemoveSelectorFormat (line 586) | interface RemoveSelectorFormat extends Selector, CommonRemoveFormat<Remo...
type Format_d_Formats (line 588) | type Format_d_Formats = Formats;
type Format_d_Format (line 589) | type Format_d_Format = Format;
type Format_d_ApplyFormat (line 590) | type Format_d_ApplyFormat = ApplyFormat;
type Format_d_BlockFormat (line 591) | type Format_d_BlockFormat = BlockFormat;
type Format_d_InlineFormat (line 592) | type Format_d_InlineFormat = InlineFormat;
type Format_d_SelectorFormat (line 593) | type Format_d_SelectorFormat = SelectorFormat;
type Format_d_RemoveFormat (line 594) | type Format_d_RemoveFormat = RemoveFormat;
type Format_d_RemoveBlockFormat (line 595) | type Format_d_RemoveBlockFormat = RemoveBlockFormat;
type Format_d_RemoveInlineFormat (line 596) | type Format_d_RemoveInlineFormat = RemoveInlineFormat;
type Format_d_RemoveSelectorFormat (line 597) | type Format_d_RemoveSelectorFormat = RemoveSelectorFormat;
type StyleFormat (line 601) | type StyleFormat = BlockStyleFormat | InlineStyleFormat | SelectorStyleF...
type AllowedFormat (line 602) | type AllowedFormat = Separator | FormatReference | StyleFormat | NestedF...
type Separator (line 603) | interface Separator {
type FormatReference (line 606) | interface FormatReference {
type NestedFormatting (line 611) | interface NestedFormatting {
type CommonStyleFormat (line 615) | interface CommonStyleFormat {
type BlockStyleFormat (line 620) | interface BlockStyleFormat extends BlockFormat, CommonStyleFormat {
type InlineStyleFormat (line 622) | interface InlineStyleFormat extends InlineFormat, CommonStyleFormat {
type SelectorStyleFormat (line 624) | interface SelectorStyleFormat extends SelectorFormat, CommonStyleFormat {
type AlertBannerSpec (line 626) | interface AlertBannerSpec {
type ButtonSpec (line 633) | interface ButtonSpec {
type CheckboxSpec (line 642) | interface CheckboxSpec {
type FormComponentSpec (line 648) | interface FormComponentSpec {
type FormComponentWithLabelSpec (line 652) | interface FormComponentWithLabelSpec extends FormComponentSpec {
type CollectionSpec (line 655) | interface CollectionSpec extends FormComponentWithLabelSpec {
type ColorInputSpec (line 658) | interface ColorInputSpec extends FormComponentWithLabelSpec {
type ColorPickerSpec (line 661) | interface ColorPickerSpec extends FormComponentWithLabelSpec {
type CustomEditorInit (line 664) | interface CustomEditorInit {
type CustomEditorInitFn (line 669) | type CustomEditorInitFn = (elm: HTMLElement, settings: any) => Promise<C...
type CustomEditorOldSpec (line 670) | interface CustomEditorOldSpec extends FormComponentSpec {
type CustomEditorNewSpec (line 675) | interface CustomEditorNewSpec extends FormComponentSpec {
type CustomEditorSpec (line 682) | type CustomEditorSpec = CustomEditorOldSpec | CustomEditorNewSpec;
type DropZoneSpec (line 683) | interface DropZoneSpec extends FormComponentWithLabelSpec {
type GridSpec (line 686) | interface GridSpec {
type HtmlPanelSpec (line 691) | interface HtmlPanelSpec {
type IframeSpec (line 696) | interface IframeSpec extends FormComponentWithLabelSpec {
type ImageToolsState (line 700) | interface ImageToolsState {
type ImageToolsSpec (line 704) | interface ImageToolsSpec extends FormComponentWithLabelSpec {
type InputSpec (line 708) | interface InputSpec extends FormComponentWithLabelSpec {
type LabelSpec (line 715) | interface LabelSpec {
type ListBoxSingleItemSpec (line 720) | interface ListBoxSingleItemSpec {
type ListBoxNestedItemSpec (line 724) | interface ListBoxNestedItemSpec {
type ListBoxItemSpec (line 728) | type ListBoxItemSpec = ListBoxNestedItemSpec | ListBoxSingleItemSpec;
type ListBoxSpec (line 729) | interface ListBoxSpec extends FormComponentWithLabelSpec {
type PanelSpec (line 734) | interface PanelSpec {
type SelectBoxItemSpec (line 739) | interface SelectBoxItemSpec {
type SelectBoxSpec (line 743) | interface SelectBoxSpec extends FormComponentWithLabelSpec {
type SizeInputSpec (line 749) | interface SizeInputSpec extends FormComponentWithLabelSpec {
type TableSpec (line 754) | interface TableSpec {
type TextAreaSpec (line 759) | interface TextAreaSpec extends FormComponentWithLabelSpec {
type UrlInputSpec (line 765) | interface UrlInputSpec extends FormComponentWithLabelSpec {
type BodyComponentSpec (line 770) | type BodyComponentSpec = BarSpec | ButtonSpec | CheckboxSpec | TextAreaS...
type BarSpec (line 771) | interface BarSpec {
type CommonMenuItemSpec (line 775) | interface CommonMenuItemSpec {
type CommonMenuItemInstanceApi (line 782) | interface CommonMenuItemInstanceApi {
type DialogToggleMenuItemSpec (line 786) | interface DialogToggleMenuItemSpec extends CommonMenuItemSpec {
type DialogFooterMenuButtonItemSpec (line 790) | type DialogFooterMenuButtonItemSpec = DialogToggleMenuItemSpec;
type BaseDialogFooterButtonSpec (line 791) | interface BaseDialogFooterButtonSpec {
type DialogFooterNormalButtonSpec (line 798) | interface DialogFooterNormalButtonSpec extends BaseDialogFooterButtonSpec {
type DialogFooterMenuButtonSpec (line 802) | interface DialogFooterMenuButtonSpec extends BaseDialogFooterButtonSpec {
type DialogFooterButtonSpec (line 809) | type DialogFooterButtonSpec = DialogFooterNormalButtonSpec | DialogFoote...
type TabSpec (line 810) | interface TabSpec {
type TabPanelSpec (line 815) | interface TabPanelSpec {
type DialogDataItem (line 819) | type DialogDataItem = any;
type DialogData (line 820) | type DialogData = Record<string, DialogDataItem>;
type DialogInstanceApi (line 821) | interface DialogInstanceApi<T extends DialogData> {
type DialogActionDetails (line 833) | interface DialogActionDetails {
type DialogChangeDetails (line 837) | interface DialogChangeDetails<T> {
type DialogTabChangeDetails (line 840) | interface DialogTabChangeDetails {
type DialogActionHandler (line 844) | type DialogActionHandler<T> = (api: DialogInstanceApi<T>, details: Dialo...
type DialogChangeHandler (line 845) | type DialogChangeHandler<T> = (api: DialogInstanceApi<T>, details: Dialo...
type DialogSubmitHandler (line 846) | type DialogSubmitHandler<T> = (api: DialogInstanceApi<T>) => void;
type DialogCloseHandler (line 847) | type DialogCloseHandler = () => void;
type DialogCancelHandler (line 848) | type DialogCancelHandler<T> = (api: DialogInstanceApi<T>) => void;
type DialogTabChangeHandler (line 849) | type DialogTabChangeHandler<T> = (api: DialogInstanceApi<T>, details: Di...
type DialogSize (line 850) | type DialogSize = 'normal' | 'medium' | 'large';
type DialogSpec (line 851) | interface DialogSpec<T extends DialogData> {
type UrlDialogInstanceApi (line 864) | interface UrlDialogInstanceApi {
type UrlDialogActionDetails (line 870) | interface UrlDialogActionDetails {
type UrlDialogMessage (line 874) | interface UrlDialogMessage {
type UrlDialogActionHandler (line 878) | type UrlDialogActionHandler = (api: UrlDialogInstanceApi, actions: UrlDi...
type UrlDialogCloseHandler (line 879) | type UrlDialogCloseHandler = () => void;
type UrlDialogCancelHandler (line 880) | type UrlDialogCancelHandler = (api: UrlDialogInstanceApi) => void;
type UrlDialogMessageHandler (line 881) | type UrlDialogMessageHandler = (api: UrlDialogInstanceApi, message: UrlD...
type UrlDialogFooterButtonSpec (line 882) | interface UrlDialogFooterButtonSpec extends DialogFooterNormalButtonSpec {
type UrlDialogSpec (line 885) | interface UrlDialogSpec {
type CardContainerDirection (line 896) | type CardContainerDirection = 'vertical' | 'horizontal';
type CardContainerAlign (line 897) | type CardContainerAlign = 'left' | 'right';
type CardContainerValign (line 898) | type CardContainerValign = 'top' | 'middle' | 'bottom';
type CardContainerSpec (line 899) | interface CardContainerSpec {
type CardImageSpec (line 906) | interface CardImageSpec {
type CardTextSpec (line 912) | interface CardTextSpec {
type CardItemSpec (line 918) | type CardItemSpec = CardContainerSpec | CardImageSpec | CardTextSpec;
type CardMenuItemInstanceApi (line 919) | interface CardMenuItemInstanceApi extends CommonMenuItemInstanceApi {
type CardMenuItemSpec (line 921) | interface CardMenuItemSpec extends Omit<CommonMenuItemSpec, 'text' | 'sh...
type SeparatorMenuItemSpec (line 928) | interface SeparatorMenuItemSpec {
type ColumnTypes$1 (line 932) | type ColumnTypes$1 = number | 'auto';
type SeparatorItemSpec (line 933) | type SeparatorItemSpec = SeparatorMenuItemSpec;
type AutocompleterItemSpec (line 934) | interface AutocompleterItemSpec {
type AutocompleterContents (line 941) | type AutocompleterContents = SeparatorItemSpec | AutocompleterItemSpec |...
type AutocompleterSpec (line 942) | interface AutocompleterSpec {
type AutocompleterInstanceApi (line 953) | interface AutocompleterInstanceApi {
type ContextPosition (line 957) | type ContextPosition = 'node' | 'selection' | 'line';
type ContextScope (line 958) | type ContextScope = 'node' | 'editor';
type ContextBarSpec (line 959) | interface ContextBarSpec {
type BaseToolbarButtonSpec (line 964) | interface BaseToolbarButtonSpec<I extends BaseToolbarButtonInstanceApi> {
type BaseToolbarButtonInstanceApi (line 971) | interface BaseToolbarButtonInstanceApi {
type ToolbarButtonSpec (line 975) | interface ToolbarButtonSpec extends BaseToolbarButtonSpec<ToolbarButtonI...
type ToolbarButtonInstanceApi (line 979) | interface ToolbarButtonInstanceApi extends BaseToolbarButtonInstanceApi {
type BaseToolbarToggleButtonSpec (line 981) | interface BaseToolbarToggleButtonSpec<I extends BaseToolbarButtonInstanc...
type BaseToolbarToggleButtonInstanceApi (line 984) | interface BaseToolbarToggleButtonInstanceApi extends BaseToolbarButtonIn...
type ToolbarToggleButtonSpec (line 988) | interface ToolbarToggleButtonSpec extends BaseToolbarToggleButtonSpec<To...
type ToolbarToggleButtonInstanceApi (line 992) | interface ToolbarToggleButtonInstanceApi extends BaseToolbarToggleButton...
type ContextFormLaunchButtonApi (line 994) | interface ContextFormLaunchButtonApi extends BaseToolbarButtonSpec<BaseT...
type ContextFormLaunchToggleButtonSpec (line 997) | interface ContextFormLaunchToggleButtonSpec extends BaseToolbarToggleBut...
type ContextFormButtonInstanceApi (line 1000) | interface ContextFormButtonInstanceApi extends BaseToolbarButtonInstance...
type ContextFormToggleButtonInstanceApi (line 1002) | interface ContextFormToggleButtonInstanceApi extends BaseToolbarToggleBu...
type ContextFormButtonSpec (line 1004) | interface ContextFormButtonSpec extends BaseToolbarButtonSpec<ContextFor...
type ContextFormToggleButtonSpec (line 1009) | interface ContextFormToggleButtonSpec extends BaseToolbarToggleButtonSpe...
type ContextFormInstanceApi (line 1014) | interface ContextFormInstanceApi {
type ContextFormSpec (line 1018) | interface ContextFormSpec extends ContextBarSpec {
type ContextToolbarSpec (line 1025) | interface ContextToolbarSpec extends ContextBarSpec {
type ChoiceMenuItemSpec (line 1029) | interface ChoiceMenuItemSpec extends CommonMenuItemSpec {
type ChoiceMenuItemInstanceApi (line 1033) | interface ChoiceMenuItemInstanceApi extends CommonMenuItemInstanceApi {
type ContextMenuItem (line 1037) | interface ContextMenuItem extends CommonMenuItemSpec {
type ContextSubMenu (line 1043) | interface ContextSubMenu extends CommonMenuItemSpec {
type ContextMenuContents (line 1049) | type ContextMenuContents = string | ContextMenuItem | SeparatorMenuItemS...
type ContextMenuApi (line 1050) | interface ContextMenuApi {
type FancyActionArgsMap (line 1053) | interface FancyActionArgsMap {
type BaseFancyMenuItemSpec (line 1062) | interface BaseFancyMenuItemSpec<T extends keyof FancyActionArgsMap> {
type InsertTableMenuItemSpec (line 1068) | interface InsertTableMenuItemSpec extends BaseFancyMenuItemSpec<'insertt...
type ColorSwatchMenuItemSpec (line 1072) | interface ColorSwatchMenuItemSpec extends BaseFancyMenuItemSpec<'colorsw...
type FancyMenuItemSpec (line 1079) | type FancyMenuItemSpec = InsertTableMenuItemSpec | ColorSwatchMenuItemSpec;
type MenuItemSpec (line 1080) | interface MenuItemSpec extends CommonMenuItemSpec {
type MenuItemInstanceApi (line 1086) | interface MenuItemInstanceApi extends CommonMenuItemInstanceApi {
type NestedMenuItemContents (line 1088) | type NestedMenuItemContents = string | MenuItemSpec | NestedMenuItemSpec...
type NestedMenuItemSpec (line 1089) | interface NestedMenuItemSpec extends CommonMenuItemSpec {
type NestedMenuItemInstanceApi (line 1095) | interface NestedMenuItemInstanceApi extends CommonMenuItemInstanceApi {
type ToggleMenuItemSpec (line 1097) | interface ToggleMenuItemSpec extends CommonMenuItemSpec {
type ToggleMenuItemInstanceApi (line 1104) | interface ToggleMenuItemInstanceApi extends CommonMenuItemInstanceApi {
type PublicDialog_d_AlertBannerSpec (line 1108) | type PublicDialog_d_AlertBannerSpec = AlertBannerSpec;
type PublicDialog_d_BarSpec (line 1109) | type PublicDialog_d_BarSpec = BarSpec;
type PublicDialog_d_BodyComponentSpec (line 1110) | type PublicDialog_d_BodyComponentSpec = BodyComponentSpec;
type PublicDialog_d_ButtonSpec (line 1111) | type PublicDialog_d_ButtonSpec = ButtonSpec;
type PublicDialog_d_CheckboxSpec (line 1112) | type PublicDialog_d_CheckboxSpec = CheckboxSpec;
type PublicDialog_d_CollectionSpec (line 1113) | type PublicDialog_d_CollectionSpec = CollectionSpec;
type PublicDialog_d_ColorInputSpec (line 1114) | type PublicDialog_d_ColorInputSpec = ColorInputSpec;
type PublicDialog_d_ColorPickerSpec (line 1115) | type PublicDialog_d_ColorPickerSpec = ColorPickerSpec;
type PublicDialog_d_CustomEditorSpec (line 1116) | type PublicDialog_d_CustomEditorSpec = CustomEditorSpec;
type PublicDialog_d_CustomEditorInit (line 1117) | type PublicDialog_d_CustomEditorInit = CustomEditorInit;
type PublicDialog_d_CustomEditorInitFn (line 1118) | type PublicDialog_d_CustomEditorInitFn = CustomEditorInitFn;
type PublicDialog_d_DialogData (line 1119) | type PublicDialog_d_DialogData = DialogData;
type PublicDialog_d_DialogSize (line 1120) | type PublicDialog_d_DialogSize = DialogSize;
type PublicDialog_d_DialogSpec (line 1121) | type PublicDialog_d_DialogSpec<_0> = DialogSpec<_0>;
type PublicDialog_d_DialogInstanceApi (line 1122) | type PublicDialog_d_DialogInstanceApi<_0> = DialogInstanceApi<_0>;
type PublicDialog_d_DialogFooterButtonSpec (line 1123) | type PublicDialog_d_DialogFooterButtonSpec = DialogFooterButtonSpec;
type PublicDialog_d_DialogActionDetails (line 1124) | type PublicDialog_d_DialogActionDetails = DialogActionDetails;
type PublicDialog_d_DialogChangeDetails (line 1125) | type PublicDialog_d_DialogChangeDetails<_0> = DialogChangeDetails<_0>;
type PublicDialog_d_DialogTabChangeDetails (line 1126) | type PublicDialog_d_DialogTabChangeDetails = DialogTabChangeDetails;
type PublicDialog_d_DropZoneSpec (line 1127) | type PublicDialog_d_DropZoneSpec = DropZoneSpec;
type PublicDialog_d_GridSpec (line 1128) | type PublicDialog_d_GridSpec = GridSpec;
type PublicDialog_d_HtmlPanelSpec (line 1129) | type PublicDialog_d_HtmlPanelSpec = HtmlPanelSpec;
type PublicDialog_d_IframeSpec (line 1130) | type PublicDialog_d_IframeSpec = IframeSpec;
type PublicDialog_d_ImageToolsSpec (line 1131) | type PublicDialog_d_ImageToolsSpec = ImageToolsSpec;
type PublicDialog_d_InputSpec (line 1132) | type PublicDialog_d_InputSpec = InputSpec;
type PublicDialog_d_LabelSpec (line 1133) | type PublicDialog_d_LabelSpec = LabelSpec;
type PublicDialog_d_ListBoxSpec (line 1134) | type PublicDialog_d_ListBoxSpec = ListBoxSpec;
type PublicDialog_d_ListBoxItemSpec (line 1135) | type PublicDialog_d_ListBoxItemSpec = ListBoxItemSpec;
type PublicDialog_d_ListBoxNestedItemSpec (line 1136) | type PublicDialog_d_ListBoxNestedItemSpec = ListBoxNestedItemSpec;
type PublicDialog_d_ListBoxSingleItemSpec (line 1137) | type PublicDialog_d_ListBoxSingleItemSpec = ListBoxSingleItemSpec;
type PublicDialog_d_PanelSpec (line 1138) | type PublicDialog_d_PanelSpec = PanelSpec;
type PublicDialog_d_SelectBoxSpec (line 1139) | type PublicDialog_d_SelectBoxSpec = SelectBoxSpec;
type PublicDialog_d_SelectBoxItemSpec (line 1140) | type PublicDialog_d_SelectBoxItemSpec = SelectBoxItemSpec;
type PublicDialog_d_SizeInputSpec (line 1141) | type PublicDialog_d_SizeInputSpec = SizeInputSpec;
type PublicDialog_d_TableSpec (line 1142) | type PublicDialog_d_TableSpec = TableSpec;
type PublicDialog_d_TabSpec (line 1143) | type PublicDialog_d_TabSpec = TabSpec;
type PublicDialog_d_TabPanelSpec (line 1144) | type PublicDialog_d_TabPanelSpec = TabPanelSpec;
type PublicDialog_d_TextAreaSpec (line 1145) | type PublicDialog_d_TextAreaSpec = TextAreaSpec;
type PublicDialog_d_UrlInputSpec (line 1146) | type PublicDialog_d_UrlInputSpec = UrlInputSpec;
type PublicDialog_d_UrlDialogSpec (line 1147) | type PublicDialog_d_UrlDialogSpec = UrlDialogSpec;
type PublicDialog_d_UrlDialogFooterButtonSpec (line 1148) | type PublicDialog_d_UrlDialogFooterButtonSpec = UrlDialogFooterButtonSpec;
type PublicDialog_d_UrlDialogInstanceApi (line 1149) | type PublicDialog_d_UrlDialogInstanceApi = UrlDialogInstanceApi;
type PublicDialog_d_UrlDialogActionDetails (line 1150) | type PublicDialog_d_UrlDialogActionDetails = UrlDialogActionDetails;
type PublicDialog_d_UrlDialogMessage (line 1151) | type PublicDialog_d_UrlDialogMessage = UrlDialogMessage;
type PublicInlineContent_d_AutocompleterSpec (line 1155) | type PublicInlineContent_d_AutocompleterSpec = AutocompleterSpec;
type PublicInlineContent_d_AutocompleterItemSpec (line 1156) | type PublicInlineContent_d_AutocompleterItemSpec = AutocompleterItemSpec;
type PublicInlineContent_d_AutocompleterContents (line 1157) | type PublicInlineContent_d_AutocompleterContents = AutocompleterContents;
type PublicInlineContent_d_AutocompleterInstanceApi (line 1158) | type PublicInlineContent_d_AutocompleterInstanceApi = AutocompleterInsta...
type PublicInlineContent_d_ContextPosition (line 1159) | type PublicInlineContent_d_ContextPosition = ContextPosition;
type PublicInlineContent_d_ContextScope (line 1160) | type PublicInlineContent_d_ContextScope = ContextScope;
type PublicInlineContent_d_ContextFormSpec (line 1161) | type PublicInlineContent_d_ContextFormSpec = ContextFormSpec;
type PublicInlineContent_d_ContextFormInstanceApi (line 1162) | type PublicInlineContent_d_ContextFormInstanceApi = ContextFormInstanceApi;
type PublicInlineContent_d_ContextFormButtonSpec (line 1163) | type PublicInlineContent_d_ContextFormButtonSpec = ContextFormButtonSpec;
type PublicInlineContent_d_ContextFormButtonInstanceApi (line 1164) | type PublicInlineContent_d_ContextFormButtonInstanceApi = ContextFormBut...
type PublicInlineContent_d_ContextFormToggleButtonSpec (line 1165) | type PublicInlineContent_d_ContextFormToggleButtonSpec = ContextFormTogg...
type PublicInlineContent_d_ContextFormToggleButtonInstanceApi (line 1166) | type PublicInlineContent_d_ContextFormToggleButtonInstanceApi = ContextF...
type PublicInlineContent_d_ContextToolbarSpec (line 1167) | type PublicInlineContent_d_ContextToolbarSpec = ContextToolbarSpec;
type PublicInlineContent_d_SeparatorItemSpec (line 1168) | type PublicInlineContent_d_SeparatorItemSpec = SeparatorItemSpec;
type PublicMenu_d_MenuItemSpec (line 1172) | type PublicMenu_d_MenuItemSpec = MenuItemSpec;
type PublicMenu_d_MenuItemInstanceApi (line 1173) | type PublicMenu_d_MenuItemInstanceApi = MenuItemInstanceApi;
type PublicMenu_d_NestedMenuItemContents (line 1174) | type PublicMenu_d_NestedMenuItemContents = NestedMenuItemContents;
type PublicMenu_d_NestedMenuItemSpec (line 1175) | type PublicMenu_d_NestedMenuItemSpec = NestedMenuItemSpec;
type PublicMenu_d_NestedMenuItemInstanceApi (line 1176) | type PublicMenu_d_NestedMenuItemInstanceApi = NestedMenuItemInstanceApi;
type PublicMenu_d_FancyMenuItemSpec (line 1177) | type PublicMenu_d_FancyMenuItemSpec = FancyMenuItemSpec;
type PublicMenu_d_ColorSwatchMenuItemSpec (line 1178) | type PublicMenu_d_ColorSwatchMenuItemSpec = ColorSwatchMenuItemSpec;
type PublicMenu_d_InsertTableMenuItemSpec (line 1179) | type PublicMenu_d_InsertTableMenuItemSpec = InsertTableMenuItemSpec;
type PublicMenu_d_ToggleMenuItemSpec (line 1180) | type PublicMenu_d_ToggleMenuItemSpec = ToggleMenuItemSpec;
type PublicMenu_d_ToggleMenuItemInstanceApi (line 1181) | type PublicMenu_d_ToggleMenuItemInstanceApi = ToggleMenuItemInstanceApi;
type PublicMenu_d_ChoiceMenuItemSpec (line 1182) | type PublicMenu_d_ChoiceMenuItemSpec = ChoiceMenuItemSpec;
type PublicMenu_d_ChoiceMenuItemInstanceApi (line 1183) | type PublicMenu_d_ChoiceMenuItemInstanceApi = ChoiceMenuItemInstanceApi;
type PublicMenu_d_SeparatorMenuItemSpec (line 1184) | type PublicMenu_d_SeparatorMenuItemSpec = SeparatorMenuItemSpec;
type PublicMenu_d_ContextMenuApi (line 1185) | type PublicMenu_d_ContextMenuApi = ContextMenuApi;
type PublicMenu_d_ContextMenuContents (line 1186) | type PublicMenu_d_ContextMenuContents = ContextMenuContents;
type PublicMenu_d_ContextMenuItem (line 1187) | type PublicMenu_d_ContextMenuItem = ContextMenuItem;
type PublicMenu_d_ContextSubMenu (line 1188) | type PublicMenu_d_ContextSubMenu = ContextSubMenu;
type PublicMenu_d_CardMenuItemSpec (line 1189) | type PublicMenu_d_CardMenuItemSpec = CardMenuItemSpec;
type PublicMenu_d_CardMenuItemInstanceApi (line 1190) | type PublicMenu_d_CardMenuItemInstanceApi = CardMenuItemInstanceApi;
type PublicMenu_d_CardItemSpec (line 1191) | type PublicMenu_d_CardItemSpec = CardItemSpec;
type PublicMenu_d_CardContainerSpec (line 1192) | type PublicMenu_d_CardContainerSpec = CardContainerSpec;
type PublicMenu_d_CardImageSpec (line 1193) | type PublicMenu_d_CardImageSpec = CardImageSpec;
type PublicMenu_d_CardTextSpec (line 1194) | type PublicMenu_d_CardTextSpec = CardTextSpec;
type SidebarInstanceApi (line 1198) | interface SidebarInstanceApi {
type SidebarSpec (line 1201) | interface SidebarSpec {
type PublicSidebar_d_SidebarSpec (line 1208) | type PublicSidebar_d_SidebarSpec = SidebarSpec;
type PublicSidebar_d_SidebarInstanceApi (line 1209) | type PublicSidebar_d_SidebarInstanceApi = SidebarInstanceApi;
type ToolbarGroupSetting (line 1213) | interface ToolbarGroupSetting {
type ToolbarConfig (line 1217) | type ToolbarConfig = string | ToolbarGroupSetting[];
type GroupToolbarButtonInstanceApi (line 1218) | interface GroupToolbarButtonInstanceApi extends BaseToolbarButtonInstanc...
type GroupToolbarButtonSpec (line 1220) | interface GroupToolbarButtonSpec extends BaseToolbarButtonSpec<GroupTool...
type MenuButtonItemTypes (line 1224) | type MenuButtonItemTypes = NestedMenuItemContents;
type SuccessCallback$1 (line 1225) | type SuccessCallback$1 = (menu: string | MenuButtonItemTypes[]) => void;
type BaseMenuButtonSpec (line 1226) | interface BaseMenuButtonSpec {
type BaseMenuButtonInstanceApi (line 1233) | interface BaseMenuButtonInstanceApi {
type ToolbarMenuButtonSpec (line 1239) | interface ToolbarMenuButtonSpec extends BaseMenuButtonSpec {
type ToolbarMenuButtonInstanceApi (line 1243) | interface ToolbarMenuButtonInstanceApi extends BaseMenuButtonInstanceApi {
type ToolbarSplitButtonItemTypes (line 1245) | type ToolbarSplitButtonItemTypes = ChoiceMenuItemSpec | SeparatorMenuIte...
type SuccessCallback (line 1246) | type SuccessCallback = (menu: ToolbarSplitButtonItemTypes[]) => void;
type SelectPredicate (line 1247) | type SelectPredicate = (value: string) => boolean;
type PresetTypes (line 1248) | type PresetTypes = 'color' | 'normal' | 'listpreview';
type ColumnTypes (line 1249) | type ColumnTypes = number | 'auto';
type ToolbarSplitButtonSpec (line 1250) | interface ToolbarSplitButtonSpec {
type ToolbarSplitButtonInstanceApi (line 1263) | interface ToolbarSplitButtonInstanceApi {
type PublicToolbar_d_ToolbarButtonSpec (line 1271) | type PublicToolbar_d_ToolbarButtonSpec = ToolbarButtonSpec;
type PublicToolbar_d_ToolbarButtonInstanceApi (line 1272) | type PublicToolbar_d_ToolbarButtonInstanceApi = ToolbarButtonInstanceApi;
type PublicToolbar_d_ToolbarSplitButtonSpec (line 1273) | type PublicToolbar_d_ToolbarSplitButtonSpec = ToolbarSplitButtonSpec;
type PublicToolbar_d_ToolbarSplitButtonInstanceApi (line 1274) | type PublicToolbar_d_ToolbarSplitButtonInstanceApi = ToolbarSplitButtonI...
type PublicToolbar_d_ToolbarMenuButtonSpec (line 1275) | type PublicToolbar_d_ToolbarMenuButtonSpec = ToolbarMenuButtonSpec;
type PublicToolbar_d_ToolbarMenuButtonInstanceApi (line 1276) | type PublicToolbar_d_ToolbarMenuButtonInstanceApi = ToolbarMenuButtonIns...
type PublicToolbar_d_ToolbarToggleButtonSpec (line 1277) | type PublicToolbar_d_ToolbarToggleButtonSpec = ToolbarToggleButtonSpec;
type PublicToolbar_d_ToolbarToggleButtonInstanceApi (line 1278) | type PublicToolbar_d_ToolbarToggleButtonInstanceApi = ToolbarToggleButto...
type PublicToolbar_d_GroupToolbarButtonSpec (line 1279) | type PublicToolbar_d_GroupToolbarButtonSpec = GroupToolbarButtonSpec;
type PublicToolbar_d_GroupToolbarButtonInstanceApi (line 1280) | type PublicToolbar_d_GroupToolbarButtonInstanceApi = GroupToolbarButtonI...
type Registry$1 (line 1284) | interface Registry$1 {
type StyleSheetLoaderSettings (line 1309) | interface StyleSheetLoaderSettings {
type StyleSheetLoader (line 1314) | interface StyleSheetLoader {
type Registry (line 1321) | type Registry = Registry$1;
type EditorUiApi (line 1322) | interface EditorUiApi {
type EditorUi (line 1329) | interface EditorUi extends EditorUiApi {
type Ui_d_Registry (line 1333) | type Ui_d_Registry = Registry;
type Ui_d_EditorUiApi (line 1334) | type Ui_d_EditorUiApi = EditorUiApi;
type Ui_d_EditorUi (line 1335) | type Ui_d_EditorUi = EditorUi;
type EntityEncoding (line 1339) | type EntityEncoding = 'named' | 'numeric' | 'raw' | 'named,numeric' | 'n...
type ContentLanguage (line 1340) | interface ContentLanguage {
type ThemeInitFunc (line 1345) | type ThemeInitFunc = (editor: Editor, elm: HTMLElement) => {
type SetupCallback (line 1352) | type SetupCallback = (editor: Editor) => void;
type FilePickerCallback (line 1353) | type FilePickerCallback = (callback: Function, value: any, meta: Record<...
type FilePickerValidationStatus (line 1354) | type FilePickerValidationStatus = 'valid' | 'unknown' | 'invalid' | 'none';
type FilePickerValidationCallback (line 1355) | type FilePickerValidationCallback = (info: {
type URLConverter (line 1362) | type URLConverter = (url: string, name: string, elm?: HTMLElement) => st...
type URLConverterCallback (line 1363) | type URLConverterCallback = (url: string, node: Node, on_save: boolean, ...
type ToolbarGroup (line 1364) | interface ToolbarGroup {
type ToolbarMode (line 1368) | type ToolbarMode = 'floating' | 'sliding' | 'scrolling' | 'wrap';
type BaseEditorSettings (line 1369) | interface BaseEditorSettings {
type RawEditorSettings (line 1555) | interface RawEditorSettings extends BaseEditorSettings {
type EditorSettings (line 1560) | interface EditorSettings extends BaseEditorSettings {
type ParamTypeMap (line 1564) | interface ParamTypeMap {
type BlobInfoImagePair (line 1572) | interface BlobInfoImagePair {
class NodeChange (line 1576) | class NodeChange {
type SelectionOverrides (line 1583) | interface SelectionOverrides {
type Quirks (line 1589) | interface Quirks {
type DecoratorData (line 1593) | type DecoratorData = Record<string, any>;
type Decorator (line 1594) | type Decorator = (uid: string, data: DecoratorData) => {
type AnnotationListener (line 1598) | type AnnotationListener = (state: boolean, name: string, data?: {
type AnnotationListenerApi (line 1602) | type AnnotationListenerApi = AnnotationListener;
type AnnotatorSettings (line 1603) | interface AnnotatorSettings {
type Annotator (line 1607) | interface Annotator {
type GeomRect (line 1614) | interface GeomRect {
type Rect (line 1620) | interface Rect {
type StyleMap (line 1629) | interface StyleMap {
type StylesSettings (line 1632) | interface StylesSettings {
type Styles (line 1638) | interface Styles {
type DOMUtilsSettings (line 1643) | interface DOMUtilsSettings {
type Target (line 1657) | type Target = Node | Window;
type RunArguments (line 1658) | type RunArguments<T extends Node = Node> = string | T | Array<string | T>;
type BoundEvent (line 1659) | type BoundEvent = [
type Callback (line 1665) | type Callback<K extends string> = EventUtilsCallback<MappedEvent<HTMLEle...
type DOMUtils (line 1666) | interface DOMUtils {
type ClientRect (line 1789) | interface ClientRect {
type GetSelectionContentArgs (line 1797) | interface GetSelectionContentArgs extends GetContentArgs {
type SelectionSetContentArgs (line 1801) | interface SelectionSetContentArgs extends SetContentArgs {
type BookmarkManager (line 1804) | interface BookmarkManager {
type ControlSelection (line 1808) | interface ControlSelection {
type ParserArgs (line 1815) | interface ParserArgs {
type ParserFilterCallback (line 1825) | type ParserFilterCallback = (nodes: AstNode[], name: string, args: Parse...
type ParserFilter (line 1826) | interface ParserFilter {
type DomParserSettings (line 1830) | interface DomParserSettings {
type DomParser (line 1852) | interface DomParser {
type WriterSettings (line 1861) | interface WriterSettings {
type Attributes (line 1869) | type Attributes = Array<{
type Writer (line 1873) | interface Writer {
type HtmlSerializerSettings (line 1884) | interface HtmlSerializerSettings extends WriterSettings {
type HtmlSerializer (line 1888) | interface HtmlSerializer {
type DomSerializerSettings (line 1891) | interface DomSerializerSettings extends DomParserSettings, WriterSetting...
type DomSerializerImpl (line 1895) | interface DomSerializerImpl {
type DomSerializer (line 1912) | interface DomSerializer extends DomSerializerImpl {
type EditorSelection (line 1914) | interface EditorSelection {
type EditorCommandCallback (line 1965) | type EditorCommandCallback = (ui: boolean, value: any, args: any) => void;
type EditorCommandsCallback (line 1966) | type EditorCommandsCallback = (command: string, ui: boolean, value: any,...
type Commands (line 1967) | interface Commands {
type EditorCommandsConstructor (line 1972) | interface EditorCommandsConstructor {
class EditorCommands (line 1976) | class EditorCommands {
type WindowParams (line 1998) | interface WindowParams {
type InstanceApi (line 2002) | type InstanceApi<T> = UrlDialogInstanceApi | DialogInstanceApi<T>;
type WindowManagerImpl (line 2003) | interface WindowManagerImpl {
type WindowManager (line 2010) | interface WindowManager {
type ExecCommandEvent (line 2017) | interface ExecCommandEvent {
type GetContentEvent (line 2022) | type GetContentEvent = GetContentArgs & {
type SetContentEvent (line 2027) | type SetContentEvent = SetContentArgs & {
type NewBlockEvent (line 2032) | interface NewBlockEvent {
type NodeChangeEvent (line 2035) | interface NodeChangeEvent {
type FormatEvent (line 2041) | interface FormatEvent {
type ObjectResizeEvent (line 2046) | interface ObjectResizeEvent {
type ObjectSelectedEvent (line 2052) | interface ObjectSelectedEvent {
type ScrollIntoViewEvent (line 2056) | interface ScrollIntoViewEvent {
type SetSelectionRangeEvent (line 2060) | interface SetSelectionRangeEvent {
type ShowCaretEvent (line 2064) | interface ShowCaretEvent {
type SwitchModeEvent (line 2069) | interface SwitchModeEvent {
type AddUndoEvent (line 2072) | interface AddUndoEvent {
type UndoRedoEvent (line 2077) | interface UndoRedoEvent {
type WindowEvent (line 2080) | interface WindowEvent<T extends DialogData> {
type ProgressStateEvent (line 2083) | interface ProgressStateEvent {
type AfterProgressStateEvent (line 2087) | interface AfterProgressStateEvent {
type PlaceholderToggleEvent (line 2090) | interface PlaceholderToggleEvent {
type LoadErrorEvent (line 2093) | interface LoadErrorEvent {
type PreProcessEvent (line 2096) | interface PreProcessEvent extends ParserArgs {
type PostProcessEvent (line 2099) | interface PostProcessEvent extends ParserArgs {
type EditorEventMap (line 2102) | interface EditorEventMap extends Omit<NativeEventMap, 'blur' | 'focus'> {
type EditorManagerEventMap (line 2174) | interface EditorManagerEventMap {
type EventTypes_d_ExecCommandEvent (line 2185) | type EventTypes_d_ExecCommandEvent = ExecCommandEvent;
type EventTypes_d_GetContentEvent (line 2186) | type EventTypes_d_GetContentEvent = GetContentEvent;
type EventTypes_d_SetContentEvent (line 2187) | type EventTypes_d_SetContentEvent = SetContentEvent;
type EventTypes_d_NewBlockEvent (line 2188) | type EventTypes_d_NewBlockEvent = NewBlockEvent;
type EventTypes_d_NodeChangeEvent (line 2189) | type EventTypes_d_NodeChangeEvent = NodeChangeEvent;
type EventTypes_d_FormatEvent (line 2190) | type EventTypes_d_FormatEvent = FormatEvent;
type EventTypes_d_ObjectResizeEvent (line 2191) | type EventTypes_d_ObjectResizeEvent = ObjectResizeEvent;
type EventTypes_d_ObjectSelectedEvent (line 2192) | type EventTypes_d_ObjectSelectedEvent = ObjectSelectedEvent;
type EventTypes_d_ScrollIntoViewEvent (line 2193) | type EventTypes_d_ScrollIntoViewEvent = ScrollIntoViewEvent;
type EventTypes_d_SetSelectionRangeEvent (line 2194) | type EventTypes_d_SetSelectionRangeEvent = SetSelectionRangeEvent;
type EventTypes_d_ShowCaretEvent (line 2195) | type EventTypes_d_ShowCaretEvent = ShowCaretEvent;
type EventTypes_d_SwitchModeEvent (line 2196) | type EventTypes_d_SwitchModeEvent = SwitchModeEvent;
type EventTypes_d_AddUndoEvent (line 2197) | type EventTypes_d_AddUndoEvent = AddUndoEvent;
type EventTypes_d_UndoRedoEvent (line 2198) | type EventTypes_d_UndoRedoEvent = UndoRedoEvent;
type EventTypes_d_WindowEvent (line 2199) | type EventTypes_d_WindowEvent<_0> = WindowEvent<_0>;
type EventTypes_d_ProgressStateEvent (line 2200) | type EventTypes_d_ProgressStateEvent = ProgressStateEvent;
type EventTypes_d_AfterProgressStateEvent (line 2201) | type EventTypes_d_AfterProgressStateEvent = AfterProgressStateEvent;
type EventTypes_d_PlaceholderToggleEvent (line 2202) | type EventTypes_d_PlaceholderToggleEvent = PlaceholderToggleEvent;
type EventTypes_d_LoadErrorEvent (line 2203) | type EventTypes_d_LoadErrorEvent = LoadErrorEvent;
type EventTypes_d_PreProcessEvent (line 2204) | type EventTypes_d_PreProcessEvent = PreProcessEvent;
type EventTypes_d_PostProcessEvent (line 2205) | type EventTypes_d_PostProcessEvent = PostProcessEvent;
type EventTypes_d_EditorEventMap (line 2206) | type EventTypes_d_EditorEventMap = EditorEventMap;
type EventTypes_d_EditorManagerEventMap (line 2207) | type EventTypes_d_EditorManagerEventMap = EditorManagerEventMap;
type RawString (line 2211) | interface RawString {
type Primitive (line 2214) | type Primitive = string | number | boolean | Record<string | number, any...
type TokenisedString (line 2215) | type TokenisedString = [
type Untranslated (line 2219) | type Untranslated = Primitive | TokenisedString | RawString;
type TranslatedString (line 2220) | type TranslatedString = string;
type I18n (line 2221) | interface I18n {
type Observable (line 2230) | interface Observable<T> {
type URISettings (line 2237) | interface URISettings {
type URIConstructor (line 2240) | interface URIConstructor {
type SafeUriOptions (line 2254) | interface SafeUriOptions {
class URI (line 2259) | class URI {
type EditorManager (line 2295) | interface EditorManager extends Observable<EditorManagerEventMap> {
type EditorObservable (line 2326) | interface EditorObservable extends Observable<EditorEventMap> {
type UploadResult$1 (line 2331) | interface UploadResult$1 {
type UploadCallback (line 2337) | type UploadCallback = (results: UploadResult$1[]) => void;
type EditorUpload (line 2338) | interface EditorUpload {
type FormatChangeCallback (line 2346) | type FormatChangeCallback = (state: boolean, data: {
type FormatRegistry (line 2351) | interface FormatRegistry {
type Formatter (line 2360) | interface Formatter extends FormatRegistry {
type EditorMode (line 2374) | interface EditorMode {
type EditorModeApi (line 2380) | interface EditorModeApi {
type Plugin (line 2385) | interface Plugin {
type PluginManager (line 2392) | type PluginManager = AddOnManager<Plugin>;
type ShortcutsConstructor (line 2393) | interface ShortcutsConstructor {
type CommandFunc (line 2397) | type CommandFunc = string | [
class Shortcuts (line 2402) | class Shortcuts {
type Theme (line 2416) | interface Theme {
type ThemeManager (line 2430) | type ThemeManager = AddOnManager<Theme>;
type EditorConstructor (line 2431) | interface EditorConstructor {
class Editor (line 2435) | class Editor implements EditorObservable {
type UrlObject (line 2568) | interface UrlObject {
type WaitState (line 2573) | type WaitState = 'added' | 'loaded';
type AddOnCallback (line 2574) | type AddOnCallback<T> = (editor: Editor, url: string, $?: DomQueryConstr...
type AddOnConstructor (line 2575) | type AddOnConstructor<T> = new (editor: Editor, url: string, $?: DomQuer...
type AddOnManager (line 2576) | interface AddOnManager<T> {
type RangeUtils (line 2598) | interface RangeUtils {
type ScriptLoaderSettings (line 2603) | interface ScriptLoaderSettings {
type ScriptLoaderConstructor (line 2606) | interface ScriptLoaderConstructor {
class ScriptLoader (line 2611) | class ScriptLoader {
type TextProcessCallback (line 2630) | type TextProcessCallback = (node: Text, offset: number, text: string) =>...
type Spot (line 2631) | interface Spot {
type TextSeeker (line 2635) | interface TextSeeker {
type DomTreeWalkerConstructor (line 2639) | interface DomTreeWalkerConstructor {
class DomTreeWalker (line 2643) | class DomTreeWalker {
type Version (line 2654) | interface Version {
type Env (line 2658) | interface Env {
type FocusManager (line 2711) | interface FocusManager {
type EntitiesMap (line 2714) | interface EntitiesMap {
type Entities (line 2717) | interface Entities {
type AttrList (line 2725) | type AttrList = Array<{
type SaxParserSettings (line 2731) | interface SaxParserSettings {
type ParserFormat (line 2750) | type ParserFormat = 'html' | 'xhtml' | 'xml';
type SaxParser (line 2751) | interface SaxParser {
type IconPack (line 2754) | interface IconPack {
type IconManager (line 2757) | interface IconManager {
type Resource (line 2762) | interface Resource {
type WithSubItems (line 2766) | type WithSubItems<T, K extends keyof T> = T[K] extends Array<any> ? (T &...
type Props (line 2767) | interface Props<A extends any[] = any[]> {
type ExtendedClass (line 2775) | type ExtendedClass<T extends Props<A>, A extends any[]> = WithSubItems<T...
type ExtendedClassConstructor (line 2776) | interface ExtendedClassConstructor<T extends Props<A>, A extends any[] =...
type Class (line 2781) | interface Class {
type RGB (line 2784) | interface RGB {
type HSV (line 2789) | interface HSV {
type ColorConstructor (line 2794) | type ColorConstructor = new (value?: string | RGB | HSV) => Color;
type Color (line 2795) | interface Color {
type DebounceFunc (line 2801) | interface DebounceFunc<T extends (...args: any[]) => void> {
type Delay (line 2805) | interface Delay {
type UploadResult (line 2816) | type UploadResult = UploadResult$2;
type ImageUploader (line 2817) | interface ImageUploader {
type JSONUtils (line 2820) | interface JSONUtils {
type JSONPSettings (line 2824) | interface JSONPSettings {
type JSONP (line 2829) | interface JSONP {
type JSONRequestSettings (line 2834) | interface JSONRequestSettings {
type JSONRequestArgs (line 2847) | interface JSONRequestArgs extends JSONRequestSettings {
type JSONRequestConstructor (line 2852) | interface JSONRequestConstructor {
class JSONRequest (line 2857) | class JSONRequest {
type KeyboardLikeEvent (line 2864) | interface KeyboardLikeEvent {
type VK (line 2870) | interface VK {
type XHRSettings (line 2888) | interface XHRSettings {
type XHREventMap (line 2905) | interface XHREventMap {
type XHR (line 2914) | interface XHR extends Observable<XHREventMap> {
type DOMUtilsNamespace (line 2917) | interface DOMUtilsNamespace {
type RangeUtilsNamespace (line 2922) | interface RangeUtilsNamespace {
type AddOnManagerNamespace (line 2929) | interface AddOnManagerNamespace {
type BookmarkManagerNamespace (line 2937) | interface BookmarkManagerNamespace {
type SaxParserNamespace (line 2941) | interface SaxParserNamespace {
type TinyMCE (line 2945) | interface TinyMCE extends EditorManager {
FILE: app/src/main.js
method overridedCssVariables (line 238) | overridedCssVariables () {
method data (line 245) | data () {
method mounted (line 250) | async mounted () {
method setupAppTheme (line 314) | async setupAppTheme () {
method getCurrentAppTheme (line 336) | async getCurrentAppTheme () {
method toggleTheme (line 345) | async toggleTheme () {
method pluginsApiSaveConfigFile (line 380) | async pluginsApiSaveConfigFile (fileName, fileContent) {
method pluginsApiSaveLanguageFile (line 391) | async pluginsApiSaveLanguageFile (fileName, fileContent) {
method pluginsApiReadConfigFile (line 402) | async pluginsApiReadConfigFile (fileName) {
method pluginsApiReadLanguageFile (line 412) | async pluginsApiReadLanguageFile (fileName) {
method pluginsApiReadThemeFile (line 420) | async pluginsApiReadThemeFile (themeName, fileName) {
method pluginsApiDeleteConfigFile (line 429) | async pluginsApiDeleteConfigFile (fileName) {
method pluginsApiDeleteLanguageFile (line 439) | async pluginsApiDeleteLanguageFile (fileName) {
method pluginsApiGetThemesList (line 449) | pluginsApiGetThemesList () {
method pluginsApiGetCurrentTheme (line 452) | pluginsApiGetCurrentTheme () {
method showMessage (line 455) | showMessage (message) {
method setContentElementField (line 462) | async setContentElementField (itemType, itemID, fieldsToUpdate, callback) {
method beforeDestroy (line 496) | beforeDestroy () {
FILE: app/src/store/helpers/mutations.js
method init (line 6) | init (state, initialData) {
method setAppConfig (line 48) | setAppConfig (state, newAppConfig) {
method setAppTheme (line 51) | setAppTheme (state, newTheme) {
method setSiteDir (line 54) | setSiteDir (state, newSitesLocation) {
method clearCurrentSite (line 64) | clearCurrentSite (state) {
method copySiteConfig (line 82) | copySiteConfig (state, siteName) {
method setSiteConfig (line 85) | setSiteConfig (state, siteData) {
method replaceSiteConfig (line 95) | replaceSiteConfig (state, data) {
method replaceSite (line 101) | replaceSite (state, sitesData) {
method removeWebsite (line 106) | removeWebsite (state, name) {
method cloneWebsite (line 109) | cloneWebsite (state, data) {
method addNewSite (line 113) | addNewSite (state, siteData) {
method switchSite (line 134) | switchSite (state, data) {
method setSites (line 195) | setSites (state, sites) {
method setNewThemeConfig (line 198) | setNewThemeConfig (state, data) {
method setNotifications (line 202) | setNotifications (state, notificationsData) {
method setNotificationsCount (line 205) | setNotificationsCount (state, notificationsCount) {
method replaceAppThemes (line 208) | replaceAppThemes (state, newThemes) {
method updateSiteThemes (line 211) | updateSiteThemes (state) {
method replaceAppLanguages (line 215) | replaceAppLanguages (state, newLanguages) {
method replaceAppPlugins (line 218) | replaceAppPlugins (state, newPlugins) {
method setTags (line 221) | setTags (state, tags) {
method setPostsTags (line 224) | setPostsTags (state, postsTags) {
method removeTags (line 227) | removeTags (state, tagIDs) {
method setAuthors (line 231) | setAuthors (state, authors) {
method setPostAuthors (line 234) | setPostAuthors (state, postsAuthors) {
method setPageAuthors (line 237) | setPageAuthors (state, pagesAuthors) {
method removeAuthors (line 240) | removeAuthors (state, authorIDs) {
method removePosts (line 245) | removePosts (state, postIDs) {
method removePages (line 248) | removePages (state, pageIDs) {
method changePostsToPages (line 251) | changePostsToPages (state, config) {
method changePagesToPosts (line 285) | changePagesToPosts (state, config) {
method changePostsStatus (line 301) | changePostsStatus (state, config) {
method changePagesStatus (line 322) | changePagesStatus (state, config) {
method changeTagsVisibility (line 343) | changeTagsVisibility (state, config) {
method refreshSiteConfig (line 360) | refreshSiteConfig (state, newData) {
method refreshSiteThemeConfig (line 366) | refreshSiteThemeConfig (state, newData) {
method setSidebarStatus (line 370) | setSidebarStatus (state, newStatus) {
method setSyncStatus (line 373) | setSyncStatus (state, newStatus) {
method setMenuPosition (line 376) | setMenuPosition (state, newPositionData) {
method addNewMenu (line 380) | addNewMenu (state, newMenuName) {
method deleteMenuByIDs (line 387) | deleteMenuByIDs (state, menuIDs) {
method editMenuName (line 390) | editMenuName (state, newMenuData) {
method addNewMenuItem (line 393) | addNewMenuItem (state, data) {
method addNewSubmenuItem (line 402) | addNewSubmenuItem (state, data) {
method editMenuItem (line 411) | editMenuItem (state, data) {
method showMenuItem (line 420) | showMenuItem (state, data) {
method hideMenuItem (line 429) | hideMenuItem (state, data) {
method deleteMenuItem (line 438) | deleteMenuItem(state, data) {
method duplicateMenuItem (line 447) | duplicateMenuItem(state, data) {
method moveMenuItem (line 464) | moveMenuItem (state, data) {
method reorderMenuItems (line 518) | reorderMenuItems (state, data) {
method refreshAfterPostUpdate (line 522) | refreshAfterPostUpdate (state, data) {
method refreshAfterPageUpdate (line 529) | refreshAfterPageUpdate (state, data) {
method setThemeConfig (line 534) | setThemeConfig (state, data) {
method setEditorOpenState (line 543) | setEditorOpenState (state, isOpened) {
method setOrdering (line 546) | setOrdering (state, data) {
method setSyncDate (line 550) | setSyncDate (state, date) {
method setWindowState (line 555) | setWindowState (state, newState) {
method setAppLanguage (line 558) | setAppLanguage (state, language) {
method setAppLanguageType (line 561) | setAppLanguageType (state, type) {
method setWysiwygTranslation (line 564) | setWysiwygTranslation (state, translations) {
method setAppUIZoomLevel (line 567) | setAppUIZoomLevel (state, zoomLevel) {
method setAppNotificationsStatus (line 570) | setAppNotificationsStatus (state, enabled) {
method setNotificationsReadStatus (line 573) | setNotificationsReadStatus (state, status) {
method updateCurrentSiteItem (line 576) | updateCurrentSiteItem(state, { itemType, itemID, field, value, type, sub...
function findMenuItemByID (line 622) | function findMenuItemByID (items, menuItemID) {
function findMenuItemByIDwithParent (line 638) | function findMenuItemByIDwithParent (items, menuItemID, parentItemID = 0) {
function insertSubmenuItem (line 657) | function insertSubmenuItem (menuItems, menuItem, parentItemID) {
function insertMenuItem (line 672) | function insertMenuItem (menuItems, menuItem, parentItemID) {
function editMenuItemByID (line 692) | function editMenuItemByID (item, editedMenuItem) {
function deleteMenuItemByID (line 709) | function deleteMenuItemByID (item, id) {
function updateMenuItemIDs (line 719) | function updateMenuItemIDs (item, newID) {
function hideMenuItemByID (line 731) | function hideMenuItemByID (item, itemID) {
function showMenuItemByID (line 741) | function showMenuItemByID (item, itemID) {
FILE: gulpfile.js
function updateBuildNumber (line 37) | function updateBuildNumber (cb) {
FILE: internal-tools/loc.js
function countLines (line 65) | function countLines (filePath) {
Condensed preview — 777 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (6,895K chars).
[
{
"path": ".editorconfig",
"chars": 198,
"preview": "# top-most EditorConfig file\nroot = true\n\n# Unix-style newlines with a newline ending every file\n[*]\nend_of_line = lf\nin"
},
{
"path": ".github/DISCUSSION_TEMPLATE/bug-report.yml",
"chars": 2029,
"preview": "title: \"[Bug report] \"\nlabels: [\"Thank you for reporting a bug!\"]\nbody:\n - type: markdown\n attributes:\n value: "
},
{
"path": ".github/FUNDING.yml",
"chars": 127,
"preview": "# These are supported funding model platforms\n\ngithub: GetPublii\nopen_collective: publii\ncustom: https://getpublii.com/d"
},
{
"path": ".github/ISSUE_TEMPLATE/bug.yml",
"chars": 1967,
"preview": "name: Bug\ndescription: File a bug report\ntitle: \"[Bug]: \"\nbody:\n - type: markdown\n attributes:\n value: |\n "
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 482,
"preview": "blank_issues_enabled: true\ncontact_links:\n - name: Check the docs\n url: https://getpublii.com/docs/\n about: 'This"
},
{
"path": ".github/ISSUE_TEMPLATE/feature.yml",
"chars": 418,
"preview": "name: Feature Request\ndescription: Propose a new feature for Publii\ntitle: \"[Feature Request]: \"\nlabels: [feature reques"
},
{
"path": ".gitignore",
"chars": 673,
"preview": "*~\n.idea\n.DS_Store\n.coveralls.yml\nnpm-debug.log\n/node_modules/\n/app/node_modules/\n/coverage\n/app/dist/css\n/app/dist/vend"
},
{
"path": ".nvmrc",
"chars": 9,
"preview": "v22.18.0\n"
},
{
"path": "LICENSE",
"chars": 35147,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
},
{
"path": "README.md",
"chars": 5139,
"preview": "# Publii - Static CMS for privacy-focused, SEO-optimized websites.\n\n[;\n\ncontextBridge.exposeInMainWorld('mainProcessAPI',"
},
{
"path": "app/back-end/app.js",
"chars": 28555,
"preview": "/*\n * Main Application class\n */\n\n// Necessary packages\nconst fs = require('fs-extra');\nconst os = require('os');\nconst "
},
{
"path": "app/back-end/author.js",
"chars": 13877,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst Model = require('./model.js');\nconst Authors = requi"
},
{
"path": "app/back-end/authors.js",
"chars": 691,
"preview": "/*\n * Authors instance\n */\n\nconst Model = require('./model.js');\n\nclass Authors extends Model {\n /**\n * Authors c"
},
{
"path": "app/back-end/builddata.json",
"chars": 44,
"preview": "{\n \"version\": \"0.47.5\",\n \"build\": 17411\n}\n"
},
{
"path": "app/back-end/events/_modules.js",
"chars": 968,
"preview": "/*\n * Module which loads all Event classes\n */\nmodule.exports = {\n AppEvents: require('./app.js'),\n ContentEvents:"
},
{
"path": "app/back-end/events/app.js",
"chars": 17818,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst FileHelper = require('../helpers/file.js');\nconst ip"
},
{
"path": "app/back-end/events/author.js",
"chars": 1273,
"preview": "const ipcMain = require('electron').ipcMain;\nconst Author = require('../author.js');\n\n/*\n * Events for the IPC communica"
},
{
"path": "app/back-end/events/authors.js",
"chars": 679,
"preview": "const ipcMain = require('electron').ipcMain;\nconst Posts = require('../posts.js');\nconst Authors = require('../authors.j"
},
{
"path": "app/back-end/events/backup.js",
"chars": 4739,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst ipcMain = require('electron').ipcMain;\nconst Backup "
},
{
"path": "app/back-end/events/content.js",
"chars": 651,
"preview": "const ipcMain = require('electron').ipcMain;\nconst Model = require('../model.js');\n\n/*\n * Events for the IPC communicati"
},
{
"path": "app/back-end/events/credits.js",
"chars": 825,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst ipcMain = require('electron').ipcMain;\nconst FileHel"
},
{
"path": "app/back-end/events/deploy.js",
"chars": 7012,
"preview": "const fs = require('fs-extra');\nconst ipcMain = require('electron').ipcMain;\nconst Deployment = require('../modules/depl"
},
{
"path": "app/back-end/events/file-manager.js",
"chars": 8557,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst ipcMain = require('electron').ipcMain;\nconst isBinar"
},
{
"path": "app/back-end/events/image-uploader.js",
"chars": 1827,
"preview": "const fs = require('fs');\nconst path = require('path');\nconst ipcMain = require('electron').ipcMain;\nconst Image = requi"
},
{
"path": "app/back-end/events/import.js",
"chars": 2889,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst ipcMain = require('electron').ipcMain;\nconst Import "
},
{
"path": "app/back-end/events/menu.js",
"chars": 847,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst ipcMain = require('electron').ipcMain;\n\n/*\n * Events"
},
{
"path": "app/back-end/events/notifications.js",
"chars": 1631,
"preview": "const ipcMain = require('electron').ipcMain;\nconst path = require('path');\nconst UpdatesHelper = require('../helpers/upd"
},
{
"path": "app/back-end/events/page.js",
"chars": 5216,
"preview": "const fs = require('fs');\nconst path = require('path');\nconst FileHelper = require('../helpers/file.js');\nconst ipcMain "
},
{
"path": "app/back-end/events/plugin.js",
"chars": 2670,
"preview": "const ipcMain = require('electron').ipcMain;\nconst Plugins = require('../plugins.js');\n\n/*\n * Events for the IPC communi"
},
{
"path": "app/back-end/events/plugins-api.js",
"chars": 5687,
"preview": "const ipcMain = require('electron').ipcMain;\nconst fs = require('fs');\nconst path = require('path');\nconst FileHelper = "
},
{
"path": "app/back-end/events/post.js",
"chars": 2448,
"preview": "const ipcMain = require('electron').ipcMain;\nconst Post = require('../post.js');\n\n/*\n * Events for the IPC communication"
},
{
"path": "app/back-end/events/preview.js",
"chars": 6052,
"preview": "const fs = require('fs');\nconst path = require('path');\nconst electron = require('electron');\nconst shell = electron.she"
},
{
"path": "app/back-end/events/site.js",
"chars": 26043,
"preview": "const fs = require('fs-extra');\nconst os = require('os');\nconst path = require('path');\nconst FileHelper = require('../h"
},
{
"path": "app/back-end/events/sync.js",
"chars": 1163,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst FileHelper = require('../helpers/file.js');\nconst ip"
},
{
"path": "app/back-end/events/tag.js",
"chars": 1700,
"preview": "const ipcMain = require('electron').ipcMain;\nconst Tag = require('../tag.js');\n\n/*\n * Events for the IPC communication r"
},
{
"path": "app/back-end/events/tags.js",
"chars": 646,
"preview": "const ipcMain = require('electron').ipcMain;\nconst Posts = require('../posts.js');\nconst Tags = require('../tags.js');\n\n"
},
{
"path": "app/back-end/helpers/app-files.js",
"chars": 3596,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst Utils = require('./utils.js');\n\n/**\n * Helper class "
},
{
"path": "app/back-end/helpers/avatar.js",
"chars": 1978,
"preview": "const sizeOf = require('image-size');\n\nclass AvatarHelper {\n /*\n * Check if the provided path is a local avatar f"
},
{
"path": "app/back-end/helpers/context-menu-builder.js",
"chars": 3359,
"preview": "const electron = require('electron');\nconst shell = electron.shell;\nconst Menu = electron.Menu;\nconst MenuItem = electro"
},
{
"path": "app/back-end/helpers/db.utils.js",
"chars": 2250,
"preview": "const os = require('os');\n\n/*\n * Other helper functions\n */\nclass DBUtils {\n constructor (dbInstance) {\n this."
},
{
"path": "app/back-end/helpers/file.js",
"chars": 735,
"preview": "const fs = require('fs');\n\n/**\n * FileHelper wraps fs.readFileSync to avoid leaking file descriptors.\n */\nclass FileHelp"
},
{
"path": "app/back-end/helpers/image.helper.js",
"chars": 5221,
"preview": "/*\n * Image helper for posts\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\nconst normalizePath = re"
},
{
"path": "app/back-end/helpers/slug.js",
"chars": 2959,
"preview": "const transliterate = require('transliteration').transliterate;\nconst slug = require('slug');\n\n/*\n * Custom mode of rfc3"
},
{
"path": "app/back-end/helpers/specs/avatar.spec.js",
"chars": 1821,
"preview": "const assert = require('assert');\nconst path = require('path');\nconst avatarHelper = require('../avatar.js');\n\ndescribe("
},
{
"path": "app/back-end/helpers/specs/slug.spec.js",
"chars": 3513,
"preview": "const assert = require('assert');\nconst slug = require('../slug.js');\n\ndescribe('Slug creation', function() {\n it('sh"
},
{
"path": "app/back-end/helpers/updates.helper.js",
"chars": 1884,
"preview": "const fs = require('fs');\nconst FileHelper = require('./file.js');\nconst https = require('https');\n\nclass UpdatesHelper "
},
{
"path": "app/back-end/helpers/utils.js",
"chars": 9813,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst FileHelper = require('./file.js');\nconst normalizePa"
},
{
"path": "app/back-end/helpers/validators/language-config.js",
"chars": 886,
"preview": "const FileHelper = require('../file.js');\n\n/**\n * Checks if language config file meets the requirements\n *\n * @param con"
},
{
"path": "app/back-end/helpers/validators/plugin-config.js",
"chars": 984,
"preview": "const FileHelper = require('../file.js');\n\n/**\n * Checks if plugin config file meets the requirements\n *\n * @param confi"
},
{
"path": "app/back-end/image.js",
"chars": 24523,
"preview": "/*\n * Image instance\n */\n\nconst FileHelper = require('./helpers/file.js');\nconst fs = require('fs-extra');\nconst os = re"
},
{
"path": "app/back-end/languages.js",
"chars": 5858,
"preview": "/*\n * Languages instance\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\nconst FileHelper = require('"
},
{
"path": "app/back-end/migrators/site-config.js",
"chars": 2126,
"preview": "const fs = require('fs');\nconst path = require('path');\nconst os = require('os');\nconst slug = require('./../helpers/slu"
},
{
"path": "app/back-end/model.js",
"chars": 5448,
"preview": "/*\n * Model base class\n */\n\nconst fs = require('fs');\nconst path = require('path');\n\nclass Model {\n /**\n * Model "
},
{
"path": "app/back-end/modules/backup/backup.js",
"chars": 12135,
"preview": "/*\n * Class used to create backups\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\nconst FileHelper ="
},
{
"path": "app/back-end/modules/backup/create-from-backup.js",
"chars": 4217,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst FileHelper = require('./../../helpers/file.js');\ncon"
},
{
"path": "app/back-end/modules/custom-changes/ftp/LICENSE",
"chars": 1067,
"preview": "Copyright Brian White. All rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
},
{
"path": "app/back-end/modules/custom-changes/ftp/README.md",
"chars": 9513,
"preview": "Description\n===========\n\nnode-ftp is an FTP client module for [node.js](http://nodejs.org/) that provides an asynchronou"
},
{
"path": "app/back-end/modules/custom-changes/ftp/TODO",
"chars": 127,
"preview": " - Add support for some SITE commands such as CHMOD, CHGRP, and QUOTA\n - Active (non-passive) data connections\n - IPv6 s"
},
{
"path": "app/back-end/modules/custom-changes/ftp/lib/connection.js",
"chars": 29826,
"preview": "var fs = require('fs'),\n tls = require('tls'),\n zlib = require('zlib'),\n Socket = require('net').Socket,\n Ev"
},
{
"path": "app/back-end/modules/custom-changes/ftp/lib/parser.js",
"chars": 7608,
"preview": "var WritableStream = require('stream').Writable\n || require('readable-stream').Writable,\n inherit"
},
{
"path": "app/back-end/modules/custom-changes/ftp/package.json",
"chars": 2121,
"preview": "{\n \"_args\": [\n [\n {\n \"raw\": \"ftp@^0.3.10\",\n \"scope\": null,\n \"escapedName\": \"ftp\",\n "
},
{
"path": "app/back-end/modules/deploy/deployment.js",
"chars": 19075,
"preview": "// Necessary packages\nconst fs = require('fs-extra');\nconst path = require('path');\nconst FileHelper = require('./../../"
},
{
"path": "app/back-end/modules/deploy/ftp-alt.js",
"chars": 14019,
"preview": "/*\n * Class used to upload files to the FTP(S) server\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');"
},
{
"path": "app/back-end/modules/deploy/ftp.js",
"chars": 19246,
"preview": "/*\n * Class used to upload files to the FTP(S) server\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');"
},
{
"path": "app/back-end/modules/deploy/git.js",
"chars": 13097,
"preview": "/*\n * Class used to upload files to the Github Pages\n */\n\nconst fs = require('fs-extra');\nconst gitClient = require('iso"
},
{
"path": "app/back-end/modules/deploy/github-pages.js",
"chars": 23603,
"preview": "/*\n * Class used to upload files to the Github Pages\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\n"
},
{
"path": "app/back-end/modules/deploy/gitlab-pages.js",
"chars": 20029,
"preview": "/*\n * Class used to upload files to the Github Pages\n */\n\nconst path = require('path');\nconst FileHelper = require('./.."
},
{
"path": "app/back-end/modules/deploy/google-cloud.js",
"chars": 10197,
"preview": "/*\n * Class used to upload files to the FTP(S) server\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');"
},
{
"path": "app/back-end/modules/deploy/libraries/netlify-api.js",
"chars": 7736,
"preview": "const fs = require('fs');\nconst path = require('path');\nconst util = require('util');\nconst crypto = require('crypto');\n"
},
{
"path": "app/back-end/modules/deploy/manual.js",
"chars": 6285,
"preview": "/*\n * Manual deployment class\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\nconst slug = require('."
},
{
"path": "app/back-end/modules/deploy/netlify.js",
"chars": 6022,
"preview": "/*\n * Class used to upload files to the Netlify\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\nconst"
},
{
"path": "app/back-end/modules/deploy/s3.js",
"chars": 15421,
"preview": "/*\n * Class used to upload files to the S3 bucket\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\ncon"
},
{
"path": "app/back-end/modules/deploy/sftp.js",
"chars": 16881,
"preview": "/*\n * Class used to upload files to the SFTP server\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\nc"
},
{
"path": "app/back-end/modules/import/automatic-paragraphs.js",
"chars": 2273,
"preview": "function automaticParagraphs (inputText) {\n let rules = [\n [/<br \\/>/gmi, '<br>'],\n [/<object[\\s\\S]+?<\\"
},
{
"path": "app/back-end/modules/import/import.js",
"chars": 2839,
"preview": "/*\n * Class used to import data from WP to Publii using WXR file\n */\n\nconst fs = require('fs-extra');\nconst path = requi"
},
{
"path": "app/back-end/modules/import/wxr-parser.js",
"chars": 26126,
"preview": "const fs = require('fs');\nconst url = require('url');\nconst path = require('path');\nconst FileHelper = require('./../../"
},
{
"path": "app/back-end/modules/plugins/plugins-api.js",
"chars": 1912,
"preview": "class PluginsAPI {\n constructor () {\n this.events = {\n app: {},\n site: {}\n };\n "
},
{
"path": "app/back-end/modules/plugins/plugins-helpers.js",
"chars": 1971,
"preview": "const path = require('path');\nconst FileHelper = require('./../../helpers/file.js');\n\nclass PluginsHelpers {\n // Retu"
},
{
"path": "app/back-end/modules/render-html/contexts/404.js",
"chars": 3494,
"preview": "// Necessary packages\nconst RendererContext = require('../renderer-context.js');\n\n/**\n * Class used create context\n * fo"
},
{
"path": "app/back-end/modules/render-html/contexts/author.js",
"chars": 7440,
"preview": "// Necessary packages\nconst RendererContext = require('../renderer-context');\nconst slug = require('./../../../helpers/s"
},
{
"path": "app/back-end/modules/render-html/contexts/feed.js",
"chars": 6543,
"preview": "// Necessary packages\nconst RendererContext = require('../renderer-context.js');\nconst URLHelper = require('./../helpers"
},
{
"path": "app/back-end/modules/render-html/contexts/home.js",
"chars": 6595,
"preview": "// Necessary packages\nconst RendererContext = require('../renderer-context.js');\nconst RendererHelpers = require('./../h"
},
{
"path": "app/back-end/modules/render-html/contexts/page-preview.js",
"chars": 15495,
"preview": "// Necessary packages\nconst fs = require('fs');\nconst path = require('path');\nconst sizeOf = require('image-size');\ncons"
},
{
"path": "app/back-end/modules/render-html/contexts/page.js",
"chars": 5776,
"preview": "// Necessary packages\nconst RendererContext = require('../renderer-context.js');\nconst stripTags = require('striptags');"
},
{
"path": "app/back-end/modules/render-html/contexts/post-preview.js",
"chars": 23028,
"preview": "// Necessary packages\nconst fs = require('fs');\nconst path = require('path');\nconst sizeOf = require('image-size');\ncons"
},
{
"path": "app/back-end/modules/render-html/contexts/post.js",
"chars": 16470,
"preview": "// Necessary packages\nconst RendererContext = require('../renderer-context.js');\nconst RendererHelpers = require('./../h"
},
{
"path": "app/back-end/modules/render-html/contexts/search.js",
"chars": 3503,
"preview": "// Necessary packages\nconst RendererContext = require('../renderer-context.js');\n\n/**\n * Class used create context\n * fo"
},
{
"path": "app/back-end/modules/render-html/contexts/tag.js",
"chars": 7430,
"preview": "// Necessary packages\nconst RendererContext = require('../renderer-context.js');\nconst RendererHelpers = require('./../h"
},
{
"path": "app/back-end/modules/render-html/contexts/tags.js",
"chars": 3355,
"preview": "// Necessary packages\nconst RendererContext = require('../renderer-context.js');\n\n/**\n * Class used create context\n * fo"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/_modules.js",
"chars": 2748,
"preview": "/*\n * Module which loads all Handlebar's helpers\n */\nmodule.exports = {\n assetHelper: require('./asset.js').assetHelp"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/asset.js",
"chars": 731,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper function for generating asset URL based on a given path\n *\n * @"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/canonical-link.js",
"chars": 1989,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper for creating canonical link\n *\n * {{canonicalLink}}\n *\n * @retu"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/check-if-all.js",
"chars": 609,
"preview": "/**\n * Helper for creating conditions where all\n * elements are connected using AND operator\n *\n * {{#checkIfAll value1 "
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/check-if-any.js",
"chars": 559,
"preview": "/**\n * Helper for creating conditions where all\n * elements are connected using OR operator\n *\n * {{#checkIfAny value1 v"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/check-if-none.js",
"chars": 586,
"preview": "/**\n * Helper for creating conditions where all\n * elements are connected using AND operator\n * and are all false\n *\n * "
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/check-if.js",
"chars": 2525,
"preview": "/**\n * Helper for creating conditions\n *\n * {{#checkIf author '&&' avatar}}\n * ...\n * {{/checkIf}}\n *\n * Available op"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/concatenate.js",
"chars": 294,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper for concatenating values\n *\n * {{concatenate 'abc' 3 'def'}}\n *"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/contains.js",
"chars": 657,
"preview": "/**\n * Helper for checking if a specifc value is inside comma-separated string\n *\n * {{#contains 'abc' 'abc,def'}}\n *\n *"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/css.js",
"chars": 2160,
"preview": "const fs = require('fs');\nconst FileHelper = require('./../../../../helpers/file.js');\nconst crypto = require('crypto');"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/date.js",
"chars": 1562,
"preview": "const Handlebars = require('handlebars');\nconst moment = require('moment');\n\n/**\n * Helper for creating customized date "
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/encode-url-fragment.js",
"chars": 374,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper for creating encoded output inside URLs\n *\n * {{encodeUrlFragme"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/encode-url.js",
"chars": 455,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper for creating encoded output of URLs\n *\n * Useful for the social"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/feed-link.js",
"chars": 1796,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper for creating link element with feed URL (for RSS and JSON)\n *\n "
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/font.js",
"chars": 800,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper function for generating Google Fonts API URL based on a given f"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/gdpr-script-blocker.js",
"chars": 658,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper for creating proper script type value according to the\n *\n * {{"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-author.js",
"chars": 1086,
"preview": "/**\n * Helper for loading author data\n *\n * {{#getAuthor AUTHOR_ID}}\n * <p>{{ name }}</p>\n * {{/getAuthor}}\n * \n * {{"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-authors.js",
"chars": 1349,
"preview": "/**\n * Helper for loading authors data\n *\n * {{#getAuthors \"AUTHOR_ID_1,AUTHOR_ID_2,AUTHOR_ID_N\" \"prefix\" \"suffix\"}}\n * "
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-page.js",
"chars": 763,
"preview": "/**\n * Helper for loading page data\n *\n * {{#getPage PAGE_ID}}\n * <h2>{{ title }}</h2>\n * <div>{{{ excerpt }}}</di"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-pages-by-custom-field.js",
"chars": 8332,
"preview": "/**\n * Helper for loading pages data which contains a specific custom fields\n * \n * QueryString options:\n * * count - ho"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-pages.js",
"chars": 1364,
"preview": "/**\n * Helper for loading posts data\n *\n * {{#getPages \"PAGE_ID_1,PAGE_ID_2,PAGE_ID_N\" \"prefix\" \"suffix\"}}\n * <article>\n"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-post-by-tags.js",
"chars": 2472,
"preview": "/**\n * Helper for loading single post data which contains a specific tag(s) - specified by tag ID or tag slugs separated"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-post.js",
"chars": 763,
"preview": "/**\n * Helper for loading post data\n *\n * {{#getPost POST_ID}}\n * <h2>{{ title }}</h2>\n * <div>{{{ excerpt }}}</di"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-posts-by-custom-field.js",
"chars": 10071,
"preview": "/**\n * Helper for loading posts data which contains a specific custom fields\n * \n * QueryString options:\n * * count - ho"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-posts-by-tags.js",
"chars": 11449,
"preview": "/**\n * Helper for loading posts data which contains a specific tag(s) - specified by tag ID or tag slugs separated by co"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-posts.js",
"chars": 1363,
"preview": "/**\n * Helper for loading posts data\n *\n * {{#getPosts \"POST_ID_1,POST_ID_2,POST_ID_N\" \"prefix\" \"suffix\"}}\n * <article>\n"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-tag.js",
"chars": 999,
"preview": "/**\n * Helper for loading tag data\n *\n * {{#getTag TAG_ID}}\n * <p>{{ name }}</p>\n * {{/getTag}}\n * \n * {{#getTag \"TAG"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/get-tags.js",
"chars": 1282,
"preview": "/**\n * Helper for loading tags data\n *\n * {{#getTags \"TAG_ID_1,TAG_ID_2,TAG_ID_N\" \"prefix\" \"suffix\"}}\n * <li>{{ name }}<"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/image-dimensions.js",
"chars": 1303,
"preview": "const Handlebars = require('handlebars');\nconst sizeOf = require('image-size');\nconst path = require('path');\nconst norm"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/is-current-page.js",
"chars": 375,
"preview": "/**\n * Helper for checking if a given page number is a current page\n *\n * Useful in pagination\n *\n * {{#isCurrentPage @p"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/is-empty.js",
"chars": 323,
"preview": "/**\n * Helper for checking if collection is empty\n *\n * {{#isEmpty value}}\n * ...\n * {{/isEmpty}}\n *\n * @returns {cal"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/is-not-empty.js",
"chars": 342,
"preview": "/**\n * Helper for checking if collection is not empty\n *\n * {{#isNotEmpty value}}\n * ...\n * {{/isNotEmpty}}\n *\n * @re"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/is-not.js",
"chars": 805,
"preview": "/**\n * Helper for detecting contexts - opposite to #is helper\n *\n * {{#isNot 'index'}}\n *\n * {{#isNot 'tag,post'}}\n *\n *"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/is.js",
"chars": 766,
"preview": "/**\n * Helper for detecting contexts\n *\n * {{#is 'index'}}\n *\n * {{#is 'tag,post'}}\n *\n * Available phrases: index, blog"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/join.js",
"chars": 342,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper for concatenating values with a specific separator\n *\n * {{join"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/js.js",
"chars": 2158,
"preview": "const fs = require('fs');\nconst FileHelper = require('./../../../../helpers/file.js');\nconst crypto = require('crypto');"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/json-ld.js",
"chars": 8509,
"preview": "const Handlebars = require('handlebars');\nconst moment = require('moment');\nconst sizeOf = require('image-size');\nconst "
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/jsonify.js",
"chars": 232,
"preview": "/**\n * Helper for creating JSON-safe strings\n *\n * {{{jsonify string|object}}}\n *\n * @returns {string} string prepared f"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/lazyload.js",
"chars": 607,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper for creating loading attributes\n *\n * {{ lazyload eager }}\n *\n "
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/math.js",
"chars": 455,
"preview": "/**\n * Helper for doing a simple math operations\n *\n * {{math @index '+' 1}}\n *\n * {{math @index '-' 1}}\n *\n * Available"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/menu-item-classes.js",
"chars": 4658,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helpers for creating CSS classes in menu\n *\n * {{menuItemClasses}}\n * "
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/menu-url.js",
"chars": 8405,
"preview": "const Handlebars = require('handlebars');\nconst slug = require('./../../../../helpers/slug');\n\n/**\n * Helper for creatin"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/meta-description.js",
"chars": 609,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper for generating meta_description\n *\n * {{metaDescription}}\n *\n *"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/meta-robots.js",
"chars": 1586,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper for generating meta_robots\n *\n * {{metaRobots}}\n *\n * @returns "
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/not-contains.js",
"chars": 672,
"preview": "/**\n * Helper for checking if a specifc value is not inside comma-separated string\n *\n * {{#notContains 'abc' 'abc,def'}"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/orderby.js",
"chars": 1082,
"preview": "/**\n * Helper used to order collection\n *\n * @param collection\n * @param field\n * @param direction\n * @param langForLoca"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/page-url.js",
"chars": 1476,
"preview": "/**\n * Helper for creating pagination URL\n *\n * {{pageUrl @pagination.context NUMBER}}\n *\n * @returns {string} URL for t"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/publii-footer.js",
"chars": 975,
"preview": "const Handlebars = require('handlebars');\nconst Gdpr = require('./../../helpers/gdpr.js');\n\n/**\n * Helper for creating a"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/publii-head.js",
"chars": 3596,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper for creating additional useful tags\n *\n * {{publiiHead}}\n *\n * "
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/responsive-image-attributes.js",
"chars": 2204,
"preview": "const Handlebars = require('handlebars');\nconst responsiveSrcSet = require('./responsive-srcset.js');\nconst responsiveSi"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/responsive-sizes.js",
"chars": 1376,
"preview": "const Handlebars = require('handlebars');\nconst UtilsHelper = require('./../../../../helpers/utils.js');\n\n/**\n * Helper "
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/responsive-srcset.js",
"chars": 2820,
"preview": "const Handlebars = require('handlebars');\nconst path = require('path');\nconst normalizePath = require('normalize-path');"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/reverse.js",
"chars": 157,
"preview": "/**\n * Helper used to reverse collection\n *\n * @param collection\n */\n\nfunction reverse (collection) {\n collection.rev"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/social-meta-tags.js",
"chars": 7414,
"preview": "const stripTags = require('striptags');\nconst sizeOf = require('image-size');\nconst path = require('path');\nconst normal"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/specs/check-if-all.spec.js",
"chars": 2350,
"preview": "const assert = require('assert');\nconst checkIfAll = require('../check-if-all.js');\n\ndescribe('Handlebars - checkIfAll b"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/specs/check-if-any.spec.js",
"chars": 2337,
"preview": "const assert = require('assert');\nconst checkIfAny = require('../check-if-any.js');\n\ndescribe('Handlebars - checkIfAny b"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/specs/check-if-none.spec.js",
"chars": 2359,
"preview": "const assert = require('assert');\nconst checkIfNone = require('../check-if-none.js');\n\ndescribe('Handlebars - checkIfNon"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/specs/check-if.spec.js",
"chars": 8498,
"preview": "const assert = require('assert');\nconst checkIf = require('../check-if.js');\n\ndescribe('Handlebars - checkIf block helpe"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/specs/feed-link.spec.js",
"chars": 2624,
"preview": "const assert = require('assert');\nconst Handlebars = require('handlebars');\nconst feedLink = require('../feed-link.js')."
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/specs/font.spec.js",
"chars": 496,
"preview": "const assert = require('assert');\nconst Handlebars = require('handlebars');\nconst font = require('../font.js');\n\ndescrib"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/specs/is-empty.spec.js",
"chars": 791,
"preview": "const assert = require('assert');\nconst isEmpty = require('../is-empty.js');\n\ndescribe('Handlebars - isEmpty block helpe"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/specs/is-not-empty.spec.js",
"chars": 813,
"preview": "const assert = require('assert');\nconst isNotEmpty = require('../is-not-empty.js');\n\ndescribe('Handlebars - isNotEmpty b"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/specs/jsonify.spec.js",
"chars": 650,
"preview": "const assert = require('assert');\nconst Handlebars = require('handlebars');\nconst jsonify = require('../jsonify.js');\n\nd"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/specs/translate.spec.js",
"chars": 8289,
"preview": "const assert = require('assert');\nconst Handlebars = require('handlebars');\nconst translate = require('../translate.js')"
},
{
"path": "app/back-end/modules/render-html/handlebars/helpers/translate.js",
"chars": 3300,
"preview": "const Handlebars = require('handlebars');\n\n/**\n * Helper functin used for creating translatable phrases\n *\n * {{ transla"
},
{
"path": "app/back-end/modules/render-html/helpers/content.js",
"chars": 30260,
"preview": "/*\n * Class used to help with operations on\n * the URLs and slugs\n */\n\nconst slug = require('./../../../helpers/slug');\n"
},
{
"path": "app/back-end/modules/render-html/helpers/deleteEmpty.js",
"chars": 1093,
"preview": "const fs = require('fs');\nconst path = require('path');\nconst systemFiles = [\n '.DS_Store', \n 'desktop.ini', \n "
},
{
"path": "app/back-end/modules/render-html/helpers/diffCopy.js",
"chars": 4946,
"preview": "const fs = require('fs-extra');\nconst list = require('ls-all');\nconst path = require('path');\n\nclass DiffCopy {\n stat"
},
{
"path": "app/back-end/modules/render-html/helpers/files.js",
"chars": 9413,
"preview": "const fs = require('fs-extra');\nconst list = require('ls-all');\nconst path = require('path');\nconst { deleteEmpty } = re"
},
{
"path": "app/back-end/modules/render-html/helpers/gdpr.js",
"chars": 8587,
"preview": "const FileHelper = require('./../../../helpers/file.js');\nclass Gdpr {\n static popupHtmlOutput (configuration, render"
},
{
"path": "app/back-end/modules/render-html/helpers/helpers.js",
"chars": 487,
"preview": "/**\n * Class used to manage common operations in the renderer\n */\n\nclass RendererHelpers {\n static getRendererOptionV"
},
{
"path": "app/back-end/modules/render-html/helpers/sitemap.js",
"chars": 29877,
"preview": "/*\n * Note for the future: for big websites most probably the better solution\n * would be replace reading post files in "
},
{
"path": "app/back-end/modules/render-html/helpers/specs/url.spec.js",
"chars": 7140,
"preview": "const assert = require('assert');\nconst URLHelper = require('../url.js');\n\ndescribe('URL helper', function() {\n descr"
},
{
"path": "app/back-end/modules/render-html/helpers/template.js",
"chars": 15648,
"preview": "// Necessary packages\nconst fs = require('fs-extra');\nconst path = require('path');\nconst FileHelper = require('./../../"
},
{
"path": "app/back-end/modules/render-html/helpers/url.js",
"chars": 7671,
"preview": "/*\n * Class used to help with operations on\n * the URLs and slugs\n */\n\nconst slug = require('./../../../helpers/slug');\n"
},
{
"path": "app/back-end/modules/render-html/helpers/view-settings.js",
"chars": 5667,
"preview": "class ViewSettings {\n static override(viewSettings, defaultViewConfig, itemData, rendererInstance) {\n let outp"
},
{
"path": "app/back-end/modules/render-html/items/author.js",
"chars": 5115,
"preview": "const path = require('path');\nconst normalizePath = require('normalize-path');\nconst AvatarHelper = require('./../../../"
},
{
"path": "app/back-end/modules/render-html/items/featured-image.js",
"chars": 5413,
"preview": "const path = require('path');\nconst sizeOf = require('image-size');\nconst URLHelper = require('./../helpers/url');\nconst"
},
{
"path": "app/back-end/modules/render-html/items/page.js",
"chars": 6465,
"preview": "const path = require('path');\nconst ContentHelper = require('./../helpers/content');\n\n/**\n * Page item for the renderer\n"
},
{
"path": "app/back-end/modules/render-html/items/post.js",
"chars": 7935,
"preview": "const path = require('path');\nconst ContentHelper = require('./../helpers/content');\n\n/**\n * Post item for the renderer\n"
},
{
"path": "app/back-end/modules/render-html/items/tag.js",
"chars": 2850,
"preview": "const URLHelper = require('./../helpers/url');\n\n/**\n * Tag item for the renderer\n */\nclass TagItem {\n /**\n * Cons"
},
{
"path": "app/back-end/modules/render-html/renderer-cache.js",
"chars": 21267,
"preview": "const fs = require('fs');\nconst path = require('path');\nconst FileHelper = require('./../../helpers/file.js');\nconst Pag"
},
{
"path": "app/back-end/modules/render-html/renderer-context.js",
"chars": 32982,
"preview": "// Necessary packages\nconst path = require('path');\nconst FileHelper = require('./../../helpers/file.js');\nconst slug = "
},
{
"path": "app/back-end/modules/render-html/renderer-plugins.js",
"chars": 7033,
"preview": "const fs = require('fs');\nconst path = require('path');\nconst FileHelper = require('./../../helpers/file.js');\n\nclass Re"
},
{
"path": "app/back-end/modules/render-html/renderer.js",
"chars": 90983,
"preview": "// Necessary packages\nconst fs = require('fs-extra');\nconst FileHelper = require('./../../helpers/file.js');\nconst listA"
},
{
"path": "app/back-end/modules/render-html/text-renderers/blockeditor.js",
"chars": 714,
"preview": "const blocksMapping = require('./../../../../src/components/block-editor/blocks-mapping.js');\n\nclass BlocksToHtml {\n "
},
{
"path": "app/back-end/modules/render-html/text-renderers/markdown.js",
"chars": 2214,
"preview": "const marked = require('marked');\n\nclass MarkdownToHtml {\n static parse (inputText) {\n // Added support for im"
},
{
"path": "app/back-end/modules/render-html/validators/theme-config.js",
"chars": 787,
"preview": "const FileHelper = require('./../../../helpers/file.js');\n\n/**\n * Checks if theme config file meets the requirements\n *\n"
},
{
"path": "app/back-end/page.js",
"chars": 23672,
"preview": "/*\n * Page instance\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\nconst slug = require('./helpers/s"
},
{
"path": "app/back-end/pages.js",
"chars": 1604,
"preview": "/*\n * Pages instance\n */\n\nconst Model = require('./model.js');\n\nclass Pages extends Model {\n constructor(appInstance,"
},
{
"path": "app/back-end/plugins.js",
"chars": 10476,
"preview": "/*\n * Plugins instance\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\nconst FileHelper = require('./"
},
{
"path": "app/back-end/post.js",
"chars": 27659,
"preview": "/*\n * Post instance\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\nconst slug = require('./helpers/s"
},
{
"path": "app/back-end/posts.js",
"chars": 2128,
"preview": "/*\n * Posts instance\n */\n\nconst Model = require('./model.js');\n\nclass Posts extends Model {\n constructor(appInstance,"
},
{
"path": "app/back-end/site.js",
"chars": 22604,
"preview": "/*\n * Site instance\n */\n\nconst fs = require('fs-extra');\nconst os = require('os');\nconst path = require('path');\nconst F"
},
{
"path": "app/back-end/sites.js",
"chars": 125,
"preview": "/*\n * Class used to manage the Site class instances\n */\n\nclass Sites {\n constructor() {\n\n }\n}\n\nmodule.exports = Si"
},
{
"path": "app/back-end/sql/1.0.0.sql",
"chars": 1010,
"preview": "----\n-- Basic SQL dump\n----\nBEGIN TRANSACTION;\n\nCREATE TABLE 'authors' ('id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
},
{
"path": "app/back-end/tag.js",
"chars": 12912,
"preview": "/*\n * Tag instance\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\nconst Model = require('./model.js'"
},
{
"path": "app/back-end/tags.js",
"chars": 557,
"preview": "/*\n * Tags instance\n */\n\nconst Model = require('./model.js');\n\nclass Tags extends Model {\n constructor(appInstance, t"
},
{
"path": "app/back-end/themes.js",
"chars": 23578,
"preview": "/*\n * Themes instance\n */\n\nconst fs = require('fs-extra');\nconst path = require('path');\nconst FileHelper = require('./h"
},
{
"path": "app/back-end/vendor/locutus/htmlspecialchars.js",
"chars": 2581,
"preview": "module.exports = function htmlspecialchars (string, quoteStyle, charset, doubleEncode) {\n // discuss at: http:/"
},
{
"path": "app/back-end/window-manager.js",
"chars": 365,
"preview": "class PubliiWindowManager {\n constructor () {\n this.initEvents();\n this.createMainWindow();\n }\n\n "
},
{
"path": "app/back-end/workers/backup/create.js",
"chars": 438,
"preview": "const { parentPort } = require('worker_threads');\nconst Backup = require('./../../modules/backup/backup.js');\n\nparentPor"
},
{
"path": "app/back-end/workers/backup/restore.js",
"chars": 487,
"preview": "const { parentPort } = require('worker_threads');\nconst Backup = require('./../../modules/backup/backup.js');\n\nparentPor"
},
{
"path": "app/back-end/workers/deploy/deployment.js",
"chars": 1441,
"preview": "const Deployment = require('./../../modules/deploy/deployment.js');\nlet deploymentInstance = false;\n\nprocess.on('message"
},
{
"path": "app/back-end/workers/import/check.js",
"chars": 476,
"preview": "const Import = require('./../../modules/import/import.js');\n\nprocess.on('message', function(msg){\n if(msg.type === 'd"
},
{
"path": "app/back-end/workers/import/import.js",
"chars": 570,
"preview": "const Import = require('./../../modules/import/import.js');\n\nprocess.on('message', function(msg){\n if(msg.type === 'd"
},
{
"path": "app/back-end/workers/renderer/preview.js",
"chars": 1141,
"preview": "const Renderer = require('./../../modules/render-html/renderer.js');\n\nprocess.on('message', async function(msg){\n if("
},
{
"path": "app/back-end/workers/thumbnails/post-images.js",
"chars": 2649,
"preview": "const Image = require('./../../image.js');\nconst normalizePath = require('normalize-path');\nconst sizeOf = require('imag"
},
{
"path": "app/back-end/workers/thumbnails/regenerate.js",
"chars": 5873,
"preview": "const fs = require('fs-extra');\nconst path = require('path');\nconst Image = require('./../../image.js');\nconst UtilsHelp"
},
{
"path": "app/build/config.gypi",
"chars": 2356,
"preview": "# Do not edit. File was generated by node-gyp's \"configure\" step\n{\n \"target_defaults\": {\n \"cflags\": [],\n \"default"
}
]
// ... and 577 more files (download for full content)
About this extraction
This page contains the full source code of the GetPublii/Publii GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 777 files (20.8 MB), approximately 1.7M tokens, and a symbol index with 2210 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.