parent
ec43a9e894
commit
4132e00c28
@ -0,0 +1,9 @@
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"healthCheckPath": "/",
|
||||
"httpPort": 3000,
|
||||
"addons": {
|
||||
"localstorage": {}
|
||||
},
|
||||
"manifestVersion": 2
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
\NeedsTeXFormat{LaTeX2e}
|
||||
\ProvidesPackage{awesomebox}[2019/07/27 v0.6]
|
||||
|
||||
% Awesome Box has been written by Étienne Deparis and is released under
|
||||
% the WTFPL (http://www.wtfpl.net/txt/copying/).
|
||||
% A copy of this license is distributed in this package.
|
||||
%
|
||||
% Contributors:
|
||||
% v0.2: Vincent Goulet https://github.com/vigou3
|
||||
% v0.3: Gilbert Fuerer https://github.com/foreachthing
|
||||
% * Remove xelatex/luatex requirement and add pdflatex compatibility
|
||||
% v0.4: Marcel Krüger https://github.com/zauguin
|
||||
% * Fontawesome5 compatibility
|
||||
% Gilbert Fuerer
|
||||
% * Custom vertical rule color
|
||||
% v0.5: Georger Araújo https://github.com/georgerbr
|
||||
% * Horizontal rules at top and bottom, title
|
||||
% v0.6: Vincent Goulet https://github.com/vigou3
|
||||
% * Improving table cell rendering
|
||||
|
||||
% https://ctan.org/pkg/fontawesome5
|
||||
\RequirePackage{fontawesome5}
|
||||
|
||||
% Compatibility with old version of this package
|
||||
\def\abIconCheck{\faCheck}
|
||||
\def\abIconInfoCircle{\faInfoCircle}
|
||||
\def\abIconFire{\faBomb}
|
||||
\def\abIconExclamationCircle{\faExclamationCircle}
|
||||
\def\abIconExclamationTriangle{\faExclamationTriangle}
|
||||
\def\abIconCogs{\faCogs}
|
||||
\def\abIconThumbsUp{\faThumbsUp}
|
||||
\def\abIconThumbsDown{\faThumbsDown}
|
||||
\def\abIconCertificate{\faCertificate}
|
||||
\def\abIconLightBulb{\faLightbulb[regular]}
|
||||
\def\abIconTwitter{\faTwitter}
|
||||
\def\abIconGithub{\faGithub}
|
||||
|
||||
% https://ctan.org/pkg/xcolor
|
||||
\RequirePackage{xcolor}
|
||||
% Some basic colors
|
||||
\definecolor{abnote}{RGB}{25,64,122}
|
||||
\definecolor{abcaution}{RGB}{245,0,0}
|
||||
\definecolor{abwarning}{RGB}{255,215,0}
|
||||
\definecolor{abimportant}{RGB}{220,0,0}
|
||||
\definecolor{abvrulecolor}{RGB}{221,221,216}
|
||||
|
||||
% Customizable length
|
||||
\newlength{\aweboxleftmargin}
|
||||
\newlength{\aweboxcontentwidth}
|
||||
\newlength{\aweboxvskip}
|
||||
\setlength{\aweboxvskip}{5mm}
|
||||
\newlength{\aweboxsignraise}
|
||||
\setlength{\aweboxsignraise}{-5mm}
|
||||
\newlength{\aweboxrulewidth}
|
||||
\setlength{\aweboxrulewidth}{2pt}
|
||||
|
||||
\AtBeginDocument{%
|
||||
\setlength{\aweboxleftmargin}{0.12\linewidth}%
|
||||
\setlength{\aweboxcontentwidth}{0.88\linewidth}}
|
||||
|
||||
\RequirePackage{array}
|
||||
|
||||
% To allow for more than one optional argument
|
||||
\RequirePackage{xparse}
|
||||
|
||||
% Horizontal rule definitions used with second optional argument [hrule]
|
||||
\def\abShortLine{\cline{2-2}}
|
||||
\def\abLongLine{\hline}
|
||||
|
||||
% The following commands are used to adjust and restore awesome boxes
|
||||
% content width in respect to the current environment (e.g. lists).
|
||||
\RequirePackage{ifthen}
|
||||
\newlength{\aweboxlinewidthvar}
|
||||
\setlength{\aweboxlinewidthvar}{0pt}
|
||||
\newlength{\aweboxlinewidthref}
|
||||
\AtBeginDocument{\setlength{\aweboxlinewidthref}{\linewidth}}
|
||||
\newcommand{\awesomeboxadjustcontentwidth}{%
|
||||
\ifthenelse{\lengthtest{\linewidth=\aweboxlinewidthref}}{}{%
|
||||
\setlength{\aweboxlinewidthvar}{\dimexpr\aweboxlinewidthref-\linewidth}%
|
||||
\setlength{\aweboxcontentwidth}{\dimexpr\aweboxcontentwidth-\aweboxlinewidthvar}}}%
|
||||
%\aweboxdebug}}
|
||||
\newcommand{\awesomeboxrestorecontentwidth}{%
|
||||
\ifthenelse{\lengthtest{\linewidth=\textwidth}}{}{%
|
||||
\setlength{\aweboxcontentwidth}{\dimexpr\aweboxcontentwidth+\aweboxlinewidthvar}%
|
||||
\setlength{\aweboxlinewidthvar}{0pt}}}
|
||||
|
||||
% Commands API
|
||||
% \awesomebox[vrulecolor][hrule][title]{vrulewidth}{icon}{iconcolor}{content}
|
||||
\NewDocumentCommand \awesomebox { O{abvrulecolor} O{} o m m m +m }{%
|
||||
{\vskip \aweboxvskip}\noindent\awesomeboxadjustcontentwidth%
|
||||
\begin{tabular}%
|
||||
{@{}>{\centering\arraybackslash}%
|
||||
p{\aweboxleftmargin}@{}!{\color{#1}\vrule width #4}%
|
||||
p{\dimexpr\aweboxcontentwidth-#4-\tabcolsep}@{}}
|
||||
\IfValueTF {#3}
|
||||
{ & #3 \\ #2 \raisebox{\aweboxsignraise}{\textcolor{#6}{\Huge#5}} & #7 \\ #2}
|
||||
{ #2 \raisebox{\aweboxsignraise}{\textcolor{#6}{\Huge#5}} & #7 \\ #2}
|
||||
\end{tabular}{\vskip \aweboxvskip}\awesomeboxrestorecontentwidth}
|
||||
|
||||
\newcommand{\notebox}[1]{%
|
||||
\awesomebox[abnote]{\aweboxrulewidth}{\abIconInfoCircle}{abnote}{#1}}
|
||||
|
||||
\newcommand{\tipbox}[1]{%
|
||||
\awesomebox{\aweboxrulewidth}{\abIconLightBulb}{black}{#1}}
|
||||
|
||||
\newcommand{\warningbox}[1]{%
|
||||
\awesomebox[abwarning]{\aweboxrulewidth}{\abIconExclamationTriangle}{abwarning}{#1}}
|
||||
|
||||
\newcommand{\cautionbox}[1]{%
|
||||
\awesomebox[abcaution]{\aweboxrulewidth}{\abIconFire}{abcaution}{#1}}
|
||||
|
||||
\newcommand{\importantbox}[1]{%
|
||||
\awesomebox[abimportant]{\aweboxrulewidth}{\abIconExclamationCircle}{abimportant}{#1}}
|
||||
|
||||
% Environments API
|
||||
% \begin{awesomeblock}[vrulecolor][hrule][title]{vrulewidth}{icon}{iconcolor}
|
||||
% content
|
||||
% \end{awesomeblock}
|
||||
\NewDocumentEnvironment{awesomeblock}{ O{abvrulecolor} O{} o m m m }
|
||||
{{\vskip \aweboxvskip}\noindent\awesomeboxadjustcontentwidth%
|
||||
\begin{tabular}%
|
||||
{@{}>{\centering\arraybackslash}%
|
||||
p{\aweboxleftmargin}@{}!{\color{#1}\vrule width #4}%
|
||||
p{\dimexpr\aweboxcontentwidth-#4-\tabcolsep}@{}}
|
||||
\IfValueTF {#3}
|
||||
{ & #3 \\ #2 \raisebox{\aweboxsignraise}{\textcolor{#6}{\Huge#5}} &}
|
||||
{ #2 \raisebox{\aweboxsignraise}{\textcolor{#6}{\Huge#5}} &}}
|
||||
{\\ #2 \end{tabular}{\vskip \aweboxvskip}\awesomeboxrestorecontentwidth}
|
||||
|
||||
\newenvironment{noteblock}%
|
||||
{\begin{awesomeblock}[abnote]{\aweboxrulewidth}{\abIconInfoCircle}{abnote}}
|
||||
{\end{awesomeblock}}
|
||||
|
||||
\newenvironment{tipblock}%
|
||||
{\begin{awesomeblock}{\aweboxrulewidth}{\abIconLightBulb}{black}}
|
||||
{\end{awesomeblock}}
|
||||
|
||||
\newenvironment{warningblock}%
|
||||
{\begin{awesomeblock}[abwarning]{\aweboxrulewidth}{\abIconExclamationTriangle}{abwarning}}
|
||||
{\end{awesomeblock}}
|
||||
|
||||
\newenvironment{cautionblock}%
|
||||
{\begin{awesomeblock}[abcaution]{\aweboxrulewidth}{\abIconFire}{abcaution}}
|
||||
{\end{awesomeblock}}
|
||||
|
||||
\newenvironment{importantblock}%
|
||||
{\begin{awesomeblock}[abimportant]{\aweboxrulewidth}{\abIconExclamationCircle}{abimportant}}
|
||||
{\end{awesomeblock}}
|
||||
|
||||
\newcommand{\aweboxdebug}{%
|
||||
\typeout{**************************}%
|
||||
\typeout{Line width: \the\linewidth}%
|
||||
\typeout{Reference line width: \the\aweboxlinewidthref\space(text width: \the\textwidth)}%
|
||||
\typeout{Width difference: \the\aweboxlinewidthvar}%
|
||||
\typeout{Margin width: \the\aweboxleftmargin}%
|
||||
\typeout{Content width: \the\aweboxcontentwidth}%
|
||||
\typeout{**************************}}
|
||||
|
||||
\endinput
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>Pandoc PDF Builder</h1>
|
||||
<hr>
|
||||
<p>Upload a source document in Markdown (.md) format plus any images to be included.</p>
|
||||
<p>This app will process them using Pandoc (https://pandoc.com) with a tweaked <a href="https://github.com/Wandmalfarbe/pandoc-latex-template">eisvogel template</a> and <a href="https://www.ctan.org/tex-archive/graphics/awesomebox">awesomebox.sty</a> to create a beautiful PDF, without the hassle of manual formatting in Word etc.</p>
|
||||
<p><strong>THIS IS IN ALPHA STATUS : STILL IN DEVELOPMENT.</strong></p>
|
||||
<hr>
|
||||
|
||||
<p>Click here to upload (1) a .md Markdown file (2) any included images</p>
|
||||
<form action="fileupload" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="filetoupload"><br><br>
|
||||
<input type="submit" value="Upload">
|
||||
</form>
|
||||
<br>
|
||||
<hr>
|
||||
<h3>Background</h3>
|
||||
<p>This app is a custom (i.e. not officially developed or maintained) app packaged for Cloudron.</p>
|
||||
<p>It packages an instance of the excellent document conversion utility <a href="https://pandoc.org">Pandoc</a>.</p>
|
||||
<p>Pandoc only runs from the command line. By packaging it into a web app, a consistent publishing environment can be maintained in a single location (avoiding multiple local installs which might change over time) and be accessible from any device, even without Pandoc and its utilities installed.</p>
|
||||
<p>It is based on Cloudron's tutorial-supervisor app and the "pandoc docker" app from <a href="https://github.com/vpetersson/docker-pandoc">Viktor Petersson</a>.</p>
|
||||
<p>Once the source Markdown and related images files are uploaded, click the button to process them.</p>
|
||||
<p>The app will create a PDF, which must be downloaded to the local computer, as it cannot be retrieved later.</p>
|
||||
<p>The source Markdown file will be moved to /app/data/done (in future version, it will be deleted).</p>
|
||||
<p>Image files will not be moved, in case they are required for subsequent PDF creations, e.g.on updating and re-uploading the source Markdown file.</p>
|
||||
<p>NB : currently source image files might be overwritten by other users of the app uploading a file of the same name but different content. Your document will then be. reated with the wrong image. If so, re-upload them and retry. This issue will be addressed in a future version.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,128 @@
|
||||
{
|
||||
"name": "pandoc-cloudron",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"node_modules/asap": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
|
||||
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/destroy": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.1.0.tgz",
|
||||
"integrity": "sha512-R5QZrOXxSs0JDUIU/VANvRJlQVMts9C0L76HToQdPdlftfZCE7W6dyH0G4GZ5UW9fRqUOhAoCE2aGekuu+3HjQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/dezalgo": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
|
||||
"integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=",
|
||||
"dependencies": {
|
||||
"asap": "^2.0.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
||||
},
|
||||
"node_modules/formidable": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz",
|
||||
"integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==",
|
||||
"dependencies": {
|
||||
"dezalgo": "1.0.3",
|
||||
"hexoid": "1.0.0",
|
||||
"once": "1.4.0",
|
||||
"qs": "6.9.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/tunnckoCore/commissions"
|
||||
}
|
||||
},
|
||||
"node_modules/fs": {
|
||||
"version": "0.0.1-security",
|
||||
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
|
||||
"integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ="
|
||||
},
|
||||
"node_modules/hexoid": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
|
||||
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/on-finished": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
|
||||
"dependencies": {
|
||||
"ee-first": "1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.9.3",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz",
|
||||
"integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
|
||||
## 2.0.6
|
||||
|
||||
Version 2.0.4 adds support for React Native by clarifying in package.json that
|
||||
the browser environment does not support Node.js domains.
|
||||
Why this is necessary, we leave as an exercise for the user.
|
||||
|
||||
## 2.0.3
|
||||
|
||||
Version 2.0.3 fixes a bug when adjusting the capacity of the task queue.
|
||||
|
||||
## 2.0.1-2.02
|
||||
|
||||
Version 2.0.1 fixes a bug in the way redirects were expressed that affected the
|
||||
function of Browserify, but which Mr would tolerate.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
Version 2 of ASAP is a full rewrite with a few salient changes.
|
||||
First, the ASAP source is CommonJS only and designed with [Browserify][] and
|
||||
[Browserify-compatible][Mr] module loaders in mind.
|
||||
|
||||
[Browserify]: https://github.com/substack/node-browserify
|
||||
[Mr]: https://github.com/montagejs/mr
|
||||
|
||||
The new version has been refactored in two dimensions.
|
||||
Support for Node.js and browsers have been separated, using Browserify
|
||||
redirects and ASAP has been divided into two modules.
|
||||
The "raw" layer depends on the tasks to catch thrown exceptions and unravel
|
||||
Node.js domains.
|
||||
|
||||
The full implementation of ASAP is loadable as `require("asap")` in both Node.js
|
||||
and browsers.
|
||||
|
||||
The raw layer that lacks exception handling overhead is loadable as
|
||||
`require("asap/raw")`.
|
||||
The interface is the same for both layers.
|
||||
|
||||
Tasks are no longer required to be functions, but can rather be any object that
|
||||
implements `task.call()`.
|
||||
With this feature you can recycle task objects to avoid garbage collector churn
|
||||
and avoid closures in general.
|
||||
|
||||
The implementation has been rigorously documented so that our successors can
|
||||
understand the scope of the problem that this module solves and all of its
|
||||
nuances, ensuring that the next generation of implementations know what details
|
||||
are essential.
|
||||
|
||||
- [asap.js](https://github.com/kriskowal/asap/blob/master/asap.js)
|
||||
- [raw.js](https://github.com/kriskowal/asap/blob/master/raw.js)
|
||||
- [browser-asap.js](https://github.com/kriskowal/asap/blob/master/browser-asap.js)
|
||||
- [browser-raw.js](https://github.com/kriskowal/asap/blob/master/browser-raw.js)
|
||||
|
||||
The new version has also been rigorously tested across a broad spectrum of
|
||||
browsers, in both the window and worker context.
|
||||
The following charts capture the browser test results for the most recent
|
||||
release.
|
||||
The first chart shows test results for ASAP running in the main window context.
|
||||
The second chart shows test results for ASAP running in a web worker context.
|
||||
Test results are inconclusive (grey) on browsers that do not support web
|
||||
workers.
|
||||
These data are captured automatically by [Continuous
|
||||
Integration][].
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
[Continuous Integration]: https://github.com/kriskowal/asap/blob/master/CONTRIBUTING.md
|
||||
|
@ -0,0 +1,65 @@
|
||||
"use strict";
|
||||
|
||||
var rawAsap = require("./raw");
|
||||
var freeTasks = [];
|
||||
|
||||
/**
|
||||
* Calls a task as soon as possible after returning, in its own event, with
|
||||
* priority over IO events. An exception thrown in a task can be handled by
|
||||
* `process.on("uncaughtException") or `domain.on("error")`, but will otherwise
|
||||
* crash the process. If the error is handled, all subsequent tasks will
|
||||
* resume.
|
||||
*
|
||||
* @param {{call}} task A callable object, typically a function that takes no
|
||||
* arguments.
|
||||
*/
|
||||
module.exports = asap;
|
||||
function asap(task) {
|
||||
var rawTask;
|
||||
if (freeTasks.length) {
|
||||
rawTask = freeTasks.pop();
|
||||
} else {
|
||||
rawTask = new RawTask();
|
||||
}
|
||||
rawTask.task = task;
|
||||
rawTask.domain = process.domain;
|
||||
rawAsap(rawTask);
|
||||
}
|
||||
|
||||
function RawTask() {
|
||||
this.task = null;
|
||||
this.domain = null;
|
||||
}
|
||||
|
||||
RawTask.prototype.call = function () {
|
||||
if (this.domain) {
|
||||
this.domain.enter();
|
||||
}
|
||||
var threw = true;
|
||||
try {
|
||||
this.task.call();
|
||||
threw = false;
|
||||
// If the task throws an exception (presumably) Node.js restores the
|
||||
// domain stack for the next event.
|
||||
if (this.domain) {
|
||||
this.domain.exit();
|
||||
}
|
||||
} finally {
|
||||
// We use try/finally and a threw flag to avoid messing up stack traces
|
||||
// when we catch and release errors.
|
||||
if (threw) {
|
||||
// In Node.js, uncaught exceptions are considered fatal errors.
|
||||
// Re-throw them to interrupt flushing!
|
||||
// Ensure that flushing continues if an uncaught exception is
|
||||
// suppressed listening process.on("uncaughtException") or
|
||||
// domain.on("error").
|
||||
rawAsap.requestFlush();
|
||||
}
|
||||
// If the task threw an error, we do not want to exit the domain here.
|
||||
// Exiting the domain would prevent the domain from catching the error.
|
||||
this.task = null;
|
||||
this.domain = null;
|
||||
freeTasks.push(this);
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,66 @@
|
||||
"use strict";
|
||||
|
||||
// rawAsap provides everything we need except exception management.
|
||||
var rawAsap = require("./raw");
|
||||
// RawTasks are recycled to reduce GC churn.
|
||||
var freeTasks = [];
|
||||
// We queue errors to ensure they are thrown in right order (FIFO).
|
||||
// Array-as-queue is good enough here, since we are just dealing with exceptions.
|
||||
var pendingErrors = [];
|
||||
var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
|
||||
|
||||
function throwFirstError() {
|
||||
if (pendingErrors.length) {
|
||||
throw pendingErrors.shift();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a task as soon as possible after returning, in its own event, with priority
|
||||
* over other events like animation, reflow, and repaint. An error thrown from an
|
||||
* event will not interrupt, nor even substantially slow down the processing of
|
||||
* other events, but will be rather postponed to a lower priority event.
|
||||
* @param {{call}} task A callable object, typically a function that takes no
|
||||
* arguments.
|
||||
*/
|
||||
module.exports = asap;
|
||||
function asap(task) {
|
||||
var rawTask;
|
||||
if (freeTasks.length) {
|
||||
rawTask = freeTasks.pop();
|
||||
} else {
|
||||
rawTask = new RawTask();
|
||||
}
|
||||
rawTask.task = task;
|
||||
rawAsap(rawTask);
|
||||
}
|
||||
|
||||
// We wrap tasks with recyclable task objects. A task object implements
|
||||
// `call`, just like a function.
|
||||
function RawTask() {
|
||||
this.task = null;
|
||||
}
|
||||
|
||||
// The sole purpose of wrapping the task is to catch the exception and recycle
|
||||
// the task object after its single use.
|
||||
RawTask.prototype.call = function () {
|
||||
try {
|
||||
this.task.call();
|
||||
} catch (error) {
|
||||
if (asap.onerror) {
|
||||
// This hook exists purely for testing purposes.
|
||||
// Its name will be periodically randomized to break any code that
|
||||
// depends on its existence.
|
||||
asap.onerror(error);
|
||||
} else {
|
||||
// In a web browser, exceptions are not fatal. However, to avoid
|
||||
// slowing down the queue of pending tasks, we rethrow the error in a
|
||||
// lower priority turn.
|
||||
pendingErrors.push(error);
|
||||
requestErrorThrow();
|
||||
}
|
||||
} finally {
|
||||
this.task = null;
|
||||
freeTasks[freeTasks.length] = this;
|
||||
}
|
||||
};
|
@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "asap",
|
||||
"version": "2.0.6",
|
||||
"description": "High-priority task queue for Node.js and browsers",
|
||||
"keywords": [
|
||||
"event",
|
||||
"task",
|
||||
"queue"
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/kriskowal/asap.git"
|
||||
},
|
||||
"main": "./asap.js",
|
||||
"browser": {
|
||||
"./asap": "./browser-asap.js",
|
||||
"./asap.js": "./browser-asap.js",
|
||||
"./raw": "./browser-raw.js",
|
||||
"./raw.js": "./browser-raw.js",
|
||||
"./test/domain.js": "./test/browser-domain.js"
|
||||
},
|
||||
"react-native": {
|
||||
"domain": false
|
||||
},
|
||||
"files": [
|
||||
"raw.js",
|
||||
"asap.js",
|
||||
"browser-raw.js",
|
||||
"browser-asap.js"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "npm run lint && npm run test-node",
|
||||
"test-travis": "npm run lint && npm run test-node && npm run test-saucelabs && npm run test-saucelabs-worker",
|
||||
"test-node": "node test/asap-test.js",
|
||||
"test-publish": "node scripts/publish-bundle.js test/asap-test.js | pbcopy",
|
||||
"test-browser": "node scripts/publish-bundle.js test/asap-test.js | xargs opener",
|
||||
"test-saucelabs": "node scripts/saucelabs.js test/asap-test.js scripts/saucelabs-spot-configurations.json",
|
||||
"test-saucelabs-all": "node scripts/saucelabs.js test/asap-test.js scripts/saucelabs-all-configurations.json",
|
||||
"test-saucelabs-worker": "node scripts/saucelabs-worker-test.js scripts/saucelabs-spot-configurations.json",
|
||||
"test-saucelabs-worker-all": "node scripts/saucelabs-worker-test.js scripts/saucelabs-all-configurations.json",
|
||||
"lint": "jshint raw.js asap.js browser-raw.js browser-asap.js $(find scripts -name '*.js' | grep -v gauntlet)",
|
||||
"benchmarks": "node benchmarks"
|
||||
},
|
||||
"devDependencies": {
|
||||
"events": "^1.0.1",
|
||||
"jshint": "^2.5.1",
|
||||
"knox": "^0.8.10",
|
||||
"mr": "^2.0.5",
|
||||
"opener": "^1.3.0",
|
||||
"q": "^2.0.3",
|
||||
"q-io": "^2.0.3",
|
||||
"saucelabs": "^0.1.1",
|
||||
"wd": "^0.2.21",
|
||||
"weak-map": "^1.0.5",
|
||||
"benchmark": "^1.0.0"
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
"use strict";
|
||||
|
||||
var domain; // The domain module is executed on demand
|
||||
var hasSetImmediate = typeof setImmediate === "function";
|
||||
|
||||
// Use the fastest means possible to execute a task in its own turn, with
|
||||
// priority over other events including network IO events in Node.js.
|
||||
//
|
||||
// An exception thrown by a task will permanently interrupt the processing of
|
||||
// subsequent tasks. The higher level `asap` function ensures that if an
|
||||
// exception is thrown by a task, that the task queue will continue flushing as
|
||||
// soon as possible, but if you use `rawAsap` directly, you are responsible to
|
||||
// either ensure that no exceptions are thrown from your task, or to manually
|
||||
// call `rawAsap.requestFlush` if an exception is thrown.
|
||||
module.exports = rawAsap;
|
||||
function rawAsap(task) {
|
||||
if (!queue.length) {
|
||||
requestFlush();
|
||||
flushing = true;
|
||||
}
|
||||
// Avoids a function call
|
||||
queue[queue.length] = task;
|
||||
}
|
||||
|
||||
var queue = [];
|
||||
// Once a flush has been requested, no further calls to `requestFlush` are
|
||||
// necessary until the next `flush` completes.
|
||||
var flushing = false;
|
||||
// The position of the next task to execute in the task queue. This is
|
||||
// preserved between calls to `flush` so that it can be resumed if
|
||||
// a task throws an exception.
|
||||
var index = 0;
|
||||
// If a task schedules additional tasks recursively, the task queue can grow
|
||||
// unbounded. To prevent memory excaustion, the task queue will periodically
|
||||
// truncate already-completed tasks.
|
||||
var capacity = 1024;
|
||||
|
||||
// The flush function processes all tasks that have been scheduled with
|
||||
// `rawAsap` unless and until one of those tasks throws an exception.
|
||||
// If a task throws an exception, `flush` ensures that its state will remain
|
||||
// consistent and will resume where it left off when called again.
|
||||
// However, `flush` does not make any arrangements to be called again if an
|
||||
// exception is thrown.
|
||||
function flush() {
|
||||
while (index < queue.length) {
|
||||
var currentIndex = index;
|
||||
// Advance the index before calling the task. This ensures that we will
|
||||
// begin flushing on the next task the task throws an error.
|
||||
index = index + 1;
|
||||
queue[currentIndex].call();
|
||||
// Prevent leaking memory for long chains of recursive calls to `asap`.
|
||||
// If we call `asap` within tasks scheduled by `asap`, the queue will
|
||||
// grow, but to avoid an O(n) walk for every task we execute, we don't
|
||||
// shift tasks off the queue after they have been executed.
|
||||
// Instead, we periodically shift 1024 tasks off the queue.
|
||||
if (index > capacity) {
|
||||
// Manually shift all values starting at the index back to the
|
||||
// beginning of the queue.
|
||||
for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
|
||||
queue[scan] = queue[scan + index];
|
||||
}
|
||||
queue.length -= index;
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
queue.length = 0;
|
||||
index = 0;
|
||||
flushing = false;
|
||||
}
|
||||
|
||||
rawAsap.requestFlush = requestFlush;
|
||||
function requestFlush() {
|
||||
// Ensure flushing is not bound to any domain.
|
||||
// It is not sufficient to exit the domain, because domains exist on a stack.
|
||||
// To execute code outside of any domain, the following dance is necessary.
|
||||
var parentDomain = process.domain;
|
||||
if (parentDomain) {
|
||||
if (!domain) {
|
||||
// Lazy execute the domain module.
|
||||
// Only employed if the user elects to use domains.
|
||||
domain = require("domain");
|
||||
}
|
||||
domain.active = process.domain = null;
|
||||
}
|
||||
|
||||
// `setImmediate` is slower that `process.nextTick`, but `process.nextTick`
|
||||
// cannot handle recursion.
|
||||
// `requestFlush` will only be called recursively from `asap.js`, to resume
|
||||
// flushing after an error is thrown into a domain.
|
||||
// Conveniently, `setImmediate` was introduced in the same version
|
||||
// `process.nextTick` started throwing recursion errors.
|
||||
if (flushing && hasSetImmediate) {
|
||||
setImmediate(flush);
|
||||
} else {
|
||||
process.nextTick(flush);
|
||||
}
|
||||
|
||||
if (parentDomain) {
|
||||
domain.active = process.domain = parentDomain;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
0.5.4 / 2021-12-10
|
||||
==================
|
||||
|
||||
* deps: safe-buffer@5.2.1
|
||||
|
||||
0.5.3 / 2018-12-17
|
||||
==================
|
||||
|
||||
* Use `safe-buffer` for improved Buffer API
|
||||
|
||||
0.5.2 / 2016-12-08
|
||||
==================
|
||||
|
||||
* Fix `parse` to accept any linear whitespace character
|
||||
|
||||
0.5.1 / 2016-01-17
|
||||
==================
|
||||
|
||||
* perf: enable strict mode
|
||||
|
||||
0.5.0 / 2014-10-11
|
||||
==================
|
||||
|
||||
* Add `parse` function
|
||||
|
||||
0.4.0 / 2014-09-21
|
||||
==================
|
||||
|
||||
* Expand non-Unicode `filename` to the full ISO-8859-1 charset
|
||||
|
||||
0.3.0 / 2014-09-20
|
||||
==================
|
||||
|
||||
* Add `fallback` option
|
||||
* Add `type` option
|
||||
|
||||
0.2.0 / 2014-09-19
|
||||
==================
|
||||
|
||||
* Reduce ambiguity of file names with hex escape in buggy browsers
|
||||
|
||||
0.1.2 / 2014-09-19
|
||||
==================
|
||||
|
||||
* Fix periodic invalid Unicode filename header
|
||||
|
||||
0.1.1 / 2014-09-19
|
||||
==================
|
||||
|
||||
* Fix invalid characters appearing in `filename*` parameter
|
||||
|
||||
0.1.0 / 2014-09-18
|
||||
==================
|
||||
|
||||
* Make the `filename` argument optional
|
||||
|
||||
0.0.0 / 2014-09-18
|
||||
==================
|
||||
|
||||
* Initial release
|
@ -0,0 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014-2017 Douglas Christopher Wilson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -0,0 +1,142 @@
|
||||
# content-disposition
|
||||
|
||||
[![NPM Version][npm-image]][npm-url]
|
||||
[![NPM Downloads][downloads-image]][downloads-url]
|
||||
[![Node.js Version][node-version-image]][node-version-url]
|
||||
[![Build Status][github-actions-ci-image]][github-actions-ci-url]
|
||||
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||
|
||||
Create and parse HTTP `Content-Disposition` header
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
$ npm install content-disposition
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var contentDisposition = require('content-disposition')
|
||||
```
|
||||
|
||||
### contentDisposition(filename, options)
|
||||
|
||||
Create an attachment `Content-Disposition` header value using the given file name,
|
||||
if supplied. The `filename` is optional and if no file name is desired, but you
|
||||
want to specify `options`, set `filename` to `undefined`.
|
||||
|
||||
```js
|
||||
res.setHeader('Content-Disposition', contentDisposition('∫ maths.pdf'))
|
||||
```
|
||||
|
||||
**note** HTTP headers are of the ISO-8859-1 character set. If you are writing this
|
||||
header through a means different from `setHeader` in Node.js, you'll want to specify
|
||||
the `'binary'` encoding in Node.js.
|
||||
|
||||
#### Options
|
||||
|
||||
`contentDisposition` accepts these properties in the options object.
|
||||
|
||||
##### fallback
|
||||
|
||||
If the `filename` option is outside ISO-8859-1, then the file name is actually
|
||||
stored in a supplemental field for clients that support Unicode file names and
|
||||
a ISO-8859-1 version of the file name is automatically generated.
|
||||
|
||||
This specifies the ISO-8859-1 file name to override the automatic generation or
|
||||
disables the generation all together, defaults to `true`.
|
||||
|
||||
- A string will specify the ISO-8859-1 file name to use in place of automatic
|
||||
generation.
|
||||
- `false` will disable including a ISO-8859-1 file name and only include the
|
||||
Unicode version (unless the file name is already ISO-8859-1).
|
||||
- `true` will enable automatic generation if the file name is outside ISO-8859-1.
|
||||
|
||||
If the `filename` option is ISO-8859-1 and this option is specified and has a
|
||||
different value, then the `filename` option is encoded in the extended field
|
||||
and this set as the fallback field, even though they are both ISO-8859-1.
|
||||
|
||||
##### type
|
||||
|
||||
Specifies the disposition type, defaults to `"attachment"`. This can also be
|
||||
`"inline"`, or any other value (all values except inline are treated like
|
||||
`attachment`, but can convey additional information if both parties agree to
|
||||
it). The type is normalized to lower-case.
|
||||
|
||||
### contentDisposition.parse(string)
|
||||
|
||||
```js
|
||||
var disposition = contentDisposition.parse('attachment; filename="EURO rates.txt"; filename*=UTF-8\'\'%e2%82%ac%20rates.txt')
|
||||
```
|
||||
|
||||
Parse a `Content-Disposition` header string. This automatically handles extended
|
||||
("Unicode") parameters by decoding them and providing them under the standard
|
||||
parameter name. This will return an object with the following properties (examples
|
||||
are shown for the string `'attachment; filename="EURO rates.txt"; filename*=UTF-8\'\'%e2%82%ac%20rates.txt'`):
|
||||
|
||||
- `type`: The disposition type (always lower case). Example: `'attachment'`
|
||||
|
||||
- `parameters`: An object of the parameters in the disposition (name of parameter
|
||||
always lower case and extended versions replace non-extended versions). Example:
|
||||
`{filename: "€ rates.txt"}`
|
||||
|
||||
## Examples
|
||||
|
||||
### Send a file for download
|
||||
|
||||
```js
|
||||
var contentDisposition = require('content-disposition')
|
||||
var destroy = require('destroy')
|
||||
var fs = require('fs')
|
||||
var http = require('http')
|
||||
var onFinished = require('on-finished')
|
||||
|
||||
var filePath = '/path/to/public/plans.pdf'
|
||||
|
||||
http.createServer(function onRequest (req, res) {
|
||||
// set headers
|
||||
res.setHeader('Content-Type', 'application/pdf')
|
||||
res.setHeader('Content-Disposition', contentDisposition(filePath))
|
||||
|
||||
// send file
|
||||
var stream = fs.createReadStream(filePath)
|
||||
stream.pipe(res)
|
||||
onFinished(res, function () {
|
||||
destroy(stream)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```sh
|
||||
$ npm test
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1][rfc-2616]
|
||||
- [RFC 5987: Character Set and Language Encoding for Hypertext Transfer Protocol (HTTP) Header Field Parameters][rfc-5987]
|
||||
- [RFC 6266: Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)][rfc-6266]
|
||||
- [Test Cases for HTTP Content-Disposition header field (RFC 6266) and the Encodings defined in RFCs 2047, 2231 and 5987][tc-2231]
|
||||
|
||||
[rfc-2616]: https://tools.ietf.org/html/rfc2616
|
||||
[rfc-5987]: https://tools.ietf.org/html/rfc5987
|
||||
[rfc-6266]: https://tools.ietf.org/html/rfc6266
|
||||
[tc-2231]: http://greenbytes.de/tech/tc2231/
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/content-disposition.svg
|
||||
[npm-url]: https://npmjs.org/package/content-disposition
|
||||
[node-version-image]: https://img.shields.io/node/v/content-disposition.svg
|
||||
[node-version-url]: https://nodejs.org/en/download
|
||||
[coveralls-image]: https://img.shields.io/coveralls/jshttp/content-disposition.svg
|
||||
[coveralls-url]: https://coveralls.io/r/jshttp/content-disposition?branch=master
|
||||
[downloads-image]: https://img.shields.io/npm/dm/content-disposition.svg
|
||||
[downloads-url]: https://npmjs.org/package/content-disposition
|
||||
[github-actions-ci-image]: https://img.shields.io/github/workflow/status/jshttp/content-disposition/ci/master?label=ci
|
||||
[github-actions-ci-url]: https://github.com/jshttp/content-disposition?query=workflow%3Aci
|
@ -0,0 +1,458 @@
|
||||
/*!
|
||||
* content-disposition
|
||||
* Copyright(c) 2014-2017 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
* @public
|
||||
*/
|
||||
|
||||
module.exports = contentDisposition
|
||||
module.exports.parse = parse
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var basename = require('path').basename
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
|
||||
/**
|
||||
* RegExp to match non attr-char, *after* encodeURIComponent (i.e. not including "%")
|
||||
* @private
|
||||
*/
|
||||
|
||||
var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g // eslint-disable-line no-control-regex
|
||||
|
||||
/**
|
||||
* RegExp to match percent encoding escape.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/
|
||||
var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g
|
||||
|
||||
/**
|
||||
* RegExp to match non-latin1 characters.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var NON_LATIN1_REGEXP = /[^\x20-\x7e\xa0-\xff]/g
|
||||
|
||||
/**
|
||||
* RegExp to match quoted-pair in RFC 2616
|
||||
*
|
||||
* quoted-pair = "\" CHAR
|
||||
* CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||
* @private
|
||||
*/
|
||||
|
||||
var QESC_REGEXP = /\\([\u0000-\u007f])/g // eslint-disable-line no-control-regex
|
||||
|
||||
/**
|
||||
* RegExp to match chars that must be quoted-pair in RFC 2616
|
||||
* @private
|
||||
*/
|
||||
|
||||
var QUOTE_REGEXP = /([\\"])/g
|
||||
|
||||
/**
|
||||
* RegExp for various RFC 2616 grammar
|
||||
*
|
||||
* parameter = token "=" ( token | quoted-string )
|
||||
* token = 1*<any CHAR except CTLs or separators>
|
||||
* separators = "(" | ")" | "<" | ">" | "@"
|
||||
* | "," | ";" | ":" | "\" | <">
|
||||
* | "/" | "[" | "]" | "?" | "="
|
||||
* | "{" | "}" | SP | HT
|
||||
* quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
|
||||
* qdtext = <any TEXT except <">>
|
||||
* quoted-pair = "\" CHAR
|
||||
* CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||
* TEXT = <any OCTET except CTLs, but including LWS>
|
||||
* LWS = [CRLF] 1*( SP | HT )
|
||||
* CRLF = CR LF
|
||||
* CR = <US-ASCII CR, carriage return (13)>
|
||||
* LF = <US-ASCII LF, linefeed (10)>
|
||||
* SP = <US-ASCII SP, space (32)>
|
||||
* HT = <US-ASCII HT, horizontal-tab (9)>
|
||||
* CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
|
||||
* OCTET = <any 8-bit sequence of data>
|
||||
* @private
|
||||
*/
|
||||
|
||||
var PARAM_REGEXP = /;[\x09\x20]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*=[\x09\x20]*("(?:[\x20!\x23-\x5b\x5d-\x7e\x80-\xff]|\\[\x20-\x7e])*"|[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*/g // eslint-disable-line no-control-regex
|
||||
var TEXT_REGEXP = /^[\x20-\x7e\x80-\xff]+$/
|
||||
var TOKEN_REGEXP = /^[!#$%&'*+.0-9A-Z^_`a-z|~-]+$/
|
||||
|
||||
/**
|
||||
* RegExp for various RFC 5987 grammar
|
||||
*
|
||||
* ext-value = charset "'" [ language ] "'" value-chars
|
||||
* charset = "UTF-8" / "ISO-8859-1" / mime-charset
|
||||
* mime-charset = 1*mime-charsetc
|
||||
* mime-charsetc = ALPHA / DIGIT
|
||||
* / "!" / "#" / "$" / "%" / "&"
|
||||
* / "+" / "-" / "^" / "_" / "`"
|
||||
* / "{" / "}" / "~"
|
||||
* language = ( 2*3ALPHA [ extlang ] )
|
||||
* / 4ALPHA
|
||||
* / 5*8ALPHA
|
||||
* extlang = *3( "-" 3ALPHA )
|
||||
* value-chars = *( pct-encoded / attr-char )
|
||||
* pct-encoded = "%" HEXDIG HEXDIG
|
||||
* attr-char = ALPHA / DIGIT
|
||||
* / "!" / "#" / "$" / "&" / "+" / "-" / "."
|
||||
* / "^" / "_" / "`" / "|" / "~"
|
||||
* @private
|
||||
*/
|
||||
|
||||
var EXT_VALUE_REGEXP = /^([A-Za-z0-9!#$%&+\-^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+.^_`|~-])+)$/
|
||||
|
||||
/**
|
||||
* RegExp for various RFC 6266 grammar
|
||||
*
|
||||
* disposition-type = "inline" | "attachment" | disp-ext-type
|
||||
* disp-ext-type = token
|
||||
* disposition-parm = filename-parm | disp-ext-parm
|
||||
* filename-parm = "filename" "=" value
|
||||
* | "filename*" "=" ext-value
|
||||
* disp-ext-parm = token "=" value
|
||||
* | ext-token "=" ext-value
|
||||
* ext-token = <the characters in token, followed by "*">
|
||||
* @private
|
||||
*/
|
||||
|
||||
var DISPOSITION_TYPE_REGEXP = /^([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*(?:$|;)/ // eslint-disable-line no-control-regex
|
||||
|
||||
/**
|
||||
* Create an attachment Content-Disposition header.
|
||||
*
|
||||
* @param {string} [filename]
|
||||
* @param {object} [options]
|
||||
* @param {string} [options.type=attachment]
|
||||
* @param {string|boolean} [options.fallback=true]
|
||||
* @return {string}
|
||||
* @public
|
||||
*/
|
||||
|
||||
function contentDisposition (filename, options) {
|
||||
var opts = options || {}
|
||||
|
||||
// get type
|
||||
var type = opts.type || 'attachment'
|
||||
|
||||
// get parameters
|
||||
var params = createparams(filename, opts.fallback)
|
||||
|
||||
// format into string
|
||||
return format(new ContentDisposition(type, params))
|
||||
}
|
||||
|
||||
/**
|
||||
* Create parameters object from filename and fallback.
|
||||
*
|
||||
* @param {string} [filename]
|
||||
* @param {string|boolean} [fallback=true]
|
||||
* @return {object}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function createparams (filename, fallback) {
|
||||
if (filename === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
var params = {}
|
||||
|
||||
if (typeof filename !== 'string') {
|
||||
throw new TypeError('filename must be a string')
|
||||
}
|
||||
|
||||
// fallback defaults to true
|
||||
if (fallback === undefined) {
|
||||
fallback = true
|
||||
}
|
||||
|
||||
if (typeof fallback !== 'string' && typeof fallback !== 'boolean') {
|
||||
throw new TypeError('fallback must be a string or boolean')
|
||||
}
|
||||
|
||||
if (typeof fallback === 'string' && NON_LATIN1_REGEXP.test(fallback)) {
|
||||
throw new TypeError('fallback must be ISO-8859-1 string')
|
||||
}
|
||||
|
||||
// restrict to file base name
|
||||
var name = basename( |