1
0
Fork 0
mirror of https://github.com/DanielnetoDotCom/YouPHPTube synced 2025-10-03 01:39:24 +02:00

Git update

This commit is contained in:
Daniel 2022-03-17 11:43:59 -03:00
parent bd8d7eedb6
commit 602ca1128e
3123 changed files with 521005 additions and 521005 deletions

View file

@ -1,3 +1,3 @@
export default function _writeOnlyError(name) { export default function _writeOnlyError(name) {
throw new TypeError("\"" + name + "\" is write-only"); throw new TypeError("\"" + name + "\" is write-only");
} }

View file

@ -1,21 +1,21 @@
function _extends() { function _extends() {
module.exports = _extends = Object.assign || function (target) { module.exports = _extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) { for (var i = 1; i < arguments.length; i++) {
var source = arguments[i]; var source = arguments[i];
for (var key in source) { for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) { if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key]; target[key] = source[key];
} }
} }
} }
return target; return target;
}; };
module.exports["default"] = module.exports, module.exports.__esModule = true; module.exports["default"] = module.exports, module.exports.__esModule = true;
return _extends.apply(this, arguments); return _extends.apply(this, arguments);
} }
module.exports = _extends; module.exports = _extends;
module.exports["default"] = module.exports, module.exports.__esModule = true; module.exports["default"] = module.exports, module.exports.__esModule = true;

View file

@ -1,27 +1,27 @@
var superPropBase = require("./superPropBase.js"); var superPropBase = require("./superPropBase.js");
function _get(target, property, receiver) { function _get(target, property, receiver) {
if (typeof Reflect !== "undefined" && Reflect.get) { if (typeof Reflect !== "undefined" && Reflect.get) {
module.exports = _get = Reflect.get; module.exports = _get = Reflect.get;
module.exports["default"] = module.exports, module.exports.__esModule = true; module.exports["default"] = module.exports, module.exports.__esModule = true;
} else { } else {
module.exports = _get = function _get(target, property, receiver) { module.exports = _get = function _get(target, property, receiver) {
var base = superPropBase(target, property); var base = superPropBase(target, property);
if (!base) return; if (!base) return;
var desc = Object.getOwnPropertyDescriptor(base, property); var desc = Object.getOwnPropertyDescriptor(base, property);
if (desc.get) { if (desc.get) {
return desc.get.call(receiver); return desc.get.call(receiver);
} }
return desc.value; return desc.value;
}; };
module.exports["default"] = module.exports, module.exports.__esModule = true; module.exports["default"] = module.exports, module.exports.__esModule = true;
} }
return _get(target, property, receiver || target); return _get(target, property, receiver || target);
} }
module.exports = _get; module.exports = _get;
module.exports["default"] = module.exports, module.exports.__esModule = true; module.exports["default"] = module.exports, module.exports.__esModule = true;

View file

@ -1,10 +1,10 @@
function _getPrototypeOf(o) { function _getPrototypeOf(o) {
module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o); return o.__proto__ || Object.getPrototypeOf(o);
}; };
module.exports["default"] = module.exports, module.exports.__esModule = true; module.exports["default"] = module.exports, module.exports.__esModule = true;
return _getPrototypeOf(o); return _getPrototypeOf(o);
} }
module.exports = _getPrototypeOf; module.exports = _getPrototypeOf;
module.exports["default"] = module.exports, module.exports.__esModule = true; module.exports["default"] = module.exports, module.exports.__esModule = true;

View file

@ -1,19 +1,19 @@
var setPrototypeOf = require("./setPrototypeOf.js"); var setPrototypeOf = require("./setPrototypeOf.js");
function _inherits(subClass, superClass) { function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) { if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function"); throw new TypeError("Super expression must either be null or a function");
} }
subClass.prototype = Object.create(superClass && superClass.prototype, { subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: { constructor: {
value: subClass, value: subClass,
writable: true, writable: true,
configurable: true configurable: true
} }
}); });
if (superClass) setPrototypeOf(subClass, superClass); if (superClass) setPrototypeOf(subClass, superClass);
} }
module.exports = _inherits; module.exports = _inherits;
module.exports["default"] = module.exports, module.exports.__esModule = true; module.exports["default"] = module.exports, module.exports.__esModule = true;

View file

@ -1,16 +1,16 @@
/*! /*!
* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/ */
@font-face { @font-face {
font-family: 'Font Awesome 5 Free'; font-family: 'Font Awesome 5 Free';
font-style: normal; font-style: normal;
font-weight: 900; font-weight: 900;
font-display: block; font-display: block;
src: url("../webfonts/fa-solid-900.eot"); src: url("../webfonts/fa-solid-900.eot");
src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); } src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); }
.fa, .fa,
.fas { .fas {
font-family: 'Font Awesome 5 Free'; font-family: 'Font Awesome 5 Free';
font-weight: 900; } font-weight: 900; }

View file

@ -1,5 +1,5 @@
/*! /*!
* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/ */
@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Free";font-weight:900} @font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Free";font-weight:900}

View file

@ -1,371 +1,371 @@
/*! /*!
* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/ */
svg:not(:root).svg-inline--fa { svg:not(:root).svg-inline--fa {
overflow: visible; } overflow: visible; }
.svg-inline--fa { .svg-inline--fa {
display: inline-block; display: inline-block;
font-size: inherit; font-size: inherit;
height: 1em; height: 1em;
overflow: visible; overflow: visible;
vertical-align: -.125em; } vertical-align: -.125em; }
.svg-inline--fa.fa-lg { .svg-inline--fa.fa-lg {
vertical-align: -.225em; } vertical-align: -.225em; }
.svg-inline--fa.fa-w-1 { .svg-inline--fa.fa-w-1 {
width: 0.0625em; } width: 0.0625em; }
.svg-inline--fa.fa-w-2 { .svg-inline--fa.fa-w-2 {
width: 0.125em; } width: 0.125em; }
.svg-inline--fa.fa-w-3 { .svg-inline--fa.fa-w-3 {
width: 0.1875em; } width: 0.1875em; }
.svg-inline--fa.fa-w-4 { .svg-inline--fa.fa-w-4 {
width: 0.25em; } width: 0.25em; }
.svg-inline--fa.fa-w-5 { .svg-inline--fa.fa-w-5 {
width: 0.3125em; } width: 0.3125em; }
.svg-inline--fa.fa-w-6 { .svg-inline--fa.fa-w-6 {
width: 0.375em; } width: 0.375em; }
.svg-inline--fa.fa-w-7 { .svg-inline--fa.fa-w-7 {
width: 0.4375em; } width: 0.4375em; }
.svg-inline--fa.fa-w-8 { .svg-inline--fa.fa-w-8 {
width: 0.5em; } width: 0.5em; }
.svg-inline--fa.fa-w-9 { .svg-inline--fa.fa-w-9 {
width: 0.5625em; } width: 0.5625em; }
.svg-inline--fa.fa-w-10 { .svg-inline--fa.fa-w-10 {
width: 0.625em; } width: 0.625em; }
.svg-inline--fa.fa-w-11 { .svg-inline--fa.fa-w-11 {
width: 0.6875em; } width: 0.6875em; }
.svg-inline--fa.fa-w-12 { .svg-inline--fa.fa-w-12 {
width: 0.75em; } width: 0.75em; }
.svg-inline--fa.fa-w-13 { .svg-inline--fa.fa-w-13 {
width: 0.8125em; } width: 0.8125em; }
.svg-inline--fa.fa-w-14 { .svg-inline--fa.fa-w-14 {
width: 0.875em; } width: 0.875em; }
.svg-inline--fa.fa-w-15 { .svg-inline--fa.fa-w-15 {
width: 0.9375em; } width: 0.9375em; }
.svg-inline--fa.fa-w-16 { .svg-inline--fa.fa-w-16 {
width: 1em; } width: 1em; }
.svg-inline--fa.fa-w-17 { .svg-inline--fa.fa-w-17 {
width: 1.0625em; } width: 1.0625em; }
.svg-inline--fa.fa-w-18 { .svg-inline--fa.fa-w-18 {
width: 1.125em; } width: 1.125em; }
.svg-inline--fa.fa-w-19 { .svg-inline--fa.fa-w-19 {
width: 1.1875em; } width: 1.1875em; }
.svg-inline--fa.fa-w-20 { .svg-inline--fa.fa-w-20 {
width: 1.25em; } width: 1.25em; }
.svg-inline--fa.fa-pull-left { .svg-inline--fa.fa-pull-left {
margin-right: .3em; margin-right: .3em;
width: auto; } width: auto; }
.svg-inline--fa.fa-pull-right { .svg-inline--fa.fa-pull-right {
margin-left: .3em; margin-left: .3em;
width: auto; } width: auto; }
.svg-inline--fa.fa-border { .svg-inline--fa.fa-border {
height: 1.5em; } height: 1.5em; }
.svg-inline--fa.fa-li { .svg-inline--fa.fa-li {
width: 2em; } width: 2em; }
.svg-inline--fa.fa-fw { .svg-inline--fa.fa-fw {
width: 1.25em; } width: 1.25em; }
.fa-layers svg.svg-inline--fa { .fa-layers svg.svg-inline--fa {
bottom: 0; bottom: 0;
left: 0; left: 0;
margin: auto; margin: auto;
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; } top: 0; }
.fa-layers { .fa-layers {
display: inline-block; display: inline-block;
height: 1em; height: 1em;
position: relative; position: relative;
text-align: center; text-align: center;
vertical-align: -.125em; vertical-align: -.125em;
width: 1em; } width: 1em; }
.fa-layers svg.svg-inline--fa { .fa-layers svg.svg-inline--fa {
-webkit-transform-origin: center center; -webkit-transform-origin: center center;
transform-origin: center center; } transform-origin: center center; }
.fa-layers-text, .fa-layers-counter { .fa-layers-text, .fa-layers-counter {
display: inline-block; display: inline-block;
position: absolute; position: absolute;
text-align: center; } text-align: center; }
.fa-layers-text { .fa-layers-text {
left: 50%; left: 50%;
top: 50%; top: 50%;
-webkit-transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
-webkit-transform-origin: center center; -webkit-transform-origin: center center;
transform-origin: center center; } transform-origin: center center; }
.fa-layers-counter { .fa-layers-counter {
background-color: #ff253a; background-color: #ff253a;
border-radius: 1em; border-radius: 1em;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
color: #fff; color: #fff;
height: 1.5em; height: 1.5em;
line-height: 1; line-height: 1;
max-width: 5em; max-width: 5em;
min-width: 1.5em; min-width: 1.5em;
overflow: hidden; overflow: hidden;
padding: .25em; padding: .25em;
right: 0; right: 0;
text-overflow: ellipsis; text-overflow: ellipsis;
top: 0; top: 0;
-webkit-transform: scale(0.25); -webkit-transform: scale(0.25);
transform: scale(0.25); transform: scale(0.25);
-webkit-transform-origin: top right; -webkit-transform-origin: top right;
transform-origin: top right; } transform-origin: top right; }
.fa-layers-bottom-right { .fa-layers-bottom-right {
bottom: 0; bottom: 0;
right: 0; right: 0;
top: auto; top: auto;
-webkit-transform: scale(0.25); -webkit-transform: scale(0.25);
transform: scale(0.25); transform: scale(0.25);
-webkit-transform-origin: bottom right; -webkit-transform-origin: bottom right;
transform-origin: bottom right; } transform-origin: bottom right; }
.fa-layers-bottom-left { .fa-layers-bottom-left {
bottom: 0; bottom: 0;
left: 0; left: 0;
right: auto; right: auto;
top: auto; top: auto;
-webkit-transform: scale(0.25); -webkit-transform: scale(0.25);
transform: scale(0.25); transform: scale(0.25);
-webkit-transform-origin: bottom left; -webkit-transform-origin: bottom left;
transform-origin: bottom left; } transform-origin: bottom left; }
.fa-layers-top-right { .fa-layers-top-right {
right: 0; right: 0;
top: 0; top: 0;
-webkit-transform: scale(0.25); -webkit-transform: scale(0.25);
transform: scale(0.25); transform: scale(0.25);
-webkit-transform-origin: top right; -webkit-transform-origin: top right;
transform-origin: top right; } transform-origin: top right; }
.fa-layers-top-left { .fa-layers-top-left {
left: 0; left: 0;
right: auto; right: auto;
top: 0; top: 0;
-webkit-transform: scale(0.25); -webkit-transform: scale(0.25);
transform: scale(0.25); transform: scale(0.25);
-webkit-transform-origin: top left; -webkit-transform-origin: top left;
transform-origin: top left; } transform-origin: top left; }
.fa-lg { .fa-lg {
font-size: 1.33333em; font-size: 1.33333em;
line-height: 0.75em; line-height: 0.75em;
vertical-align: -.0667em; } vertical-align: -.0667em; }
.fa-xs { .fa-xs {
font-size: .75em; } font-size: .75em; }
.fa-sm { .fa-sm {
font-size: .875em; } font-size: .875em; }
.fa-1x { .fa-1x {
font-size: 1em; } font-size: 1em; }
.fa-2x { .fa-2x {
font-size: 2em; } font-size: 2em; }
.fa-3x { .fa-3x {
font-size: 3em; } font-size: 3em; }
.fa-4x { .fa-4x {
font-size: 4em; } font-size: 4em; }
.fa-5x { .fa-5x {
font-size: 5em; } font-size: 5em; }
.fa-6x { .fa-6x {
font-size: 6em; } font-size: 6em; }
.fa-7x { .fa-7x {
font-size: 7em; } font-size: 7em; }
.fa-8x { .fa-8x {
font-size: 8em; } font-size: 8em; }
.fa-9x { .fa-9x {
font-size: 9em; } font-size: 9em; }
.fa-10x { .fa-10x {
font-size: 10em; } font-size: 10em; }
.fa-fw { .fa-fw {
text-align: center; text-align: center;
width: 1.25em; } width: 1.25em; }
.fa-ul { .fa-ul {
list-style-type: none; list-style-type: none;
margin-left: 2.5em; margin-left: 2.5em;
padding-left: 0; } padding-left: 0; }
.fa-ul > li { .fa-ul > li {
position: relative; } position: relative; }
.fa-li { .fa-li {
left: -2em; left: -2em;
position: absolute; position: absolute;
text-align: center; text-align: center;
width: 2em; width: 2em;
line-height: inherit; } line-height: inherit; }
.fa-border { .fa-border {
border: solid 0.08em #eee; border: solid 0.08em #eee;
border-radius: .1em; border-radius: .1em;
padding: .2em .25em .15em; } padding: .2em .25em .15em; }
.fa-pull-left { .fa-pull-left {
float: left; } float: left; }
.fa-pull-right { .fa-pull-right {
float: right; } float: right; }
.fa.fa-pull-left, .fa.fa-pull-left,
.fas.fa-pull-left, .fas.fa-pull-left,
.far.fa-pull-left, .far.fa-pull-left,
.fal.fa-pull-left, .fal.fa-pull-left,
.fab.fa-pull-left { .fab.fa-pull-left {
margin-right: .3em; } margin-right: .3em; }
.fa.fa-pull-right, .fa.fa-pull-right,
.fas.fa-pull-right, .fas.fa-pull-right,
.far.fa-pull-right, .far.fa-pull-right,
.fal.fa-pull-right, .fal.fa-pull-right,
.fab.fa-pull-right { .fab.fa-pull-right {
margin-left: .3em; } margin-left: .3em; }
.fa-spin { .fa-spin {
-webkit-animation: fa-spin 2s infinite linear; -webkit-animation: fa-spin 2s infinite linear;
animation: fa-spin 2s infinite linear; } animation: fa-spin 2s infinite linear; }
.fa-pulse { .fa-pulse {
-webkit-animation: fa-spin 1s infinite steps(8); -webkit-animation: fa-spin 1s infinite steps(8);
animation: fa-spin 1s infinite steps(8); } animation: fa-spin 1s infinite steps(8); }
@-webkit-keyframes fa-spin { @-webkit-keyframes fa-spin {
0% { 0% {
-webkit-transform: rotate(0deg); -webkit-transform: rotate(0deg);
transform: rotate(0deg); } transform: rotate(0deg); }
100% { 100% {
-webkit-transform: rotate(360deg); -webkit-transform: rotate(360deg);
transform: rotate(360deg); } } transform: rotate(360deg); } }
@keyframes fa-spin { @keyframes fa-spin {
0% { 0% {
-webkit-transform: rotate(0deg); -webkit-transform: rotate(0deg);
transform: rotate(0deg); } transform: rotate(0deg); }
100% { 100% {
-webkit-transform: rotate(360deg); -webkit-transform: rotate(360deg);
transform: rotate(360deg); } } transform: rotate(360deg); } }
.fa-rotate-90 { .fa-rotate-90 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
-webkit-transform: rotate(90deg); -webkit-transform: rotate(90deg);
transform: rotate(90deg); } transform: rotate(90deg); }
.fa-rotate-180 { .fa-rotate-180 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
-webkit-transform: rotate(180deg); -webkit-transform: rotate(180deg);
transform: rotate(180deg); } transform: rotate(180deg); }
.fa-rotate-270 { .fa-rotate-270 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
-webkit-transform: rotate(270deg); -webkit-transform: rotate(270deg);
transform: rotate(270deg); } transform: rotate(270deg); }
.fa-flip-horizontal { .fa-flip-horizontal {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
-webkit-transform: scale(-1, 1); -webkit-transform: scale(-1, 1);
transform: scale(-1, 1); } transform: scale(-1, 1); }
.fa-flip-vertical { .fa-flip-vertical {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
-webkit-transform: scale(1, -1); -webkit-transform: scale(1, -1);
transform: scale(1, -1); } transform: scale(1, -1); }
.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical { .fa-flip-both, .fa-flip-horizontal.fa-flip-vertical {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
-webkit-transform: scale(-1, -1); -webkit-transform: scale(-1, -1);
transform: scale(-1, -1); } transform: scale(-1, -1); }
:root .fa-rotate-90, :root .fa-rotate-90,
:root .fa-rotate-180, :root .fa-rotate-180,
:root .fa-rotate-270, :root .fa-rotate-270,
:root .fa-flip-horizontal, :root .fa-flip-horizontal,
:root .fa-flip-vertical, :root .fa-flip-vertical,
:root .fa-flip-both { :root .fa-flip-both {
-webkit-filter: none; -webkit-filter: none;
filter: none; } filter: none; }
.fa-stack { .fa-stack {
display: inline-block; display: inline-block;
height: 2em; height: 2em;
position: relative; position: relative;
width: 2.5em; } width: 2.5em; }
.fa-stack-1x, .fa-stack-1x,
.fa-stack-2x { .fa-stack-2x {
bottom: 0; bottom: 0;
left: 0; left: 0;
margin: auto; margin: auto;
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; } top: 0; }
.svg-inline--fa.fa-stack-1x { .svg-inline--fa.fa-stack-1x {
height: 1em; height: 1em;
width: 1.25em; } width: 1.25em; }
.svg-inline--fa.fa-stack-2x { .svg-inline--fa.fa-stack-2x {
height: 2em; height: 2em;
width: 2.5em; } width: 2.5em; }
.fa-inverse { .fa-inverse {
color: #fff; } color: #fff; }
.sr-only { .sr-only {
border: 0; border: 0;
clip: rect(0, 0, 0, 0); clip: rect(0, 0, 0, 0);
height: 1px; height: 1px;
margin: -1px; margin: -1px;
overflow: hidden; overflow: hidden;
padding: 0; padding: 0;
position: absolute; position: absolute;
width: 1px; } width: 1px; }
.sr-only-focusable:active, .sr-only-focusable:focus { .sr-only-focusable:active, .sr-only-focusable:focus {
clip: auto; clip: auto;
height: auto; height: auto;
margin: 0; margin: 0;
overflow: visible; overflow: visible;
position: static; position: static;
width: auto; } width: auto; }
.svg-inline--fa .fa-primary { .svg-inline--fa .fa-primary {
fill: var(--fa-primary-color, currentColor); fill: var(--fa-primary-color, currentColor);
opacity: 1; opacity: 1;
opacity: var(--fa-primary-opacity, 1); } opacity: var(--fa-primary-opacity, 1); }
.svg-inline--fa .fa-secondary { .svg-inline--fa .fa-secondary {
fill: var(--fa-secondary-color, currentColor); fill: var(--fa-secondary-color, currentColor);
opacity: 0.4; opacity: 0.4;
opacity: var(--fa-secondary-opacity, 0.4); } opacity: var(--fa-secondary-opacity, 0.4); }
.svg-inline--fa.fa-swap-opacity .fa-primary { .svg-inline--fa.fa-swap-opacity .fa-primary {
opacity: 0.4; opacity: 0.4;
opacity: var(--fa-secondary-opacity, 0.4); } opacity: var(--fa-secondary-opacity, 0.4); }
.svg-inline--fa.fa-swap-opacity .fa-secondary { .svg-inline--fa.fa-swap-opacity .fa-secondary {
opacity: 1; opacity: 1;
opacity: var(--fa-primary-opacity, 1); } opacity: var(--fa-primary-opacity, 1); }
.svg-inline--fa mask .fa-primary, .svg-inline--fa mask .fa-primary,
.svg-inline--fa mask .fa-secondary { .svg-inline--fa mask .fa-secondary {
fill: black; } fill: black; }
.fad.fa-inverse { .fad.fa-inverse {
color: #fff; } color: #fff; }

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,23 +1,23 @@
/*! /*!
* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/ */
@import 'variables'; @import 'variables';
@font-face { @font-face {
font-family: 'Font Awesome 5 Free'; font-family: 'Font Awesome 5 Free';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-display: $fa-font-display; font-display: $fa-font-display;
src: url('#{$fa-font-path}/fa-regular-400.eot'); src: url('#{$fa-font-path}/fa-regular-400.eot');
src: url('#{$fa-font-path}/fa-regular-400.eot?#iefix') format('embedded-opentype'), src: url('#{$fa-font-path}/fa-regular-400.eot?#iefix') format('embedded-opentype'),
url('#{$fa-font-path}/fa-regular-400.woff2') format('woff2'), url('#{$fa-font-path}/fa-regular-400.woff2') format('woff2'),
url('#{$fa-font-path}/fa-regular-400.woff') format('woff'), url('#{$fa-font-path}/fa-regular-400.woff') format('woff'),
url('#{$fa-font-path}/fa-regular-400.ttf') format('truetype'), url('#{$fa-font-path}/fa-regular-400.ttf') format('truetype'),
url('#{$fa-font-path}/fa-regular-400.svg#fontawesome') format('svg'); url('#{$fa-font-path}/fa-regular-400.svg#fontawesome') format('svg');
} }
.far { .far {
font-family: 'Font Awesome 5 Free'; font-family: 'Font Awesome 5 Free';
font-weight: 400; font-weight: 400;
} }

View file

@ -1,24 +1,24 @@
/*! /*!
* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/ */
@import 'variables'; @import 'variables';
@font-face { @font-face {
font-family: 'Font Awesome 5 Free'; font-family: 'Font Awesome 5 Free';
font-style: normal; font-style: normal;
font-weight: 900; font-weight: 900;
font-display: $fa-font-display; font-display: $fa-font-display;
src: url('#{$fa-font-path}/fa-solid-900.eot'); src: url('#{$fa-font-path}/fa-solid-900.eot');
src: url('#{$fa-font-path}/fa-solid-900.eot?#iefix') format('embedded-opentype'), src: url('#{$fa-font-path}/fa-solid-900.eot?#iefix') format('embedded-opentype'),
url('#{$fa-font-path}/fa-solid-900.woff2') format('woff2'), url('#{$fa-font-path}/fa-solid-900.woff2') format('woff2'),
url('#{$fa-font-path}/fa-solid-900.woff') format('woff'), url('#{$fa-font-path}/fa-solid-900.woff') format('woff'),
url('#{$fa-font-path}/fa-solid-900.ttf') format('truetype'), url('#{$fa-font-path}/fa-solid-900.ttf') format('truetype'),
url('#{$fa-font-path}/fa-solid-900.svg#fontawesome') format('svg'); url('#{$fa-font-path}/fa-solid-900.svg#fontawesome') format('svg');
} }
.fa, .fa,
.fas { .fas {
font-family: 'Font Awesome 5 Free'; font-family: 'Font Awesome 5 Free';
font-weight: 900; font-weight: 900;
} }

View file

@ -1,6 +1,6 @@
/*! /*!
* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/ */
@import 'variables'; @import 'variables';
@import 'shims'; @import 'shims';

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 460 KiB

After

Width:  |  Height:  |  Size: 461 KiB

Before After
Before After

View file

@ -1,102 +1,102 @@
'use strict'; 'use strict';
const Assert = require('./assert'); const Assert = require('./assert');
const Clone = require('./clone'); const Clone = require('./clone');
const Merge = require('./merge'); const Merge = require('./merge');
const Reach = require('./reach'); const Reach = require('./reach');
const internals = {}; const internals = {};
module.exports = function (defaults, source, options = {}) { module.exports = function (defaults, source, options = {}) {
Assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object'); Assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object');
Assert(!source || source === true || typeof source === 'object', 'Invalid source value: must be true, falsy or an object'); Assert(!source || source === true || typeof source === 'object', 'Invalid source value: must be true, falsy or an object');
Assert(typeof options === 'object', 'Invalid options: must be an object'); Assert(typeof options === 'object', 'Invalid options: must be an object');
if (!source) { // If no source, return null if (!source) { // If no source, return null
return null; return null;
} }
if (options.shallow) { if (options.shallow) {
return internals.applyToDefaultsWithShallow(defaults, source, options); return internals.applyToDefaultsWithShallow(defaults, source, options);
} }
const copy = Clone(defaults); const copy = Clone(defaults);
if (source === true) { // If source is set to true, use defaults if (source === true) { // If source is set to true, use defaults
return copy; return copy;
} }
const nullOverride = options.nullOverride !== undefined ? options.nullOverride : false; const nullOverride = options.nullOverride !== undefined ? options.nullOverride : false;
return Merge(copy, source, { nullOverride, mergeArrays: false }); return Merge(copy, source, { nullOverride, mergeArrays: false });
}; };
internals.applyToDefaultsWithShallow = function (defaults, source, options) { internals.applyToDefaultsWithShallow = function (defaults, source, options) {
const keys = options.shallow; const keys = options.shallow;
Assert(Array.isArray(keys), 'Invalid keys'); Assert(Array.isArray(keys), 'Invalid keys');
const seen = new Map(); const seen = new Map();
const merge = source === true ? null : new Set(); const merge = source === true ? null : new Set();
for (let key of keys) { for (let key of keys) {
key = Array.isArray(key) ? key : key.split('.'); // Pre-split optimization key = Array.isArray(key) ? key : key.split('.'); // Pre-split optimization
const ref = Reach(defaults, key); const ref = Reach(defaults, key);
if (ref && if (ref &&
typeof ref === 'object') { typeof ref === 'object') {
seen.set(ref, merge && Reach(source, key) || ref); seen.set(ref, merge && Reach(source, key) || ref);
} }
else if (merge) { else if (merge) {
merge.add(key); merge.add(key);
} }
} }
const copy = Clone(defaults, {}, seen); const copy = Clone(defaults, {}, seen);
if (!merge) { if (!merge) {
return copy; return copy;
} }
for (const key of merge) { for (const key of merge) {
internals.reachCopy(copy, source, key); internals.reachCopy(copy, source, key);
} }
const nullOverride = options.nullOverride !== undefined ? options.nullOverride : false; const nullOverride = options.nullOverride !== undefined ? options.nullOverride : false;
return Merge(copy, source, { nullOverride, mergeArrays: false }); return Merge(copy, source, { nullOverride, mergeArrays: false });
}; };
internals.reachCopy = function (dst, src, path) { internals.reachCopy = function (dst, src, path) {
for (const segment of path) { for (const segment of path) {
if (!(segment in src)) { if (!(segment in src)) {
return; return;
} }
const val = src[segment]; const val = src[segment];
if (typeof val !== 'object' || val === null) { if (typeof val !== 'object' || val === null) {
return; return;
} }
src = val; src = val;
} }
const value = src; const value = src;
let ref = dst; let ref = dst;
for (let i = 0; i < path.length - 1; ++i) { for (let i = 0; i < path.length - 1; ++i) {
const segment = path[i]; const segment = path[i];
if (typeof ref[segment] !== 'object') { if (typeof ref[segment] !== 'object') {
ref[segment] = {}; ref[segment] = {};
} }
ref = ref[segment]; ref = ref[segment];
} }
ref[path[path.length - 1]] = value; ref[path[path.length - 1]] = value;
}; };

View file

@ -1,21 +1,21 @@
'use strict'; 'use strict';
const AssertError = require('./error'); const AssertError = require('./error');
const internals = {}; const internals = {};
module.exports = function (condition, ...args) { module.exports = function (condition, ...args) {
if (condition) { if (condition) {
return; return;
} }
if (args.length === 1 && if (args.length === 1 &&
args[0] instanceof Error) { args[0] instanceof Error) {
throw args[0]; throw args[0];
} }
throw new AssertError(args); throw new AssertError(args);
}; };

58
node_modules/@hapi/hoek/lib/bench.js generated vendored
View file

@ -1,29 +1,29 @@
'use strict'; 'use strict';
const internals = {}; const internals = {};
module.exports = internals.Bench = class { module.exports = internals.Bench = class {
constructor() { constructor() {
this.ts = 0; this.ts = 0;
this.reset(); this.reset();
} }
reset() { reset() {
this.ts = internals.Bench.now(); this.ts = internals.Bench.now();
} }
elapsed() { elapsed() {
return internals.Bench.now() - this.ts; return internals.Bench.now() - this.ts;
} }
static now() { static now() {
const ts = process.hrtime(); const ts = process.hrtime();
return (ts[0] * 1e3) + (ts[1] / 1e6); return (ts[0] * 1e3) + (ts[1] / 1e6);
} }
}; };

24
node_modules/@hapi/hoek/lib/block.js generated vendored
View file

@ -1,12 +1,12 @@
'use strict'; 'use strict';
const Ignore = require('./ignore'); const Ignore = require('./ignore');
const internals = {}; const internals = {};
module.exports = function () { module.exports = function () {
return new Promise(Ignore); return new Promise(Ignore);
}; };

352
node_modules/@hapi/hoek/lib/clone.js generated vendored
View file

@ -1,176 +1,176 @@
'use strict'; 'use strict';
const Reach = require('./reach'); const Reach = require('./reach');
const Types = require('./types'); const Types = require('./types');
const Utils = require('./utils'); const Utils = require('./utils');
const internals = { const internals = {
needsProtoHack: new Set([Types.set, Types.map, Types.weakSet, Types.weakMap]) needsProtoHack: new Set([Types.set, Types.map, Types.weakSet, Types.weakMap])
}; };
module.exports = internals.clone = function (obj, options = {}, _seen = null) { module.exports = internals.clone = function (obj, options = {}, _seen = null) {
if (typeof obj !== 'object' || if (typeof obj !== 'object' ||
obj === null) { obj === null) {
return obj; return obj;
} }
let clone = internals.clone; let clone = internals.clone;
let seen = _seen; let seen = _seen;
if (options.shallow) { if (options.shallow) {
if (options.shallow !== true) { if (options.shallow !== true) {
return internals.cloneWithShallow(obj, options); return internals.cloneWithShallow(obj, options);
} }
clone = (value) => value; clone = (value) => value;
} }
else if (seen) { else if (seen) {
const lookup = seen.get(obj); const lookup = seen.get(obj);
if (lookup) { if (lookup) {
return lookup; return lookup;
} }
} }
else { else {
seen = new Map(); seen = new Map();
} }
// Built-in object types // Built-in object types
const baseProto = Types.getInternalProto(obj); const baseProto = Types.getInternalProto(obj);
if (baseProto === Types.buffer) { if (baseProto === Types.buffer) {
return Buffer && Buffer.from(obj); // $lab:coverage:ignore$ return Buffer && Buffer.from(obj); // $lab:coverage:ignore$
} }
if (baseProto === Types.date) { if (baseProto === Types.date) {
return new Date(obj.getTime()); return new Date(obj.getTime());
} }
if (baseProto === Types.regex) { if (baseProto === Types.regex) {
return new RegExp(obj); return new RegExp(obj);
} }
// Generic objects // Generic objects
const newObj = internals.base(obj, baseProto, options); const newObj = internals.base(obj, baseProto, options);
if (newObj === obj) { if (newObj === obj) {
return obj; return obj;
} }
if (seen) { if (seen) {
seen.set(obj, newObj); // Set seen, since obj could recurse seen.set(obj, newObj); // Set seen, since obj could recurse
} }
if (baseProto === Types.set) { if (baseProto === Types.set) {
for (const value of obj) { for (const value of obj) {
newObj.add(clone(value, options, seen)); newObj.add(clone(value, options, seen));
} }
} }
else if (baseProto === Types.map) { else if (baseProto === Types.map) {
for (const [key, value] of obj) { for (const [key, value] of obj) {
newObj.set(key, clone(value, options, seen)); newObj.set(key, clone(value, options, seen));
} }
} }
const keys = Utils.keys(obj, options); const keys = Utils.keys(obj, options);
for (const key of keys) { for (const key of keys) {
if (key === '__proto__') { if (key === '__proto__') {
continue; continue;
} }
if (baseProto === Types.array && if (baseProto === Types.array &&
key === 'length') { key === 'length') {
newObj.length = obj.length; newObj.length = obj.length;
continue; continue;
} }
const descriptor = Object.getOwnPropertyDescriptor(obj, key); const descriptor = Object.getOwnPropertyDescriptor(obj, key);
if (descriptor) { if (descriptor) {
if (descriptor.get || if (descriptor.get ||
descriptor.set) { descriptor.set) {
Object.defineProperty(newObj, key, descriptor); Object.defineProperty(newObj, key, descriptor);
} }
else if (descriptor.enumerable) { else if (descriptor.enumerable) {
newObj[key] = clone(obj[key], options, seen); newObj[key] = clone(obj[key], options, seen);
} }
else { else {
Object.defineProperty(newObj, key, { enumerable: false, writable: true, configurable: true, value: clone(obj[key], options, seen) }); Object.defineProperty(newObj, key, { enumerable: false, writable: true, configurable: true, value: clone(obj[key], options, seen) });
} }
} }
else { else {
Object.defineProperty(newObj, key, { Object.defineProperty(newObj, key, {
enumerable: true, enumerable: true,
writable: true, writable: true,
configurable: true, configurable: true,
value: clone(obj[key], options, seen) value: clone(obj[key], options, seen)
}); });
} }
} }
return newObj; return newObj;
}; };
internals.cloneWithShallow = function (source, options) { internals.cloneWithShallow = function (source, options) {
const keys = options.shallow; const keys = options.shallow;
options = Object.assign({}, options); options = Object.assign({}, options);
options.shallow = false; options.shallow = false;
const seen = new Map(); const seen = new Map();
for (const key of keys) { for (const key of keys) {
const ref = Reach(source, key); const ref = Reach(source, key);
if (typeof ref === 'object' || if (typeof ref === 'object' ||
typeof ref === 'function') { typeof ref === 'function') {
seen.set(ref, ref); seen.set(ref, ref);
} }
} }
return internals.clone(source, options, seen); return internals.clone(source, options, seen);
}; };
internals.base = function (obj, baseProto, options) { internals.base = function (obj, baseProto, options) {
if (options.prototype === false) { // Defaults to true if (options.prototype === false) { // Defaults to true
if (internals.needsProtoHack.has(baseProto)) { if (internals.needsProtoHack.has(baseProto)) {
return new baseProto.constructor(); return new baseProto.constructor();
} }
return baseProto === Types.array ? [] : {}; return baseProto === Types.array ? [] : {};
} }
const proto = Object.getPrototypeOf(obj); const proto = Object.getPrototypeOf(obj);
if (proto && if (proto &&
proto.isImmutable) { proto.isImmutable) {
return obj; return obj;
} }
if (baseProto === Types.array) { if (baseProto === Types.array) {
const newObj = []; const newObj = [];
if (proto !== baseProto) { if (proto !== baseProto) {
Object.setPrototypeOf(newObj, proto); Object.setPrototypeOf(newObj, proto);
} }
return newObj; return newObj;
} }
if (internals.needsProtoHack.has(baseProto)) { if (internals.needsProtoHack.has(baseProto)) {
const newObj = new proto.constructor(); const newObj = new proto.constructor();
if (proto !== baseProto) { if (proto !== baseProto) {
Object.setPrototypeOf(newObj, proto); Object.setPrototypeOf(newObj, proto);
} }
return newObj; return newObj;
} }
return Object.create(proto); return Object.create(proto);
}; };

View file

@ -1,49 +1,49 @@
Copyright Brightcove, Inc. Copyright Brightcove, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
The AES decryption implementation in this project is derived from the The AES decryption implementation in this project is derived from the
Stanford Javascript Cryptography Library Stanford Javascript Cryptography Library
(http://bitwiseshiftleft.github.io/sjcl/). That work is covered by the (http://bitwiseshiftleft.github.io/sjcl/). That work is covered by the
following copyright and permission notice: following copyright and permission notice:
Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh. Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
met: met:
1. Redistributions of source code must retain the above copyright 1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above 2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided disclaimer in the documentation and/or other materials provided
with the distribution. with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation The views and conclusions contained in the software and documentation
are those of the authors and should not be interpreted as representing are those of the authors and should not be interpreted as representing
official policies, either expressed or implied, of the authors. official policies, either expressed or implied, of the authors.

File diff suppressed because it is too large Load diff

View file

@ -1,246 +1,246 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>videojs-http-streaming Demo</title> <title>videojs-http-streaming Demo</title>
<link rel="icon" href="logo.svg"> <link rel="icon" href="logo.svg">
<link href="node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet"> <link href="node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet">
<link href="node_modules/video.js/dist/video-js.css" rel="stylesheet"> <link href="node_modules/video.js/dist/video-js.css" rel="stylesheet">
<link href="node_modules/videojs-http-source-selector/dist/videojs-http-source-selector.css" rel="stylesheet"> <link href="node_modules/videojs-http-source-selector/dist/videojs-http-source-selector.css" rel="stylesheet">
<style> <style>
.form-check { .form-check {
background-color: hsl(0, 0%, 90%); background-color: hsl(0, 0%, 90%);
margin-block: 0.5rem; margin-block: 0.5rem;
padding: 0.25em 0.25em 0.25em 1.75em; padding: 0.25em 0.25em 0.25em 1.75em;
width: 700px; width: 700px;
width: fit-content; width: fit-content;
} }
#player-fixture { #player-fixture {
min-height: 250px; min-height: 250px;
} }
#segment-metadata { #segment-metadata {
list-style: none; list-style: none;
} }
#segment-metadata pre { #segment-metadata pre {
overflow: scroll; overflow: scroll;
} }
</style> </style>
</head> </head>
<body class="m-4"> <body class="m-4">
<script> <script>
// if we're on IE, load up the load index page // if we're on IE, load up the load index page
var result = (/MSIE\s(\d+)\.\d/).exec(navigator.userAgent); var result = (/MSIE\s(\d+)\.\d/).exec(navigator.userAgent);
var version = result && parseFloat(result[1]); var version = result && parseFloat(result[1]);
if (!version && (/Trident\/7.0/i).test(navigator.userAgent) && (/rv:11.0/).test(navigator.userAgent)) { if (!version && (/Trident\/7.0/i).test(navigator.userAgent) && (/rv:11.0/).test(navigator.userAgent)) {
// IE 11 has a different user agent string than other IE versions // IE 11 has a different user agent string than other IE versions
version = 11.0; version = 11.0;
} }
if (version) { if (version) {
window.location.href = './old-index.html'; window.location.href = './old-index.html';
} }
</script> </script>
<header class="container-fluid"> <header class="container-fluid">
<a href="https://github.com/videojs/http-streaming" class="d-flex align-items-center pb-3 mb-5 border-bottom" style="height: 4em"> <a href="https://github.com/videojs/http-streaming" class="d-flex align-items-center pb-3 mb-5 border-bottom" style="height: 4em">
<img src="./logo.svg" alt="VHS logo showcasing a VHS tape with the Video.js logo on the label" class="rounded mh-100"> <img src="./logo.svg" alt="VHS logo showcasing a VHS tape with the Video.js logo on the label" class="rounded mh-100">
<span class="fs-1 ps-2">VHS: videojs-http-streaming</span> <span class="fs-1 ps-2">VHS: videojs-http-streaming</span>
</a> </a>
</header> </header>
<div id="player-fixture" class="container-fluid pb-3 mb-3"></div> <div id="player-fixture" class="container-fluid pb-3 mb-3"></div>
<ul class="nav nav-tabs container-fluid mb-3" id="myTab" role="tablist"> <ul class="nav nav-tabs container-fluid mb-3" id="myTab" role="tablist">
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-target="#sources" type="button" role="tab" aria-selected="true">Sources</button> <button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-target="#sources" type="button" role="tab" aria-selected="true">Sources</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link" id="contact-tab" data-bs-toggle="tab" data-bs-target="#options" type="button" role="tab" aria-selected="false">Options</button> <button class="nav-link" id="contact-tab" data-bs-toggle="tab" data-bs-target="#options" type="button" role="tab" aria-selected="false">Options</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-target="#levels" type="button" role="tab" aria-selected="false">Representations</button> <button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-target="#levels" type="button" role="tab" aria-selected="false">Representations</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-target="#player-stats" type="button" role="tab" aria-selected="false">Player Stats</button> <button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-target="#player-stats" type="button" role="tab" aria-selected="false">Player Stats</button>
</li> </li>
</ul> </ul>
<div class="tab-content container-fluid"> <div class="tab-content container-fluid">
<div class="tab-pane active" id="sources" role="tabpanel"> <div class="tab-pane active" id="sources" role="tabpanel">
<div class="input-group mb-2"> <div class="input-group mb-2">
<span class="input-group-text"><label for=load-source>Preloaded Sources</label></span> <span class="input-group-text"><label for=load-source>Preloaded Sources</label></span>
<select id=load-source class="form-select"> <select id=load-source class="form-select">
<optgroup label="hls"> <optgroup label="hls">
</optgroup> </optgroup>
<optgroup label="dash"> <optgroup label="dash">
</optgroup> </optgroup>
<optgroup label="drm"> <optgroup label="drm">
</optgroup> </optgroup>
<optgroup label="live"> <optgroup label="live">
</optgroup> </optgroup>
<optgroup label="low latency live"> <optgroup label="low latency live">
</optgroup> </optgroup>
<optgroup label="json manifest object"> <optgroup label="json manifest object">
</optgroup> </optgroup>
</select> </select>
</div> </div>
<label for=url class="form-label">Source URL</label> <label for=url class="form-label">Source URL</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-text"><label for=url>Url</label></span> <span class="input-group-text"><label for=url>Url</label></span>
<input id=url type=url class="form-control"> <input id=url type=url class="form-control">
</div> </div>
<label for=type class="form-label">Source Type (uses url extension if blank, usually application/x-mpegURL or application/dash+xml)</label> <label for=type class="form-label">Source Type (uses url extension if blank, usually application/x-mpegURL or application/dash+xml)</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-text"><label for=type>Type</label></span> <span class="input-group-text"><label for=type>Type</label></span>
<input id=type type=text class="form-control"> <input id=type type=text class="form-control">
</div> </div>
<label for="keysystems" class="form-label">Optional Keystems JSON:</label> <label for="keysystems" class="form-label">Optional Keystems JSON:</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-text"><label for=keysystems>keySystems JSON</label></span> <span class="input-group-text"><label for=keysystems>keySystems JSON</label></span>
<textarea id=keysystems cols=100 rows=5 class="form-control"></textarea> <textarea id=keysystems cols=100 rows=5 class="form-control"></textarea>
</div> </div>
<button id=load-url type=button class="btn btn-primary my-2">Load</button> <button id=load-url type=button class="btn btn-primary my-2">Load</button>
</div> </div>
<div class="tab-pane" id="options" role="tabpanel"> <div class="tab-pane" id="options" role="tabpanel">
<div class="options"> <div class="options">
<div class="form-check"> <div class="form-check">
<input id=minified type="checkbox" class="form-check-input"> <input id=minified type="checkbox" class="form-check-input">
<label class="form-check-label" for="minified">Minified VHS (reloads player)</label> <label class="form-check-label" for="minified">Minified VHS (reloads player)</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=sync-workers type="checkbox" class="form-check-input"> <input id=sync-workers type="checkbox" class="form-check-input">
<label class="form-check-label" for="sync-workers">Synchronous Web Workers (reloads player)</label> <label class="form-check-label" for="sync-workers">Synchronous Web Workers (reloads player)</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=liveui type="checkbox" class="form-check-input" checked> <input id=liveui type="checkbox" class="form-check-input" checked>
<label class="form-check-label" for="liveui">Enable the live UI (reloads player)</label> <label class="form-check-label" for="liveui">Enable the live UI (reloads player)</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=fluid type="checkbox" class="form-check-input"> <input id=fluid type="checkbox" class="form-check-input">
<label class="form-check-label" for="fluid">Fluid mode</label> <label class="form-check-label" for="fluid">Fluid mode</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=debug type="checkbox" class="form-check-input"> <input id=debug type="checkbox" class="form-check-input">
<label class="form-check-label" for="debug">Debug Logging</label> <label class="form-check-label" for="debug">Debug Logging</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=muted type="checkbox" class="form-check-input"> <input id=muted type="checkbox" class="form-check-input">
<label class="form-check-label" for="muted">Muted</label> <label class="form-check-label" for="muted">Muted</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=autoplay type="checkbox" class="form-check-input"> <input id=autoplay type="checkbox" class="form-check-input">
<label class="form-check-label" for="autoplay">Autoplay</label> <label class="form-check-label" for="autoplay">Autoplay</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=llhls type="checkbox" class="form-check-input"> <input id=llhls type="checkbox" class="form-check-input">
<label class="form-check-label" for="llhls">[EXPERIMENTAL] Enables support for ll-hls (reloads player)</label> <label class="form-check-label" for="llhls">[EXPERIMENTAL] Enables support for ll-hls (reloads player)</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=buffer-water type="checkbox" class="form-check-input"> <input id=buffer-water type="checkbox" class="form-check-input">
<label class="form-check-label" for="buffer-water">[EXPERIMENTAL] Use Buffer Level for ABR (reloads player)</label> <label class="form-check-label" for="buffer-water">[EXPERIMENTAL] Use Buffer Level for ABR (reloads player)</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=exact-manifest-timings type="checkbox" class="form-check-input"> <input id=exact-manifest-timings type="checkbox" class="form-check-input">
<label class="form-check-label" for="exact-manifest-timings">[EXPERIMENTAL] Use exact manifest timings for segment choices (reloads player)</label> <label class="form-check-label" for="exact-manifest-timings">[EXPERIMENTAL] Use exact manifest timings for segment choices (reloads player)</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=pixel-diff-selector type="checkbox" class="form-check-input"> <input id=pixel-diff-selector type="checkbox" class="form-check-input">
<label class="form-check-label" for="pixel-diff-selector">[EXPERIMENTAL] Use the Pixel difference resolution selector (reloads player)</label> <label class="form-check-label" for="pixel-diff-selector">[EXPERIMENTAL] Use the Pixel difference resolution selector (reloads player)</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=override-native type="checkbox" class="form-check-input" checked> <input id=override-native type="checkbox" class="form-check-input" checked>
<label class="form-check-label" for="override-native">Override Native (reloads player)</label> <label class="form-check-label" for="override-native">Override Native (reloads player)</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input id=mirror-source type="checkbox" class="form-check-input" checked> <input id=mirror-source type="checkbox" class="form-check-input" checked>
<label class="form-check-label" for="mirror-source">Mirror sources from player.src (reloads player, uses EXPERIMENTAL sourceset option)</label> <label class="form-check-label" for="mirror-source">Mirror sources from player.src (reloads player, uses EXPERIMENTAL sourceset option)</label>
</div> </div>
<div class="input-group"> <div class="input-group">
<span class="input-group-text"><label for=preload>Preload (reloads player)</label></span> <span class="input-group-text"><label for=preload>Preload (reloads player)</label></span>
<select id=preload class="form-select"> <select id=preload class="form-select">
<option selected>auto</option> <option selected>auto</option>
<option>none</option> <option>none</option>
<option>metadata</option> <option>metadata</option>
</select> </select>
</div> </div>
</div> </div>
</div> </div>
<div class="tab-pane" id="levels" role="tabpanel"> <div class="tab-pane" id="levels" role="tabpanel">
<div class="input-group"> <div class="input-group">
<span class="input-group-text"><label for=representations>Representations</label></span> <span class="input-group-text"><label for=representations>Representations</label></span>
<select id='representations' class="form-select"></select> <select id='representations' class="form-select"></select>
</div> </div>
</div> </div>
<div class="tab-pane" id="player-stats" role="tabpanel"> <div class="tab-pane" id="player-stats" role="tabpanel">
<div class="row"> <div class="row">
<div class="player-stats col-4"> <div class="player-stats col-4">
<dl> <dl>
<dt>Current Time:</dt> <dt>Current Time:</dt>
<dd class="current-time-stat">0</dd> <dd class="current-time-stat">0</dd>
<dt>Buffered:</dt> <dt>Buffered:</dt>
<dd class="buffered-stat">-</dd> <dd class="buffered-stat">-</dd>
<dt>Video Buffered:</dt> <dt>Video Buffered:</dt>
<dd class="video-buffered-stat">-</dd> <dd class="video-buffered-stat">-</dd>
<dt>Audio Buffered:</dt> <dt>Audio Buffered:</dt>
<dd class="audio-buffered-stat">-</dd> <dd class="audio-buffered-stat">-</dd>
<dt>Seekable:</dt> <dt>Seekable:</dt>
<dd><span class="seekable-start-stat">-</span> - <span class="seekable-end-stat">-</span></dd> <dd><span class="seekable-start-stat">-</span> - <span class="seekable-end-stat">-</span></dd>
<dt>Video Bitrate:</dt> <dt>Video Bitrate:</dt>
<dd class="video-bitrate-stat">0 kbps</dd> <dd class="video-bitrate-stat">0 kbps</dd>
<dt>Measured Bitrate:</dt> <dt>Measured Bitrate:</dt>
<dd class="measured-bitrate-stat">0 kbps</dd> <dd class="measured-bitrate-stat">0 kbps</dd>
<dt>Video Timestamp Offset</dt> <dt>Video Timestamp Offset</dt>
<dd class="video-timestampoffset">0</dd> <dd class="video-timestampoffset">0</dd>
<dt>Audio Timestamp Offset</dt> <dt>Audio Timestamp Offset</dt>
<dd class="audio-timestampoffset">0</dd> <dd class="audio-timestampoffset">0</dd>
</dl> </dl>
</div> </div>
<ul id="segment-metadata" class="col-8"></ul> <ul id="segment-metadata" class="col-8"></ul>
</div> </div>
</div> </div>
</div> </div>
<footer class="text-center p-3" id=unit-test-link> <footer class="text-center p-3" id=unit-test-link>
<a href="test/debug.html">Run unit tests</a> <a href="test/debug.html">Run unit tests</a>
</footer> </footer>
<script> <script>
var unitTestLink = document.getElementById('unit-test-link'); var unitTestLink = document.getElementById('unit-test-link');
// removal test run link on netlify, as we cannot run tests there. // removal test run link on netlify, as we cannot run tests there.
if ((/netlify.app/).test(window.location.host)) { if ((/netlify.app/).test(window.location.host)) {
unitTestLink.remove(); unitTestLink.remove();
} }
</script> </script>
<script src="node_modules/bootstrap/dist/js/bootstrap.js"></script> <script src="node_modules/bootstrap/dist/js/bootstrap.js"></script>
<script src="scripts/index.js"></script> <script src="scripts/index.js"></script>
<script> <script>
window.startDemo(function(player) { window.startDemo(function(player) {
// do something with setup player // do something with setup player
}); });
</script> </script>
</body> </body>
</html> </html>

View file

@ -1,150 +1,150 @@
<a name="3.0.3"></a> <a name="3.0.3"></a>
## [3.0.3](https://github.com/videojs/vhs-utils/compare/v3.0.2...v3.0.3) (2021-07-26) ## [3.0.3](https://github.com/videojs/vhs-utils/compare/v3.0.2...v3.0.3) (2021-07-26)
### Bug Fixes ### Bug Fixes
* detect mp4 starting with moof/moov box as mp4 ([#29](https://github.com/videojs/vhs-utils/issues/29)) ([51d995d](https://github.com/videojs/vhs-utils/commit/51d995d)) * detect mp4 starting with moof/moov box as mp4 ([#29](https://github.com/videojs/vhs-utils/issues/29)) ([51d995d](https://github.com/videojs/vhs-utils/commit/51d995d))
* look at all program map tables for ts stream types ([#28](https://github.com/videojs/vhs-utils/issues/28)) ([1edb519](https://github.com/videojs/vhs-utils/commit/1edb519)) * look at all program map tables for ts stream types ([#28](https://github.com/videojs/vhs-utils/issues/28)) ([1edb519](https://github.com/videojs/vhs-utils/commit/1edb519))
<a name="3.0.2"></a> <a name="3.0.2"></a>
## [3.0.2](https://github.com/videojs/vhs-utils/compare/v3.0.1...v3.0.2) (2021-05-20) ## [3.0.2](https://github.com/videojs/vhs-utils/compare/v3.0.1...v3.0.2) (2021-05-20)
### Bug Fixes ### Bug Fixes
* properly handle data URIs ([#27](https://github.com/videojs/vhs-utils/issues/27)) ([9b10245](https://github.com/videojs/vhs-utils/commit/9b10245)), closes [videojs/video.js#7240](https://github.com/videojs/video.js/issues/7240) * properly handle data URIs ([#27](https://github.com/videojs/vhs-utils/issues/27)) ([9b10245](https://github.com/videojs/vhs-utils/commit/9b10245)), closes [videojs/video.js#7240](https://github.com/videojs/video.js/issues/7240)
<a name="3.0.1"></a> <a name="3.0.1"></a>
## [3.0.1](https://github.com/videojs/vhs-utils/compare/v3.0.0...v3.0.1) (2021-04-29) ## [3.0.1](https://github.com/videojs/vhs-utils/compare/v3.0.0...v3.0.1) (2021-04-29)
### Bug Fixes ### Bug Fixes
* binary issues ([e9f5079](https://github.com/videojs/vhs-utils/commit/e9f5079)) * binary issues ([e9f5079](https://github.com/videojs/vhs-utils/commit/e9f5079))
### Chores ### Chores
* update vjsverify ([105c26a](https://github.com/videojs/vhs-utils/commit/105c26a)) * update vjsverify ([105c26a](https://github.com/videojs/vhs-utils/commit/105c26a))
### Performance Improvements ### Performance Improvements
* use native URL when available ([#26](https://github.com/videojs/vhs-utils/issues/26)) ([e7eaab9](https://github.com/videojs/vhs-utils/commit/e7eaab9)) * use native URL when available ([#26](https://github.com/videojs/vhs-utils/issues/26)) ([e7eaab9](https://github.com/videojs/vhs-utils/commit/e7eaab9))
<a name="3.0.0"></a> <a name="3.0.0"></a>
# [3.0.0](https://github.com/videojs/vhs-utils/compare/v2.3.0...v3.0.0) (2020-12-18) # [3.0.0](https://github.com/videojs/vhs-utils/compare/v2.3.0...v3.0.0) (2020-12-18)
### Features ### Features
* Extend our current container parsing logic and add logic for parsing codecs from files ([#14](https://github.com/videojs/vhs-utils/issues/14)) ([d425956](https://github.com/videojs/vhs-utils/commit/d425956)) * Extend our current container parsing logic and add logic for parsing codecs from files ([#14](https://github.com/videojs/vhs-utils/issues/14)) ([d425956](https://github.com/videojs/vhs-utils/commit/d425956))
* parse any number of codecs rather than just the last audio or the last video codec. ([#23](https://github.com/videojs/vhs-utils/issues/23)) ([33ec9f5](https://github.com/videojs/vhs-utils/commit/33ec9f5)) * parse any number of codecs rather than just the last audio or the last video codec. ([#23](https://github.com/videojs/vhs-utils/issues/23)) ([33ec9f5](https://github.com/videojs/vhs-utils/commit/33ec9f5))
* use [@videojs](https://github.com/videojs)/babel-config to transpile code to cjs/es for node ([#20](https://github.com/videojs/vhs-utils/issues/20)) ([c6dbd0b](https://github.com/videojs/vhs-utils/commit/c6dbd0b)) * use [@videojs](https://github.com/videojs)/babel-config to transpile code to cjs/es for node ([#20](https://github.com/videojs/vhs-utils/issues/20)) ([c6dbd0b](https://github.com/videojs/vhs-utils/commit/c6dbd0b))
### Chores ### Chores
* switch from travis to github ci ([#24](https://github.com/videojs/vhs-utils/issues/24)) ([cfee30b](https://github.com/videojs/vhs-utils/commit/cfee30b)) * switch from travis to github ci ([#24](https://github.com/videojs/vhs-utils/issues/24)) ([cfee30b](https://github.com/videojs/vhs-utils/commit/cfee30b))
### BREAKING CHANGES ### BREAKING CHANGES
* cjs dist files changed from './dist' to './cjs' * cjs dist files changed from './dist' to './cjs'
* parseCodecs now returns an array of codecs that where parsed so that we can support any number of codecs instead of just two. * parseCodecs now returns an array of codecs that where parsed so that we can support any number of codecs instead of just two.
* toUint8 in byte-helpers functions slightly differently * toUint8 in byte-helpers functions slightly differently
* getId3Offset is exported from id3-helpers rather than containers * getId3Offset is exported from id3-helpers rather than containers
We can now parse the container for and many of the codecs within (where applicable) for mp4, avi, ts, mkv, webm, ogg, wav, aac, ac3 (and ec3 which is contained in ac3 files), mp3, flac, raw h265, and raw h264. We can now parse the container for and many of the codecs within (where applicable) for mp4, avi, ts, mkv, webm, ogg, wav, aac, ac3 (and ec3 which is contained in ac3 files), mp3, flac, raw h265, and raw h264.
Codec parsing has also been extended to parse codec details in a file for vp09, avc (h264), hevc (h265), av1, and opus Codec parsing has also been extended to parse codec details in a file for vp09, avc (h264), hevc (h265), av1, and opus
Finally we have the following additional features to our parsing of codec/container information: Finally we have the following additional features to our parsing of codec/container information:
* skipping multiple id3 tags at the start of a file for flac, mp3, and aac * skipping multiple id3 tags at the start of a file for flac, mp3, and aac
* discarding emulation prevention bits (in h264, h265) * discarding emulation prevention bits (in h264, h265)
* parsing raw h264/h265 to get codec params for ts, avi, and even raw h264/h265 files * parsing raw h264/h265 to get codec params for ts, avi, and even raw h264/h265 files
<a name="2.3.0"></a> <a name="2.3.0"></a>
# [2.3.0](https://github.com/videojs/vhs-utils/compare/v2.2.1...v2.3.0) (2020-12-03) # [2.3.0](https://github.com/videojs/vhs-utils/compare/v2.2.1...v2.3.0) (2020-12-03)
### Features ### Features
* parse unknown and text codecs ([#19](https://github.com/videojs/vhs-utils/issues/19)) ([9c90076](https://github.com/videojs/vhs-utils/commit/9c90076)) * parse unknown and text codecs ([#19](https://github.com/videojs/vhs-utils/issues/19)) ([9c90076](https://github.com/videojs/vhs-utils/commit/9c90076))
### Chores ### Chores
* Add repository info to package.json ([#22](https://github.com/videojs/vhs-utils/issues/22)) ([a22ae78](https://github.com/videojs/vhs-utils/commit/a22ae78)) * Add repository info to package.json ([#22](https://github.com/videojs/vhs-utils/issues/22)) ([a22ae78](https://github.com/videojs/vhs-utils/commit/a22ae78))
<a name="2.2.1"></a> <a name="2.2.1"></a>
## [2.2.1](https://github.com/videojs/stream/compare/v2.2.0...v2.2.1) (2020-10-06) ## [2.2.1](https://github.com/videojs/stream/compare/v2.2.0...v2.2.1) (2020-10-06)
### Bug Fixes ### Bug Fixes
* check for multiple id3 sections in a file (#21) ([759a039](https://github.com/videojs/stream/commit/759a039)), closes [#21](https://github.com/videojs/stream/issues/21) * check for multiple id3 sections in a file (#21) ([759a039](https://github.com/videojs/stream/commit/759a039)), closes [#21](https://github.com/videojs/stream/issues/21)
* parse unknown codecs as audio or video (#15) ([cd2c9bb](https://github.com/videojs/stream/commit/cd2c9bb)), closes [#15](https://github.com/videojs/stream/issues/15) * parse unknown codecs as audio or video (#15) ([cd2c9bb](https://github.com/videojs/stream/commit/cd2c9bb)), closes [#15](https://github.com/videojs/stream/issues/15)
### Reverts ### Reverts
* "fix: parse unknown codecs as audio or video (#15)" (#18) ([9983be8](https://github.com/videojs/stream/commit/9983be8)), closes [#15](https://github.com/videojs/stream/issues/15) [#18](https://github.com/videojs/stream/issues/18) * "fix: parse unknown codecs as audio or video (#15)" (#18) ([9983be8](https://github.com/videojs/stream/commit/9983be8)), closes [#15](https://github.com/videojs/stream/issues/15) [#18](https://github.com/videojs/stream/issues/18)
<a name="2.2.0"></a> <a name="2.2.0"></a>
# [2.2.0](https://github.com/videojs/stream/compare/v2.1.0...v2.2.0) (2020-05-01) # [2.2.0](https://github.com/videojs/stream/compare/v2.1.0...v2.2.0) (2020-05-01)
### Features ### Features
* Add a function to concat typed arrays into one Uint8Array (#13) ([e733509](https://github.com/videojs/stream/commit/e733509)), closes [#13](https://github.com/videojs/stream/issues/13) * Add a function to concat typed arrays into one Uint8Array (#13) ([e733509](https://github.com/videojs/stream/commit/e733509)), closes [#13](https://github.com/videojs/stream/issues/13)
<a name="2.1.0"></a> <a name="2.1.0"></a>
# [2.1.0](https://github.com/videojs/stream/compare/v2.0.0...v2.1.0) (2020-04-27) # [2.1.0](https://github.com/videojs/stream/compare/v2.0.0...v2.1.0) (2020-04-27)
### Features ### Features
* Add functions for byte manipulation and segment container detection (#12) ([325f677](https://github.com/videojs/stream/commit/325f677)), closes [#12](https://github.com/videojs/stream/issues/12) * Add functions for byte manipulation and segment container detection (#12) ([325f677](https://github.com/videojs/stream/commit/325f677)), closes [#12](https://github.com/videojs/stream/issues/12)
<a name="2.0.0"></a> <a name="2.0.0"></a>
# [2.0.0](https://github.com/videojs/stream/compare/v1.3.0...v2.0.0) (2020-04-07) # [2.0.0](https://github.com/videojs/stream/compare/v1.3.0...v2.0.0) (2020-04-07)
### Features ### Features
* **codec:** changes to handle muxer/browser/video/audio support separately (#10) ([1f92865](https://github.com/videojs/stream/commit/1f92865)), closes [#10](https://github.com/videojs/stream/issues/10) * **codec:** changes to handle muxer/browser/video/audio support separately (#10) ([1f92865](https://github.com/videojs/stream/commit/1f92865)), closes [#10](https://github.com/videojs/stream/issues/10)
### Bug Fixes ### Bug Fixes
* Allow VP9 and AV1 codecs through in VHS ([b32e35b](https://github.com/videojs/stream/commit/b32e35b)) * Allow VP9 and AV1 codecs through in VHS ([b32e35b](https://github.com/videojs/stream/commit/b32e35b))
### BREAKING CHANGES ### BREAKING CHANGES
* **codec:** parseCodecs output has been changed. It now returns an object that can have an audio or video property, depending on the codecs found. Those properties are object that contain type. and details. Type being the codec name and details being codec specific information usually with a leading period. * **codec:** parseCodecs output has been changed. It now returns an object that can have an audio or video property, depending on the codecs found. Those properties are object that contain type. and details. Type being the codec name and details being codec specific information usually with a leading period.
* **codec:** `audioProfileFromDefault` has been renamed to `codecsFromDefault` and now returns all output from `parseCodecs` not just audio or audio profile. * **codec:** `audioProfileFromDefault` has been renamed to `codecsFromDefault` and now returns all output from `parseCodecs` not just audio or audio profile.
<a name="1.3.0"></a> <a name="1.3.0"></a>
# [1.3.0](https://github.com/videojs/vhs-utils/compare/v1.2.1...v1.3.0) (2020-02-05) # [1.3.0](https://github.com/videojs/vhs-utils/compare/v1.2.1...v1.3.0) (2020-02-05)
### Features ### Features
* add forEachMediaGroup in media-groups module (#8) ([a1eacf4](https://github.com/videojs/vhs-utils/commit/a1eacf4)), closes [#8](https://github.com/videojs/vhs-utils/issues/8) * add forEachMediaGroup in media-groups module (#8) ([a1eacf4](https://github.com/videojs/vhs-utils/commit/a1eacf4)), closes [#8](https://github.com/videojs/vhs-utils/issues/8)
<a name="1.2.1"></a> <a name="1.2.1"></a>
## [1.2.1](https://github.com/videojs/vhs-utils/compare/v1.2.0...v1.2.1) (2020-01-15) ## [1.2.1](https://github.com/videojs/vhs-utils/compare/v1.2.0...v1.2.1) (2020-01-15)
### Bug Fixes ### Bug Fixes
* include videojs in VHS JSON media type (#7) ([da072f0](https://github.com/videojs/vhs-utils/commit/da072f0)), closes [#7](https://github.com/videojs/vhs-utils/issues/7) * include videojs in VHS JSON media type (#7) ([da072f0](https://github.com/videojs/vhs-utils/commit/da072f0)), closes [#7](https://github.com/videojs/vhs-utils/issues/7)
<a name="1.2.0"></a> <a name="1.2.0"></a>
# [1.2.0](https://github.com/videojs/vhs-utils/compare/v1.1.0...v1.2.0) (2019-12-06) # [1.2.0](https://github.com/videojs/vhs-utils/compare/v1.1.0...v1.2.0) (2019-12-06)
### Features ### Features
* add media-types module with simpleTypeFromSourceType function (#4) ([d3ebd3f](https://github.com/videojs/vhs-utils/commit/d3ebd3f)), closes [#4](https://github.com/videojs/vhs-utils/issues/4) * add media-types module with simpleTypeFromSourceType function (#4) ([d3ebd3f](https://github.com/videojs/vhs-utils/commit/d3ebd3f)), closes [#4](https://github.com/videojs/vhs-utils/issues/4)
* add VHS codec parsing and translation functions (#5) ([4fe0e22](https://github.com/videojs/vhs-utils/commit/4fe0e22)), closes [#5](https://github.com/videojs/vhs-utils/issues/5) * add VHS codec parsing and translation functions (#5) ([4fe0e22](https://github.com/videojs/vhs-utils/commit/4fe0e22)), closes [#5](https://github.com/videojs/vhs-utils/issues/5)
<a name="1.1.0"></a> <a name="1.1.0"></a>
# [1.1.0](https://github.com/videojs/stream/compare/v1.0.0...v1.1.0) (2019-08-30) # [1.1.0](https://github.com/videojs/stream/compare/v1.0.0...v1.1.0) (2019-08-30)
### Features ### Features
* node support and more stream tests ([315ab8d](https://github.com/videojs/stream/commit/315ab8d)) * node support and more stream tests ([315ab8d](https://github.com/videojs/stream/commit/315ab8d))
<a name="1.0.0"></a> <a name="1.0.0"></a>
# 1.0.0 (2019-08-21) # 1.0.0 (2019-08-21)
### Features ### Features
* clones from mpd-parser, m3u8-parser, mux.js, aes-decrypter, and vhs ([5e89042](https://github.com/videojs/stream/commit/5e89042)) * clones from mpd-parser, m3u8-parser, mux.js, aes-decrypter, and vhs ([5e89042](https://github.com/videojs/stream/commit/5e89042))

View file

@ -1,30 +1,30 @@
# CONTRIBUTING # CONTRIBUTING
We welcome contributions from everyone! We welcome contributions from everyone!
## Getting Started ## Getting Started
Make sure you have Node.js 8 or higher and npm installed. Make sure you have Node.js 8 or higher and npm installed.
1. Fork this repository and clone your fork 1. Fork this repository and clone your fork
1. Install dependencies: `npm install` 1. Install dependencies: `npm install`
1. Run a development server: `npm start` 1. Run a development server: `npm start`
### Making Changes ### Making Changes
Refer to the [video.js plugin conventions][conventions] for more detail on best practices and tooling for video.js plugin authorship. Refer to the [video.js plugin conventions][conventions] for more detail on best practices and tooling for video.js plugin authorship.
When you've made your changes, push your commit(s) to your fork and issue a pull request against the original repository. When you've made your changes, push your commit(s) to your fork and issue a pull request against the original repository.
### Running Tests ### Running Tests
Testing is a crucial part of any software project. For all but the most trivial changes (typos, etc) test cases are expected. Tests are run in actual browsers using [Karma][karma]. Testing is a crucial part of any software project. For all but the most trivial changes (typos, etc) test cases are expected. Tests are run in actual browsers using [Karma][karma].
- In all available and supported browsers: `npm test` - In all available and supported browsers: `npm test`
- In a specific browser: `npm run test:chrome`, `npm run test:firefox`, etc. - In a specific browser: `npm run test:chrome`, `npm run test:firefox`, etc.
- While development server is running (`npm start`), navigate to [`http://localhost:9999/test/`][local] - While development server is running (`npm start`), navigate to [`http://localhost:9999/test/`][local]
[karma]: http://karma-runner.github.io/ [karma]: http://karma-runner.github.io/
[local]: http://localhost:9999/test/ [local]: http://localhost:9999/test/
[conventions]: https://github.com/videojs/generator-videojs-plugin/blob/master/docs/conventions.md [conventions]: https://github.com/videojs/generator-videojs-plugin/blob/master/docs/conventions.md

View file

@ -1,19 +1,19 @@
Copyright (c) brandonocasey <brandonocasey@gmail.com> Copyright (c) brandonocasey <brandonocasey@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

View file

@ -1,41 +1,41 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [@videojs/vhs-utils](#videojsvhs-utils) - [@videojs/vhs-utils](#videojsvhs-utils)
- [Installation](#installation) - [Installation](#installation)
- [Usage](#usage) - [Usage](#usage)
<!-- END doctoc generated TOC please keep comment here to allow auto update --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->
# @videojs/vhs-utils # @videojs/vhs-utils
vhs-utils serves two purposes: vhs-utils serves two purposes:
1. It extracts objects and functions shared throughout @videojs/http-streaming code to save on package size. See [the original @videojs/http-streaming PR](https://github.com/videojs/http-streaming/pull/637) for details. 1. It extracts objects and functions shared throughout @videojs/http-streaming code to save on package size. See [the original @videojs/http-streaming PR](https://github.com/videojs/http-streaming/pull/637) for details.
2. It exports generic functions from VHS that may be useful to plugin authors. 2. It exports generic functions from VHS that may be useful to plugin authors.
## Installation ## Installation
```sh ```sh
npm install --save @videojs/vhs-utils npm install --save @videojs/vhs-utils
``` ```
## Usage ## Usage
All utility functions are published under dist and can be required/imported like so: All utility functions are published under dist and can be required/imported like so:
> es import using es dist > es import using es dist
```js ```js
import resolveUrl from '@videojs/vhs-utils/es/resolve-url'; import resolveUrl from '@videojs/vhs-utils/es/resolve-url';
``` ```
> cjs import using cjs dist > cjs import using cjs dist
```js ```js
const resolveUrl = require('@videojs/vhs-utils/cjs/resolve-url'); const resolveUrl = require('@videojs/vhs-utils/cjs/resolve-url');
``` ```
> depricated cjs dist > depricated cjs dist
```js ```js
const resolveUrl = require('@videojs/vhs-utils/dist/resolve-url'); const resolveUrl = require('@videojs/vhs-utils/dist/resolve-url');
``` ```

View file

@ -1,323 +1,323 @@
"use strict"; "use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "__esModule", {
value: true value: true
}); });
exports.reverseBytes = exports.sliceBytes = exports.bytesMatch = exports.concatTypedArrays = exports.stringToBytes = exports.bytesToString = exports.numberToBytes = exports.bytesToNumber = exports.IS_LITTLE_ENDIAN = exports.IS_BIG_ENDIAN = exports.ENDIANNESS = exports.toBinaryString = exports.toHexString = exports.toUint8 = exports.isTypedArray = exports.padStart = exports.countBytes = exports.countBits = void 0; exports.reverseBytes = exports.sliceBytes = exports.bytesMatch = exports.concatTypedArrays = exports.stringToBytes = exports.bytesToString = exports.numberToBytes = exports.bytesToNumber = exports.IS_LITTLE_ENDIAN = exports.IS_BIG_ENDIAN = exports.ENDIANNESS = exports.toBinaryString = exports.toHexString = exports.toUint8 = exports.isTypedArray = exports.padStart = exports.countBytes = exports.countBits = void 0;
var _window = _interopRequireDefault(require("global/window")); var _window = _interopRequireDefault(require("global/window"));
// const log2 = Math.log2 ? Math.log2 : (x) => (Math.log(x) / Math.log(2)); // const log2 = Math.log2 ? Math.log2 : (x) => (Math.log(x) / Math.log(2));
var repeat = function repeat(str, len) { var repeat = function repeat(str, len) {
var acc = ''; var acc = '';
while (len--) { while (len--) {
acc += str; acc += str;
} }
return acc; return acc;
}; // count the number of bits it would take to represent a number }; // count the number of bits it would take to represent a number
// we used to do this with log2 but BigInt does not support builtin math // we used to do this with log2 but BigInt does not support builtin math
// Math.ceil(log2(x)); // Math.ceil(log2(x));
var countBits = function countBits(x) { var countBits = function countBits(x) {
return x.toString(2).length; return x.toString(2).length;
}; // count the number of whole bytes it would take to represent a number }; // count the number of whole bytes it would take to represent a number
exports.countBits = countBits; exports.countBits = countBits;
var countBytes = function countBytes(x) { var countBytes = function countBytes(x) {
return Math.ceil(countBits(x) / 8); return Math.ceil(countBits(x) / 8);
}; };
exports.countBytes = countBytes; exports.countBytes = countBytes;
var padStart = function padStart(b, len, str) { var padStart = function padStart(b, len, str) {
if (str === void 0) { if (str === void 0) {
str = ' '; str = ' ';
} }
return (repeat(str, len) + b.toString()).slice(-len); return (repeat(str, len) + b.toString()).slice(-len);
}; };
exports.padStart = padStart; exports.padStart = padStart;
var isTypedArray = function isTypedArray(obj) { var isTypedArray = function isTypedArray(obj) {
return ArrayBuffer.isView(obj); return ArrayBuffer.isView(obj);
}; };
exports.isTypedArray = isTypedArray; exports.isTypedArray = isTypedArray;
var toUint8 = function toUint8(bytes) { var toUint8 = function toUint8(bytes) {
if (bytes instanceof Uint8Array) { if (bytes instanceof Uint8Array) {
return bytes; return bytes;
} }
if (!Array.isArray(bytes) && !isTypedArray(bytes) && !(bytes instanceof ArrayBuffer)) { if (!Array.isArray(bytes) && !isTypedArray(bytes) && !(bytes instanceof ArrayBuffer)) {
// any non-number or NaN leads to empty uint8array // any non-number or NaN leads to empty uint8array
// eslint-disable-next-line // eslint-disable-next-line
if (typeof bytes !== 'number' || typeof bytes === 'number' && bytes !== bytes) { if (typeof bytes !== 'number' || typeof bytes === 'number' && bytes !== bytes) {
bytes = 0; bytes = 0;
} else { } else {
bytes = [bytes]; bytes = [bytes];
} }
} }
return new Uint8Array(bytes && bytes.buffer || bytes, bytes && bytes.byteOffset || 0, bytes && bytes.byteLength || 0); return new Uint8Array(bytes && bytes.buffer || bytes, bytes && bytes.byteOffset || 0, bytes && bytes.byteLength || 0);
}; };
exports.toUint8 = toUint8; exports.toUint8 = toUint8;
var toHexString = function toHexString(bytes) { var toHexString = function toHexString(bytes) {
bytes = toUint8(bytes); bytes = toUint8(bytes);
var str = ''; var str = '';
for (var i = 0; i < bytes.length; i++) { for (var i = 0; i < bytes.length; i++) {
str += padStart(bytes[i].toString(16), 2, '0'); str += padStart(bytes[i].toString(16), 2, '0');
} }
return str; return str;
}; };
exports.toHexString = toHexString; exports.toHexString = toHexString;
var toBinaryString = function toBinaryString(bytes) { var toBinaryString = function toBinaryString(bytes) {
bytes = toUint8(bytes); bytes = toUint8(bytes);
var str = ''; var str = '';
for (var i = 0; i < bytes.length; i++) { for (var i = 0; i < bytes.length; i++) {
str += padStart(bytes[i].toString(2), 8, '0'); str += padStart(bytes[i].toString(2), 8, '0');
} }
return str; return str;
}; };
exports.toBinaryString = toBinaryString; exports.toBinaryString = toBinaryString;
var BigInt = _window.default.BigInt || Number; var BigInt = _window.default.BigInt || Number;
var BYTE_TABLE = [BigInt('0x1'), BigInt('0x100'), BigInt('0x10000'), BigInt('0x1000000'), BigInt('0x100000000'), BigInt('0x10000000000'), BigInt('0x1000000000000'), BigInt('0x100000000000000'), BigInt('0x10000000000000000')]; var BYTE_TABLE = [BigInt('0x1'), BigInt('0x100'), BigInt('0x10000'), BigInt('0x1000000'), BigInt('0x100000000'), BigInt('0x10000000000'), BigInt('0x1000000000000'), BigInt('0x100000000000000'), BigInt('0x10000000000000000')];
var ENDIANNESS = function () { var ENDIANNESS = function () {
var a = new Uint16Array([0xFFCC]); var a = new Uint16Array([0xFFCC]);
var b = new Uint8Array(a.buffer, a.byteOffset, a.byteLength); var b = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
if (b[0] === 0xFF) { if (b[0] === 0xFF) {
return 'big'; return 'big';
} }
if (b[0] === 0xCC) { if (b[0] === 0xCC) {
return 'little'; return 'little';
} }
return 'unknown'; return 'unknown';
}(); }();
exports.ENDIANNESS = ENDIANNESS; exports.ENDIANNESS = ENDIANNESS;
var IS_BIG_ENDIAN = ENDIANNESS === 'big'; var IS_BIG_ENDIAN = ENDIANNESS === 'big';
exports.IS_BIG_ENDIAN = IS_BIG_ENDIAN; exports.IS_BIG_ENDIAN = IS_BIG_ENDIAN;
var IS_LITTLE_ENDIAN = ENDIANNESS === 'little'; var IS_LITTLE_ENDIAN = ENDIANNESS === 'little';
exports.IS_LITTLE_ENDIAN = IS_LITTLE_ENDIAN; exports.IS_LITTLE_ENDIAN = IS_LITTLE_ENDIAN;
var bytesToNumber = function bytesToNumber(bytes, _temp) { var bytesToNumber = function bytesToNumber(bytes, _temp) {
var _ref = _temp === void 0 ? {} : _temp, var _ref = _temp === void 0 ? {} : _temp,
_ref$signed = _ref.signed, _ref$signed = _ref.signed,
signed = _ref$signed === void 0 ? false : _ref$signed, signed = _ref$signed === void 0 ? false : _ref$signed,
_ref$le = _ref.le, _ref$le = _ref.le,
le = _ref$le === void 0 ? false : _ref$le; le = _ref$le === void 0 ? false : _ref$le;
bytes = toUint8(bytes); bytes = toUint8(bytes);
var fn = le ? 'reduce' : 'reduceRight'; var fn = le ? 'reduce' : 'reduceRight';
var obj = bytes[fn] ? bytes[fn] : Array.prototype[fn]; var obj = bytes[fn] ? bytes[fn] : Array.prototype[fn];
var number = obj.call(bytes, function (total, byte, i) { var number = obj.call(bytes, function (total, byte, i) {
var exponent = le ? i : Math.abs(i + 1 - bytes.length); var exponent = le ? i : Math.abs(i + 1 - bytes.length);
return total + BigInt(byte) * BYTE_TABLE[exponent]; return total + BigInt(byte) * BYTE_TABLE[exponent];
}, BigInt(0)); }, BigInt(0));
if (signed) { if (signed) {
var max = BYTE_TABLE[bytes.length] / BigInt(2) - BigInt(1); var max = BYTE_TABLE[bytes.length] / BigInt(2) - BigInt(1);
number = BigInt(number); number = BigInt(number);
if (number > max) { if (number > max) {
number -= max; number -= max;
number -= max; number -= max;
number -= BigInt(2); number -= BigInt(2);
} }
} }
return Number(number); return Number(number);
}; };
exports.bytesToNumber = bytesToNumber; exports.bytesToNumber = bytesToNumber;
var numberToBytes = function numberToBytes(number, _temp2) { var numberToBytes = function numberToBytes(number, _temp2) {
var _ref2 = _temp2 === void 0 ? {} : _temp2, var _ref2 = _temp2 === void 0 ? {} : _temp2,
_ref2$le = _ref2.le, _ref2$le = _ref2.le,
le = _ref2$le === void 0 ? false : _ref2$le; le = _ref2$le === void 0 ? false : _ref2$le;
// eslint-disable-next-line // eslint-disable-next-line
if (typeof number !== 'bigint' && typeof number !== 'number' || typeof number === 'number' && number !== number) { if (typeof number !== 'bigint' && typeof number !== 'number' || typeof number === 'number' && number !== number) {
number = 0; number = 0;
} }
number = BigInt(number); number = BigInt(number);
var byteCount = countBytes(number); var byteCount = countBytes(number);
var bytes = new Uint8Array(new ArrayBuffer(byteCount)); var bytes = new Uint8Array(new ArrayBuffer(byteCount));
for (var i = 0; i < byteCount; i++) { for (var i = 0; i < byteCount; i++) {
var byteIndex = le ? i : Math.abs(i + 1 - bytes.length); var byteIndex = le ? i : Math.abs(i + 1 - bytes.length);
bytes[byteIndex] = Number(number / BYTE_TABLE[i] & BigInt(0xFF)); bytes[byteIndex] = Number(number / BYTE_TABLE[i] & BigInt(0xFF));
if (number < 0) { if (number < 0) {
bytes[byteIndex] = Math.abs(~bytes[byteIndex]); bytes[byteIndex] = Math.abs(~bytes[byteIndex]);
bytes[byteIndex] -= i === 0 ? 1 : 2; bytes[byteIndex] -= i === 0 ? 1 : 2;
} }
} }
return bytes; return bytes;
}; };
exports.numberToBytes = numberToBytes; exports.numberToBytes = numberToBytes;
var bytesToString = function bytesToString(bytes) { var bytesToString = function bytesToString(bytes) {
if (!bytes) { if (!bytes) {
return ''; return '';
} // TODO: should toUint8 handle cases where we only have 8 bytes } // TODO: should toUint8 handle cases where we only have 8 bytes
// but report more since this is a Uint16+ Array? // but report more since this is a Uint16+ Array?
bytes = Array.prototype.slice.call(bytes); bytes = Array.prototype.slice.call(bytes);
var string = String.fromCharCode.apply(null, toUint8(bytes)); var string = String.fromCharCode.apply(null, toUint8(bytes));
try { try {
return decodeURIComponent(escape(string)); return decodeURIComponent(escape(string));
} catch (e) {// if decodeURIComponent/escape fails, we are dealing with partial } catch (e) {// if decodeURIComponent/escape fails, we are dealing with partial
// or full non string data. Just return the potentially garbled string. // or full non string data. Just return the potentially garbled string.
} }
return string; return string;
}; };
exports.bytesToString = bytesToString; exports.bytesToString = bytesToString;
var stringToBytes = function stringToBytes(string, stringIsBytes) { var stringToBytes = function stringToBytes(string, stringIsBytes) {
if (typeof string !== 'string' && string && typeof string.toString === 'function') { if (typeof string !== 'string' && string && typeof string.toString === 'function') {
string = string.toString(); string = string.toString();
} }
if (typeof string !== 'string') { if (typeof string !== 'string') {
return new Uint8Array(); return new Uint8Array();
} // If the string already is bytes, we don't have to do this } // If the string already is bytes, we don't have to do this
// otherwise we do this so that we split multi length characters // otherwise we do this so that we split multi length characters
// into individual bytes // into individual bytes
if (!stringIsBytes) { if (!stringIsBytes) {
string = unescape(encodeURIComponent(string)); string = unescape(encodeURIComponent(string));
} }
var view = new Uint8Array(string.length); var view = new Uint8Array(string.length);
for (var i = 0; i < string.length; i++) { for (var i = 0; i < string.length; i++) {
view[i] = string.charCodeAt(i); view[i] = string.charCodeAt(i);
} }
return view; return view;
}; };
exports.stringToBytes = stringToBytes; exports.stringToBytes = stringToBytes;
var concatTypedArrays = function concatTypedArrays() { var concatTypedArrays = function concatTypedArrays() {
for (var _len = arguments.length, buffers = new Array(_len), _key = 0; _key < _len; _key++) { for (var _len = arguments.length, buffers = new Array(_len), _key = 0; _key < _len; _key++) {
buffers[_key] = arguments[_key]; buffers[_key] = arguments[_key];
} }
buffers = buffers.filter(function (b) { buffers = buffers.filter(function (b) {
return b && (b.byteLength || b.length) && typeof b !== 'string'; return b && (b.byteLength || b.length) && typeof b !== 'string';
}); });
if (buffers.length <= 1) { if (buffers.length <= 1) {
// for 0 length we will return empty uint8 // for 0 length we will return empty uint8
// for 1 length we return the first uint8 // for 1 length we return the first uint8
return toUint8(buffers[0]); return toUint8(buffers[0]);
} }
var totalLen = buffers.reduce(function (total, buf, i) { var totalLen = buffers.reduce(function (total, buf, i) {
return total + (buf.byteLength || buf.length); return total + (buf.byteLength || buf.length);
}, 0); }, 0);
var tempBuffer = new Uint8Array(totalLen); var tempBuffer = new Uint8Array(totalLen);
var offset = 0; var offset = 0;
buffers.forEach(function (buf) { buffers.forEach(function (buf) {
buf = toUint8(buf); buf = toUint8(buf);
tempBuffer.set(buf, offset); tempBuffer.set(buf, offset);
offset += buf.byteLength; offset += buf.byteLength;
}); });
return tempBuffer; return tempBuffer;
}; };
/** /**
* Check if the bytes "b" are contained within bytes "a". * Check if the bytes "b" are contained within bytes "a".
* *
* @param {Uint8Array|Array} a * @param {Uint8Array|Array} a
* Bytes to check in * Bytes to check in
* *
* @param {Uint8Array|Array} b * @param {Uint8Array|Array} b
* Bytes to check for * Bytes to check for
* *
* @param {Object} options * @param {Object} options
* options * options
* *
* @param {Array|Uint8Array} [offset=0] * @param {Array|Uint8Array} [offset=0]
* offset to use when looking at bytes in a * offset to use when looking at bytes in a
* *
* @param {Array|Uint8Array} [mask=[]] * @param {Array|Uint8Array} [mask=[]]
* mask to use on bytes before comparison. * mask to use on bytes before comparison.
* *
* @return {boolean} * @return {boolean}
* If all bytes in b are inside of a, taking into account * If all bytes in b are inside of a, taking into account
* bit masks. * bit masks.
*/ */
exports.concatTypedArrays = concatTypedArrays; exports.concatTypedArrays = concatTypedArrays;
var bytesMatch = function bytesMatch(a, b, _temp3) { var bytesMatch = function bytesMatch(a, b, _temp3) {
var _ref3 = _temp3 === void 0 ? {} : _temp3, var _ref3 = _temp3 === void 0 ? {} : _temp3,
_ref3$offset = _ref3.offset, _ref3$offset = _ref3.offset,
offset = _ref3$offset === void 0 ? 0 : _ref3$offset, offset = _ref3$offset === void 0 ? 0 : _ref3$offset,
_ref3$mask = _ref3.mask, _ref3$mask = _ref3.mask,
mask = _ref3$mask === void 0 ? [] : _ref3$mask; mask = _ref3$mask === void 0 ? [] : _ref3$mask;
a = toUint8(a); a = toUint8(a);
b = toUint8(b); // ie 11 does not support uint8 every b = toUint8(b); // ie 11 does not support uint8 every
var fn = b.every ? b.every : Array.prototype.every; var fn = b.every ? b.every : Array.prototype.every;
return b.length && a.length - offset >= b.length && // ie 11 doesn't support every on uin8 return b.length && a.length - offset >= b.length && // ie 11 doesn't support every on uin8
fn.call(b, function (bByte, i) { fn.call(b, function (bByte, i) {
var aByte = mask[i] ? mask[i] & a[offset + i] : a[offset + i]; var aByte = mask[i] ? mask[i] & a[offset + i] : a[offset + i];
return bByte === aByte; return bByte === aByte;
}); });
}; };
exports.bytesMatch = bytesMatch; exports.bytesMatch = bytesMatch;
var sliceBytes = function sliceBytes(src, start, end) { var sliceBytes = function sliceBytes(src, start, end) {
if (Uint8Array.prototype.slice) { if (Uint8Array.prototype.slice) {
return Uint8Array.prototype.slice.call(src, start, end); return Uint8Array.prototype.slice.call(src, start, end);
} }
return new Uint8Array(Array.prototype.slice.call(src, start, end)); return new Uint8Array(Array.prototype.slice.call(src, start, end));
}; };
exports.sliceBytes = sliceBytes; exports.sliceBytes = sliceBytes;
var reverseBytes = function reverseBytes(src) { var reverseBytes = function reverseBytes(src) {
if (src.reverse) { if (src.reverse) {
return src.reverse(); return src.reverse();
} }
return Array.prototype.reverse.call(src); return Array.prototype.reverse.call(src);
}; };
exports.reverseBytes = reverseBytes; exports.reverseBytes = reverseBytes;

View file

@ -1,112 +1,112 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "__esModule", {
value: true value: true
}); });
exports.getHvcCodec = exports.getAvcCodec = exports.getAv1Codec = void 0; exports.getHvcCodec = exports.getAvcCodec = exports.getAv1Codec = void 0;
var _byteHelpers = require("./byte-helpers.js"); var _byteHelpers = require("./byte-helpers.js");
// https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-syntax // https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-syntax
// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter#AV1 // https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter#AV1
var getAv1Codec = function getAv1Codec(bytes) { var getAv1Codec = function getAv1Codec(bytes) {
var codec = ''; var codec = '';
var profile = bytes[1] >>> 3; var profile = bytes[1] >>> 3;
var level = bytes[1] & 0x1F; var level = bytes[1] & 0x1F;
var tier = bytes[2] >>> 7; var tier = bytes[2] >>> 7;
var highBitDepth = (bytes[2] & 0x40) >> 6; var highBitDepth = (bytes[2] & 0x40) >> 6;
var twelveBit = (bytes[2] & 0x20) >> 5; var twelveBit = (bytes[2] & 0x20) >> 5;
var monochrome = (bytes[2] & 0x10) >> 4; var monochrome = (bytes[2] & 0x10) >> 4;
var chromaSubsamplingX = (bytes[2] & 0x08) >> 3; var chromaSubsamplingX = (bytes[2] & 0x08) >> 3;
var chromaSubsamplingY = (bytes[2] & 0x04) >> 2; var chromaSubsamplingY = (bytes[2] & 0x04) >> 2;
var chromaSamplePosition = bytes[2] & 0x03; var chromaSamplePosition = bytes[2] & 0x03;
codec += profile + "." + (0, _byteHelpers.padStart)(level, 2, '0'); codec += profile + "." + (0, _byteHelpers.padStart)(level, 2, '0');
if (tier === 0) { if (tier === 0) {
codec += 'M'; codec += 'M';
} else if (tier === 1) { } else if (tier === 1) {
codec += 'H'; codec += 'H';
} }
var bitDepth; var bitDepth;
if (profile === 2 && highBitDepth) { if (profile === 2 && highBitDepth) {
bitDepth = twelveBit ? 12 : 10; bitDepth = twelveBit ? 12 : 10;
} else { } else {
bitDepth = highBitDepth ? 10 : 8; bitDepth = highBitDepth ? 10 : 8;
} }
codec += "." + (0, _byteHelpers.padStart)(bitDepth, 2, '0'); // TODO: can we parse color range?? codec += "." + (0, _byteHelpers.padStart)(bitDepth, 2, '0'); // TODO: can we parse color range??
codec += "." + monochrome; codec += "." + monochrome;
codec += "." + chromaSubsamplingX + chromaSubsamplingY + chromaSamplePosition; codec += "." + chromaSubsamplingX + chromaSubsamplingY + chromaSamplePosition;
return codec; return codec;
}; };
exports.getAv1Codec = getAv1Codec; exports.getAv1Codec = getAv1Codec;
var getAvcCodec = function getAvcCodec(bytes) { var getAvcCodec = function getAvcCodec(bytes) {
var profileId = (0, _byteHelpers.toHexString)(bytes[1]); var profileId = (0, _byteHelpers.toHexString)(bytes[1]);
var constraintFlags = (0, _byteHelpers.toHexString)(bytes[2] & 0xFC); var constraintFlags = (0, _byteHelpers.toHexString)(bytes[2] & 0xFC);
var levelId = (0, _byteHelpers.toHexString)(bytes[3]); var levelId = (0, _byteHelpers.toHexString)(bytes[3]);
return "" + profileId + constraintFlags + levelId; return "" + profileId + constraintFlags + levelId;
}; };
exports.getAvcCodec = getAvcCodec; exports.getAvcCodec = getAvcCodec;
var getHvcCodec = function getHvcCodec(bytes) { var getHvcCodec = function getHvcCodec(bytes) {
var codec = ''; var codec = '';
var profileSpace = bytes[1] >> 6; var profileSpace = bytes[1] >> 6;
var profileId = bytes[1] & 0x1F; var profileId = bytes[1] & 0x1F;
var tierFlag = (bytes[1] & 0x20) >> 5; var tierFlag = (bytes[1] & 0x20) >> 5;
var profileCompat = bytes.subarray(2, 6); var profileCompat = bytes.subarray(2, 6);
var constraintIds = bytes.subarray(6, 12); var constraintIds = bytes.subarray(6, 12);
var levelId = bytes[12]; var levelId = bytes[12];
if (profileSpace === 1) { if (profileSpace === 1) {
codec += 'A'; codec += 'A';
} else if (profileSpace === 2) { } else if (profileSpace === 2) {
codec += 'B'; codec += 'B';
} else if (profileSpace === 3) { } else if (profileSpace === 3) {
codec += 'C'; codec += 'C';
} }
codec += profileId + "."; // ffmpeg does this in big endian codec += profileId + "."; // ffmpeg does this in big endian
var profileCompatVal = parseInt((0, _byteHelpers.toBinaryString)(profileCompat).split('').reverse().join(''), 2); // apple does this in little endian... var profileCompatVal = parseInt((0, _byteHelpers.toBinaryString)(profileCompat).split('').reverse().join(''), 2); // apple does this in little endian...
if (profileCompatVal > 255) { if (profileCompatVal > 255) {
profileCompatVal = parseInt((0, _byteHelpers.toBinaryString)(profileCompat), 2); profileCompatVal = parseInt((0, _byteHelpers.toBinaryString)(profileCompat), 2);
} }
codec += profileCompatVal.toString(16) + "."; codec += profileCompatVal.toString(16) + ".";
if (tierFlag === 0) { if (tierFlag === 0) {
codec += 'L'; codec += 'L';
} else { } else {
codec += 'H'; codec += 'H';
} }
codec += levelId; codec += levelId;
var constraints = ''; var constraints = '';
for (var i = 0; i < constraintIds.length; i++) { for (var i = 0; i < constraintIds.length; i++) {
var v = constraintIds[i]; var v = constraintIds[i];
if (v) { if (v) {
if (constraints) { if (constraints) {
constraints += '.'; constraints += '.';
} }
constraints += v.toString(16); constraints += v.toString(16);
} }
} }
if (constraints) { if (constraints) {
codec += "." + constraints; codec += "." + constraints;
} }
return codec; return codec;
}; };
exports.getHvcCodec = getHvcCodec; exports.getHvcCodec = getHvcCodec;

File diff suppressed because it is too large Load diff

View file

@ -1,109 +1,109 @@
import {bytesMatch, toUint8} from './byte-helpers.js'; import {bytesMatch, toUint8} from './byte-helpers.js';
export const NAL_TYPE_ONE = toUint8([0x00, 0x00, 0x00, 0x01]); export const NAL_TYPE_ONE = toUint8([0x00, 0x00, 0x00, 0x01]);
export const NAL_TYPE_TWO = toUint8([0x00, 0x00, 0x01]); export const NAL_TYPE_TWO = toUint8([0x00, 0x00, 0x01]);
export const EMULATION_PREVENTION = toUint8([0x00, 0x00, 0x03]); export const EMULATION_PREVENTION = toUint8([0x00, 0x00, 0x03]);
/** /**
* Expunge any "Emulation Prevention" bytes from a "Raw Byte * Expunge any "Emulation Prevention" bytes from a "Raw Byte
* Sequence Payload" * Sequence Payload"
* *
* @param data {Uint8Array} the bytes of a RBSP from a NAL * @param data {Uint8Array} the bytes of a RBSP from a NAL
* unit * unit
* @return {Uint8Array} the RBSP without any Emulation * @return {Uint8Array} the RBSP without any Emulation
* Prevention Bytes * Prevention Bytes
*/ */
export const discardEmulationPreventionBytes = function(bytes) { export const discardEmulationPreventionBytes = function(bytes) {
const positions = []; const positions = [];
let i = 1; let i = 1;
// Find all `Emulation Prevention Bytes` // Find all `Emulation Prevention Bytes`
while (i < bytes.length - 2) { while (i < bytes.length - 2) {
if (bytesMatch(bytes.subarray(i, i + 3), EMULATION_PREVENTION)) { if (bytesMatch(bytes.subarray(i, i + 3), EMULATION_PREVENTION)) {
positions.push(i + 2); positions.push(i + 2);
i++; i++;
} }
i++; i++;
} }
// If no Emulation Prevention Bytes were found just return the original // If no Emulation Prevention Bytes were found just return the original
// array // array
if (positions.length === 0) { if (positions.length === 0) {
return bytes; return bytes;
} }
// Create a new array to hold the NAL unit data // Create a new array to hold the NAL unit data
const newLength = bytes.length - positions.length; const newLength = bytes.length - positions.length;
const newData = new Uint8Array(newLength); const newData = new Uint8Array(newLength);
let sourceIndex = 0; let sourceIndex = 0;
for (i = 0; i < newLength; sourceIndex++, i++) { for (i = 0; i < newLength; sourceIndex++, i++) {
if (sourceIndex === positions[0]) { if (sourceIndex === positions[0]) {
// Skip this byte // Skip this byte
sourceIndex++; sourceIndex++;
// Remove this position index // Remove this position index
positions.shift(); positions.shift();
} }
newData[i] = bytes[sourceIndex]; newData[i] = bytes[sourceIndex];
} }
return newData; return newData;
}; };
export const findNal = function(bytes, dataType, types, nalLimit = Infinity) { export const findNal = function(bytes, dataType, types, nalLimit = Infinity) {
bytes = toUint8(bytes); bytes = toUint8(bytes);
types = [].concat(types); types = [].concat(types);
let i = 0; let i = 0;
let nalStart; let nalStart;
let nalsFound = 0; let nalsFound = 0;
// keep searching until: // keep searching until:
// we reach the end of bytes // we reach the end of bytes
// we reach the maximum number of nals they want to seach // we reach the maximum number of nals they want to seach
// NOTE: that we disregard nalLimit when we have found the start // NOTE: that we disregard nalLimit when we have found the start
// of the nal we want so that we can find the end of the nal we want. // of the nal we want so that we can find the end of the nal we want.
while (i < bytes.length && (nalsFound < nalLimit || nalStart)) { while (i < bytes.length && (nalsFound < nalLimit || nalStart)) {
let nalOffset; let nalOffset;
if (bytesMatch(bytes.subarray(i), NAL_TYPE_ONE)) { if (bytesMatch(bytes.subarray(i), NAL_TYPE_ONE)) {
nalOffset = 4; nalOffset = 4;
} else if (bytesMatch(bytes.subarray(i), NAL_TYPE_TWO)) { } else if (bytesMatch(bytes.subarray(i), NAL_TYPE_TWO)) {
nalOffset = 3; nalOffset = 3;
} }
// we are unsynced, // we are unsynced,
// find the next nal unit // find the next nal unit
if (!nalOffset) { if (!nalOffset) {
i++; i++;
continue; continue;
} }
nalsFound++; nalsFound++;
if (nalStart) { if (nalStart) {
return discardEmulationPreventionBytes(bytes.subarray(nalStart, i)); return discardEmulationPreventionBytes(bytes.subarray(nalStart, i));
} }
let nalType; let nalType;
if (dataType === 'h264') { if (dataType === 'h264') {
nalType = (bytes[i + nalOffset] & 0x1f); nalType = (bytes[i + nalOffset] & 0x1f);
} else if (dataType === 'h265') { } else if (dataType === 'h265') {
nalType = (bytes[i + nalOffset] >> 1) & 0x3f; nalType = (bytes[i + nalOffset] >> 1) & 0x3f;
} }
if (types.indexOf(nalType) !== -1) { if (types.indexOf(nalType) !== -1) {
nalStart = i + nalOffset; nalStart = i + nalOffset;
} }
// nal header is 1 length for h264, and 2 for h265 // nal header is 1 length for h264, and 2 for h265
i += nalOffset + (dataType === 'h264' ? 1 : 2); i += nalOffset + (dataType === 'h264' ? 1 : 2);
} }
return bytes.subarray(0, 0); return bytes.subarray(0, 0);
}; };
export const findH264Nal = (bytes, type, nalLimit) => findNal(bytes, 'h264', type, nalLimit); export const findH264Nal = (bytes, type, nalLimit) => findNal(bytes, 'h264', type, nalLimit);
export const findH265Nal = (bytes, type, nalLimit) => findNal(bytes, 'h265', type, nalLimit); export const findH265Nal = (bytes, type, nalLimit) => findNal(bytes, 'h265', type, nalLimit);

View file

@ -1,27 +1,27 @@
import {bytesMatch, toUint8} from './byte-helpers'; import {bytesMatch, toUint8} from './byte-helpers';
const SYNC_WORD = toUint8([0x4f, 0x67, 0x67, 0x53]); const SYNC_WORD = toUint8([0x4f, 0x67, 0x67, 0x53]);
export const getPages = function(bytes, start, end = Infinity) { export const getPages = function(bytes, start, end = Infinity) {
bytes = toUint8(bytes); bytes = toUint8(bytes);
const pages = []; const pages = [];
let i = 0; let i = 0;
while (i < bytes.length && pages.length < end) { while (i < bytes.length && pages.length < end) {
// we are unsynced, // we are unsynced,
// find the next syncword // find the next syncword
if (!bytesMatch(bytes, SYNC_WORD, {offset: i})) { if (!bytesMatch(bytes, SYNC_WORD, {offset: i})) {
i++; i++;
continue; continue;
} }
const segmentLength = bytes[i + 27]; const segmentLength = bytes[i + 27];
pages.push(bytes.subarray(i, i + 28 + segmentLength)); pages.push(bytes.subarray(i, i + 28 + segmentLength));
i += pages[pages.length - 1].length; i += pages[pages.length - 1].length;
} }
return pages.slice(start, end); return pages.slice(start, end);
}; };

View file

@ -1,61 +1,61 @@
export const OPUS_HEAD = new Uint8Array([ export const OPUS_HEAD = new Uint8Array([
// O, p, u, s // O, p, u, s
0x4f, 0x70, 0x75, 0x73, 0x4f, 0x70, 0x75, 0x73,
// H, e, a, d // H, e, a, d
0x48, 0x65, 0x61, 0x64 0x48, 0x65, 0x61, 0x64
]); ]);
// https://wiki.xiph.org/OggOpus // https://wiki.xiph.org/OggOpus
// https://vfrmaniac.fushizen.eu/contents/opus_in_isobmff.html // https://vfrmaniac.fushizen.eu/contents/opus_in_isobmff.html
// https://opus-codec.org/docs/opusfile_api-0.7/structOpusHead.html // https://opus-codec.org/docs/opusfile_api-0.7/structOpusHead.html
export const parseOpusHead = function(bytes) { export const parseOpusHead = function(bytes) {
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
const version = view.getUint8(0); const version = view.getUint8(0);
// version 0, from mp4, does not use littleEndian. // version 0, from mp4, does not use littleEndian.
const littleEndian = version !== 0; const littleEndian = version !== 0;
const config = { const config = {
version, version,
channels: view.getUint8(1), channels: view.getUint8(1),
preSkip: view.getUint16(2, littleEndian), preSkip: view.getUint16(2, littleEndian),
sampleRate: view.getUint32(4, littleEndian), sampleRate: view.getUint32(4, littleEndian),
outputGain: view.getUint16(8, littleEndian), outputGain: view.getUint16(8, littleEndian),
channelMappingFamily: view.getUint8(10) channelMappingFamily: view.getUint8(10)
}; };
if (config.channelMappingFamily > 0 && bytes.length > 10) { if (config.channelMappingFamily > 0 && bytes.length > 10) {
config.streamCount = view.getUint8(11); config.streamCount = view.getUint8(11);
config.twoChannelStreamCount = view.getUint8(12); config.twoChannelStreamCount = view.getUint8(12);
config.channelMapping = []; config.channelMapping = [];
for (let c = 0; c < config.channels; c++) { for (let c = 0; c < config.channels; c++) {
config.channelMapping.push(view.getUint8(13 + c)); config.channelMapping.push(view.getUint8(13 + c));
} }
} }
return config; return config;
}; };
export const setOpusHead = function(config) { export const setOpusHead = function(config) {
const size = config.channelMappingFamily <= 0 ? 11 : (12 + config.channels); const size = config.channelMappingFamily <= 0 ? 11 : (12 + config.channels);
const view = new DataView(new ArrayBuffer(size)); const view = new DataView(new ArrayBuffer(size));
const littleEndian = config.version !== 0; const littleEndian = config.version !== 0;
view.setUint8(0, config.version); view.setUint8(0, config.version);
view.setUint8(1, config.channels); view.setUint8(1, config.channels);
view.setUint16(2, config.preSkip, littleEndian); view.setUint16(2, config.preSkip, littleEndian);
view.setUint32(4, config.sampleRate, littleEndian); view.setUint32(4, config.sampleRate, littleEndian);
view.setUint16(8, config.outputGain, littleEndian); view.setUint16(8, config.outputGain, littleEndian);
view.setUint8(10, config.channelMappingFamily); view.setUint8(10, config.channelMappingFamily);
if (config.channelMappingFamily > 0) { if (config.channelMappingFamily > 0) {
view.setUint8(11, config.streamCount); view.setUint8(11, config.streamCount);
config.channelMapping.foreach(function(cm, i) { config.channelMapping.foreach(function(cm, i) {
view.setUint8(12 + i, cm); view.setUint8(12 + i, cm);
}); });
} }
return new Uint8Array(view.buffer); return new Uint8Array(view.buffer);
}; };

View file

@ -1,51 +1,51 @@
import URLToolkit from 'url-toolkit'; import URLToolkit from 'url-toolkit';
import window from 'global/window'; import window from 'global/window';
const DEFAULT_LOCATION = 'http://example.com'; const DEFAULT_LOCATION = 'http://example.com';
const resolveUrl = (baseUrl, relativeUrl) => { const resolveUrl = (baseUrl, relativeUrl) => {
// return early if we don't need to resolve // return early if we don't need to resolve
if ((/^[a-z]+:/i).test(relativeUrl)) { if ((/^[a-z]+:/i).test(relativeUrl)) {
return relativeUrl; return relativeUrl;
} }
// if baseUrl is a data URI, ignore it and resolve everything relative to window.location // if baseUrl is a data URI, ignore it and resolve everything relative to window.location
if ((/^data:/).test(baseUrl)) { if ((/^data:/).test(baseUrl)) {
baseUrl = window.location && window.location.href || ''; baseUrl = window.location && window.location.href || '';
} }
// IE11 supports URL but not the URL constructor // IE11 supports URL but not the URL constructor
// feature detect the behavior we want // feature detect the behavior we want
const nativeURL = typeof window.URL === 'function'; const nativeURL = typeof window.URL === 'function';
const protocolLess = (/^\/\//.test(baseUrl)); const protocolLess = (/^\/\//.test(baseUrl));
// remove location if window.location isn't available (i.e. we're in node) // remove location if window.location isn't available (i.e. we're in node)
// and if baseUrl isn't an absolute url // and if baseUrl isn't an absolute url
const removeLocation = !window.location && !(/\/\//i).test(baseUrl); const removeLocation = !window.location && !(/\/\//i).test(baseUrl);
// if the base URL is relative then combine with the current location // if the base URL is relative then combine with the current location
if (nativeURL) { if (nativeURL) {
baseUrl = new window.URL(baseUrl, window.location || DEFAULT_LOCATION); baseUrl = new window.URL(baseUrl, window.location || DEFAULT_LOCATION);
} else if (!(/\/\//i).test(baseUrl)) { } else if (!(/\/\//i).test(baseUrl)) {
baseUrl = URLToolkit.buildAbsoluteURL(window.location && window.location.href || '', baseUrl); baseUrl = URLToolkit.buildAbsoluteURL(window.location && window.location.href || '', baseUrl);
} }
if (nativeURL) { if (nativeURL) {
const newUrl = new URL(relativeUrl, baseUrl); const newUrl = new URL(relativeUrl, baseUrl);
// if we're a protocol-less url, remove the protocol // if we're a protocol-less url, remove the protocol
// and if we're location-less, remove the location // and if we're location-less, remove the location
// otherwise, return the url unmodified // otherwise, return the url unmodified
if (removeLocation) { if (removeLocation) {
return newUrl.href.slice(DEFAULT_LOCATION.length); return newUrl.href.slice(DEFAULT_LOCATION.length);
} else if (protocolLess) { } else if (protocolLess) {
return newUrl.href.slice(newUrl.protocol.length); return newUrl.href.slice(newUrl.protocol.length);
} }
return newUrl.href; return newUrl.href;
} }
return URLToolkit.buildAbsoluteURL(baseUrl, relativeUrl); return URLToolkit.buildAbsoluteURL(baseUrl, relativeUrl);
}; };
export default resolveUrl; export default resolveUrl;

View file

@ -1,75 +1,75 @@
import {toUint8, stringToBytes, bytesMatch} from './byte-helpers.js'; import {toUint8, stringToBytes, bytesMatch} from './byte-helpers.js';
const CONSTANTS = { const CONSTANTS = {
LIST: toUint8([0x4c, 0x49, 0x53, 0x54]), LIST: toUint8([0x4c, 0x49, 0x53, 0x54]),
RIFF: toUint8([0x52, 0x49, 0x46, 0x46]), RIFF: toUint8([0x52, 0x49, 0x46, 0x46]),
WAVE: toUint8([0x57, 0x41, 0x56, 0x45]) WAVE: toUint8([0x57, 0x41, 0x56, 0x45])
}; };
const normalizePath = function(path) { const normalizePath = function(path) {
if (typeof path === 'string') { if (typeof path === 'string') {
return stringToBytes(path); return stringToBytes(path);
} }
if (typeof path === 'number') { if (typeof path === 'number') {
return path; return path;
} }
return path; return path;
}; };
const normalizePaths = function(paths) { const normalizePaths = function(paths) {
if (!Array.isArray(paths)) { if (!Array.isArray(paths)) {
return [normalizePath(paths)]; return [normalizePath(paths)];
} }
return paths.map((p) => normalizePath(p)); return paths.map((p) => normalizePath(p));
}; };
export const findFourCC = function(bytes, paths) { export const findFourCC = function(bytes, paths) {
paths = normalizePaths(paths); paths = normalizePaths(paths);
bytes = toUint8(bytes); bytes = toUint8(bytes);
let results = []; let results = [];
if (!paths.length) { if (!paths.length) {
// short-circuit the search for empty paths // short-circuit the search for empty paths
return results; return results;
} }
let i = 0; let i = 0;
while (i < bytes.length) { while (i < bytes.length) {
let type = bytes.subarray(i, i + 4); let type = bytes.subarray(i, i + 4);
let size = ((bytes[i + 7] << 24 | bytes[i + 6] << 16 | bytes[i + 5] << 8 | bytes[i + 4]) >>> 0); let size = ((bytes[i + 7] << 24 | bytes[i + 6] << 16 | bytes[i + 5] << 8 | bytes[i + 4]) >>> 0);
// skip LIST/RIFF and get the actual type // skip LIST/RIFF and get the actual type
if (bytesMatch(type, CONSTANTS.LIST) || bytesMatch(type, CONSTANTS.RIFF) || bytesMatch(type, CONSTANTS.WAVE)) { if (bytesMatch(type, CONSTANTS.LIST) || bytesMatch(type, CONSTANTS.RIFF) || bytesMatch(type, CONSTANTS.WAVE)) {
type = bytes.subarray(i + 8, i + 12); type = bytes.subarray(i + 8, i + 12);
i += 4; i += 4;
size -= 4; size -= 4;
} }
const data = bytes.subarray(i + 8, i + 8 + size); const data = bytes.subarray(i + 8, i + 8 + size);
if (bytesMatch(type, paths[0])) { if (bytesMatch(type, paths[0])) {
if (paths.length === 1) { if (paths.length === 1) {
// this is the end of the path and we've found the box we were // this is the end of the path and we've found the box we were
// looking for // looking for
results.push(data); results.push(data);
} else { } else {
// recursively search for the next box along the path // recursively search for the next box along the path
const subresults = findFourCC(data, paths.slice(1)); const subresults = findFourCC(data, paths.slice(1));
if (subresults.length) { if (subresults.length) {
results = results.concat(subresults); results = results.concat(subresults);
} }
} }
} }
i += 8 + data.length; i += 8 + data.length;
} }
// we've finished searching all of bytes // we've finished searching all of bytes
return results; return results;
}; };

View file

@ -1,42 +1,42 @@
import {isVideoCodec, isAudioCodec} from '../src/codecs.js'; import {isVideoCodec, isAudioCodec} from '../src/codecs.js';
const codecAliasMap = { const codecAliasMap = {
mp3: ['mp3', 'mp4a.40.34', 'mp4a.6b'], mp3: ['mp3', 'mp4a.40.34', 'mp4a.6b'],
aac: ['aac', 'mp4a.40.2', 'mp4a.40.5', 'mp4a.40.29'] aac: ['aac', 'mp4a.40.2', 'mp4a.40.5', 'mp4a.40.29']
}; };
Object.keys(codecAliasMap).forEach((alias) => { Object.keys(codecAliasMap).forEach((alias) => {
// map aliases as keys so that everything is linked to each other // map aliases as keys so that everything is linked to each other
codecAliasMap[alias].forEach((subalias) => { codecAliasMap[alias].forEach((subalias) => {
codecAliasMap[subalias] = codecAliasMap[alias]; codecAliasMap[subalias] = codecAliasMap[alias];
}); });
}); });
export const doesCodecMatch = function(a, b) { export const doesCodecMatch = function(a, b) {
if (!a) { if (!a) {
return false; return false;
} }
if (codecAliasMap[b]) { if (codecAliasMap[b]) {
return codecAliasMap[a].indexOf(b) !== -1; return codecAliasMap[a].indexOf(b) !== -1;
} }
return a === b; return a === b;
}; };
export const codecsFromFile = function(file) { export const codecsFromFile = function(file) {
const codecs = {}; const codecs = {};
const extension = file.split('.').pop(); const extension = file.split('.').pop();
const codecStr = file.replace(`.${extension}`, ''); const codecStr = file.replace(`.${extension}`, '');
codecStr.split(',').forEach((codec) => { codecStr.split(',').forEach((codec) => {
if (isVideoCodec(codec)) { if (isVideoCodec(codec)) {
codecs.video = codec; codecs.video = codec;
} else if (isAudioCodec(codec)) { } else if (isAudioCodec(codec)) {
codecs.audio = codec; codecs.audio = codec;
} else { } else {
throw new Error(`${codec} is not detected as audio or video`); throw new Error(`${codec} is not detected as audio or video`);
} }
}); });
return codecs; return codecs;
}; };

View file

@ -1,64 +1,64 @@
name: ci name: ci
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
should-skip: should-skip:
continue-on-error: true continue-on-error: true
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Map a step output to a job output # Map a step output to a job output
outputs: outputs:
should-skip-job: ${{steps.skip-check.outputs.should_skip}} should-skip-job: ${{steps.skip-check.outputs.should_skip}}
steps: steps:
- id: skip-check - id: skip-check
uses: fkirc/skip-duplicate-actions@v2.1.0 uses: fkirc/skip-duplicate-actions@v2.1.0
with: with:
github_token: ${{github.token}} github_token: ${{github.token}}
ci: ci:
needs: should-skip needs: should-skip
if: ${{needs.should-skip.outputs.should-skip-job != 'true' || github.ref == 'refs/heads/main'}} if: ${{needs.should-skip.outputs.should-skip-job != 'true' || github.ref == 'refs/heads/main'}}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest] os: [ubuntu-latest]
env: env:
BROWSER_STACK_USERNAME: ${{secrets.BROWSER_STACK_USERNAME}} BROWSER_STACK_USERNAME: ${{secrets.BROWSER_STACK_USERNAME}}
BROWSER_STACK_ACCESS_KEY: ${{secrets.BROWSER_STACK_ACCESS_KEY}} BROWSER_STACK_ACCESS_KEY: ${{secrets.BROWSER_STACK_ACCESS_KEY}}
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
steps: steps:
- name: checkout code - name: checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: read node version from .nvmrc - name: read node version from .nvmrc
run: echo ::set-output name=NVMRC::$(cat .nvmrc) run: echo ::set-output name=NVMRC::$(cat .nvmrc)
shell: bash shell: bash
id: nvm id: nvm
- name: update apt cache on linux w/o browserstack - name: update apt cache on linux w/o browserstack
run: sudo apt-get update run: sudo apt-get update
- name: install ffmpeg/pulseaudio for firefox on linux w/o browserstack - name: install ffmpeg/pulseaudio for firefox on linux w/o browserstack
run: sudo apt-get install ffmpeg pulseaudio run: sudo apt-get install ffmpeg pulseaudio
- name: start pulseaudio for firefox on linux w/o browserstack - name: start pulseaudio for firefox on linux w/o browserstack
run: pulseaudio -D run: pulseaudio -D
- name: setup node - name: setup node
uses: actions/setup-node@v2 uses: actions/setup-node@v2
with: with:
node-version: '${{steps.nvm.outputs.NVMRC}}' node-version: '${{steps.nvm.outputs.NVMRC}}'
cache: npm cache: npm
# turn off the default setup-node problem watchers... # turn off the default setup-node problem watchers...
- run: echo "::remove-matcher owner=eslint-compact::" - run: echo "::remove-matcher owner=eslint-compact::"
- run: echo "::remove-matcher owner=eslint-stylish::" - run: echo "::remove-matcher owner=eslint-stylish::"
- run: echo "::remove-matcher owner=tsc::" - run: echo "::remove-matcher owner=tsc::"
- name: npm install - name: npm install
run: npm i --prefer-offline --no-audit run: npm i --prefer-offline --no-audit
- name: run npm test - name: run npm test
uses: GabrielBB/xvfb-action@v1 uses: GabrielBB/xvfb-action@v1
with: with:
run: npm run test run: npm run test

2
node_modules/@videojs/xhr/.nvmrc generated vendored
View file

@ -1 +1 @@
10 10

View file

@ -1,27 +1,27 @@
# XHR is an OPEN Open Source Project # XHR is an OPEN Open Source Project
----------------------------------------- -----------------------------------------
## What? ## What?
Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project. Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project.
## Rules ## Rules
There are a few basic ground-rules for contributors: There are a few basic ground-rules for contributors:
1. **No `--force` pushes** or modifying the Git history in any way. 1. **No `--force` pushes** or modifying the Git history in any way.
1. **Non-master branches** ought to be used for ongoing work. 1. **Non-master branches** ought to be used for ongoing work.
1. **External API changes and significant modifications** ought to be subject to an **internal pull-request** to solicit feedback from other contributors. 1. **External API changes and significant modifications** ought to be subject to an **internal pull-request** to solicit feedback from other contributors.
1. Internal pull-requests to solicit feedback are *encouraged* for any other non-trivial contribution but left to the discretion of the contributor. 1. Internal pull-requests to solicit feedback are *encouraged* for any other non-trivial contribution but left to the discretion of the contributor.
1. Contributors should attempt to adhere to the prevailing code-style. 1. Contributors should attempt to adhere to the prevailing code-style.
## Releases ## Releases
Declaring formal releases remains the prerogative of the project maintainer. Declaring formal releases remains the prerogative of the project maintainer.
## Changes to this arrangement ## Changes to this arrangement
This is an experiment and feedback is welcome! This document may also be subject to pull-requests or changes by contributors where you believe you have something valuable to add or change. This is an experiment and feedback is welcome! This document may also be subject to pull-requests or changes by contributors where you believe you have something valuable to add or change.
----------------------------------------- -----------------------------------------

36
node_modules/@videojs/xhr/LICENCE generated vendored
View file

@ -1,19 +1,19 @@
Copyright (c) 2012 Raynos. Copyright (c) 2012 Raynos.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.

View file

@ -1,296 +1,296 @@
"use strict"; "use strict";
var window = require("global/window"); var window = require("global/window");
var _extends = require("@babel/runtime/helpers/extends"); var _extends = require("@babel/runtime/helpers/extends");
var isFunction = require('is-function'); var isFunction = require('is-function');
createXHR.httpHandler = require('./http-handler.js'); createXHR.httpHandler = require('./http-handler.js');
/** /**
* @license * @license
* slighly modified parse-headers 2.0.2 <https://github.com/kesla/parse-headers/> * slighly modified parse-headers 2.0.2 <https://github.com/kesla/parse-headers/>
* Copyright (c) 2014 David Björklund * Copyright (c) 2014 David Björklund
* Available under the MIT license * Available under the MIT license
* <https://github.com/kesla/parse-headers/blob/master/LICENCE> * <https://github.com/kesla/parse-headers/blob/master/LICENCE>
*/ */
var parseHeaders = function parseHeaders(headers) { var parseHeaders = function parseHeaders(headers) {
var result = {}; var result = {};
if (!headers) { if (!headers) {
return result; return result;
} }
headers.trim().split('\n').forEach(function (row) { headers.trim().split('\n').forEach(function (row) {
var index = row.indexOf(':'); var index = row.indexOf(':');
var key = row.slice(0, index).trim().toLowerCase(); var key = row.slice(0, index).trim().toLowerCase();
var value = row.slice(index + 1).trim(); var value = row.slice(index + 1).trim();
if (typeof result[key] === 'undefined') { if (typeof result[key] === 'undefined') {
result[key] = value; result[key] = value;
} else if (Array.isArray(result[key])) { } else if (Array.isArray(result[key])) {
result[key].push(value); result[key].push(value);
} else { } else {
result[key] = [result[key], value]; result[key] = [result[key], value];
} }
}); });
return result; return result;
}; };
module.exports = createXHR; // Allow use of default import syntax in TypeScript module.exports = createXHR; // Allow use of default import syntax in TypeScript
module.exports.default = createXHR; module.exports.default = createXHR;
createXHR.XMLHttpRequest = window.XMLHttpRequest || noop; createXHR.XMLHttpRequest = window.XMLHttpRequest || noop;
createXHR.XDomainRequest = "withCredentials" in new createXHR.XMLHttpRequest() ? createXHR.XMLHttpRequest : window.XDomainRequest; createXHR.XDomainRequest = "withCredentials" in new createXHR.XMLHttpRequest() ? createXHR.XMLHttpRequest : window.XDomainRequest;
forEachArray(["get", "put", "post", "patch", "head", "delete"], function (method) { forEachArray(["get", "put", "post", "patch", "head", "delete"], function (method) {
createXHR[method === "delete" ? "del" : method] = function (uri, options, callback) { createXHR[method === "delete" ? "del" : method] = function (uri, options, callback) {
options = initParams(uri, options, callback); options = initParams(uri, options, callback);
options.method = method.toUpperCase(); options.method = method.toUpperCase();
return _createXHR(options); return _createXHR(options);
}; };
}); });
function forEachArray(array, iterator) { function forEachArray(array, iterator) {
for (var i = 0; i < array.length; i++) { for (var i = 0; i < array.length; i++) {
iterator(array[i]); iterator(array[i]);
} }
} }
function isEmpty(obj) { function isEmpty(obj) {
for (var i in obj) { for (var i in obj) {
if (obj.hasOwnProperty(i)) return false; if (obj.hasOwnProperty(i)) return false;
} }
return true; return true;
} }
function initParams(uri, options, callback) { function initParams(uri, options, callback) {
var params = uri; var params = uri;
if (isFunction(options)) { if (isFunction(options)) {
callback = options; callback = options;
if (typeof uri === "string") { if (typeof uri === "string") {
params = { params = {
uri: uri uri: uri
}; };
} }
} else { } else {
params = _extends({}, options, { params = _extends({}, options, {
uri: uri uri: uri
}); });
} }
params.callback = callback; params.callback = callback;
return params; return params;
} }
function createXHR(uri, options, callback) { function createXHR(uri, options, callback) {
options = initParams(uri, options, callback); options = initParams(uri, options, callback);
return _createXHR(options); return _createXHR(options);
} }
function _createXHR(options) { function _createXHR(options) {
if (typeof options.callback === "undefined") { if (typeof options.callback === "undefined") {
throw new Error("callback argument missing"); throw new Error("callback argument missing");
} }
var called = false; var called = false;
var callback = function cbOnce(err, response, body) { var callback = function cbOnce(err, response, body) {
if (!called) { if (!called) {
called = true; called = true;
options.callback(err, response, body); options.callback(err, response, body);
} }
}; };
function readystatechange() { function readystatechange() {
if (xhr.readyState === 4) { if (xhr.readyState === 4) {
setTimeout(loadFunc, 0); setTimeout(loadFunc, 0);
} }
} }
function getBody() { function getBody() {
// Chrome with requestType=blob throws errors arround when even testing access to responseText // Chrome with requestType=blob throws errors arround when even testing access to responseText
var body = undefined; var body = undefined;
if (xhr.response) { if (xhr.response) {
body = xhr.response; body = xhr.response;
} else { } else {
body = xhr.responseText || getXml(xhr); body = xhr.responseText || getXml(xhr);
} }
if (isJson) { if (isJson) {
try { try {
body = JSON.parse(body); body = JSON.parse(body);
} catch (e) {} } catch (e) {}
} }
return body; return body;
} }
function errorFunc(evt) { function errorFunc(evt) {
clearTimeout(timeoutTimer); clearTimeout(timeoutTimer);
if (!(evt instanceof Error)) { if (!(evt instanceof Error)) {
evt = new Error("" + (evt || "Unknown XMLHttpRequest Error")); evt = new Error("" + (evt || "Unknown XMLHttpRequest Error"));
} }
evt.statusCode = 0; evt.statusCode = 0;
return callback(evt, failureResponse); return callback(evt, failureResponse);
} // will load the data & process the response in a special response object } // will load the data & process the response in a special response object
function loadFunc() { function loadFunc() {
if (aborted) return; if (aborted) return;
var status; var status;
clearTimeout(timeoutTimer); clearTimeout(timeoutTimer);
if (options.useXDR && xhr.status === undefined) { if (options.useXDR && xhr.status === undefined) {
//IE8 CORS GET successful response doesn't have a status field, but body is fine //IE8 CORS GET successful response doesn't have a status field, but body is fine
status = 200; status = 200;
} else { } else {
status = xhr.status === 1223 ? 204 : xhr.status; status = xhr.status === 1223 ? 204 : xhr.status;
} }
var response = failureResponse; var response = failureResponse;
var err = null; var err = null;
if (status !== 0) { if (status !== 0) {
response = { response = {
body: getBody(), body: getBody(),
statusCode: status, statusCode: status,
method: method, method: method,
headers: {}, headers: {},
url: uri, url: uri,
rawRequest: xhr rawRequest: xhr
}; };
if (xhr.getAllResponseHeaders) { if (xhr.getAllResponseHeaders) {
//remember xhr can in fact be XDR for CORS in IE //remember xhr can in fact be XDR for CORS in IE
response.headers = parseHeaders(xhr.getAllResponseHeaders()); response.headers = parseHeaders(xhr.getAllResponseHeaders());
} }
} else { } else {
err = new Error("Internal XMLHttpRequest Error"); err = new Error("Internal XMLHttpRequest Error");
} }
return callback(err, response, response.body); return callback(err, response, response.body);
} }
var xhr = options.xhr || null; var xhr = options.xhr || null;
if (!xhr) { if (!xhr) {
if (options.cors || options.useXDR) { if (options.cors || options.useXDR) {
xhr = new createXHR.XDomainRequest(); xhr = new createXHR.XDomainRequest();
} else { } else {
xhr = new createXHR.XMLHttpRequest(); xhr = new createXHR.XMLHttpRequest();
} }
} }
var key; var key;
var aborted; var aborted;
var uri = xhr.url = options.uri || options.url; var uri = xhr.url = options.uri || options.url;
var method = xhr.method = options.method || "GET"; var method = xhr.method = options.method || "GET";
var body = options.body || options.data; var body = options.body || options.data;
var headers = xhr.headers = options.headers || {}; var headers = xhr.headers = options.headers || {};
var sync = !!options.sync; var sync = !!options.sync;
var isJson = false; var isJson = false;
var timeoutTimer; var timeoutTimer;
var failureResponse = { var failureResponse = {
body: undefined, body: undefined,
headers: {}, headers: {},
statusCode: 0, statusCode: 0,
method: method, method: method,
url: uri, url: uri,
rawRequest: xhr rawRequest: xhr
}; };
if ("json" in options && options.json !== false) { if ("json" in options && options.json !== false) {
isJson = true; isJson = true;
headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json"); //Don't override existing accept header declared by user headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json"); //Don't override existing accept header declared by user
if (method !== "GET" && method !== "HEAD") { if (method !== "GET" && method !== "HEAD") {
headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json"); //Don't override existing accept header declared by user headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json"); //Don't override existing accept header declared by user
body = JSON.stringify(options.json === true ? body : options.json); body = JSON.stringify(options.json === true ? body : options.json);
} }
} }
xhr.onreadystatechange = readystatechange; xhr.onreadystatechange = readystatechange;
xhr.onload = loadFunc; xhr.onload = loadFunc;
xhr.onerror = errorFunc; // IE9 must have onprogress be set to a unique function. xhr.onerror = errorFunc; // IE9 must have onprogress be set to a unique function.
xhr.onprogress = function () {// IE must die xhr.onprogress = function () {// IE must die
}; };
xhr.onabort = function () { xhr.onabort = function () {
aborted = true; aborted = true;
}; };
xhr.ontimeout = errorFunc; xhr.ontimeout = errorFunc;
xhr.open(method, uri, !sync, options.username, options.password); //has to be after open xhr.open(method, uri, !sync, options.username, options.password); //has to be after open
if (!sync) { if (!sync) {
xhr.withCredentials = !!options.withCredentials; xhr.withCredentials = !!options.withCredentials;
} // Cannot set timeout with sync request } // Cannot set timeout with sync request
// not setting timeout on the xhr object, because of old webkits etc. not handling that correctly // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly
// both npm's request and jquery 1.x use this kind of timeout, so this is being consistent // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent
if (!sync && options.timeout > 0) { if (!sync && options.timeout > 0) {
timeoutTimer = setTimeout(function () { timeoutTimer = setTimeout(function () {
if (aborted) return; if (aborted) return;
aborted = true; //IE9 may still call readystatechange aborted = true; //IE9 may still call readystatechange
xhr.abort("timeout"); xhr.abort("timeout");
var e = new Error("XMLHttpRequest timeout"); var e = new Error("XMLHttpRequest timeout");
e.code = "ETIMEDOUT"; e.code = "ETIMEDOUT";
errorFunc(e); errorFunc(e);
}, options.timeout); }, options.timeout);
} }
if (xhr.setRequestHeader) { if (xhr.setRequestHeader) {
for (key in headers) { for (key in headers) {
if (headers.hasOwnProperty(key)) { if (headers.hasOwnProperty(key)) {
xhr.setRequestHeader(key, headers[key]); xhr.setRequestHeader(key, headers[key]);
} }
} }
} else if (options.headers && !isEmpty(options.headers)) { } else if (options.headers && !isEmpty(options.headers)) {
throw new Error("Headers cannot be set on an XDomainRequest object"); throw new Error("Headers cannot be set on an XDomainRequest object");
} }
if ("responseType" in options) { if ("responseType" in options) {
xhr.responseType = options.responseType; xhr.responseType = options.responseType;
} }
if ("beforeSend" in options && typeof options.beforeSend === "function") { if ("beforeSend" in options && typeof options.beforeSend === "function") {
options.beforeSend(xhr); options.beforeSend(xhr);
} // Microsoft Edge browser sends "undefined" when send is called with undefined value. } // Microsoft Edge browser sends "undefined" when send is called with undefined value.
// XMLHttpRequest spec says to pass null as body to indicate no body // XMLHttpRequest spec says to pass null as body to indicate no body
// See https://github.com/naugtur/xhr/issues/100. // See https://github.com/naugtur/xhr/issues/100.
xhr.send(body || null); xhr.send(body || null);
return xhr; return xhr;
} }
function getXml(xhr) { function getXml(xhr) {
// xhr.responseXML will throw Exception "InvalidStateError" or "DOMException" // xhr.responseXML will throw Exception "InvalidStateError" or "DOMException"
// See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseXML. // See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseXML.
try { try {
if (xhr.responseType === "document") { if (xhr.responseType === "document") {
return xhr.responseXML; return xhr.responseXML;
} }
var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror"; var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror";
if (xhr.responseType === "" && !firefoxBugTakenEffect) { if (xhr.responseType === "" && !firefoxBugTakenEffect) {
return xhr.responseXML; return xhr.responseXML;
} }
} catch (e) {} } catch (e) {}
return null; return null;
} }
function noop() {} function noop() {}

View file

@ -1,133 +1,133 @@
{ {
"_from": "aes-decrypter@3.1.2", "_from": "aes-decrypter@3.1.2",
"_id": "aes-decrypter@3.1.2", "_id": "aes-decrypter@3.1.2",
"_inBundle": false, "_inBundle": false,
"_integrity": "sha512-42nRwfQuPRj9R1zqZBdoxnaAmnIFyDi0MNyTVhjdFOd8fifXKKRfwIHIZ6AMn1or4x5WONzjwRTbTWcsIQ0O4A==", "_integrity": "sha512-42nRwfQuPRj9R1zqZBdoxnaAmnIFyDi0MNyTVhjdFOd8fifXKKRfwIHIZ6AMn1or4x5WONzjwRTbTWcsIQ0O4A==",
"_location": "/aes-decrypter", "_location": "/aes-decrypter",
"_phantomChildren": {}, "_phantomChildren": {},
"_requested": { "_requested": {
"type": "version", "type": "version",
"registry": true, "registry": true,
"raw": "aes-decrypter@3.1.2", "raw": "aes-decrypter@3.1.2",
"name": "aes-decrypter", "name": "aes-decrypter",
"escapedName": "aes-decrypter", "escapedName": "aes-decrypter",
"rawSpec": "3.1.2", "rawSpec": "3.1.2",
"saveSpec": null, "saveSpec": null,
"fetchSpec": "3.1.2" "fetchSpec": "3.1.2"
}, },
"_requiredBy": [ "_requiredBy": [
"/@videojs/http-streaming", "/@videojs/http-streaming",
"/video.js" "/video.js"
], ],
"_resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.2.tgz", "_resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.2.tgz",
"_shasum": "3545546f8e9f6b878640339a242efe221ba7a7cb", "_shasum": "3545546f8e9f6b878640339a242efe221ba7a7cb",
"_spec": "aes-decrypter@3.1.2", "_spec": "aes-decrypter@3.1.2",
"_where": "G:\\GDrive\\htdocs\\YouPHPTube\\node_modules\\video.js", "_where": "G:\\GDrive\\htdocs\\YouPHPTube\\node_modules\\video.js",
"author": { "author": {
"name": "Brightcove, Inc." "name": "Brightcove, Inc."
}, },
"browserslist": [ "browserslist": [
"defaults", "defaults",
"ie 11" "ie 11"
], ],
"bugs": { "bugs": {
"url": "https://github.com/videojs/aes-decrypter/issues" "url": "https://github.com/videojs/aes-decrypter/issues"
}, },
"bundleDependencies": false, "bundleDependencies": false,
"contributors": [ "contributors": [
{ {
"name": "gkatsev" "name": "gkatsev"
}, },
{ {
"name": "imbcmdth" "name": "imbcmdth"
}, },
{ {
"name": "dmlap" "name": "dmlap"
}, },
{ {
"name": "bcasey" "name": "bcasey"
} }
], ],
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "^3.0.0", "@videojs/vhs-utils": "^3.0.0",
"global": "^4.4.0", "global": "^4.4.0",
"pkcs7": "^1.0.4" "pkcs7": "^1.0.4"
}, },
"deprecated": false, "deprecated": false,
"description": "decrypt aes-128 content using a key", "description": "decrypt aes-128 content using a key",
"devDependencies": { "devDependencies": {
"@rollup/plugin-replace": "^2.3.4", "@rollup/plugin-replace": "^2.3.4",
"@videojs/generator-helpers": "~2.0.1", "@videojs/generator-helpers": "~2.0.1",
"karma": "^5.2.3", "karma": "^5.2.3",
"rollup": "^2.36.1", "rollup": "^2.36.1",
"sinon": "^9.2.3", "sinon": "^9.2.3",
"videojs-generate-karma-config": "~7.0.0", "videojs-generate-karma-config": "~7.0.0",
"videojs-generate-rollup-config": "~6.1.0", "videojs-generate-rollup-config": "~6.1.0",
"videojs-generator-verify": "~3.0.1", "videojs-generator-verify": "~3.0.1",
"videojs-standard": "^8.0.4" "videojs-standard": "^8.0.4"
}, },
"directories": { "directories": {
"test": "test" "test": "test"
}, },
"files": [ "files": [
"CONTRIBUTING.md", "CONTRIBUTING.md",
"dist/", "dist/",
"docs/", "docs/",
"index.html", "index.html",
"scripts/", "scripts/",
"src/", "src/",
"test/" "test/"
], ],
"generator-videojs-plugin": { "generator-videojs-plugin": {
"version": "7.7.3" "version": "7.7.3"
}, },
"homepage": "https://github.com/videojs/aes-decrypter#readme", "homepage": "https://github.com/videojs/aes-decrypter#readme",
"husky": { "husky": {
"hooks": { "hooks": {
"pre-commit": "lint-staged" "pre-commit": "lint-staged"
} }
}, },
"keywords": [ "keywords": [
"videojs", "videojs",
"videojs-plugin" "videojs-plugin"
], ],
"license": "Apache-2.0", "license": "Apache-2.0",
"lint-staged": { "lint-staged": {
"*.js": "vjsstandard --fix", "*.js": "vjsstandard --fix",
"README.md": "doctoc --notitle" "README.md": "doctoc --notitle"
}, },
"main": "dist/aes-decrypter.cjs.js", "main": "dist/aes-decrypter.cjs.js",
"module": "dist/aes-decrypter.es.js", "module": "dist/aes-decrypter.es.js",
"name": "aes-decrypter", "name": "aes-decrypter",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/videojs/aes-decrypter.git" "url": "git+https://github.com/videojs/aes-decrypter.git"
}, },
"scripts": { "scripts": {
"build": "npm-run-all -s clean -p build:*", "build": "npm-run-all -s clean -p build:*",
"build-prod": "cross-env-shell NO_TEST_BUNDLE=1 'npm run build'", "build-prod": "cross-env-shell NO_TEST_BUNDLE=1 'npm run build'",
"build-test": "cross-env-shell TEST_BUNDLE_ONLY=1 'npm run build'", "build-test": "cross-env-shell TEST_BUNDLE_ONLY=1 'npm run build'",
"build:js": "rollup -c scripts/rollup.config.js", "build:js": "rollup -c scripts/rollup.config.js",
"clean": "shx rm -rf ./dist ./test/dist && shx mkdir -p ./dist ./test/dist", "clean": "shx rm -rf ./dist ./test/dist && shx mkdir -p ./dist ./test/dist",
"lint": "vjsstandard", "lint": "vjsstandard",
"posttest": "shx cat test/dist/coverage/text.txt", "posttest": "shx cat test/dist/coverage/text.txt",
"prepublishOnly": "npm-run-all build-prod && vjsverify --verbose", "prepublishOnly": "npm-run-all build-prod && vjsverify --verbose",
"preversion": "npm test", "preversion": "npm test",
"server": "karma start scripts/karma.conf.js --singleRun=false --auto-watch", "server": "karma start scripts/karma.conf.js --singleRun=false --auto-watch",
"start": "npm-run-all -p server watch", "start": "npm-run-all -p server watch",
"test": "npm-run-all lint build-test && karma start scripts/karma.conf.js", "test": "npm-run-all lint build-test && karma start scripts/karma.conf.js",
"update-changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s", "update-changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s",
"version": "is-prerelease || npm run update-changelog && git add CHANGELOG.md", "version": "is-prerelease || npm run update-changelog && git add CHANGELOG.md",
"watch": "npm-run-all -p watch:*", "watch": "npm-run-all -p watch:*",
"watch:js": "npm run build:js -- -w" "watch:js": "npm run build:js -- -w"
}, },
"version": "3.1.2", "version": "3.1.2",
"vjsstandard": { "vjsstandard": {
"ignore": [ "ignore": [
"dist", "dist",
"docs", "docs",
"test/dist" "test/dist"
] ]
} }
} }

View file

@ -1,12 +1,12 @@
const generate = require('videojs-generate-karma-config'); const generate = require('videojs-generate-karma-config');
module.exports = function(config) { module.exports = function(config) {
// see https://github.com/videojs/videojs-generate-karma-config // see https://github.com/videojs/videojs-generate-karma-config
// for options // for options
const options = {}; const options = {};
config = generate(config, options); config = generate(config, options);
// any other custom stuff not supported by options here! // any other custom stuff not supported by options here!
}; };

View file

@ -1,36 +1,36 @@
const generate = require('videojs-generate-rollup-config'); const generate = require('videojs-generate-rollup-config');
const replace = require('@rollup/plugin-replace'); const replace = require('@rollup/plugin-replace');
// see https://github.com/videojs/videojs-generate-rollup-config // see https://github.com/videojs/videojs-generate-rollup-config
// for options // for options
const options = { const options = {
input: 'src/index.js', input: 'src/index.js',
externals(defaults) { externals(defaults) {
defaults.module.push('pkcs7'); defaults.module.push('pkcs7');
defaults.module.push('@videojs/vhs-utils'); defaults.module.push('@videojs/vhs-utils');
return defaults; return defaults;
}, },
primedPlugins(defaults) { primedPlugins(defaults) {
// when using "require" rather than import // when using "require" rather than import
// require cjs module // require cjs module
defaults.replace = replace({ defaults.replace = replace({
// single quote replace // single quote replace
"require('@videojs/vhs-utils/es": "require('@videojs/vhs-utils/cjs", "require('@videojs/vhs-utils/es": "require('@videojs/vhs-utils/cjs",
// double quote replace // double quote replace
'require("@videojs/vhs-utils/es': 'require("@videojs/vhs-utils/cjs' 'require("@videojs/vhs-utils/es': 'require("@videojs/vhs-utils/cjs'
}); });
return defaults; return defaults;
}, },
plugins(defaults) { plugins(defaults) {
defaults.module.unshift('replace'); defaults.module.unshift('replace');
return defaults; return defaults;
} }
}; };
const config = generate(options); const config = generate(options);
// Add additonal builds/customization here! // Add additonal builds/customization here!
// export the builds to rollup // export the builds to rollup
export default Object.values(config.builds); export default Object.values(config.builds);

516
node_modules/aes-decrypter/src/aes.js generated vendored
View file

@ -1,258 +1,258 @@
/** /**
* @file aes.js * @file aes.js
* *
* This file contains an adaptation of the AES decryption algorithm * This file contains an adaptation of the AES decryption algorithm
* from the Standford Javascript Cryptography Library. That work is * from the Standford Javascript Cryptography Library. That work is
* covered by the following copyright and permissions notice: * covered by the following copyright and permissions notice:
* *
* Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh. * Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are * modification, are permitted provided that the following conditions are
* met: * met:
* *
* 1. Redistributions of source code must retain the above copyright * 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above * 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following * copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided * disclaimer in the documentation and/or other materials provided
* with the distribution. * with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation * The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing * are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of the authors. * official policies, either expressed or implied, of the authors.
*/ */
/** /**
* Expand the S-box tables. * Expand the S-box tables.
* *
* @private * @private
*/ */
const precompute = function() { const precompute = function() {
const tables = [[[], [], [], [], []], [[], [], [], [], []]]; const tables = [[[], [], [], [], []], [[], [], [], [], []]];
const encTable = tables[0]; const encTable = tables[0];
const decTable = tables[1]; const decTable = tables[1];
const sbox = encTable[4]; const sbox = encTable[4];
const sboxInv = decTable[4]; const sboxInv = decTable[4];
let i; let i;
let x; let x;
let xInv; let xInv;
const d = []; const d = [];
const th = []; const th = [];
let x2; let x2;
let x4; let x4;
let x8; let x8;
let s; let s;
let tEnc; let tEnc;
let tDec; let tDec;
// Compute double and third tables // Compute double and third tables
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i; th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i;
} }
for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) { for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
// Compute sbox // Compute sbox
s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4; s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;
s = s >> 8 ^ s & 255 ^ 99; s = s >> 8 ^ s & 255 ^ 99;
sbox[x] = s; sbox[x] = s;
sboxInv[s] = x; sboxInv[s] = x;
// Compute MixColumns // Compute MixColumns
x8 = d[x4 = d[x2 = d[x]]]; x8 = d[x4 = d[x2 = d[x]]];
tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100; tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
tEnc = d[s] * 0x101 ^ s * 0x1010100; tEnc = d[s] * 0x101 ^ s * 0x1010100;
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8; encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;
decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8; decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8;
} }
} }
// Compactify. Considerable speedup on Firefox. // Compactify. Considerable speedup on Firefox.
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
encTable[i] = encTable[i].slice(0); encTable[i] = encTable[i].slice(0);
decTable[i] = decTable[i].slice(0); decTable[i] = decTable[i].slice(0);
} }
return tables; return tables;
}; };
let aesTables = null; let aesTables = null;
/** /**
* Schedule out an AES key for both encryption and decryption. This * Schedule out an AES key for both encryption and decryption. This
* is a low-level class. Use a cipher mode to do bulk encryption. * is a low-level class. Use a cipher mode to do bulk encryption.
* *
* @class AES * @class AES
* @param key {Array} The key as an array of 4, 6 or 8 words. * @param key {Array} The key as an array of 4, 6 or 8 words.
*/ */
export default class AES { export default class AES {
constructor(key) { constructor(key) {
/** /**
* The expanded S-box and inverse S-box tables. These will be computed * The expanded S-box and inverse S-box tables. These will be computed
* on the client so that we don't have to send them down the wire. * on the client so that we don't have to send them down the wire.
* *
* There are two tables, _tables[0] is for encryption and * There are two tables, _tables[0] is for encryption and
* _tables[1] is for decryption. * _tables[1] is for decryption.
* *
* The first 4 sub-tables are the expanded S-box with MixColumns. The * The first 4 sub-tables are the expanded S-box with MixColumns. The
* last (_tables[01][4]) is the S-box itself. * last (_tables[01][4]) is the S-box itself.
* *
* @private * @private
*/ */
// if we have yet to precompute the S-box tables // if we have yet to precompute the S-box tables
// do so now // do so now
if (!aesTables) { if (!aesTables) {
aesTables = precompute(); aesTables = precompute();
} }
// then make a copy of that object for use // then make a copy of that object for use
this._tables = [[aesTables[0][0].slice(), this._tables = [[aesTables[0][0].slice(),
aesTables[0][1].slice(), aesTables[0][1].slice(),
aesTables[0][2].slice(), aesTables[0][2].slice(),
aesTables[0][3].slice(), aesTables[0][3].slice(),
aesTables[0][4].slice()], aesTables[0][4].slice()],
[aesTables[1][0].slice(), [aesTables[1][0].slice(),
aesTables[1][1].slice(), aesTables[1][1].slice(),
aesTables[1][2].slice(), aesTables[1][2].slice(),
aesTables[1][3].slice(), aesTables[1][3].slice(),
aesTables[1][4].slice()]]; aesTables[1][4].slice()]];
let i; let i;
let j; let j;
let tmp; let tmp;
const sbox = this._tables[0][4]; const sbox = this._tables[0][4];
const decTable = this._tables[1]; const decTable = this._tables[1];
const keyLen = key.length; const keyLen = key.length;
let rcon = 1; let rcon = 1;
if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) { if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
throw new Error('Invalid aes key size'); throw new Error('Invalid aes key size');
} }
const encKey = key.slice(0); const encKey = key.slice(0);
const decKey = []; const decKey = [];
this._key = [encKey, decKey]; this._key = [encKey, decKey];
// schedule encryption keys // schedule encryption keys
for (i = keyLen; i < 4 * keyLen + 28; i++) { for (i = keyLen; i < 4 * keyLen + 28; i++) {
tmp = encKey[i - 1]; tmp = encKey[i - 1];
// apply sbox // apply sbox
if (i % keyLen === 0 || (keyLen === 8 && i % keyLen === 4)) { if (i % keyLen === 0 || (keyLen === 8 && i % keyLen === 4)) {
tmp = sbox[tmp >>> 24] << 24 ^ tmp = sbox[tmp >>> 24] << 24 ^
sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 16 & 255] << 16 ^
sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp >> 8 & 255] << 8 ^
sbox[tmp & 255]; sbox[tmp & 255];
// shift rows and add rcon // shift rows and add rcon
if (i % keyLen === 0) { if (i % keyLen === 0) {
tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24; tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;
rcon = rcon << 1 ^ (rcon >> 7) * 283; rcon = rcon << 1 ^ (rcon >> 7) * 283;
} }
} }
encKey[i] = encKey[i - keyLen] ^ tmp; encKey[i] = encKey[i - keyLen] ^ tmp;
} }
// schedule decryption keys // schedule decryption keys
for (j = 0; i; j++, i--) { for (j = 0; i; j++, i--) {
tmp = encKey[j & 3 ? i : i - 4]; tmp = encKey[j & 3 ? i : i - 4];
if (i <= 4 || j < 4) { if (i <= 4 || j < 4) {
decKey[j] = tmp; decKey[j] = tmp;
} else { } else {
decKey[j] = decTable[0][sbox[tmp >>> 24 ]] ^ decKey[j] = decTable[0][sbox[tmp >>> 24 ]] ^
decTable[1][sbox[tmp >> 16 & 255]] ^ decTable[1][sbox[tmp >> 16 & 255]] ^
decTable[2][sbox[tmp >> 8 & 255]] ^ decTable[2][sbox[tmp >> 8 & 255]] ^
decTable[3][sbox[tmp & 255]]; decTable[3][sbox[tmp & 255]];
} }
} }
} }
/** /**
* Decrypt 16 bytes, specified as four 32-bit words. * Decrypt 16 bytes, specified as four 32-bit words.
* *
* @param {number} encrypted0 the first word to decrypt * @param {number} encrypted0 the first word to decrypt
* @param {number} encrypted1 the second word to decrypt * @param {number} encrypted1 the second word to decrypt
* @param {number} encrypted2 the third word to decrypt * @param {number} encrypted2 the third word to decrypt
* @param {number} encrypted3 the fourth word to decrypt * @param {number} encrypted3 the fourth word to decrypt
* @param {Int32Array} out the array to write the decrypted words * @param {Int32Array} out the array to write the decrypted words
* into * into
* @param {number} offset the offset into the output array to start * @param {number} offset the offset into the output array to start
* writing results * writing results
* @return {Array} The plaintext. * @return {Array} The plaintext.
*/ */
decrypt(encrypted0, encrypted1, encrypted2, encrypted3, out, offset) { decrypt(encrypted0, encrypted1, encrypted2, encrypted3, out, offset) {
const key = this._key[1]; const key = this._key[1];
// state variables a,b,c,d are loaded with pre-whitened data // state variables a,b,c,d are loaded with pre-whitened data
let a = encrypted0 ^ key[0]; let a = encrypted0 ^ key[0];
let b = encrypted3 ^ key[1]; let b = encrypted3 ^ key[1];
let c = encrypted2 ^ key[2]; let c = encrypted2 ^ key[2];
let d = encrypted1 ^ key[3]; let d = encrypted1 ^ key[3];
let a2; let a2;
let b2; let b2;
let c2; let c2;
// key.length === 2 ? // key.length === 2 ?
const nInnerRounds = key.length / 4 - 2; const nInnerRounds = key.length / 4 - 2;
let i; let i;
let kIndex = 4; let kIndex = 4;
const table = this._tables[1]; const table = this._tables[1];
// load up the tables // load up the tables
const table0 = table[0]; const table0 = table[0];
const table1 = table[1]; const table1 = table[1];
const table2 = table[2]; const table2 = table[2];
const table3 = table[3]; const table3 = table[3];
const sbox = table[4]; const sbox = table[4];
// Inner rounds. Cribbed from OpenSSL. // Inner rounds. Cribbed from OpenSSL.
for (i = 0; i < nInnerRounds; i++) { for (i = 0; i < nInnerRounds; i++) {
a2 = table0[a >>> 24] ^ a2 = table0[a >>> 24] ^
table1[b >> 16 & 255] ^ table1[b >> 16 & 255] ^
table2[c >> 8 & 255] ^ table2[c >> 8 & 255] ^
table3[d & 255] ^ table3[d & 255] ^
key[kIndex]; key[kIndex];
b2 = table0[b >>> 24] ^ b2 = table0[b >>> 24] ^
table1[c >> 16 & 255] ^ table1[c >> 16 & 255] ^
table2[d >> 8 & 255] ^ table2[d >> 8 & 255] ^
table3[a & 255] ^ table3[a & 255] ^
key[kIndex + 1]; key[kIndex + 1];
c2 = table0[c >>> 24] ^ c2 = table0[c >>> 24] ^
table1[d >> 16 & 255] ^ table1[d >> 16 & 255] ^
table2[a >> 8 & 255] ^ table2[a >> 8 & 255] ^
table3[b & 255] ^ table3[b & 255] ^
key[kIndex + 2]; key[kIndex + 2];
d = table0[d >>> 24] ^ d = table0[d >>> 24] ^
table1[a >> 16 & 255] ^ table1[a >> 16 & 255] ^
table2[b >> 8 & 255] ^ table2[b >> 8 & 255] ^
table3[c & 255] ^ table3[c & 255] ^
key[kIndex + 3]; key[kIndex + 3];
kIndex += 4; kIndex += 4;
a = a2; b = b2; c = c2; a = a2; b = b2; c = c2;
} }
// Last round. // Last round.
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
out[(3 & -i) + offset] = out[(3 & -i) + offset] =
sbox[a >>> 24] << 24 ^ sbox[a >>> 24] << 24 ^
sbox[b >> 16 & 255] << 16 ^ sbox[b >> 16 & 255] << 16 ^
sbox[c >> 8 & 255] << 8 ^ sbox[c >> 8 & 255] << 8 ^
sbox[d & 255] ^ sbox[d & 255] ^
key[kIndex++]; key[kIndex++];
a2 = a; a = b; b = c; c = d; d = a2; a2 = a; a = b; b = c; c = d; d = a2;
} }
} }
} }

View file

@ -1,14 +1,14 @@
@keyframes fadeOutUpBig { @keyframes fadeOutUpBig {
from { from {
opacity: 1; opacity: 1;
} }
to { to {
opacity: 0; opacity: 0;
transform: translate3d(0, -2000px, 0); transform: translate3d(0, -2000px, 0);
} }
} }
.fadeOutUpBig { .fadeOutUpBig {
animation-name: fadeOutUpBig; animation-name: fadeOutUpBig;
} }

View file

@ -1,34 +1,34 @@
@keyframes flip { @keyframes flip {
from { from {
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg); transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg);
animation-timing-function: ease-out; animation-timing-function: ease-out;
} }
40% { 40% {
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
rotate3d(0, 1, 0, -190deg); rotate3d(0, 1, 0, -190deg);
animation-timing-function: ease-out; animation-timing-function: ease-out;
} }
50% { 50% {
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
rotate3d(0, 1, 0, -170deg); rotate3d(0, 1, 0, -170deg);
animation-timing-function: ease-in; animation-timing-function: ease-in;
} }
80% { 80% {
transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0) transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)
rotate3d(0, 1, 0, 0deg); rotate3d(0, 1, 0, 0deg);
animation-timing-function: ease-in; animation-timing-function: ease-in;
} }
to { to {
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg);
animation-timing-function: ease-in; animation-timing-function: ease-in;
} }
} }
.animated.flip { .animated.flip {
backface-visibility: visible; backface-visibility: visible;
animation-name: flip; animation-name: flip;
} }

View file

@ -1,30 +1,30 @@
@keyframes flipInX { @keyframes flipInX {
from { from {
transform: perspective(400px) rotate3d(1, 0, 0, 90deg); transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
animation-timing-function: ease-in; animation-timing-function: ease-in;
opacity: 0; opacity: 0;
} }
40% { 40% {
transform: perspective(400px) rotate3d(1, 0, 0, -20deg); transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
animation-timing-function: ease-in; animation-timing-function: ease-in;
} }
60% { 60% {
transform: perspective(400px) rotate3d(1, 0, 0, 10deg); transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
opacity: 1; opacity: 1;
} }
80% { 80% {
transform: perspective(400px) rotate3d(1, 0, 0, -5deg); transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
} }
to { to {
transform: perspective(400px); transform: perspective(400px);
} }
} }
.flipInX { .flipInX {
backface-visibility: visible !important; backface-visibility: visible !important;
animation-name: flipInX; animation-name: flipInX;
} }

View file

@ -1,30 +1,30 @@
@keyframes flipInY { @keyframes flipInY {
from { from {
transform: perspective(400px) rotate3d(0, 1, 0, 90deg); transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
animation-timing-function: ease-in; animation-timing-function: ease-in;
opacity: 0; opacity: 0;
} }
40% { 40% {
transform: perspective(400px) rotate3d(0, 1, 0, -20deg); transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
animation-timing-function: ease-in; animation-timing-function: ease-in;
} }
60% { 60% {
transform: perspective(400px) rotate3d(0, 1, 0, 10deg); transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
opacity: 1; opacity: 1;
} }
80% { 80% {
transform: perspective(400px) rotate3d(0, 1, 0, -5deg); transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
} }
to { to {
transform: perspective(400px); transform: perspective(400px);
} }
} }
.flipInY { .flipInY {
backface-visibility: visible !important; backface-visibility: visible !important;
animation-name: flipInY; animation-name: flipInY;
} }

View file

@ -1,21 +1,21 @@
@keyframes flipOutX { @keyframes flipOutX {
from { from {
transform: perspective(400px); transform: perspective(400px);
} }
30% { 30% {
transform: perspective(400px) rotate3d(1, 0, 0, -20deg); transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
opacity: 1; opacity: 1;
} }
to { to {
transform: perspective(400px) rotate3d(1, 0, 0, 90deg); transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
opacity: 0; opacity: 0;
} }
} }
.flipOutX { .flipOutX {
animation-duration: calc(var(--animate-duration) * 0.75); animation-duration: calc(var(--animate-duration) * 0.75);
animation-name: flipOutX; animation-name: flipOutX;
backface-visibility: visible !important; backface-visibility: visible !important;
} }

View file

@ -1,17 +1,17 @@
@keyframes zoomInLeft { @keyframes zoomInLeft {
from { from {
opacity: 0; opacity: 0;
transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
} }
60% { 60% {
opacity: 1; opacity: 1;
transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
} }
} }
.zoomInLeft { .zoomInLeft {
animation-name: zoomInLeft; animation-name: zoomInLeft;
} }

View file

@ -1,17 +1,17 @@
@keyframes zoomInRight { @keyframes zoomInRight {
from { from {
opacity: 0; opacity: 0;
transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
} }
60% { 60% {
opacity: 1; opacity: 1;
transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
} }
} }
.zoomInRight { .zoomInRight {
animation-name: zoomInRight; animation-name: zoomInRight;
} }

View file

@ -1,17 +1,17 @@
@keyframes zoomInUp { @keyframes zoomInUp {
from { from {
opacity: 0; opacity: 0;
transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
} }
60% { 60% {
opacity: 1; opacity: 1;
transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
} }
} }
.zoomInUp { .zoomInUp {
animation-name: zoomInUp; animation-name: zoomInUp;
} }

View file

@ -1,18 +1,18 @@
@keyframes zoomOut { @keyframes zoomOut {
from { from {
opacity: 1; opacity: 1;
} }
50% { 50% {
opacity: 0; opacity: 0;
transform: scale3d(0.3, 0.3, 0.3); transform: scale3d(0.3, 0.3, 0.3);
} }
to { to {
opacity: 0; opacity: 0;
} }
} }
.zoomOut { .zoomOut {
animation-name: zoomOut; animation-name: zoomOut;
} }

View file

@ -1,18 +1,18 @@
@keyframes zoomOutDown { @keyframes zoomOutDown {
40% { 40% {
opacity: 1; opacity: 1;
transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
} }
to { to {
opacity: 0; opacity: 0;
transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
} }
} }
.zoomOutDown { .zoomOutDown {
animation-name: zoomOutDown; animation-name: zoomOutDown;
transform-origin: center bottom; transform-origin: center bottom;
} }

View file

@ -1,16 +1,16 @@
@keyframes zoomOutLeft { @keyframes zoomOutLeft {
40% { 40% {
opacity: 1; opacity: 1;
transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
} }
to { to {
opacity: 0; opacity: 0;
transform: scale(0.1) translate3d(-2000px, 0, 0); transform: scale(0.1) translate3d(-2000px, 0, 0);
} }
} }
.zoomOutLeft { .zoomOutLeft {
animation-name: zoomOutLeft; animation-name: zoomOutLeft;
transform-origin: left center; transform-origin: left center;
} }

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,18 +1,18 @@
/*! /*!
* Bootstrap Utilities v5.1.3 (https://getbootstrap.com/) * Bootstrap Utilities v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc. * Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/ */
// Configuration // Configuration
@import "functions"; @import "functions";
@import "variables"; @import "variables";
@import "mixins"; @import "mixins";
@import "utilities"; @import "utilities";
// Helpers // Helpers
@import "helpers"; @import "helpers";
// Utilities // Utilities
@import "utilities/api"; @import "utilities/api";

View file

@ -1,53 +1,53 @@
/*! /*!
* Bootstrap v5.1.3 (https://getbootstrap.com/) * Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc. * Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/ */
// scss-docs-start import-stack // scss-docs-start import-stack
// Configuration // Configuration
@import "functions"; @import "functions";
@import "variables"; @import "variables";
@import "mixins"; @import "mixins";
@import "utilities"; @import "utilities";
// Layout & components // Layout & components
@import "root"; @import "root";
@import "reboot"; @import "reboot";
@import "type"; @import "type";
@import "images"; @import "images";
@import "containers"; @import "containers";
@import "grid"; @import "grid";
@import "tables"; @import "tables";
@import "forms"; @import "forms";
@import "buttons"; @import "buttons";
@import "transitions"; @import "transitions";
@import "dropdown"; @import "dropdown";
@import "button-group"; @import "button-group";
@import "nav"; @import "nav";
@import "navbar"; @import "navbar";
@import "card"; @import "card";
@import "accordion"; @import "accordion";
@import "breadcrumb"; @import "breadcrumb";
@import "pagination"; @import "pagination";
@import "badge"; @import "badge";
@import "alert"; @import "alert";
@import "progress"; @import "progress";
@import "list-group"; @import "list-group";
@import "close"; @import "close";
@import "toasts"; @import "toasts";
@import "modal"; @import "modal";
@import "tooltip"; @import "tooltip";
@import "popover"; @import "popover";
@import "carousel"; @import "carousel";
@import "spinners"; @import "spinners";
@import "offcanvas"; @import "offcanvas";
@import "placeholders"; @import "placeholders";
// Helpers // Helpers
@import "helpers"; @import "helpers";
// Utilities // Utilities
@import "utilities/api"; @import "utilities/api";
// scss-docs-end import-stack // scss-docs-end import-stack

View file

@ -1,63 +1,63 @@
.form-floating { .form-floating {
position: relative; position: relative;
> .form-control, > .form-control,
> .form-select { > .form-select {
height: $form-floating-height; height: $form-floating-height;
line-height: $form-floating-line-height; line-height: $form-floating-line-height;
} }
> label { > label {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
height: 100%; // allow textareas height: 100%; // allow textareas
padding: $form-floating-padding-y $form-floating-padding-x; padding: $form-floating-padding-y $form-floating-padding-x;
pointer-events: none; pointer-events: none;
border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model
transform-origin: 0 0; transform-origin: 0 0;
@include transition($form-floating-transition); @include transition($form-floating-transition);
} }
// stylelint-disable no-duplicate-selectors // stylelint-disable no-duplicate-selectors
> .form-control { > .form-control {
padding: $form-floating-padding-y $form-floating-padding-x; padding: $form-floating-padding-y $form-floating-padding-x;
&::placeholder { &::placeholder {
color: transparent; color: transparent;
} }
&:focus, &:focus,
&:not(:placeholder-shown) { &:not(:placeholder-shown) {
padding-top: $form-floating-input-padding-t; padding-top: $form-floating-input-padding-t;
padding-bottom: $form-floating-input-padding-b; padding-bottom: $form-floating-input-padding-b;
} }
// Duplicated because `:-webkit-autofill` invalidates other selectors when grouped // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
&:-webkit-autofill { &:-webkit-autofill {
padding-top: $form-floating-input-padding-t; padding-top: $form-floating-input-padding-t;
padding-bottom: $form-floating-input-padding-b; padding-bottom: $form-floating-input-padding-b;
} }
} }
> .form-select { > .form-select {
padding-top: $form-floating-input-padding-t; padding-top: $form-floating-input-padding-t;
padding-bottom: $form-floating-input-padding-b; padding-bottom: $form-floating-input-padding-b;
} }
> .form-control:focus, > .form-control:focus,
> .form-control:not(:placeholder-shown), > .form-control:not(:placeholder-shown),
> .form-select { > .form-select {
~ label { ~ label {
opacity: $form-floating-label-opacity; opacity: $form-floating-label-opacity;
transform: $form-floating-label-transform; transform: $form-floating-label-transform;
} }
} }
// Duplicated because `:-webkit-autofill` invalidates other selectors when grouped // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
> .form-control:-webkit-autofill { > .form-control:-webkit-autofill {
~ label { ~ label {
opacity: $form-floating-label-opacity; opacity: $form-floating-label-opacity;
transform: $form-floating-label-transform; transform: $form-floating-label-transform;
} }
} }
// stylelint-enable no-duplicate-selectors // stylelint-enable no-duplicate-selectors
} }

View file

@ -1,152 +1,152 @@
// //
// Check/radio // Check/radio
// //
.form-check { .form-check {
display: block; display: block;
min-height: $form-check-min-height; min-height: $form-check-min-height;
padding-left: $form-check-padding-start; padding-left: $form-check-padding-start;
margin-bottom: $form-check-margin-bottom; margin-bottom: $form-check-margin-bottom;
.form-check-input { .form-check-input {
float: left; float: left;
margin-left: $form-check-padding-start * -1; margin-left: $form-check-padding-start * -1;
} }
} }
.form-check-input { .form-check-input {
width: $form-check-input-width; width: $form-check-input-width;
height: $form-check-input-width; height: $form-check-input-width;
margin-top: ($line-height-base - $form-check-input-width) * .5; // line-height minus check height margin-top: ($line-height-base - $form-check-input-width) * .5; // line-height minus check height
vertical-align: top; vertical-align: top;
background-color: $form-check-input-bg; background-color: $form-check-input-bg;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
background-size: contain; background-size: contain;
border: $form-check-input-border; border: $form-check-input-border;
appearance: none; appearance: none;
color-adjust: exact; // Keep themed appearance for print color-adjust: exact; // Keep themed appearance for print
@include transition($form-check-transition); @include transition($form-check-transition);
&[type="checkbox"] { &[type="checkbox"] {
@include border-radius($form-check-input-border-radius); @include border-radius($form-check-input-border-radius);
} }
&[type="radio"] { &[type="radio"] {
// stylelint-disable-next-line property-disallowed-list // stylelint-disable-next-line property-disallowed-list
border-radius: $form-check-radio-border-radius; border-radius: $form-check-radio-border-radius;
} }
&:active { &:active {
filter: $form-check-input-active-filter; filter: $form-check-input-active-filter;
} }
&:focus { &:focus {
border-color: $form-check-input-focus-border; border-color: $form-check-input-focus-border;
outline: 0; outline: 0;
box-shadow: $form-check-input-focus-box-shadow; box-shadow: $form-check-input-focus-box-shadow;
} }
&:checked { &:checked {
background-color: $form-check-input-checked-bg-color; background-color: $form-check-input-checked-bg-color;
border-color: $form-check-input-checked-border-color; border-color: $form-check-input-checked-border-color;
&[type="checkbox"] { &[type="checkbox"] {
@if $enable-gradients { @if $enable-gradients {
background-image: escape-svg($form-check-input-checked-bg-image), var(--#{$variable-prefix}gradient); background-image: escape-svg($form-check-input-checked-bg-image), var(--#{$variable-prefix}gradient);
} @else { } @else {
background-image: escape-svg($form-check-input-checked-bg-image); background-image: escape-svg($form-check-input-checked-bg-image);
} }
} }
&[type="radio"] { &[type="radio"] {
@if $enable-gradients { @if $enable-gradients {
background-image: escape-svg($form-check-radio-checked-bg-image), var(--#{$variable-prefix}gradient); background-image: escape-svg($form-check-radio-checked-bg-image), var(--#{$variable-prefix}gradient);
} @else { } @else {
background-image: escape-svg($form-check-radio-checked-bg-image); background-image: escape-svg($form-check-radio-checked-bg-image);
} }
} }
} }
&[type="checkbox"]:indeterminate { &[type="checkbox"]:indeterminate {
background-color: $form-check-input-indeterminate-bg-color; background-color: $form-check-input-indeterminate-bg-color;
border-color: $form-check-input-indeterminate-border-color; border-color: $form-check-input-indeterminate-border-color;
@if $enable-gradients { @if $enable-gradients {
background-image: escape-svg($form-check-input-indeterminate-bg-image), var(--#{$variable-prefix}gradient); background-image: escape-svg($form-check-input-indeterminate-bg-image), var(--#{$variable-prefix}gradient);
} @else { } @else {
background-image: escape-svg($form-check-input-indeterminate-bg-image); background-image: escape-svg($form-check-input-indeterminate-bg-image);
} }
} }
&:disabled { &:disabled {
pointer-events: none; pointer-events: none;
filter: none; filter: none;
opacity: $form-check-input-disabled-opacity; opacity: $form-check-input-disabled-opacity;
} }
// Use disabled attribute in addition of :disabled pseudo-class // Use disabled attribute in addition of :disabled pseudo-class
// See: https://github.com/twbs/bootstrap/issues/28247 // See: https://github.com/twbs/bootstrap/issues/28247
&[disabled], &[disabled],
&:disabled { &:disabled {
~ .form-check-label { ~ .form-check-label {
opacity: $form-check-label-disabled-opacity; opacity: $form-check-label-disabled-opacity;
} }
} }
} }
.form-check-label { .form-check-label {
color: $form-check-label-color; color: $form-check-label-color;
cursor: $form-check-label-cursor; cursor: $form-check-label-cursor;
} }
// //
// Switch // Switch
// //
.form-switch { .form-switch {
padding-left: $form-switch-padding-start; padding-left: $form-switch-padding-start;
.form-check-input { .form-check-input {
width: $form-switch-width; width: $form-switch-width;
margin-left: $form-switch-padding-start * -1; margin-left: $form-switch-padding-start * -1;
background-image: escape-svg($form-switch-bg-image); background-image: escape-svg($form-switch-bg-image);
background-position: left center; background-position: left center;
@include border-radius($form-switch-border-radius); @include border-radius($form-switch-border-radius);
@include transition($form-switch-transition); @include transition($form-switch-transition);
&:focus { &:focus {
background-image: escape-svg($form-switch-focus-bg-image); background-image: escape-svg($form-switch-focus-bg-image);
} }
&:checked { &:checked {
background-position: $form-switch-checked-bg-position; background-position: $form-switch-checked-bg-position;
@if $enable-gradients { @if $enable-gradients {
background-image: escape-svg($form-switch-checked-bg-image), var(--#{$variable-prefix}gradient); background-image: escape-svg($form-switch-checked-bg-image), var(--#{$variable-prefix}gradient);
} @else { } @else {
background-image: escape-svg($form-switch-checked-bg-image); background-image: escape-svg($form-switch-checked-bg-image);
} }
} }
} }
} }
.form-check-inline { .form-check-inline {
display: inline-block; display: inline-block;
margin-right: $form-check-inline-margin-end; margin-right: $form-check-inline-margin-end;
} }
.btn-check { .btn-check {
position: absolute; position: absolute;
clip: rect(0, 0, 0, 0); clip: rect(0, 0, 0, 0);
pointer-events: none; pointer-events: none;
&[disabled], &[disabled],
&:disabled { &:disabled {
+ .btn { + .btn {
pointer-events: none; pointer-events: none;
filter: none; filter: none;
opacity: $form-check-btn-check-disabled-opacity; opacity: $form-check-btn-check-disabled-opacity;
} }
} }
} }

View file

@ -1,219 +1,219 @@
// //
// General form controls (plus a few specific high-level interventions) // General form controls (plus a few specific high-level interventions)
// //
.form-control { .form-control {
display: block; display: block;
width: 100%; width: 100%;
padding: $input-padding-y $input-padding-x; padding: $input-padding-y $input-padding-x;
font-family: $input-font-family; font-family: $input-font-family;
@include font-size($input-font-size); @include font-size($input-font-size);
font-weight: $input-font-weight; font-weight: $input-font-weight;
line-height: $input-line-height; line-height: $input-line-height;
color: $input-color; color: $input-color;
background-color: $input-bg; background-color: $input-bg;
background-clip: padding-box; background-clip: padding-box;
border: $input-border-width solid $input-border-color; border: $input-border-width solid $input-border-color;
appearance: none; // Fix appearance for date inputs in Safari appearance: none; // Fix appearance for date inputs in Safari
// Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS. // Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS.
@include border-radius($input-border-radius, 0); @include border-radius($input-border-radius, 0);
@include box-shadow($input-box-shadow); @include box-shadow($input-box-shadow);
@include transition($input-transition); @include transition($input-transition);
&[type="file"] { &[type="file"] {
overflow: hidden; // prevent pseudo element button overlap overflow: hidden; // prevent pseudo element button overlap
&:not(:disabled):not([readonly]) { &:not(:disabled):not([readonly]) {
cursor: pointer; cursor: pointer;
} }
} }
// Customize the `:focus` state to imitate native WebKit styles. // Customize the `:focus` state to imitate native WebKit styles.
&:focus { &:focus {
color: $input-focus-color; color: $input-focus-color;
background-color: $input-focus-bg; background-color: $input-focus-bg;
border-color: $input-focus-border-color; border-color: $input-focus-border-color;
outline: 0; outline: 0;
@if $enable-shadows { @if $enable-shadows {
@include box-shadow($input-box-shadow, $input-focus-box-shadow); @include box-shadow($input-box-shadow, $input-focus-box-shadow);
} @else { } @else {
// Avoid using mixin so we can pass custom focus shadow properly // Avoid using mixin so we can pass custom focus shadow properly
box-shadow: $input-focus-box-shadow; box-shadow: $input-focus-box-shadow;
} }
} }
// Add some height to date inputs on iOS // Add some height to date inputs on iOS
// https://github.com/twbs/bootstrap/issues/23307 // https://github.com/twbs/bootstrap/issues/23307
// TODO: we can remove this workaround once https://bugs.webkit.org/show_bug.cgi?id=198959 is resolved // TODO: we can remove this workaround once https://bugs.webkit.org/show_bug.cgi?id=198959 is resolved
&::-webkit-date-and-time-value { &::-webkit-date-and-time-value {
// Multiply line-height by 1em if it has no unit // Multiply line-height by 1em if it has no unit
height: if(unit($input-line-height) == "", $input-line-height * 1em, $input-line-height); height: if(unit($input-line-height) == "", $input-line-height * 1em, $input-line-height);
} }
// Placeholder // Placeholder
&::placeholder { &::placeholder {
color: $input-placeholder-color; color: $input-placeholder-color;
// Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526. // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.
opacity: 1; opacity: 1;
} }
// Disabled and read-only inputs // Disabled and read-only inputs
// //
// HTML5 says that controls under a fieldset > legend:first-child won't be // HTML5 says that controls under a fieldset > legend:first-child won't be
// disabled if the fieldset is disabled. Due to implementation difficulty, we // disabled if the fieldset is disabled. Due to implementation difficulty, we
// don't honor that edge case; we style them as disabled anyway. // don't honor that edge case; we style them as disabled anyway.
&:disabled, &:disabled,
&[readonly] { &[readonly] {
background-color: $input-disabled-bg; background-color: $input-disabled-bg;
border-color: $input-disabled-border-color; border-color: $input-disabled-border-color;
// iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655. // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.
opacity: 1; opacity: 1;
} }
// File input buttons theming // File input buttons theming
&::file-selector-button { &::file-selector-button {
padding: $input-padding-y $input-padding-x; padding: $input-padding-y $input-padding-x;
margin: (-$input-padding-y) (-$input-padding-x); margin: (-$input-padding-y) (-$input-padding-x);
margin-inline-end: $input-padding-x; margin-inline-end: $input-padding-x;
color: $form-file-button-color; color: $form-file-button-color;
@include gradient-bg($form-file-button-bg); @include gradient-bg($form-file-button-bg);
pointer-events: none; pointer-events: none;
border-color: inherit; border-color: inherit;
border-style: solid; border-style: solid;
border-width: 0; border-width: 0;
border-inline-end-width: $input-border-width; border-inline-end-width: $input-border-width;
border-radius: 0; // stylelint-disable-line property-disallowed-list border-radius: 0; // stylelint-disable-line property-disallowed-list
@include transition($btn-transition); @include transition($btn-transition);
} }
&:hover:not(:disabled):not([readonly])::file-selector-button { &:hover:not(:disabled):not([readonly])::file-selector-button {
background-color: $form-file-button-hover-bg; background-color: $form-file-button-hover-bg;
} }
&::-webkit-file-upload-button { &::-webkit-file-upload-button {
padding: $input-padding-y $input-padding-x; padding: $input-padding-y $input-padding-x;
margin: (-$input-padding-y) (-$input-padding-x); margin: (-$input-padding-y) (-$input-padding-x);
margin-inline-end: $input-padding-x; margin-inline-end: $input-padding-x;
color: $form-file-button-color; color: $form-file-button-color;
@include gradient-bg($form-file-button-bg); @include gradient-bg($form-file-button-bg);
pointer-events: none; pointer-events: none;
border-color: inherit; border-color: inherit;
border-style: solid; border-style: solid;
border-width: 0; border-width: 0;
border-inline-end-width: $input-border-width; border-inline-end-width: $input-border-width;
border-radius: 0; // stylelint-disable-line property-disallowed-list border-radius: 0; // stylelint-disable-line property-disallowed-list
@include transition($btn-transition); @include transition($btn-transition);
} }
&:hover:not(:disabled):not([readonly])::-webkit-file-upload-button { &:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {
background-color: $form-file-button-hover-bg; background-color: $form-file-button-hover-bg;
} }
} }
// Readonly controls as plain text // Readonly controls as plain text
// //
// Apply class to a readonly input to make it appear like regular plain // Apply class to a readonly input to make it appear like regular plain
// text (without any border, background color, focus indicator) // text (without any border, background color, focus indicator)
.form-control-plaintext { .form-control-plaintext {
display: block; display: block;
width: 100%; width: 100%;
padding: $input-padding-y 0; padding: $input-padding-y 0;
margin-bottom: 0; // match inputs if this class comes on inputs with default margins margin-bottom: 0; // match inputs if this class comes on inputs with default margins
line-height: $input-line-height; line-height: $input-line-height;
color: $input-plaintext-color; color: $input-plaintext-color;
background-color: transparent; background-color: transparent;
border: solid transparent; border: solid transparent;
border-width: $input-border-width 0; border-width: $input-border-width 0;
&.form-control-sm, &.form-control-sm,
&.form-control-lg { &.form-control-lg {
padding-right: 0; padding-right: 0;
padding-left: 0; padding-left: 0;
} }
} }
// Form control sizing // Form control sizing
// //
// Build on `.form-control` with modifier classes to decrease or increase the // Build on `.form-control` with modifier classes to decrease or increase the
// height and font-size of form controls. // height and font-size of form controls.
// //
// Repeated in `_input_group.scss` to avoid Sass extend issues. // Repeated in `_input_group.scss` to avoid Sass extend issues.
.form-control-sm { .form-control-sm {
min-height: $input-height-sm; min-height: $input-height-sm;
padding: $input-padding-y-sm $input-padding-x-sm; padding: $input-padding-y-sm $input-padding-x-sm;
@include font-size($input-font-size-sm); @include font-size($input-font-size-sm);
@include border-radius($input-border-radius-sm); @include border-radius($input-border-radius-sm);
&::file-selector-button { &::file-selector-button {
padding: $input-padding-y-sm $input-padding-x-sm; padding: $input-padding-y-sm $input-padding-x-sm;
margin: (-$input-padding-y-sm) (-$input-padding-x-sm); margin: (-$input-padding-y-sm) (-$input-padding-x-sm);
margin-inline-end: $input-padding-x-sm; margin-inline-end: $input-padding-x-sm;
} }
&::-webkit-file-upload-button { &::-webkit-file-upload-button {
padding: $input-padding-y-sm $input-padding-x-sm; padding: $input-padding-y-sm $input-padding-x-sm;
margin: (-$input-padding-y-sm) (-$input-padding-x-sm); margin: (-$input-padding-y-sm) (-$input-padding-x-sm);
margin-inline-end: $input-padding-x-sm; margin-inline-end: $input-padding-x-sm;
} }
} }
.form-control-lg { .form-control-lg {
min-height: $input-height-lg; min-height: $input-height-lg;
padding: $input-padding-y-lg $input-padding-x-lg; padding: $input-padding-y-lg $input-padding-x-lg;
@include font-size($input-font-size-lg); @include font-size($input-font-size-lg);
@include border-radius($input-border-radius-lg); @include border-radius($input-border-radius-lg);
&::file-selector-button { &::file-selector-button {
padding: $input-padding-y-lg $input-padding-x-lg; padding: $input-padding-y-lg $input-padding-x-lg;
margin: (-$input-padding-y-lg) (-$input-padding-x-lg); margin: (-$input-padding-y-lg) (-$input-padding-x-lg);
margin-inline-end: $input-padding-x-lg; margin-inline-end: $input-padding-x-lg;
} }
&::-webkit-file-upload-button { &::-webkit-file-upload-button {
padding: $input-padding-y-lg $input-padding-x-lg; padding: $input-padding-y-lg $input-padding-x-lg;
margin: (-$input-padding-y-lg) (-$input-padding-x-lg); margin: (-$input-padding-y-lg) (-$input-padding-x-lg);
margin-inline-end: $input-padding-x-lg; margin-inline-end: $input-padding-x-lg;
} }
} }
// Make sure textareas don't shrink too much when resized // Make sure textareas don't shrink too much when resized
// https://github.com/twbs/bootstrap/pull/29124 // https://github.com/twbs/bootstrap/pull/29124
// stylelint-disable selector-no-qualifying-type // stylelint-disable selector-no-qualifying-type
textarea { textarea {
&.form-control { &.form-control {
min-height: $input-height; min-height: $input-height;
} }
&.form-control-sm { &.form-control-sm {
min-height: $input-height-sm; min-height: $input-height-sm;
} }
&.form-control-lg { &.form-control-lg {
min-height: $input-height-lg; min-height: $input-height-lg;
} }
} }
// stylelint-enable selector-no-qualifying-type // stylelint-enable selector-no-qualifying-type
.form-control-color { .form-control-color {
width: $form-color-width; width: $form-color-width;
height: auto; // Override fixed browser height height: auto; // Override fixed browser height
padding: $input-padding-y; padding: $input-padding-y;
&:not(:disabled):not([readonly]) { &:not(:disabled):not([readonly]) {
cursor: pointer; cursor: pointer;
} }
&::-moz-color-swatch { &::-moz-color-swatch {
height: if(unit($input-line-height) == "", $input-line-height * 1em, $input-line-height); height: if(unit($input-line-height) == "", $input-line-height * 1em, $input-line-height);
@include border-radius($input-border-radius); @include border-radius($input-border-radius);
} }
&::-webkit-color-swatch { &::-webkit-color-swatch {
height: if(unit($input-line-height) == "", $input-line-height * 1em, $input-line-height); height: if(unit($input-line-height) == "", $input-line-height * 1em, $input-line-height);
@include border-radius($input-border-radius); @include border-radius($input-border-radius);
} }
} }

View file

@ -1,91 +1,91 @@
// Range // Range
// //
// Style range inputs the same across browsers. Vendor-specific rules for pseudo // Style range inputs the same across browsers. Vendor-specific rules for pseudo
// elements cannot be mixed. As such, there are no shared styles for focus or // elements cannot be mixed. As such, there are no shared styles for focus or
// active states on prefixed selectors. // active states on prefixed selectors.
.form-range { .form-range {
width: 100%; width: 100%;
height: add($form-range-thumb-height, $form-range-thumb-focus-box-shadow-width * 2); height: add($form-range-thumb-height, $form-range-thumb-focus-box-shadow-width * 2);
padding: 0; // Need to reset padding padding: 0; // Need to reset padding
background-color: transparent; background-color: transparent;
appearance: none; appearance: none;
&:focus { &:focus {
outline: 0; outline: 0;
// Pseudo-elements must be split across multiple rulesets to have an effect. // Pseudo-elements must be split across multiple rulesets to have an effect.
// No box-shadow() mixin for focus accessibility. // No box-shadow() mixin for focus accessibility.
&::-webkit-slider-thumb { box-shadow: $form-range-thumb-focus-box-shadow; } &::-webkit-slider-thumb { box-shadow: $form-range-thumb-focus-box-shadow; }
&::-moz-range-thumb { box-shadow: $form-range-thumb-focus-box-shadow; } &::-moz-range-thumb { box-shadow: $form-range-thumb-focus-box-shadow; }
} }
&::-moz-focus-outer { &::-moz-focus-outer {
border: 0; border: 0;
} }
&::-webkit-slider-thumb { &::-webkit-slider-thumb {
width: $form-range-thumb-width; width: $form-range-thumb-width;
height: $form-range-thumb-height; height: $form-range-thumb-height;
margin-top: ($form-range-track-height - $form-range-thumb-height) * .5; // Webkit specific margin-top: ($form-range-track-height - $form-range-thumb-height) * .5; // Webkit specific
@include gradient-bg($form-range-thumb-bg); @include gradient-bg($form-range-thumb-bg);
border: $form-range-thumb-border; border: $form-range-thumb-border;
@include border-radius($form-range-thumb-border-radius); @include border-radius($form-range-thumb-border-radius);
@include box-shadow($form-range-thumb-box-shadow); @include box-shadow($form-range-thumb-box-shadow);
@include transition($form-range-thumb-transition); @include transition($form-range-thumb-transition);
appearance: none; appearance: none;
&:active { &:active {
@include gradient-bg($form-range-thumb-active-bg); @include gradient-bg($form-range-thumb-active-bg);
} }
} }
&::-webkit-slider-runnable-track { &::-webkit-slider-runnable-track {
width: $form-range-track-width; width: $form-range-track-width;
height: $form-range-track-height; height: $form-range-track-height;
color: transparent; // Why? color: transparent; // Why?
cursor: $form-range-track-cursor; cursor: $form-range-track-cursor;
background-color: $form-range-track-bg; background-color: $form-range-track-bg;
border-color: transparent; border-color: transparent;
@include border-radius($form-range-track-border-radius); @include border-radius($form-range-track-border-radius);
@include box-shadow($form-range-track-box-shadow); @include box-shadow($form-range-track-box-shadow);
} }
&::-moz-range-thumb { &::-moz-range-thumb {
width: $form-range-thumb-width; width: $form-range-thumb-width;
height: $form-range-thumb-height; height: $form-range-thumb-height;
@include gradient-bg($form-range-thumb-bg); @include gradient-bg($form-range-thumb-bg);
border: $form-range-thumb-border; border: $form-range-thumb-border;
@include border-radius($form-range-thumb-border-radius); @include border-radius($form-range-thumb-border-radius);
@include box-shadow($form-range-thumb-box-shadow); @include box-shadow($form-range-thumb-box-shadow);
@include transition($form-range-thumb-transition); @include transition($form-range-thumb-transition);
appearance: none; appearance: none;
&:active { &:active {
@include gradient-bg($form-range-thumb-active-bg); @include gradient-bg($form-range-thumb-active-bg);
} }
} }
&::-moz-range-track { &::-moz-range-track {
width: $form-range-track-width; width: $form-range-track-width;
height: $form-range-track-height; height: $form-range-track-height;
color: transparent; color: transparent;
cursor: $form-range-track-cursor; cursor: $form-range-track-cursor;
background-color: $form-range-track-bg; background-color: $form-range-track-bg;
border-color: transparent; // Firefox specific? border-color: transparent; // Firefox specific?
@include border-radius($form-range-track-border-radius); @include border-radius($form-range-track-border-radius);
@include box-shadow($form-range-track-box-shadow); @include box-shadow($form-range-track-box-shadow);
} }
&:disabled { &:disabled {
pointer-events: none; pointer-events: none;
&::-webkit-slider-thumb { &::-webkit-slider-thumb {
background-color: $form-range-thumb-disabled-bg; background-color: $form-range-thumb-disabled-bg;
} }
&::-moz-range-thumb { &::-moz-range-thumb {
background-color: $form-range-thumb-disabled-bg; background-color: $form-range-thumb-disabled-bg;
} }
} }
} }

View file

@ -1,72 +1,72 @@
// Select // Select
// //
// Replaces the browser default select with a custom one, mostly pulled from // Replaces the browser default select with a custom one, mostly pulled from
// https://primer.github.io/. // https://primer.github.io/.
.form-select { .form-select {
display: block; display: block;
width: 100%; width: 100%;
padding: $form-select-padding-y $form-select-indicator-padding $form-select-padding-y $form-select-padding-x; padding: $form-select-padding-y $form-select-indicator-padding $form-select-padding-y $form-select-padding-x;
// stylelint-disable-next-line property-no-vendor-prefix // stylelint-disable-next-line property-no-vendor-prefix
-moz-padding-start: subtract($form-select-padding-x, 3px); // See https://github.com/twbs/bootstrap/issues/32636 -moz-padding-start: subtract($form-select-padding-x, 3px); // See https://github.com/twbs/bootstrap/issues/32636
font-family: $form-select-font-family; font-family: $form-select-font-family;
@include font-size($form-select-font-size); @include font-size($form-select-font-size);
font-weight: $form-select-font-weight; font-weight: $form-select-font-weight;
line-height: $form-select-line-height; line-height: $form-select-line-height;
color: $form-select-color; color: $form-select-color;
background-color: $form-select-bg; background-color: $form-select-bg;
background-image: escape-svg($form-select-indicator); background-image: escape-svg($form-select-indicator);
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: $form-select-bg-position; background-position: $form-select-bg-position;
background-size: $form-select-bg-size; background-size: $form-select-bg-size;
border: $form-select-border-width solid $form-select-border-color; border: $form-select-border-width solid $form-select-border-color;
@include border-radius($form-select-border-radius, 0); @include border-radius($form-select-border-radius, 0);
@include box-shadow($form-select-box-shadow); @include box-shadow($form-select-box-shadow);
@include transition($form-select-transition); @include transition($form-select-transition);
appearance: none; appearance: none;
&:focus { &:focus {
border-color: $form-select-focus-border-color; border-color: $form-select-focus-border-color;
outline: 0; outline: 0;
@if $enable-shadows { @if $enable-shadows {
@include box-shadow($form-select-box-shadow, $form-select-focus-box-shadow); @include box-shadow($form-select-box-shadow, $form-select-focus-box-shadow);
} @else { } @else {
// Avoid using mixin so we can pass custom focus shadow properly // Avoid using mixin so we can pass custom focus shadow properly
box-shadow: $form-select-focus-box-shadow; box-shadow: $form-select-focus-box-shadow;
} }
} }
&[multiple], &[multiple],
&[size]:not([size="1"]) { &[size]:not([size="1"]) {
padding-right: $form-select-padding-x; padding-right: $form-select-padding-x;
background-image: none; background-image: none;
} }
&:disabled { &:disabled {
color: $form-select-disabled-color; color: $form-select-disabled-color;
background-color: $form-select-disabled-bg; background-color: $form-select-disabled-bg;
border-color: $form-select-disabled-border-color; border-color: $form-select-disabled-border-color;
} }
// Remove outline from select box in FF // Remove outline from select box in FF
&:-moz-focusring { &:-moz-focusring {
color: transparent; color: transparent;
text-shadow: 0 0 0 $form-select-color; text-shadow: 0 0 0 $form-select-color;
} }
} }
.form-select-sm { .form-select-sm {
padding-top: $form-select-padding-y-sm; padding-top: $form-select-padding-y-sm;
padding-bottom: $form-select-padding-y-sm; padding-bottom: $form-select-padding-y-sm;
padding-left: $form-select-padding-x-sm; padding-left: $form-select-padding-x-sm;
@include font-size($form-select-font-size-sm); @include font-size($form-select-font-size-sm);
@include border-radius($form-select-border-radius-sm); @include border-radius($form-select-border-radius-sm);
} }
.form-select-lg { .form-select-lg {
padding-top: $form-select-padding-y-lg; padding-top: $form-select-padding-y-lg;
padding-bottom: $form-select-padding-y-lg; padding-bottom: $form-select-padding-y-lg;
padding-left: $form-select-padding-x-lg; padding-left: $form-select-padding-x-lg;
@include font-size($form-select-font-size-lg); @include font-size($form-select-font-size-lg);
@include border-radius($form-select-border-radius-lg); @include border-radius($form-select-border-radius-lg);
} }

View file

@ -1,11 +1,11 @@
// //
// Form text // Form text
// //
.form-text { .form-text {
margin-top: $form-text-margin-top; margin-top: $form-text-margin-top;
@include font-size($form-text-font-size); @include font-size($form-text-font-size);
font-style: $form-text-font-style; font-style: $form-text-font-style;
font-weight: $form-text-font-weight; font-weight: $form-text-font-weight;
color: $form-text-color; color: $form-text-color;
} }

View file

@ -1,121 +1,121 @@
// //
// Base styles // Base styles
// //
.input-group { .input-group {
position: relative; position: relative;
display: flex; display: flex;
flex-wrap: wrap; // For form validation feedback flex-wrap: wrap; // For form validation feedback
align-items: stretch; align-items: stretch;
width: 100%; width: 100%;
> .form-control, > .form-control,
> .form-select { > .form-select {
position: relative; // For focus state's z-index position: relative; // For focus state's z-index
flex: 1 1 auto; flex: 1 1 auto;
width: 1%; width: 1%;
min-width: 0; // https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size min-width: 0; // https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size
} }
// Bring the "active" form control to the top of surrounding elements // Bring the "active" form control to the top of surrounding elements
> .form-control:focus, > .form-control:focus,
> .form-select:focus { > .form-select:focus {
z-index: 3; z-index: 3;
} }
// Ensure buttons are always above inputs for more visually pleasing borders. // Ensure buttons are always above inputs for more visually pleasing borders.
// This isn't needed for `.input-group-text` since it shares the same border-color // This isn't needed for `.input-group-text` since it shares the same border-color
// as our inputs. // as our inputs.
.btn { .btn {
position: relative; position: relative;
z-index: 2; z-index: 2;
&:focus { &:focus {
z-index: 3; z-index: 3;
} }
} }
} }
// Textual addons // Textual addons
// //
// Serves as a catch-all element for any text or radio/checkbox input you wish // Serves as a catch-all element for any text or radio/checkbox input you wish
// to prepend or append to an input. // to prepend or append to an input.
.input-group-text { .input-group-text {
display: flex; display: flex;
align-items: center; align-items: center;
padding: $input-group-addon-padding-y $input-group-addon-padding-x; padding: $input-group-addon-padding-y $input-group-addon-padding-x;
@include font-size($input-font-size); // Match inputs @include font-size($input-font-size); // Match inputs
font-weight: $input-group-addon-font-weight; font-weight: $input-group-addon-font-weight;
line-height: $input-line-height; line-height: $input-line-height;
color: $input-group-addon-color; color: $input-group-addon-color;
text-align: center; text-align: center;
white-space: nowrap; white-space: nowrap;
background-color: $input-group-addon-bg; background-color: $input-group-addon-bg;
border: $input-border-width solid $input-group-addon-border-color; border: $input-border-width solid $input-group-addon-border-color;
@include border-radius($input-border-radius); @include border-radius($input-border-radius);
} }
// Sizing // Sizing
// //
// Remix the default form control sizing classes into new ones for easier // Remix the default form control sizing classes into new ones for easier
// manipulation. // manipulation.
.input-group-lg > .form-control, .input-group-lg > .form-control,
.input-group-lg > .form-select, .input-group-lg > .form-select,
.input-group-lg > .input-group-text, .input-group-lg > .input-group-text,
.input-group-lg > .btn { .input-group-lg > .btn {
padding: $input-padding-y-lg $input-padding-x-lg; padding: $input-padding-y-lg $input-padding-x-lg;
@include font-size($input-font-size-lg); @include font-size($input-font-size-lg);
@include border-radius($input-border-radius-lg); @include border-radius($input-border-radius-lg);
} }
.input-group-sm > .form-control, .input-group-sm > .form-control,
.input-group-sm > .form-select, .input-group-sm > .form-select,
.input-group-sm > .input-group-text, .input-group-sm > .input-group-text,
.input-group-sm > .btn { .input-group-sm > .btn {
padding: $input-padding-y-sm $input-padding-x-sm; padding: $input-padding-y-sm $input-padding-x-sm;
@include font-size($input-font-size-sm); @include font-size($input-font-size-sm);
@include border-radius($input-border-radius-sm); @include border-radius($input-border-radius-sm);
} }
.input-group-lg > .form-select, .input-group-lg > .form-select,
.input-group-sm > .form-select { .input-group-sm > .form-select {
padding-right: $form-select-padding-x + $form-select-indicator-padding; padding-right: $form-select-padding-x + $form-select-indicator-padding;
} }
// Rounded corners // Rounded corners
// //
// These rulesets must come after the sizing ones to properly override sm and lg // These rulesets must come after the sizing ones to properly override sm and lg
// border-radius values when extending. They're more specific than we'd like // border-radius values when extending. They're more specific than we'd like
// with the `.input-group >` part, but without it, we cannot override the sizing. // with the `.input-group >` part, but without it, we cannot override the sizing.
// stylelint-disable-next-line no-duplicate-selectors // stylelint-disable-next-line no-duplicate-selectors
.input-group { .input-group {
&:not(.has-validation) { &:not(.has-validation) {
> :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu), > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu),
> .dropdown-toggle:nth-last-child(n + 3) { > .dropdown-toggle:nth-last-child(n + 3) {
@include border-end-radius(0); @include border-end-radius(0);
} }
} }
&.has-validation { &.has-validation {
> :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu), > :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu),
> .dropdown-toggle:nth-last-child(n + 4) { > .dropdown-toggle:nth-last-child(n + 4) {
@include border-end-radius(0); @include border-end-radius(0);
} }
} }
$validation-messages: ""; $validation-messages: "";
@each $state in map-keys($form-validation-states) { @each $state in map-keys($form-validation-states) {
$validation-messages: $validation-messages + ":not(." + unquote($state) + "-tooltip)" + ":not(." + unquote($state) + "-feedback)"; $validation-messages: $validation-messages + ":not(." + unquote($state) + "-tooltip)" + ":not(." + unquote($state) + "-feedback)";
} }
> :not(:first-child):not(.dropdown-menu)#{$validation-messages} { > :not(:first-child):not(.dropdown-menu)#{$validation-messages} {
margin-left: -$input-border-width; margin-left: -$input-border-width;
@include border-start-radius(0); @include border-start-radius(0);
} }
} }

View file

@ -1,36 +1,36 @@
// //
// Labels // Labels
// //
.form-label { .form-label {
margin-bottom: $form-label-margin-bottom; margin-bottom: $form-label-margin-bottom;
@include font-size($form-label-font-size); @include font-size($form-label-font-size);
font-style: $form-label-font-style; font-style: $form-label-font-style;
font-weight: $form-label-font-weight; font-weight: $form-label-font-weight;
color: $form-label-color; color: $form-label-color;
} }
// For use with horizontal and inline forms, when you need the label (or legend) // For use with horizontal and inline forms, when you need the label (or legend)
// text to align with the form controls. // text to align with the form controls.
.col-form-label { .col-form-label {
padding-top: add($input-padding-y, $input-border-width); padding-top: add($input-padding-y, $input-border-width);
padding-bottom: add($input-padding-y, $input-border-width); padding-bottom: add($input-padding-y, $input-border-width);
margin-bottom: 0; // Override the `<legend>` default margin-bottom: 0; // Override the `<legend>` default
@include font-size(inherit); // Override the `<legend>` default @include font-size(inherit); // Override the `<legend>` default
font-style: $form-label-font-style; font-style: $form-label-font-style;
font-weight: $form-label-font-weight; font-weight: $form-label-font-weight;
line-height: $input-line-height; line-height: $input-line-height;
color: $form-label-color; color: $form-label-color;
} }
.col-form-label-lg { .col-form-label-lg {
padding-top: add($input-padding-y-lg, $input-border-width); padding-top: add($input-padding-y-lg, $input-border-width);
padding-bottom: add($input-padding-y-lg, $input-border-width); padding-bottom: add($input-padding-y-lg, $input-border-width);
@include font-size($input-font-size-lg); @include font-size($input-font-size-lg);
} }
.col-form-label-sm { .col-form-label-sm {
padding-top: add($input-padding-y-sm, $input-border-width); padding-top: add($input-padding-y-sm, $input-border-width);
padding-bottom: add($input-padding-y-sm, $input-border-width); padding-bottom: add($input-padding-y-sm, $input-border-width);
@include font-size($input-font-size-sm); @include font-size($input-font-size-sm);
} }

View file

@ -1,12 +1,12 @@
// Form validation // Form validation
// //
// Provide feedback to users when form field values are valid or invalid. Works // Provide feedback to users when form field values are valid or invalid. Works
// primarily for client-side validation via scoped `:invalid` and `:valid` // primarily for client-side validation via scoped `:invalid` and `:valid`
// pseudo-classes but also includes `.is-invalid` and `.is-valid` classes for // pseudo-classes but also includes `.is-invalid` and `.is-valid` classes for
// server-side validation. // server-side validation.
// scss-docs-start form-validation-states-loop // scss-docs-start form-validation-states-loop
@each $state, $data in $form-validation-states { @each $state, $data in $form-validation-states {
@include form-validation-state($state, $data...); @include form-validation-state($state, $data...);
} }
// scss-docs-end form-validation-states-loop // scss-docs-end form-validation-states-loop

View file

@ -1,3 +1,3 @@
.clearfix { .clearfix {
@include clearfix(); @include clearfix();
} }

View file

@ -1,12 +1,12 @@
@each $color, $value in $theme-colors { @each $color, $value in $theme-colors {
.link-#{$color} { .link-#{$color} {
color: $value; color: $value;
@if $link-shade-percentage != 0 { @if $link-shade-percentage != 0 {
&:hover, &:hover,
&:focus { &:focus {
color: if(color-contrast($value) == $color-contrast-light, shade-color($value, $link-shade-percentage), tint-color($value, $link-shade-percentage)); color: if(color-contrast($value) == $color-contrast-light, shade-color($value, $link-shade-percentage), tint-color($value, $link-shade-percentage));
} }
} }
} }
} }

View file

@ -1,30 +1,30 @@
// Shorthand // Shorthand
.fixed-top { .fixed-top {
position: fixed; position: fixed;
top: 0; top: 0;
right: 0; right: 0;
left: 0; left: 0;
z-index: $zindex-fixed; z-index: $zindex-fixed;
} }
.fixed-bottom { .fixed-bottom {
position: fixed; position: fixed;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: $zindex-fixed; z-index: $zindex-fixed;
} }
// Responsive sticky top // Responsive sticky top
@each $breakpoint in map-keys($grid-breakpoints) { @each $breakpoint in map-keys($grid-breakpoints) {
@include media-breakpoint-up($breakpoint) { @include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints); $infix: breakpoint-infix($breakpoint, $grid-breakpoints);
.sticky#{$infix}-top { .sticky#{$infix}-top {
position: sticky; position: sticky;
top: 0; top: 0;
z-index: $zindex-sticky; z-index: $zindex-sticky;
} }
} }
} }

View file

@ -1,26 +1,26 @@
// Credit: Nicolas Gallagher and SUIT CSS. // Credit: Nicolas Gallagher and SUIT CSS.
.ratio { .ratio {
position: relative; position: relative;
width: 100%; width: 100%;
&::before { &::before {
display: block; display: block;
padding-top: var(--#{$variable-prefix}aspect-ratio); padding-top: var(--#{$variable-prefix}aspect-ratio);
content: ""; content: "";
} }
> * { > * {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
@each $key, $ratio in $aspect-ratios { @each $key, $ratio in $aspect-ratios {
.ratio-#{$key} { .ratio-#{$key} {
--#{$variable-prefix}aspect-ratio: #{$ratio}; --#{$variable-prefix}aspect-ratio: #{$ratio};
} }
} }

View file

@ -1,15 +1,15 @@
// scss-docs-start stacks // scss-docs-start stacks
.hstack { .hstack {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
align-self: stretch; align-self: stretch;
} }
.vstack { .vstack {
display: flex; display: flex;
flex: 1 1 auto; flex: 1 1 auto;
flex-direction: column; flex-direction: column;
align-self: stretch; align-self: stretch;
} }
// scss-docs-end stacks // scss-docs-end stacks

View file

@ -1,15 +1,15 @@
// //
// Stretched link // Stretched link
// //
.stretched-link { .stretched-link {
&::#{$stretched-link-pseudo-element} { &::#{$stretched-link-pseudo-element} {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: $stretched-link-z-index; z-index: $stretched-link-z-index;
content: ""; content: "";
} }
} }

View file

@ -1,7 +1,7 @@
// //
// Text truncation // Text truncation
// //
.text-truncate { .text-truncate {
@include text-truncate(); @include text-truncate();
} }

View file

@ -1,8 +1,8 @@
// //
// Visually hidden // Visually hidden
// //
.visually-hidden, .visually-hidden,
.visually-hidden-focusable:not(:focus):not(:focus-within) { .visually-hidden-focusable:not(:focus):not(:focus-within) {
@include visually-hidden(); @include visually-hidden();
} }

View file

@ -1,185 +1,185 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE // Distributed under an MIT license: https://codemirror.net/LICENSE
/** /**
* Tag-closer extension for CodeMirror. * Tag-closer extension for CodeMirror.
* *
* This extension adds an "autoCloseTags" option that can be set to * This extension adds an "autoCloseTags" option that can be set to
* either true to get the default behavior, or an object to further * either true to get the default behavior, or an object to further
* configure its behavior. * configure its behavior.
* *
* These are supported options: * These are supported options:
* *
* `whenClosing` (default true) * `whenClosing` (default true)
* Whether to autoclose when the '/' of a closing tag is typed. * Whether to autoclose when the '/' of a closing tag is typed.
* `whenOpening` (default true) * `whenOpening` (default true)
* Whether to autoclose the tag when the final '>' of an opening * Whether to autoclose the tag when the final '>' of an opening
* tag is typed. * tag is typed.
* `dontCloseTags` (default is empty tags for HTML, none for XML) * `dontCloseTags` (default is empty tags for HTML, none for XML)
* An array of tag names that should not be autoclosed. * An array of tag names that should not be autoclosed.
* `indentTags` (default is block tags for HTML, none for XML) * `indentTags` (default is block tags for HTML, none for XML)
* An array of tag names that should, when opened, cause a * An array of tag names that should, when opened, cause a
* blank line to be added inside the tag, and the blank line and * blank line to be added inside the tag, and the blank line and
* closing line to be indented. * closing line to be indented.
* `emptyTags` (default is none) * `emptyTags` (default is none)
* An array of XML tag names that should be autoclosed with '/>'. * An array of XML tag names that should be autoclosed with '/>'.
* *
* See demos/closetag.html for a usage example. * See demos/closetag.html for a usage example.
*/ */
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../fold/xml-fold")); mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../fold/xml-fold"], mod); define(["../../lib/codemirror", "../fold/xml-fold"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) { CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
if (old != CodeMirror.Init && old) if (old != CodeMirror.Init && old)
cm.removeKeyMap("autoCloseTags"); cm.removeKeyMap("autoCloseTags");
if (!val) return; if (!val) return;
var map = {name: "autoCloseTags"}; var map = {name: "autoCloseTags"};
if (typeof val != "object" || val.whenClosing !== false) if (typeof val != "object" || val.whenClosing !== false)
map["'/'"] = function(cm) { return autoCloseSlash(cm); }; map["'/'"] = function(cm) { return autoCloseSlash(cm); };
if (typeof val != "object" || val.whenOpening !== false) if (typeof val != "object" || val.whenOpening !== false)
map["'>'"] = function(cm) { return autoCloseGT(cm); }; map["'>'"] = function(cm) { return autoCloseGT(cm); };
cm.addKeyMap(map); cm.addKeyMap(map);
}); });
var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
"source", "track", "wbr"]; "source", "track", "wbr"];
var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
"h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
function autoCloseGT(cm) { function autoCloseGT(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass; if (cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(), replacements = []; var ranges = cm.listSelections(), replacements = [];
var opt = cm.getOption("autoCloseTags"); var opt = cm.getOption("autoCloseTags");
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
if (!ranges[i].empty()) return CodeMirror.Pass; if (!ranges[i].empty()) return CodeMirror.Pass;
var pos = ranges[i].head, tok = cm.getTokenAt(pos); var pos = ranges[i].head, tok = cm.getTokenAt(pos);
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
var tagInfo = inner.mode.xmlCurrentTag && inner.mode.xmlCurrentTag(state) var tagInfo = inner.mode.xmlCurrentTag && inner.mode.xmlCurrentTag(state)
var tagName = tagInfo && tagInfo.name var tagName = tagInfo && tagInfo.name
if (!tagName) return CodeMirror.Pass if (!tagName) return CodeMirror.Pass
var html = inner.mode.configuration == "html"; var html = inner.mode.configuration == "html";
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
var lowerTagName = tagName.toLowerCase(); var lowerTagName = tagName.toLowerCase();
// Don't process the '>' at the end of an end-tag or self-closing tag // Don't process the '>' at the end of an end-tag or self-closing tag
if (!tagName || if (!tagName ||
tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) || tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
tok.type == "tag" && tagInfo.close || tok.type == "tag" && tagInfo.close ||
tok.string.indexOf("/") == (pos.ch - tok.start - 1) || // match something like <someTagName /> tok.string.indexOf("/") == (pos.ch - tok.start - 1) || // match something like <someTagName />
dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 || dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
closingTagExists(cm, inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) || [], tagName, pos, true)) closingTagExists(cm, inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) || [], tagName, pos, true))
return CodeMirror.Pass; return CodeMirror.Pass;
var emptyTags = typeof opt == "object" && opt.emptyTags; var emptyTags = typeof opt == "object" && opt.emptyTags;
if (emptyTags && indexOf(emptyTags, tagName) > -1) { if (emptyTags && indexOf(emptyTags, tagName) > -1) {
replacements[i] = { text: "/>", newPos: CodeMirror.Pos(pos.line, pos.ch + 2) }; replacements[i] = { text: "/>", newPos: CodeMirror.Pos(pos.line, pos.ch + 2) };
continue; continue;
} }
var indent = indentTags && indexOf(indentTags, lowerTagName) > -1; var indent = indentTags && indexOf(indentTags, lowerTagName) > -1;
replacements[i] = {indent: indent, replacements[i] = {indent: indent,
text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">", text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">",
newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
} }
var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose); var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose);
for (var i = ranges.length - 1; i >= 0; i--) { for (var i = ranges.length - 1; i >= 0; i--) {
var info = replacements[i]; var info = replacements[i];
cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
var sel = cm.listSelections().slice(0); var sel = cm.listSelections().slice(0);
sel[i] = {head: info.newPos, anchor: info.newPos}; sel[i] = {head: info.newPos, anchor: info.newPos};
cm.setSelections(sel); cm.setSelections(sel);
if (!dontIndentOnAutoClose && info.indent) { if (!dontIndentOnAutoClose && info.indent) {
cm.indentLine(info.newPos.line, null, true); cm.indentLine(info.newPos.line, null, true);
cm.indentLine(info.newPos.line + 1, null, true); cm.indentLine(info.newPos.line + 1, null, true);
} }
} }
} }
function autoCloseCurrent(cm, typingSlash) { function autoCloseCurrent(cm, typingSlash) {
var ranges = cm.listSelections(), replacements = []; var ranges = cm.listSelections(), replacements = [];
var head = typingSlash ? "/" : "</"; var head = typingSlash ? "/" : "</";
var opt = cm.getOption("autoCloseTags"); var opt = cm.getOption("autoCloseTags");
var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnSlash); var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnSlash);
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
if (!ranges[i].empty()) return CodeMirror.Pass; if (!ranges[i].empty()) return CodeMirror.Pass;
var pos = ranges[i].head, tok = cm.getTokenAt(pos); var pos = ranges[i].head, tok = cm.getTokenAt(pos);
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" || if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" ||
tok.start != pos.ch - 1)) tok.start != pos.ch - 1))
return CodeMirror.Pass; return CodeMirror.Pass;
// Kludge to get around the fact that we are not in XML mode // Kludge to get around the fact that we are not in XML mode
// when completing in JS/CSS snippet in htmlmixed mode. Does not // when completing in JS/CSS snippet in htmlmixed mode. Does not
// work for other XML embedded languages (there is no general // work for other XML embedded languages (there is no general
// way to go from a mixed mode to its current XML state). // way to go from a mixed mode to its current XML state).
var replacement, mixed = inner.mode.name != "xml" && cm.getMode().name == "htmlmixed" var replacement, mixed = inner.mode.name != "xml" && cm.getMode().name == "htmlmixed"
if (mixed && inner.mode.name == "javascript") { if (mixed && inner.mode.name == "javascript") {
replacement = head + "script"; replacement = head + "script";
} else if (mixed && inner.mode.name == "css") { } else if (mixed && inner.mode.name == "css") {
replacement = head + "style"; replacement = head + "style";
} else { } else {
var context = inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) var context = inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state)
var top = context.length ? context[context.length - 1] : "" var top = context.length ? context[context.length - 1] : ""
if (!context || (context.length && closingTagExists(cm, context, top, pos))) if (!context || (context.length && closingTagExists(cm, context, top, pos)))
return CodeMirror.Pass; return CodeMirror.Pass;
replacement = head + top replacement = head + top
} }
if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">"; if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">";
replacements[i] = replacement; replacements[i] = replacement;
} }
cm.replaceSelections(replacements); cm.replaceSelections(replacements);
ranges = cm.listSelections(); ranges = cm.listSelections();
if (!dontIndentOnAutoClose) { if (!dontIndentOnAutoClose) {
for (var i = 0; i < ranges.length; i++) for (var i = 0; i < ranges.length; i++)
if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line) if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
cm.indentLine(ranges[i].head.line); cm.indentLine(ranges[i].head.line);
} }
} }
function autoCloseSlash(cm) { function autoCloseSlash(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass; if (cm.getOption("disableInput")) return CodeMirror.Pass;
return autoCloseCurrent(cm, true); return autoCloseCurrent(cm, true);
} }
CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); }; CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); };
function indexOf(collection, elt) { function indexOf(collection, elt) {
if (collection.indexOf) return collection.indexOf(elt); if (collection.indexOf) return collection.indexOf(elt);
for (var i = 0, e = collection.length; i < e; ++i) for (var i = 0, e = collection.length; i < e; ++i)
if (collection[i] == elt) return i; if (collection[i] == elt) return i;
return -1; return -1;
} }
// If xml-fold is loaded, we use its functionality to try and verify // If xml-fold is loaded, we use its functionality to try and verify
// whether a given tag is actually unclosed. // whether a given tag is actually unclosed.
function closingTagExists(cm, context, tagName, pos, newTag) { function closingTagExists(cm, context, tagName, pos, newTag) {
if (!CodeMirror.scanForClosingTag) return false; if (!CodeMirror.scanForClosingTag) return false;
var end = Math.min(cm.lastLine() + 1, pos.line + 500); var end = Math.min(cm.lastLine() + 1, pos.line + 500);
var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end); var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
if (!nextClose || nextClose.tag != tagName) return false; if (!nextClose || nextClose.tag != tagName) return false;
// If the immediate wrapping context contains onCx instances of // If the immediate wrapping context contains onCx instances of
// the same tag, a closing tag only exists if there are at least // the same tag, a closing tag only exists if there are at least
// that many closing tags of that type following. // that many closing tags of that type following.
var onCx = newTag ? 1 : 0 var onCx = newTag ? 1 : 0
for (var i = context.length - 1; i >= 0; i--) { for (var i = context.length - 1; i >= 0; i--) {
if (context[i] == tagName) ++onCx if (context[i] == tagName) ++onCx
else break else break
} }
pos = nextClose.to; pos = nextClose.to;
for (var i = 1; i < onCx; i++) { for (var i = 1; i < onCx; i++) {
var next = CodeMirror.scanForClosingTag(cm, pos, null, end); var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
if (!next || next.tag != tagName) return false; if (!next || next.tag != tagName) return false;
pos = next.to; pos = next.to;
} }
return true; return true;
} }
}); });

View file

@ -1,101 +1,101 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE // Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var listRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/, var listRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/,
emptyListRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/, emptyListRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/,
unorderedListRE = /[*+-]\s/; unorderedListRE = /[*+-]\s/;
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass; if (cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(), replacements = []; var ranges = cm.listSelections(), replacements = [];
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
var pos = ranges[i].head; var pos = ranges[i].head;
// If we're not in Markdown mode, fall back to normal newlineAndIndent // If we're not in Markdown mode, fall back to normal newlineAndIndent
var eolState = cm.getStateAfter(pos.line); var eolState = cm.getStateAfter(pos.line);
var inner = CodeMirror.innerMode(cm.getMode(), eolState); var inner = CodeMirror.innerMode(cm.getMode(), eolState);
if (inner.mode.name !== "markdown") { if (inner.mode.name !== "markdown") {
cm.execCommand("newlineAndIndent"); cm.execCommand("newlineAndIndent");
return; return;
} else { } else {
eolState = inner.state; eolState = inner.state;
} }
var inList = eolState.list !== false; var inList = eolState.list !== false;
var inQuote = eolState.quote !== 0; var inQuote = eolState.quote !== 0;
var line = cm.getLine(pos.line), match = listRE.exec(line); var line = cm.getLine(pos.line), match = listRE.exec(line);
var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch)); var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch));
if (!ranges[i].empty() || (!inList && !inQuote) || !match || cursorBeforeBullet) { if (!ranges[i].empty() || (!inList && !inQuote) || !match || cursorBeforeBullet) {
cm.execCommand("newlineAndIndent"); cm.execCommand("newlineAndIndent");
return; return;
} }
if (emptyListRE.test(line)) { if (emptyListRE.test(line)) {
var endOfQuote = inQuote && />\s*$/.test(line) var endOfQuote = inQuote && />\s*$/.test(line)
var endOfList = !/>\s*$/.test(line) var endOfList = !/>\s*$/.test(line)
if (endOfQuote || endOfList) cm.replaceRange("", { if (endOfQuote || endOfList) cm.replaceRange("", {
line: pos.line, ch: 0 line: pos.line, ch: 0
}, { }, {
line: pos.line, ch: pos.ch + 1 line: pos.line, ch: pos.ch + 1
}); });
replacements[i] = "\n"; replacements[i] = "\n";
} else { } else {
var indent = match[1], after = match[5]; var indent = match[1], after = match[5];
var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0); var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0);
var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " "); var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " ");
replacements[i] = "\n" + indent + bullet + after; replacements[i] = "\n" + indent + bullet + after;
if (numbered) incrementRemainingMarkdownListNumbers(cm, pos); if (numbered) incrementRemainingMarkdownListNumbers(cm, pos);
} }
} }
cm.replaceSelections(replacements); cm.replaceSelections(replacements);
}; };
// Auto-updating Markdown list numbers when a new item is added to the // Auto-updating Markdown list numbers when a new item is added to the
// middle of a list // middle of a list
function incrementRemainingMarkdownListNumbers(cm, pos) { function incrementRemainingMarkdownListNumbers(cm, pos) {
var startLine = pos.line, lookAhead = 0, skipCount = 0; var startLine = pos.line, lookAhead = 0, skipCount = 0;
var startItem = listRE.exec(cm.getLine(startLine)), startIndent = startItem[1]; var startItem = listRE.exec(cm.getLine(startLine)), startIndent = startItem[1];
do { do {
lookAhead += 1; lookAhead += 1;
var nextLineNumber = startLine + lookAhead; var nextLineNumber = startLine + lookAhead;
var nextLine = cm.getLine(nextLineNumber), nextItem = listRE.exec(nextLine); var nextLine = cm.getLine(nextLineNumber), nextItem = listRE.exec(nextLine);
if (nextItem) { if (nextItem) {
var nextIndent = nextItem[1]; var nextIndent = nextItem[1];
var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount); var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount);
var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber; var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber;
if (startIndent === nextIndent && !isNaN(nextNumber)) { if (startIndent === nextIndent && !isNaN(nextNumber)) {
if (newNumber === nextNumber) itemNumber = nextNumber + 1; if (newNumber === nextNumber) itemNumber = nextNumber + 1;
if (newNumber > nextNumber) itemNumber = newNumber + 1; if (newNumber > nextNumber) itemNumber = newNumber + 1;
cm.replaceRange( cm.replaceRange(
nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]), nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]),
{ {
line: nextLineNumber, ch: 0 line: nextLineNumber, ch: 0
}, { }, {
line: nextLineNumber, ch: nextLine.length line: nextLineNumber, ch: nextLine.length
}); });
} else { } else {
if (startIndent.length > nextIndent.length) return; if (startIndent.length > nextIndent.length) return;
// This doesn't run if the next line immediately indents, as it is // This doesn't run if the next line immediately indents, as it is
// not clear of the users intention (new indented item or same level) // not clear of the users intention (new indented item or same level)
if ((startIndent.length < nextIndent.length) && (lookAhead === 1)) return; if ((startIndent.length < nextIndent.length) && (lookAhead === 1)) return;
skipCount += 1; skipCount += 1;
} }
} }
} while (nextItem); } while (nextItem);
} }
}); });

View file

@ -1,48 +1,48 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE // Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
function lineIndent(cm, lineNo) { function lineIndent(cm, lineNo) {
var text = cm.getLine(lineNo) var text = cm.getLine(lineNo)
var spaceTo = text.search(/\S/) var spaceTo = text.search(/\S/)
if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1)))) if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1))))
return -1 return -1
return CodeMirror.countColumn(text, null, cm.getOption("tabSize")) return CodeMirror.countColumn(text, null, cm.getOption("tabSize"))
} }
CodeMirror.registerHelper("fold", "indent", function(cm, start) { CodeMirror.registerHelper("fold", "indent", function(cm, start) {
var myIndent = lineIndent(cm, start.line) var myIndent = lineIndent(cm, start.line)
if (myIndent < 0) return if (myIndent < 0) return
var lastLineInFold = null var lastLineInFold = null
// Go through lines until we find a line that definitely doesn't belong in // Go through lines until we find a line that definitely doesn't belong in
// the block we're folding, or to the end. // the block we're folding, or to the end.
for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
var indent = lineIndent(cm, i) var indent = lineIndent(cm, i)
if (indent == -1) { if (indent == -1) {
} else if (indent > myIndent) { } else if (indent > myIndent) {
// Lines with a greater indent are considered part of the block. // Lines with a greater indent are considered part of the block.
lastLineInFold = i; lastLineInFold = i;
} else { } else {
// If this line has non-space, non-comment content, and is // If this line has non-space, non-comment content, and is
// indented less or equal to the start line, it is the start of // indented less or equal to the start line, it is the start of
// another block. // another block.
break; break;
} }
} }
if (lastLineInFold) return { if (lastLineInFold) return {
from: CodeMirror.Pos(start.line, cm.getLine(start.line).length), from: CodeMirror.Pos(start.line, cm.getLine(start.line).length),
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
}; };
}); });
}); });

View file

@ -1,49 +1,49 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE // Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.registerHelper("fold", "markdown", function(cm, start) { CodeMirror.registerHelper("fold", "markdown", function(cm, start) {
var maxDepth = 100; var maxDepth = 100;
function isHeader(lineNo) { function isHeader(lineNo) {
var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)); var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0));
return tokentype && /\bheader\b/.test(tokentype); return tokentype && /\bheader\b/.test(tokentype);
} }
function headerLevel(lineNo, line, nextLine) { function headerLevel(lineNo, line, nextLine) {
var match = line && line.match(/^#+/); var match = line && line.match(/^#+/);
if (match && isHeader(lineNo)) return match[0].length; if (match && isHeader(lineNo)) return match[0].length;
match = nextLine && nextLine.match(/^[=\-]+\s*$/); match = nextLine && nextLine.match(/^[=\-]+\s*$/);
if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2; if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2;
return maxDepth; return maxDepth;
} }
var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1); var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1);
var level = headerLevel(start.line, firstLine, nextLine); var level = headerLevel(start.line, firstLine, nextLine);
if (level === maxDepth) return undefined; if (level === maxDepth) return undefined;
var lastLineNo = cm.lastLine(); var lastLineNo = cm.lastLine();
var end = start.line, nextNextLine = cm.getLine(end + 2); var end = start.line, nextNextLine = cm.getLine(end + 2);
while (end < lastLineNo) { while (end < lastLineNo) {
if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break; if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break;
++end; ++end;
nextLine = nextNextLine; nextLine = nextNextLine;
nextNextLine = cm.getLine(end + 2); nextNextLine = cm.getLine(end + 2);
} }
return { return {
from: CodeMirror.Pos(start.line, firstLine.length), from: CodeMirror.Pos(start.line, firstLine.length),
to: CodeMirror.Pos(end, cm.getLine(end).length) to: CodeMirror.Pos(end, cm.getLine(end).length)
}; };
}); });
}); });

View file

@ -1,184 +1,184 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE // Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos;
function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
function Iter(cm, line, ch, range) { function Iter(cm, line, ch, range) {
this.line = line; this.ch = ch; this.line = line; this.ch = ch;
this.cm = cm; this.text = cm.getLine(line); this.cm = cm; this.text = cm.getLine(line);
this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine(); this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine();
this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine(); this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine();
} }
function tagAt(iter, ch) { function tagAt(iter, ch) {
var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch)); var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
return type && /\btag\b/.test(type); return type && /\btag\b/.test(type);
} }
function nextLine(iter) { function nextLine(iter) {
if (iter.line >= iter.max) return; if (iter.line >= iter.max) return;
iter.ch = 0; iter.ch = 0;
iter.text = iter.cm.getLine(++iter.line); iter.text = iter.cm.getLine(++iter.line);
return true; return true;
} }
function prevLine(iter) { function prevLine(iter) {
if (iter.line <= iter.min) return; if (iter.line <= iter.min) return;
iter.text = iter.cm.getLine(--iter.line); iter.text = iter.cm.getLine(--iter.line);
iter.ch = iter.text.length; iter.ch = iter.text.length;
return true; return true;
} }
function toTagEnd(iter) { function toTagEnd(iter) {
for (;;) { for (;;) {
var gt = iter.text.indexOf(">", iter.ch); var gt = iter.text.indexOf(">", iter.ch);
if (gt == -1) { if (nextLine(iter)) continue; else return; } if (gt == -1) { if (nextLine(iter)) continue; else return; }
if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; } if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
var lastSlash = iter.text.lastIndexOf("/", gt); var lastSlash = iter.text.lastIndexOf("/", gt);
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
iter.ch = gt + 1; iter.ch = gt + 1;
return selfClose ? "selfClose" : "regular"; return selfClose ? "selfClose" : "regular";
} }
} }
function toTagStart(iter) { function toTagStart(iter) {
for (;;) { for (;;) {
var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1; var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
if (lt == -1) { if (prevLine(iter)) continue; else return; } if (lt == -1) { if (prevLine(iter)) continue; else return; }
if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; } if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
xmlTagStart.lastIndex = lt; xmlTagStart.lastIndex = lt;
iter.ch = lt; iter.ch = lt;
var match = xmlTagStart.exec(iter.text); var match = xmlTagStart.exec(iter.text);
if (match && match.index == lt) return match; if (match && match.index == lt) return match;
} }
} }
function toNextTag(iter) { function toNextTag(iter) {
for (;;) { for (;;) {
xmlTagStart.lastIndex = iter.ch; xmlTagStart.lastIndex = iter.ch;
var found = xmlTagStart.exec(iter.text); var found = xmlTagStart.exec(iter.text);
if (!found) { if (nextLine(iter)) continue; else return; } if (!found) { if (nextLine(iter)) continue; else return; }
if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; } if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
iter.ch = found.index + found[0].length; iter.ch = found.index + found[0].length;
return found; return found;
} }
} }
function toPrevTag(iter) { function toPrevTag(iter) {
for (;;) { for (;;) {
var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1; var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
if (gt == -1) { if (prevLine(iter)) continue; else return; } if (gt == -1) { if (prevLine(iter)) continue; else return; }
if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; } if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
var lastSlash = iter.text.lastIndexOf("/", gt); var lastSlash = iter.text.lastIndexOf("/", gt);
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
iter.ch = gt + 1; iter.ch = gt + 1;
return selfClose ? "selfClose" : "regular"; return selfClose ? "selfClose" : "regular";
} }
} }
function findMatchingClose(iter, tag) { function findMatchingClose(iter, tag) {
var stack = []; var stack = [];
for (;;) { for (;;) {
var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0); var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
if (!next || !(end = toTagEnd(iter))) return; if (!next || !(end = toTagEnd(iter))) return;
if (end == "selfClose") continue; if (end == "selfClose") continue;
if (next[1]) { // closing tag if (next[1]) { // closing tag
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
stack.length = i; stack.length = i;
break; break;
} }
if (i < 0 && (!tag || tag == next[2])) return { if (i < 0 && (!tag || tag == next[2])) return {
tag: next[2], tag: next[2],
from: Pos(startLine, startCh), from: Pos(startLine, startCh),
to: Pos(iter.line, iter.ch) to: Pos(iter.line, iter.ch)
}; };
} else { // opening tag } else { // opening tag
stack.push(next[2]); stack.push(next[2]);
} }
} }
} }
function findMatchingOpen(iter, tag) { function findMatchingOpen(iter, tag) {
var stack = []; var stack = [];
for (;;) { for (;;) {
var prev = toPrevTag(iter); var prev = toPrevTag(iter);
if (!prev) return; if (!prev) return;
if (prev == "selfClose") { toTagStart(iter); continue; } if (prev == "selfClose") { toTagStart(iter); continue; }
var endLine = iter.line, endCh = iter.ch; var endLine = iter.line, endCh = iter.ch;
var start = toTagStart(iter); var start = toTagStart(iter);
if (!start) return; if (!start) return;
if (start[1]) { // closing tag if (start[1]) { // closing tag
stack.push(start[2]); stack.push(start[2]);
} else { // opening tag } else { // opening tag
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) { for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
stack.length = i; stack.length = i;
break; break;
} }
if (i < 0 && (!tag || tag == start[2])) return { if (i < 0 && (!tag || tag == start[2])) return {
tag: start[2], tag: start[2],
from: Pos(iter.line, iter.ch), from: Pos(iter.line, iter.ch),
to: Pos(endLine, endCh) to: Pos(endLine, endCh)
}; };
} }
} }
} }
CodeMirror.registerHelper("fold", "xml", function(cm, start) { CodeMirror.registerHelper("fold", "xml", function(cm, start) {
var iter = new Iter(cm, start.line, 0); var iter = new Iter(cm, start.line, 0);
for (;;) { for (;;) {
var openTag = toNextTag(iter) var openTag = toNextTag(iter)
if (!openTag || iter.line != start.line) return if (!openTag || iter.line != start.line) return
var end = toTagEnd(iter) var end = toTagEnd(iter)
if (!end) return if (!end) return
if (!openTag[1] && end != "selfClose") { if (!openTag[1] && end != "selfClose") {
var startPos = Pos(iter.line, iter.ch); var startPos = Pos(iter.line, iter.ch);
var endPos = findMatchingClose(iter, openTag[2]); var endPos = findMatchingClose(iter, openTag[2]);
return endPos && cmp(endPos.from, startPos) > 0 ? {from: startPos, to: endPos.from} : null return endPos && cmp(endPos.from, startPos) > 0 ? {from: startPos, to: endPos.from} : null
} }
} }
}); });
CodeMirror.findMatchingTag = function(cm, pos, range) { CodeMirror.findMatchingTag = function(cm, pos, range) {
var iter = new Iter(cm, pos.line, pos.ch, range); var iter = new Iter(cm, pos.line, pos.ch, range);
if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return; if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
var start = end && toTagStart(iter); var start = end && toTagStart(iter);
if (!end || !start || cmp(iter, pos) > 0) return; if (!end || !start || cmp(iter, pos) > 0) return;
var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
if (end == "selfClose") return {open: here, close: null, at: "open"}; if (end == "selfClose") return {open: here, close: null, at: "open"};
if (start[1]) { // closing tag if (start[1]) { // closing tag
return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"}; return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
} else { // opening tag } else { // opening tag
iter = new Iter(cm, to.line, to.ch, range); iter = new Iter(cm, to.line, to.ch, range);
return {open: here, close: findMatchingClose(iter, start[2]), at: "open"}; return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
} }
}; };
CodeMirror.findEnclosingTag = function(cm, pos, range, tag) { CodeMirror.findEnclosingTag = function(cm, pos, range, tag) {
var iter = new Iter(cm, pos.line, pos.ch, range); var iter = new Iter(cm, pos.line, pos.ch, range);
for (;;) { for (;;) {
var open = findMatchingOpen(iter, tag); var open = findMatchingOpen(iter, tag);
if (!open) break; if (!open) break;
var forward = new Iter(cm, pos.line, pos.ch, range); var forward = new Iter(cm, pos.line, pos.ch, range);
var close = findMatchingClose(forward, open.tag); var close = findMatchingClose(forward, open.tag);
if (close) return {open: open, close: close}; if (close) return {open: open, close: close};
} }
}; };
// Used by addon/edit/closetag.js // Used by addon/edit/closetag.js
CodeMirror.scanForClosingTag = function(cm, pos, name, end) { CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null); var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
return findMatchingClose(iter, name); return findMatchingClose(iter, name);
}; };
}); });

View file

@ -1,41 +1,41 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE // Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var WORD = /[\w$]+/, RANGE = 500; var WORD = /[\w$]+/, RANGE = 500;
CodeMirror.registerHelper("hint", "anyword", function(editor, options) { CodeMirror.registerHelper("hint", "anyword", function(editor, options) {
var word = options && options.word || WORD; var word = options && options.word || WORD;
var range = options && options.range || RANGE; var range = options && options.range || RANGE;
var cur = editor.getCursor(), curLine = editor.getLine(cur.line); var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
var end = cur.ch, start = end; var end = cur.ch, start = end;
while (start && word.test(curLine.charAt(start - 1))) --start; while (start && word.test(curLine.charAt(start - 1))) --start;
var curWord = start != end && curLine.slice(start, end); var curWord = start != end && curLine.slice(start, end);
var list = options && options.list || [], seen = {}; var list = options && options.list || [], seen = {};
var re = new RegExp(word.source, "g"); var re = new RegExp(word.source, "g");
for (var dir = -1; dir <= 1; dir += 2) { for (var dir = -1; dir <= 1; dir += 2) {
var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;
for (; line != endLine; line += dir) { for (; line != endLine; line += dir) {
var text = editor.getLine(line), m; var text = editor.getLine(line), m;
while (m = re.exec(text)) { while (m = re.exec(text)) {
if (line == cur.line && m[0] === curWord) continue; if (line == cur.line && m[0] === curWord) continue;
if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) { if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) {
seen[m[0]] = true; seen[m[0]] = true;
list.push(m[0]); list.push(m[0]);
} }
} }
} }
} }
return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};
}); });
}); });

File diff suppressed because it is too large Load diff

View file

@ -1,66 +1,66 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE // Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), "cjs"); mod(require("../../lib/codemirror"), "cjs");
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], function(CM) { mod(CM, "amd"); }); define(["../../lib/codemirror"], function(CM) { mod(CM, "amd"); });
else // Plain browser env else // Plain browser env
mod(CodeMirror, "plain"); mod(CodeMirror, "plain");
})(function(CodeMirror, env) { })(function(CodeMirror, env) {
if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js"; if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
var loading = {}; var loading = {};
function splitCallback(cont, n) { function splitCallback(cont, n) {
var countDown = n; var countDown = n;
return function() { if (--countDown == 0) cont(); }; return function() { if (--countDown == 0) cont(); };
} }
function ensureDeps(mode, cont, options) { function ensureDeps(mode, cont, options) {
var modeObj = CodeMirror.modes[mode], deps = modeObj && modeObj.dependencies; var modeObj = CodeMirror.modes[mode], deps = modeObj && modeObj.dependencies;
if (!deps) return cont(); if (!deps) return cont();
var missing = []; var missing = [];
for (var i = 0; i < deps.length; ++i) { for (var i = 0; i < deps.length; ++i) {
if (!CodeMirror.modes.hasOwnProperty(deps[i])) if (!CodeMirror.modes.hasOwnProperty(deps[i]))
missing.push(deps[i]); missing.push(deps[i]);
} }
if (!missing.length) return cont(); if (!missing.length) return cont();
var split = splitCallback(cont, missing.length); var split = splitCallback(cont, missing.length);
for (var i = 0; i < missing.length; ++i) for (var i = 0; i < missing.length; ++i)
CodeMirror.requireMode(missing[i], split, options); CodeMirror.requireMode(missing[i], split, options);
} }
CodeMirror.requireMode = function(mode, cont, options) { CodeMirror.requireMode = function(mode, cont, options) {
if (typeof mode != "string") mode = mode.name; if (typeof mode != "string") mode = mode.name;
if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont, options); if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont, options);
if (loading.hasOwnProperty(mode)) return loading[mode].push(cont); if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
var file = options && options.path ? options.path(mode) : CodeMirror.modeURL.replace(/%N/g, mode); var file = options && options.path ? options.path(mode) : CodeMirror.modeURL.replace(/%N/g, mode);
if (options && options.loadMode) { if (options && options.loadMode) {
options.loadMode(file, function() { ensureDeps(mode, cont, options) }) options.loadMode(file, function() { ensureDeps(mode, cont, options) })
} else if (env == "plain") { } else if (env == "plain") {
var script = document.createElement("script"); var script = document.createElement("script");
script.src = file; script.src = file;
var others = document.getElementsByTagName("script")[0]; var others = document.getElementsByTagName("script")[0];
var list = loading[mode] = [cont]; var list = loading[mode] = [cont];
CodeMirror.on(script, "load", function() { CodeMirror.on(script, "load", function() {
ensureDeps(mode, function() { ensureDeps(mode, function() {
for (var i = 0; i < list.length; ++i) list[i](); for (var i = 0; i < list.length; ++i) list[i]();
}, options); }, options);
}); });
others.parentNode.insertBefore(script, others); others.parentNode.insertBefore(script, others);
} else if (env == "cjs") { } else if (env == "cjs") {
require(file); require(file);
cont(); cont();
} else if (env == "amd") { } else if (env == "amd") {
requirejs([file], cont); requirejs([file], cont);
} }
}; };
CodeMirror.autoLoadMode = function(instance, mode, options) { CodeMirror.autoLoadMode = function(instance, mode, options) {
if (!CodeMirror.modes.hasOwnProperty(mode)) if (!CodeMirror.modes.hasOwnProperty(mode))
CodeMirror.requireMode(mode, function() { CodeMirror.requireMode(mode, function() {
instance.setOption("mode", instance.getOption("mode")); instance.setOption("mode", instance.getOption("mode"));
}, options); }, options);
}; };
}); });

View file

@ -1,136 +1,136 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE // Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.multiplexingMode = function(outer /*, others */) { CodeMirror.multiplexingMode = function(outer /*, others */) {
// Others should be {open, close, mode [, delimStyle] [, innerStyle] [, parseDelimiters]} objects // Others should be {open, close, mode [, delimStyle] [, innerStyle] [, parseDelimiters]} objects
var others = Array.prototype.slice.call(arguments, 1); var others = Array.prototype.slice.call(arguments, 1);
function indexOf(string, pattern, from, returnEnd) { function indexOf(string, pattern, from, returnEnd) {
if (typeof pattern == "string") { if (typeof pattern == "string") {
var found = string.indexOf(pattern, from); var found = string.indexOf(pattern, from);
return returnEnd && found > -1 ? found + pattern.length : found; return returnEnd && found > -1 ? found + pattern.length : found;
} }
var m = pattern.exec(from ? string.slice(from) : string); var m = pattern.exec(from ? string.slice(from) : string);
return m ? m.index + from + (returnEnd ? m[0].length : 0) : -1; return m ? m.index + from + (returnEnd ? m[0].length : 0) : -1;
} }
return { return {
startState: function() { startState: function() {
return { return {
outer: CodeMirror.startState(outer), outer: CodeMirror.startState(outer),
innerActive: null, innerActive: null,
inner: null, inner: null,
startingInner: false startingInner: false
}; };
}, },
copyState: function(state) { copyState: function(state) {
return { return {
outer: CodeMirror.copyState(outer, state.outer), outer: CodeMirror.copyState(outer, state.outer),
innerActive: state.innerActive, innerActive: state.innerActive,
inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner), inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner),
startingInner: state.startingInner startingInner: state.startingInner
}; };
}, },
token: function(stream, state) { token: function(stream, state) {
if (!state.innerActive) { if (!state.innerActive) {
var cutOff = Infinity, oldContent = stream.string; var cutOff = Infinity, oldContent = stream.string;
for (var i = 0; i < others.length; ++i) { for (var i = 0; i < others.length; ++i) {
var other = others[i]; var other = others[i];
var found = indexOf(oldContent, other.open, stream.pos); var found = indexOf(oldContent, other.open, stream.pos);
if (found == stream.pos) { if (found == stream.pos) {
if (!other.parseDelimiters) stream.match(other.open); if (!other.parseDelimiters) stream.match(other.open);
state.startingInner = !!other.parseDelimiters state.startingInner = !!other.parseDelimiters
state.innerActive = other; state.innerActive = other;
// Get the outer indent, making sure to handle CodeMirror.Pass // Get the outer indent, making sure to handle CodeMirror.Pass
var outerIndent = 0; var outerIndent = 0;
if (outer.indent) { if (outer.indent) {
var possibleOuterIndent = outer.indent(state.outer, "", ""); var possibleOuterIndent = outer.indent(state.outer, "", "");
if (possibleOuterIndent !== CodeMirror.Pass) outerIndent = possibleOuterIndent; if (possibleOuterIndent !== CodeMirror.Pass) outerIndent = possibleOuterIndent;
} }
state.inner = CodeMirror.startState(other.mode, outerIndent); state.inner = CodeMirror.startState(other.mode, outerIndent);
return other.delimStyle && (other.delimStyle + " " + other.delimStyle + "-open"); return other.delimStyle && (other.delimStyle + " " + other.delimStyle + "-open");
} else if (found != -1 && found < cutOff) { } else if (found != -1 && found < cutOff) {
cutOff = found; cutOff = found;
} }
} }
if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff); if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);
var outerToken = outer.token(stream, state.outer); var outerToken = outer.token(stream, state.outer);
if (cutOff != Infinity) stream.string = oldContent; if (cutOff != Infinity) stream.string = oldContent;
return outerToken; return outerToken;
} else { } else {
var curInner = state.innerActive, oldContent = stream.string; var curInner = state.innerActive, oldContent = stream.string;
if (!curInner.close && stream.sol()) { if (!curInner.close && stream.sol()) {
state.innerActive = state.inner = null; state.innerActive = state.inner = null;
return this.token(stream, state); return this.token(stream, state);
} }
var found = curInner.close && !state.startingInner ? var found = curInner.close && !state.startingInner ?
indexOf(oldContent, curInner.close, stream.pos, curInner.parseDelimiters) : -1; indexOf(oldContent, curInner.close, stream.pos, curInner.parseDelimiters) : -1;
if (found == stream.pos && !curInner.parseDelimiters) { if (found == stream.pos && !curInner.parseDelimiters) {
stream.match(curInner.close); stream.match(curInner.close);
state.innerActive = state.inner = null; state.innerActive = state.inner = null;
return curInner.delimStyle && (curInner.delimStyle + " " + curInner.delimStyle + "-close"); return curInner.delimStyle && (curInner.delimStyle + " " + curInner.delimStyle + "-close");
} }
if (found > -1) stream.string = oldContent.slice(0, found); if (found > -1) stream.string = oldContent.slice(0, found);
var innerToken = curInner.mode.token(stream, state.inner); var innerToken = curInner.mode.token(stream, state.inner);
if (found > -1) stream.string = oldContent; if (found > -1) stream.string = oldContent;
else if (stream.pos > stream.start) state.startingInner = false else if (stream.pos > stream.start) state.startingInner = false
if (found == stream.pos && curInner.parseDelimiters) if (found == stream.pos && curInner.parseDelimiters)
state.innerActive = state.inner = null; state.innerActive = state.inner = null;
if (curInner.innerStyle) { if (curInner.innerStyle) {
if (innerToken) innerToken = innerToken + " " + curInner.innerStyle; if (innerToken) innerToken = innerToken + " " + curInner.innerStyle;
else innerToken = curInner.innerStyle; else innerToken = curInner.innerStyle;
} }
return innerToken; return innerToken;
} }
}, },
indent: function(state, textAfter, line) { indent: function(state, textAfter, line) {
var mode = state.innerActive ? state.innerActive.mode : outer; var mode = state.innerActive ? state.innerActive.mode : outer;
if (!mode.indent) return CodeMirror.Pass; if (!mode.indent) return CodeMirror.Pass;
return mode.indent(state.innerActive ? state.inner : state.outer, textAfter, line); return mode.indent(state.innerActive ? state.inner : state.outer, textAfter, line);
}, },
blankLine: function(state) { blankLine: function(state) {
var mode = state.innerActive ? state.innerActive.mode : outer; var mode = state.innerActive ? state.innerActive.mode : outer;
if (mode.blankLine) { if (mode.blankLine) {
mode.blankLine(state.innerActive ? state.inner : state.outer); mode.blankLine(state.innerActive ? state.inner : state.outer);
} }
if (!state.innerActive) { if (!state.innerActive) {
for (var i = 0; i < others.length; ++i) { for (var i = 0; i < others.length; ++i) {
var other = others[i]; var other = others[i];
if (other.open === "\n") { if (other.open === "\n") {
state.innerActive = other; state.innerActive = other;
state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "", "") : 0); state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "", "") : 0);
} }
} }
} else if (state.innerActive.close === "\n") { } else if (state.innerActive.close === "\n") {
state.innerActive = state.inner = null; state.innerActive = state.inner = null;
} }
}, },
electricChars: outer.electricChars, electricChars: outer.electricChars,
innerMode: function(state) { innerMode: function(state) {
return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer}; return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer};
} }
}; };
}; };
}); });

View file

@ -1,49 +1,49 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE // Distributed under an MIT license: https://codemirror.net/LICENSE
(function() { (function() {
CodeMirror.defineMode("markdown_with_stex", function(){ CodeMirror.defineMode("markdown_with_stex", function(){
var inner = CodeMirror.getMode({}, "stex"); var inner = CodeMirror.getMode({}, "stex");
var outer = CodeMirror.getMode({}, "markdown"); var outer = CodeMirror.getMode({}, "markdown");
var innerOptions = { var innerOptions = {
open: '$', open: '$',
close: '$', close: '$',
mode: inner, mode: inner,
delimStyle: 'delim', delimStyle: 'delim',
innerStyle: 'inner' innerStyle: 'inner'
}; };
return CodeMirror.multiplexingMode(outer, innerOptions); return CodeMirror.multiplexingMode(outer, innerOptions);
}); });
var mode = CodeMirror.getMode({}, "markdown_with_stex"); var mode = CodeMirror.getMode({}, "markdown_with_stex");
function MT(name) { function MT(name) {
test.mode( test.mode(
name, name,
mode, mode,
Array.prototype.slice.call(arguments, 1), Array.prototype.slice.call(arguments, 1),
'multiplexing'); 'multiplexing');
} }
MT( MT(
"stexInsideMarkdown", "stexInsideMarkdown",
"[strong **Equation:**] [delim&delim-open $][inner&tag \\pi][delim&delim-close $]"); "[strong **Equation:**] [delim&delim-open $][inner&tag \\pi][delim&delim-close $]");
CodeMirror.defineMode("identical_delim_multiplex", function() { CodeMirror.defineMode("identical_delim_multiplex", function() {
return CodeMirror.multiplexingMode(CodeMirror.getMode({indentUnit: 2}, "javascript"), { return CodeMirror.multiplexingMode(CodeMirror.getMode({indentUnit: 2}, "javascript"), {
open: "#", open: "#",
close: "#", close: "#",
mode: CodeMirror.getMode({}, "markdown"), mode: CodeMirror.getMode({}, "markdown"),
parseDelimiters: true, parseDelimiters: true,
innerStyle: "q" innerStyle: "q"
}); });
}); });
var mode2 = CodeMirror.getMode({}, "identical_delim_multiplex"); var mode2 = CodeMirror.getMode({}, "identical_delim_multiplex");
test.mode("identical_delimiters_with_parseDelimiters", mode2, [ test.mode("identical_delimiters_with_parseDelimiters", mode2, [
"[keyword let] [def x] [operator =] [q #foo][q&em *bar*][q #];" "[keyword let] [def x] [operator =] [q #foo][q&em *bar*][q #];"
], "multiplexing") ], "multiplexing")
})(); })();

View file

@ -1,90 +1,90 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE // Distributed under an MIT license: https://codemirror.net/LICENSE
// Utility function that allows modes to be combined. The mode given // Utility function that allows modes to be combined. The mode given
// as the base argument takes care of most of the normal mode // as the base argument takes care of most of the normal mode
// functionality, but a second (typically simple) mode is used, which // functionality, but a second (typically simple) mode is used, which
// can override the style of text. Both modes get to parse all of the // can override the style of text. Both modes get to parse all of the
// text, but when both assign a non-null style to a piece of code, the // text, but when both assign a non-null style to a piece of code, the
// overlay wins, unless the combine argument was true and not overridden, // overlay wins, unless the combine argument was true and not overridden,
// or state.overlay.combineTokens was true, in which case the styles are // or state.overlay.combineTokens was true, in which case the styles are
// combined. // combined.
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.overlayMode = function(base, overlay, combine) { CodeMirror.overlayMode = function(base, overlay, combine) {
return { return {
startState: function() { startState: function() {
return { return {
base: CodeMirror.startState(base), base: CodeMirror.startState(base),
overlay: CodeMirror.startState(overlay), overlay: CodeMirror.startState(overlay),
basePos: 0, baseCur: null, basePos: 0, baseCur: null,
overlayPos: 0, overlayCur: null, overlayPos: 0, overlayCur: null,
streamSeen: null streamSeen: null
}; };
}, },
copyState: function(state) { copyState: function(state) {
return { return {
base: CodeMirror.copyState(base, state.base), base: CodeMirror.copyState(base, state.base),
overlay: CodeMirror.copyState(overlay, state.overlay), overlay: CodeMirror.copyState(overlay, state.overlay),
basePos: state.basePos, baseCur: null, basePos: state.basePos, baseCur: null,
overlayPos: state.overlayPos, overlayCur: null overlayPos: state.overlayPos, overlayCur: null
}; };
}, },
token: function(stream, state) { token: function(stream, state) {
if (stream != state.streamSeen || if (stream != state.streamSeen ||
Math.min(state.basePos, state.overlayPos) < stream.start) { Math.min(state.basePos, state.overlayPos) < stream.start) {
state.streamSeen = stream; state.streamSeen = stream;
state.basePos = state.overlayPos = stream.start; state.basePos = state.overlayPos = stream.start;
} }
if (stream.start == state.basePos) { if (stream.start == state.basePos) {
state.baseCur = base.token(stream, state.base); state.baseCur = base.token(stream, state.base);
state.basePos = stream.pos; state.basePos = stream.pos;
} }
if (stream.start == state.overlayPos) { if (stream.start == state.overlayPos) {
stream.pos = stream.start; stream.pos = stream.start;
state.overlayCur = overlay.token(stream, state.overlay); state.overlayCur = overlay.token(stream, state.overlay);
state.overlayPos = stream.pos; state.overlayPos = stream.pos;
} }
stream.pos = Math.min(state.basePos, state.overlayPos); stream.pos = Math.min(state.basePos, state.overlayPos);
// state.overlay.combineTokens always takes precedence over combine, // state.overlay.combineTokens always takes precedence over combine,
// unless set to null // unless set to null
if (state.overlayCur == null) return state.baseCur; if (state.overlayCur == null) return state.baseCur;
else if (state.baseCur != null && else if (state.baseCur != null &&
state.overlay.combineTokens || state.overlay.combineTokens ||
combine && state.overlay.combineTokens == null) combine && state.overlay.combineTokens == null)
return state.baseCur + " " + state.overlayCur; return state.baseCur + " " + state.overlayCur;
else return state.overlayCur; else return state.overlayCur;
}, },
indent: base.indent && function(state, textAfter, line) { indent: base.indent && function(state, textAfter, line) {
return base.indent(state.base, textAfter, line); return base.indent(state.base, textAfter, line);
}, },
electricChars: base.electricChars, electricChars: base.electricChars,
innerMode: function(state) { return {state: state.base, mode: base}; }, innerMode: function(state) { return {state: state.base, mode: base}; },
blankLine: function(state) { blankLine: function(state) {
var baseToken, overlayToken; var baseToken, overlayToken;
if (base.blankLine) baseToken = base.blankLine(state.base); if (base.blankLine) baseToken = base.blankLine(state.base);
if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay); if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay);
return overlayToken == null ? return overlayToken == null ?
baseToken : baseToken :
(combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken); (combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken);
} }
}; };
}; };
}); });

File diff suppressed because it is too large Load diff

View file

@ -1,26 +1,26 @@
import { contains, elt, removeChildrenAndAdd } from "../util/dom.js" import { contains, elt, removeChildrenAndAdd } from "../util/dom.js"
import { e_target } from "../util/event.js" import { e_target } from "../util/event.js"
export function widgetHeight(widget) { export function widgetHeight(widget) {
if (widget.height != null) return widget.height if (widget.height != null) return widget.height
let cm = widget.doc.cm let cm = widget.doc.cm
if (!cm) return 0 if (!cm) return 0
if (!contains(document.body, widget.node)) { if (!contains(document.body, widget.node)) {
let parentStyle = "position: relative;" let parentStyle = "position: relative;"
if (widget.coverGutter) if (widget.coverGutter)
parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;" parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"
if (widget.noHScroll) if (widget.noHScroll)
parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;" parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"
removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)) removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle))
} }
return widget.height = widget.node.parentNode.offsetHeight return widget.height = widget.node.parentNode.offsetHeight
} }
// Return true when the given mouse event happened in a widget // Return true when the given mouse event happened in a widget
export function eventInWidget(display, e) { export function eventInWidget(display, e) {
for (let n = e_target(e); n != display.wrapper; n = n.parentNode) { for (let n = e_target(e); n != display.wrapper; n = n.parentNode) {
if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
(n.parentNode == display.sizer && n != display.mover)) (n.parentNode == display.sizer && n != display.mover))
return true return true
} }
} }

View file

@ -1,436 +1,436 @@
import CodeMirror from "../edit/CodeMirror.js" import CodeMirror from "../edit/CodeMirror.js"
import { docMethodOp } from "../display/operations.js" import { docMethodOp } from "../display/operations.js"
import { Line } from "../line/line_data.js" import { Line } from "../line/line_data.js"
import { clipPos, clipPosArray, Pos } from "../line/pos.js" import { clipPos, clipPosArray, Pos } from "../line/pos.js"
import { visualLine } from "../line/spans.js" import { visualLine } from "../line/spans.js"
import { getBetween, getLine, getLines, isLine, lineNo } from "../line/utils_line.js" import { getBetween, getLine, getLines, isLine, lineNo } from "../line/utils_line.js"
import { classTest } from "../util/dom.js" import { classTest } from "../util/dom.js"
import { splitLinesAuto } from "../util/feature_detection.js" import { splitLinesAuto } from "../util/feature_detection.js"
import { createObj, map, isEmpty, sel_dontScroll } from "../util/misc.js" import { createObj, map, isEmpty, sel_dontScroll } from "../util/misc.js"
import { ensureCursorVisible, scrollToCoords } from "../display/scrolling.js" import { ensureCursorVisible, scrollToCoords } from "../display/scrolling.js"
import { changeLine, makeChange, makeChangeFromHistory, replaceRange } from "./changes.js" import { changeLine, makeChange, makeChangeFromHistory, replaceRange } from "./changes.js"
import { computeReplacedSel } from "./change_measurement.js" import { computeReplacedSel } from "./change_measurement.js"
import { BranchChunk, LeafChunk } from "./chunk.js" import { BranchChunk, LeafChunk } from "./chunk.js"
import { directionChanged, linkedDocs, updateDoc } from "./document_data.js" import { directionChanged, linkedDocs, updateDoc } from "./document_data.js"
import { copyHistoryArray, History } from "./history.js" import { copyHistoryArray, History } from "./history.js"
import { addLineWidget } from "./line_widget.js" import { addLineWidget } from "./line_widget.js"
import { copySharedMarkers, detachSharedMarkers, findSharedMarkers, markText } from "./mark_text.js" import { copySharedMarkers, detachSharedMarkers, findSharedMarkers, markText } from "./mark_text.js"
import { normalizeSelection, Range, simpleSelection } from "./selection.js" import { normalizeSelection, Range, simpleSelection } from "./selection.js"
import { extendSelection, extendSelections, setSelection, setSelectionReplaceHistory, setSimpleSelection } from "./selection_updates.js" import { extendSelection, extendSelections, setSelection, setSelectionReplaceHistory, setSimpleSelection } from "./selection_updates.js"
let nextDocId = 0 let nextDocId = 0
let Doc = function(text, mode, firstLine, lineSep, direction) { let Doc = function(text, mode, firstLine, lineSep, direction) {
if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep, direction) if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep, direction)
if (firstLine == null) firstLine = 0 if (firstLine == null) firstLine = 0
BranchChunk.call(this, [new LeafChunk([new Line("", null)])]) BranchChunk.call(this, [new LeafChunk([new Line("", null)])])
this.first = firstLine this.first = firstLine
this.scrollTop = this.scrollLeft = 0 this.scrollTop = this.scrollLeft = 0
this.cantEdit = false this.cantEdit = false
this.cleanGeneration = 1 this.cleanGeneration = 1
this.modeFrontier = this.highlightFrontier = firstLine this.modeFrontier = this.highlightFrontier = firstLine
let start = Pos(firstLine, 0) let start = Pos(firstLine, 0)
this.sel = simpleSelection(start) this.sel = simpleSelection(start)
this.history = new History(null) this.history = new History(null)
this.id = ++nextDocId this.id = ++nextDocId
this.modeOption = mode this.modeOption = mode
this.lineSep = lineSep this.lineSep = lineSep
this.direction = (direction == "rtl") ? "rtl" : "ltr" this.direction = (direction == "rtl") ? "rtl" : "ltr"
this.extend = false this.extend = false
if (typeof text == "string") text = this.splitLines(text) if (typeof text == "string") text = this.splitLines(text)
updateDoc(this, {from: start, to: start, text: text}) updateDoc(this, {from: start, to: start, text: text})
setSelection(this, simpleSelection(start), sel_dontScroll) setSelection(this, simpleSelection(start), sel_dontScroll)
} }
Doc.prototype = createObj(BranchChunk.prototype, { Doc.prototype = createObj(BranchChunk.prototype, {
constructor: Doc, constructor: Doc,
// Iterate over the document. Supports two forms -- with only one // Iterate over the document. Supports two forms -- with only one
// argument, it calls that for each line in the document. With // argument, it calls that for each line in the document. With
// three, it iterates over the range given by the first two (with // three, it iterates over the range given by the first two (with
// the second being non-inclusive). // the second being non-inclusive).
iter: function(from, to, op) { iter: function(from, to, op) {
if (op) this.iterN(from - this.first, to - from, op) if (op) this.iterN(from - this.first, to - from, op)
else this.iterN(this.first, this.first + this.size, from) else this.iterN(this.first, this.first + this.size, from)
}, },
// Non-public interface for adding and removing lines. // Non-public interface for adding and removing lines.
insert: function(at, lines) { insert: function(at, lines) {
let height = 0 let height = 0
for (let i = 0; i < lines.length; ++i) height += lines[i].height for (let i = 0; i < lines.length; ++i) height += lines[i].height
this.insertInner(at - this.first, lines, height) this.insertInner(at - this.first, lines, height)
}, },
remove: function(at, n) { this.removeInner(at - this.first, n) }, remove: function(at, n) { this.removeInner(at - this.first, n) },
// From here, the methods are part of the public interface. Most // From here, the methods are part of the public interface. Most
// are also available from CodeMirror (editor) instances. // are also available from CodeMirror (editor) instances.
getValue: function(lineSep) { getValue: function(lineSep) {
let lines = getLines(this, this.first, this.first + this.size) let lines = getLines(this, this.first, this.first + this.size)
if (lineSep === false) return lines if (lineSep === false) return lines
return lines.join(lineSep || this.lineSeparator()) return lines.join(lineSep || this.lineSeparator())
}, },
setValue: docMethodOp(function(code) { setValue: docMethodOp(function(code) {
let top = Pos(this.first, 0), last = this.first + this.size - 1 let top = Pos(this.first, 0), last = this.first + this.size - 1
makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
text: this.splitLines(code), origin: "setValue", full: true}, true) text: this.splitLines(code), origin: "setValue", full: true}, true)
if (this.cm) scrollToCoords(this.cm, 0, 0) if (this.cm) scrollToCoords(this.cm, 0, 0)
setSelection(this, simpleSelection(top), sel_dontScroll) setSelection(this, simpleSelection(top), sel_dontScroll)
}), }),
replaceRange: function(code, from, to, origin) { replaceRange: function(code, from, to, origin) {
from = clipPos(this, from) from = clipPos(this, from)
to = to ? clipPos(this, to) : from to = to ? clipPos(this, to) : from
replaceRange(this, code, from, to, origin) replaceRange(this, code, from, to, origin)
}, },
getRange: function(from, to, lineSep) { getRange: function(from, to, lineSep) {
let lines = getBetween(this, clipPos(this, from), clipPos(this, to)) let lines = getBetween(this, clipPos(this, from), clipPos(this, to))
if (lineSep === false) return lines if (lineSep === false) return lines
if (lineSep === '') return lines.join('') if (lineSep === '') return lines.join('')
return lines.join(lineSep || this.lineSeparator()) return lines.join(lineSep || this.lineSeparator())
}, },
getLine: function(line) {let l = this.getLineHandle(line); return l && l.text}, getLine: function(line) {let l = this.getLineHandle(line); return l && l.text},
getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line)}, getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line)},
getLineNumber: function(line) {return lineNo(line)}, getLineNumber: function(line) {return lineNo(line)},
getLineHandleVisualStart: function(line) { getLineHandleVisualStart: function(line) {
if (typeof line == "number") line = getLine(this, line) if (typeof line == "number") line = getLine(this, line)
return visualLine(line) return visualLine(line)
}, },
lineCount: function() {return this.size}, lineCount: function() {return this.size},
firstLine: function() {return this.first}, firstLine: function() {return this.first},
lastLine: function() {return this.first + this.size - 1}, lastLine: function() {return this.first + this.size - 1},
clipPos: function(pos) {return clipPos(this, pos)}, clipPos: function(pos) {return clipPos(this, pos)},
getCursor: function(start) { getCursor: function(start) {
let range = this.sel.primary(), pos let range = this.sel.primary(), pos
if (start == null || start == "head") pos = range.head if (start == null || start == "head") pos = range.head
else if (start == "anchor") pos = range.anchor else if (start == "anchor") pos = range.anchor
else if (start == "end" || start == "to" || start === false) pos = range.to() else if (start == "end" || start == "to" || start === false) pos = range.to()
else pos = range.from() else pos = range.from()
return pos return pos
}, },
listSelections: function() { return this.sel.ranges }, listSelections: function() { return this.sel.ranges },
somethingSelected: function() {return this.sel.somethingSelected()}, somethingSelected: function() {return this.sel.somethingSelected()},
setCursor: docMethodOp(function(line, ch, options) { setCursor: docMethodOp(function(line, ch, options) {
setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options) setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options)
}), }),
setSelection: docMethodOp(function(anchor, head, options) { setSelection: docMethodOp(function(anchor, head, options) {
setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options) setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options)
}), }),
extendSelection: docMethodOp(function(head, other, options) { extendSelection: docMethodOp(function(head, other, options) {
extendSelection(this, clipPos(this, head), other && clipPos(this, other), options) extendSelection(this, clipPos(this, head), other && clipPos(this, other), options)
}), }),
extendSelections: docMethodOp(function(heads, options) { extendSelections: docMethodOp(function(heads, options) {
extendSelections(this, clipPosArray(this, heads), options) extendSelections(this, clipPosArray(this, heads), options)
}), }),
extendSelectionsBy: docMethodOp(function(f, options) { extendSelectionsBy: docMethodOp(function(f, options) {
let heads = map(this.sel.ranges, f) let heads = map(this.sel.ranges, f)
extendSelections(this, clipPosArray(this, heads), options) extendSelections(this, clipPosArray(this, heads), options)
}), }),
setSelections: docMethodOp(function(ranges, primary, options) { setSelections: docMethodOp(function(ranges, primary, options) {
if (!ranges.length) return if (!ranges.length) return
let out = [] let out = []
for (let i = 0; i < ranges.length; i++) for (let i = 0; i < ranges.length; i++)
out[i] = new Range(clipPos(this, ranges[i].anchor), out[i] = new Range(clipPos(this, ranges[i].anchor),
clipPos(this, ranges[i].head || ranges[i].anchor)) clipPos(this, ranges[i].head || ranges[i].anchor))
if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex) if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex)
setSelection(this, normalizeSelection(this.cm, out, primary), options) setSelection(this, normalizeSelection(this.cm, out, primary), options)
}), }),
addSelection: docMethodOp(function(anchor, head, options) { addSelection: docMethodOp(function(anchor, head, options) {
let ranges = this.sel.ranges.slice(0) let ranges = this.sel.ranges.slice(0)
ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))) ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)))
setSelection(this, normalizeSelection(this.cm, ranges, ranges.length - 1), options) setSelection(this, normalizeSelection(this.cm, ranges, ranges.length - 1), options)
}), }),
getSelection: function(lineSep) { getSelection: function(lineSep) {
let ranges = this.sel.ranges, lines let ranges = this.sel.ranges, lines
for (let i = 0; i < ranges.length; i++) { for (let i = 0; i < ranges.length; i++) {
let sel = getBetween(this, ranges[i].from(), ranges[i].to()) let sel = getBetween(this, ranges[i].from(), ranges[i].to())
lines = lines ? lines.concat(sel) : sel lines = lines ? lines.concat(sel) : sel
} }
if (lineSep === false) return lines if (lineSep === false) return lines
else return lines.join(lineSep || this.lineSeparator()) else return lines.join(lineSep || this.lineSeparator())
}, },
getSelections: function(lineSep) { getSelections: function(lineSep) {
let parts = [], ranges = this.sel.ranges let parts = [], ranges = this.sel.ranges
for (let i = 0; i < ranges.length; i++) { for (let i = 0; i < ranges.length; i++) {
let sel = getBetween(this, ranges[i].from(), ranges[i].to()) let sel = getBetween(this, ranges[i].from(), ranges[i].to())
if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator()) if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator())
parts[i] = sel parts[i] = sel
} }
return parts return parts
}, },
replaceSelection: function(code, collapse, origin) { replaceSelection: function(code, collapse, origin) {
let dup = [] let dup = []
for (let i = 0; i < this.sel.ranges.length; i++) for (let i = 0; i < this.sel.ranges.length; i++)
dup[i] = code dup[i] = code
this.replaceSelections(dup, collapse, origin || "+input") this.replaceSelections(dup, collapse, origin || "+input")
}, },
replaceSelections: docMethodOp(function(code, collapse, origin) { replaceSelections: docMethodOp(function(code, collapse, origin) {
let changes = [], sel = this.sel let changes = [], sel = this.sel
for (let i = 0; i < sel.ranges.length; i++) { for (let i = 0; i < sel.ranges.length; i++) {
let range = sel.ranges[i] let range = sel.ranges[i]
changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin} changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin}
} }
let newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse) let newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse)
for (let i = changes.length - 1; i >= 0; i--) for (let i = changes.length - 1; i >= 0; i--)
makeChange(this, changes[i]) makeChange(this, changes[i])
if (newSel) setSelectionReplaceHistory(this, newSel) if (newSel) setSelectionReplaceHistory(this, newSel)
else if (this.cm) ensureCursorVisible(this.cm) else if (this.cm) ensureCursorVisible(this.cm)
}), }),
undo: docMethodOp(function() {makeChangeFromHistory(this, "undo")}), undo: docMethodOp(function() {makeChangeFromHistory(this, "undo")}),
redo: docMethodOp(function() {makeChangeFromHistory(this, "redo")}), redo: docMethodOp(function() {makeChangeFromHistory(this, "redo")}),
undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true)}), undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true)}),
redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true)}), redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true)}),
setExtending: function(val) {this.extend = val}, setExtending: function(val) {this.extend = val},
getExtending: function() {return this.extend}, getExtending: function() {return this.extend},
historySize: function() { historySize: function() {
let hist = this.history, done = 0, undone = 0 let hist = this.history, done = 0, undone = 0
for (let i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done for (let i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done
for (let i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone for (let i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone
return {undo: done, redo: undone} return {undo: done, redo: undone}
}, },
clearHistory: function() { clearHistory: function() {
this.history = new History(this.history) this.history = new History(this.history)
linkedDocs(this, doc => doc.history = this.history, true) linkedDocs(this, doc => doc.history = this.history, true)
}, },
markClean: function() { markClean: function() {
this.cleanGeneration = this.changeGeneration(true) this.cleanGeneration = this.changeGeneration(true)
}, },
changeGeneration: function(forceSplit) { changeGeneration: function(forceSplit) {
if (forceSplit) if (forceSplit)
this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null
return this.history.generation return this.history.generation
}, },
isClean: function (gen) { isClean: function (gen) {
return this.history.generation == (gen || this.cleanGeneration) return this.history.generation == (gen || this.cleanGeneration)
}, },
getHistory: function() { getHistory: function() {
return {done: copyHistoryArray(this.history.done), return {done: copyHistoryArray(this.history.done),
undone: copyHistoryArray(this.history.undone)} undone: copyHistoryArray(this.history.undone)}
}, },
setHistory: function(histData) { setHistory: function(histData) {
let hist = this.history = new History(this.history) let hist = this.history = new History(this.history)
hist.done = copyHistoryArray(histData.done.slice(0), null, true) hist.done = copyHistoryArray(histData.done.slice(0), null, true)
hist.undone = copyHistoryArray(histData.undone.slice(0), null, true) hist.undone = copyHistoryArray(histData.undone.slice(0), null, true)
}, },
setGutterMarker: docMethodOp(function(line, gutterID, value) { setGutterMarker: docMethodOp(function(line, gutterID, value) {
return changeLine(this, line, "gutter", line => { return changeLine(this, line, "gutter", line => {
let markers = line.gutterMarkers || (line.gutterMarkers = {}) let markers = line.gutterMarkers || (line.gutterMarkers = {})
markers[gutterID] = value markers[gutterID] = value
if (!value && isEmpty(markers)) line.gutterMarkers = null if (!value && isEmpty(markers)) line.gutterMarkers = null
return true return true
}) })
}), }),
clearGutter: docMethodOp(function(gutterID) { clearGutter: docMethodOp(function(gutterID) {
this.iter(line => { this.iter(line => {
if (line.gutterMarkers && line.gutterMarkers[gutterID]) { if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
changeLine(this, line, "gutter", () => { changeLine(this, line, "gutter", () => {
line.gutterMarkers[gutterID] = null line.gutterMarkers[gutterID] = null
if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null
return true return true
}) })
} }
}) })
}), }),
lineInfo: function(line) { lineInfo: function(line) {
let n let n
if (typeof line == "number") { if (typeof line == "number") {
if (!isLine(this, line)) return null if (!isLine(this, line)) return null
n = line n = line
line = getLine(this, line) line = getLine(this, line)
if (!line) return null if (!line) return null
} else { } else {
n = lineNo(line) n = lineNo(line)
if (n == null) return null if (n == null) return null
} }
return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
widgets: line.widgets} widgets: line.widgets}
}, },
addLineClass: docMethodOp(function(handle, where, cls) { addLineClass: docMethodOp(function(handle, where, cls) {
return changeLine(this, handle, where == "gutter" ? "gutter" : "class", line => { return changeLine(this, handle, where == "gutter" ? "gutter" : "class", line => {
let prop = where == "text" ? "textClass" let prop = where == "text" ? "textClass"
: where == "background" ? "bgClass" : where == "background" ? "bgClass"
: where == "gutter" ? "gutterClass" : "wrapClass" : where == "gutter" ? "gutterClass" : "wrapClass"
if (!line[prop]) line[prop] = cls if (!line[prop]) line[prop] = cls
else if (classTest(cls).test(line[prop])) return false else if (classTest(cls).test(line[prop])) return false
else line[prop] += " " + cls else line[prop] += " " + cls
return true return true
}) })
}), }),
removeLineClass: docMethodOp(function(handle, where, cls) { removeLineClass: docMethodOp(function(handle, where, cls) {
return changeLine(this, handle, where == "gutter" ? "gutter" : "class", line => { return changeLine(this, handle, where == "gutter" ? "gutter" : "class", line => {
let prop = where == "text" ? "textClass" let prop = where == "text" ? "textClass"
: where == "background" ? "bgClass" : where == "background" ? "bgClass"
: where == "gutter" ? "gutterClass" : "wrapClass" : where == "gutter" ? "gutterClass" : "wrapClass"
let cur = line[prop] let cur = line[prop]
if (!cur) return false if (!cur) return false
else if (cls == null) line[prop] = null else if (cls == null) line[prop] = null
else { else {
let found = cur.match(classTest(cls)) let found = cur.match(classTest(cls))
if (!found) return false if (!found) return false
let end = found.index + found[0].length let end = found.index + found[0].length
line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null
} }
return true return true
}) })
}), }),
addLineWidget: docMethodOp(function(handle, node, options) { addLineWidget: docMethodOp(function(handle, node, options) {
return addLineWidget(this, handle, node, options) return addLineWidget(this, handle, node, options)
}), }),
removeLineWidget: function(widget) { widget.clear() }, removeLineWidget: function(widget) { widget.clear() },
markText: function(from, to, options) { markText: function(from, to, options) {
return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range") return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range")
}, },
setBookmark: function(pos, options) { setBookmark: function(pos, options) {
let realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), let realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
insertLeft: options && options.insertLeft, insertLeft: options && options.insertLeft,
clearWhenEmpty: false, shared: options && options.shared, clearWhenEmpty: false, shared: options && options.shared,
handleMouseEvents: options && options.handleMouseEvents} handleMouseEvents: options && options.handleMouseEvents}
pos = clipPos(this, pos) pos = clipPos(this, pos)
return markText(this, pos, pos, realOpts, "bookmark") return markText(this, pos, pos, realOpts, "bookmark")
}, },
findMarksAt: function(pos) { findMarksAt: function(pos) {
pos = clipPos(this, pos) pos = clipPos(this, pos)
let markers = [], spans = getLine(this, pos.line).markedSpans let markers = [], spans = getLine(this, pos.line).markedSpans
if (spans) for (let i = 0; i < spans.length; ++i) { if (spans) for (let i = 0; i < spans.length; ++i) {
let span = spans[i] let span = spans[i]
if ((span.from == null || span.from <= pos.ch) && if ((span.from == null || span.from <= pos.ch) &&
(span.to == null || span.to >= pos.ch)) (span.to == null || span.to >= pos.ch))
markers.push(span.marker.parent || span.marker) markers.push(span.marker.parent || span.marker)
} }
return markers return markers
}, },
findMarks: function(from, to, filter) { findMarks: function(from, to, filter) {
from = clipPos(this, from); to = clipPos(this, to) from = clipPos(this, from); to = clipPos(this, to)
let found = [], lineNo = from.line let found = [], lineNo = from.line
this.iter(from.line, to.line + 1, line => { this.iter(from.line, to.line + 1, line => {
let spans = line.markedSpans let spans = line.markedSpans
if (spans) for (let i = 0; i < spans.length; i++) { if (spans) for (let i = 0; i < spans.length; i++) {
let span = spans[i] let span = spans[i]
if (!(span.to != null && lineNo == from.line && from.ch >= span.to || if (!(span.to != null && lineNo == from.line && from.ch >= span.to ||
span.from == null && lineNo != from.line || span.from == null && lineNo != from.line ||
span.from != null && lineNo == to.line && span.from >= to.ch) && span.from != null && lineNo == to.line && span.from >= to.ch) &&
(!filter || filter(span.marker))) (!filter || filter(span.marker)))
found.push(span.marker.parent || span.marker) found.push(span.marker.parent || span.marker)
} }
++lineNo ++lineNo
}) })
return found return found
}, },
getAllMarks: function() { getAllMarks: function() {
let markers = [] let markers = []
this.iter(line => { this.iter(line => {
let sps = line.markedSpans let sps = line.markedSpans
if (sps) for (let i = 0; i < sps.length; ++i) if (sps) for (let i = 0; i < sps.length; ++i)
if (sps[i].from != null) markers.push(sps[i].marker) if (sps[i].from != null) markers.push(sps[i].marker)
}) })
return markers return markers
}, },
posFromIndex: function(off) { posFromIndex: function(off) {
let ch, lineNo = this.first, sepSize = this.lineSeparator().length let ch, lineNo = this.first, sepSize = this.lineSeparator().length
this.iter(line => { this.iter(line => {
let sz = line.text.length + sepSize let sz = line.text.length + sepSize
if (sz > off) { ch = off; return true } if (sz > off) { ch = off; return true }
off -= sz off -= sz
++lineNo ++lineNo
}) })
return clipPos(this, Pos(lineNo, ch)) return clipPos(this, Pos(lineNo, ch))
}, },
indexFromPos: function (coords) { indexFromPos: function (coords) {
coords = clipPos(this, coords) coords = clipPos(this, coords)
let index = coords.ch let index = coords.ch
if (coords.line < this.first || coords.ch < 0) return 0 if (coords.line < this.first || coords.ch < 0) return 0
let sepSize = this.lineSeparator().length let sepSize = this.lineSeparator().length
this.iter(this.first, coords.line, line => { // iter aborts when callback returns a truthy value this.iter(this.first, coords.line, line => { // iter aborts when callback returns a truthy value
index += line.text.length + sepSize index += line.text.length + sepSize
}) })
return index return index
}, },
copy: function(copyHistory) { copy: function(copyHistory) {
let doc = new Doc(getLines(this, this.first, this.first + this.size), let doc = new Doc(getLines(this, this.first, this.first + this.size),
this.modeOption, this.first, this.lineSep, this.direction) this.modeOption, this.first, this.lineSep, this.direction)
doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft
doc.sel = this.sel doc.sel = this.sel
doc.extend = false doc.extend = false
if (copyHistory) { if (copyHistory) {
doc.history.undoDepth = this.history.undoDepth doc.history.undoDepth = this.history.undoDepth
doc.setHistory(this.getHistory()) doc.setHistory(this.getHistory())
} }
return doc return doc
}, },
linkedDoc: function(options) { linkedDoc: function(options) {
if (!options) options = {} if (!options) options = {}
let from = this.first, to = this.first + this.size let from = this.first, to = this.first + this.size
if (options.from != null && options.from > from) from = options.from if (options.from != null && options.from > from) from = options.from
if (options.to != null && options.to < to) to = options.to if (options.to != null && options.to < to) to = options.to
let copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction) let copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction)
if (options.sharedHist) copy.history = this.history if (options.sharedHist) copy.history = this.history
;(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}) ;(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist})
copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}] copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]
copySharedMarkers(copy, findSharedMarkers(this)) copySharedMarkers(copy, findSharedMarkers(this))
return copy return copy
}, },
unlinkDoc: function(other) { unlinkDoc: function(other) {
if (other instanceof CodeMirror) other = other.doc if (other instanceof CodeMirror) other = other.doc
if (this.linked) for (let i = 0; i < this.linked.length; ++i) { if (this.linked) for (let i = 0; i < this.linked.length; ++i) {
let link = this.linked[i] let link = this.linked[i]
if (link.doc != other) continue if (link.doc != other) continue
this.linked.splice(i, 1) this.linked.splice(i, 1)
other.unlinkDoc(this) other.unlinkDoc(this)
detachSharedMarkers(findSharedMarkers(this)) detachSharedMarkers(findSharedMarkers(this))
break break
} }
// If the histories were shared, split them again // If the histories were shared, split them again
if (other.history == this.history) { if (other.history == this.history) {
let splitIds = [other.id] let splitIds = [other.id]
linkedDocs(other, doc => splitIds.push(doc.id), true) linkedDocs(other, doc => splitIds.push(doc.id), true)
other.history = new History(null) other.history = new History(null)
other.history.done = copyHistoryArray(this.history.done, splitIds) other.history.done = copyHistoryArray(this.history.done, splitIds)
other.history.undone = copyHistoryArray(this.history.undone, splitIds) other.history.undone = copyHistoryArray(this.history.undone, splitIds)
} }
}, },
iterLinkedDocs: function(f) {linkedDocs(this, f)}, iterLinkedDocs: function(f) {linkedDocs(this, f)},
getMode: function() {return this.mode}, getMode: function() {return this.mode},
getEditor: function() {return this.cm}, getEditor: function() {return this.cm},
splitLines: function(str) { splitLines: function(str) {
if (this.lineSep) return str.split(this.lineSep) if (this.lineSep) return str.split(this.lineSep)
return splitLinesAuto(str) return splitLinesAuto(str)
}, },
lineSeparator: function() { return this.lineSep || "\n" }, lineSeparator: function() { return this.lineSep || "\n" },
setDirection: docMethodOp(function (dir) { setDirection: docMethodOp(function (dir) {
if (dir != "rtl") dir = "ltr" if (dir != "rtl") dir = "ltr"
if (dir == this.direction) return if (dir == this.direction) return
this.direction = dir this.direction = dir
this.iter(line => line.order = null) this.iter(line => line.order = null)
if (this.cm) directionChanged(this.cm) if (this.cm) directionChanged(this.cm)
}) })
}) })
// Public alias. // Public alias.
Doc.prototype.eachLine = Doc.prototype.iter Doc.prototype.eachLine = Doc.prototype.iter
export default Doc export default Doc

View file

@ -1,61 +1,61 @@
import { cmp, Pos } from "../line/pos.js" import { cmp, Pos } from "../line/pos.js"
import { lst } from "../util/misc.js" import { lst } from "../util/misc.js"
import { normalizeSelection, Range, Selection } from "./selection.js" import { normalizeSelection, Range, Selection } from "./selection.js"
// Compute the position of the end of a change (its 'to' property // Compute the position of the end of a change (its 'to' property
// refers to the pre-change end). // refers to the pre-change end).
export function changeEnd(change) { export function changeEnd(change) {
if (!change.text) return change.to if (!change.text) return change.to
return Pos(change.from.line + change.text.length - 1, return Pos(change.from.line + change.text.length - 1,
lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)) lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))
} }
// Adjust a position to refer to the post-change position of the // Adjust a position to refer to the post-change position of the
// same text, or the end of the change if the change covers it. // same text, or the end of the change if the change covers it.
function adjustForChange(pos, change) { function adjustForChange(pos, change) {
if (cmp(pos, change.from) < 0) return pos if (cmp(pos, change.from) < 0) return pos
if (cmp(pos, change.to) <= 0) return changeEnd(change) if (cmp(pos, change.to) <= 0) return changeEnd(change)
let line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch let line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch
if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch
return Pos(line, ch) return Pos(line, ch)
} }
export function computeSelAfterChange(doc, change) { export function computeSelAfterChange(doc, change) {
let out = [] let out = []
for (let i = 0; i < doc.sel.ranges.length; i++) { for (let i = 0; i < doc.sel.ranges.length; i++) {
let range = doc.sel.ranges[i] let range = doc.sel.ranges[i]
out.push(new Range(adjustForChange(range.anchor, change), out.push(new Range(adjustForChange(range.anchor, change),
adjustForChange(range.head, change))) adjustForChange(range.head, change)))
} }
return normalizeSelection(doc.cm, out, doc.sel.primIndex) return normalizeSelection(doc.cm, out, doc.sel.primIndex)
} }
function offsetPos(pos, old, nw) { function offsetPos(pos, old, nw) {
if (pos.line == old.line) if (pos.line == old.line)
return Pos(nw.line, pos.ch - old.ch + nw.ch) return Pos(nw.line, pos.ch - old.ch + nw.ch)
else else
return Pos(nw.line + (pos.line - old.line), pos.ch) return Pos(nw.line + (pos.line - old.line), pos.ch)
} }
// Used by replaceSelections to allow moving the selection to the // Used by replaceSelections to allow moving the selection to the
// start or around the replaced test. Hint may be "start" or "around". // start or around the replaced test. Hint may be "start" or "around".
export function computeReplacedSel(doc, changes, hint) { export function computeReplacedSel(doc, changes, hint) {
let out = [] let out = []
let oldPrev = Pos(doc.first, 0), newPrev = oldPrev let oldPrev = Pos(doc.first, 0), newPrev = oldPrev
for (let i = 0; i < changes.length; i++) { for (let i = 0; i < changes.length; i++) {
let change = changes[i] let change = changes[i]
let from = offsetPos(change.from, oldPrev, newPrev) let from = offsetPos(change.from, oldPrev, newPrev)
let to = offsetPos(changeEnd(change), oldPrev, newPrev) let to = offsetPos(changeEnd(change), oldPrev, newPrev)
oldPrev = change.to oldPrev = change.to
newPrev = to newPrev = to
if (hint == "around") { if (hint == "around") {
let range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0 let range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0
out[i] = new Range(inv ? to : from, inv ? from : to) out[i] = new Range(inv ? to : from, inv ? from : to)
} else { } else {
out[i] = new Range(from, from) out[i] = new Range(from, from)
} }
} }
return new Selection(out, doc.sel.primIndex) return new Selection(out, doc.sel.primIndex)
} }

View file

@ -1,339 +1,339 @@
import { retreatFrontier } from "../line/highlight.js" import { retreatFrontier } from "../line/highlight.js"
import { startWorker } from "../display/highlight_worker.js" import { startWorker } from "../display/highlight_worker.js"
import { operation } from "../display/operations.js" import { operation } from "../display/operations.js"
import { regChange, regLineChange } from "../display/view_tracking.js" import { regChange, regLineChange } from "../display/view_tracking.js"
import { clipLine, clipPos, cmp, Pos } from "../line/pos.js" import { clipLine, clipPos, cmp, Pos } from "../line/pos.js"
import { sawReadOnlySpans } from "../line/saw_special_spans.js" import { sawReadOnlySpans } from "../line/saw_special_spans.js"
import { lineLength, removeReadOnlyRanges, stretchSpansOverChange, visualLine } from "../line/spans.js" import { lineLength, removeReadOnlyRanges, stretchSpansOverChange, visualLine } from "../line/spans.js"
import { getBetween, getLine, lineNo } from "../line/utils_line.js" import { getBetween, getLine, lineNo } from "../line/utils_line.js"
import { estimateHeight } from "../measurement/position_measurement.js" import { estimateHeight } from "../measurement/position_measurement.js"
import { hasHandler, signal, signalCursorActivity } from "../util/event.js" import { hasHandler, signal, signalCursorActivity } from "../util/event.js"
import { indexOf, lst, map, sel_dontScroll } from "../util/misc.js" import { indexOf, lst, map, sel_dontScroll } from "../util/misc.js"
import { signalLater } from "../util/operation_group.js" import { signalLater } from "../util/operation_group.js"
import { changeEnd, computeSelAfterChange } from "./change_measurement.js" import { changeEnd, computeSelAfterChange } from "./change_measurement.js"
import { isWholeLineUpdate, linkedDocs, updateDoc } from "./document_data.js" import { isWholeLineUpdate, linkedDocs, updateDoc } from "./document_data.js"
import { addChangeToHistory, historyChangeFromChange, mergeOldSpans, pushSelectionToHistory } from "./history.js" import { addChangeToHistory, historyChangeFromChange, mergeOldSpans, pushSelectionToHistory } from "./history.js"
import { Range, Selection } from "./selection.js" import { Range, Selection } from "./selection.js"
import { setSelection, setSelectionNoUndo, skipAtomic } from "./selection_updates.js" import { setSelection, setSelectionNoUndo, skipAtomic } from "./selection_updates.js"
// UPDATING // UPDATING
// Allow "beforeChange" event handlers to influence a change // Allow "beforeChange" event handlers to influence a change
function filterChange(doc, change, update) { function filterChange(doc, change, update) {
let obj = { let obj = {
canceled: false, canceled: false,
from: change.from, from: change.from,
to: change.to, to: change.to,
text: change.text, text: change.text,
origin: change.origin, origin: change.origin,
cancel: () => obj.canceled = true cancel: () => obj.canceled = true
} }
if (update) obj.update = (from, to, text, origin) => { if (update) obj.update = (from, to, text, origin) => {
if (from) obj.from = clipPos(doc, from) if (from) obj.from = clipPos(doc, from)
if (to) obj.to = clipPos(doc, to) if (to) obj.to = clipPos(doc, to)
if (text) obj.text = text if (text) obj.text = text
if (origin !== undefined) obj.origin = origin if (origin !== undefined) obj.origin = origin
} }
signal(doc, "beforeChange", doc, obj) signal(doc, "beforeChange", doc, obj)
if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj) if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj)
if (obj.canceled) { if (obj.canceled) {
if (doc.cm) doc.cm.curOp.updateInput = 2 if (doc.cm) doc.cm.curOp.updateInput = 2
return null return null
} }
return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin} return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
} }
// Apply a change to a document, and add it to the document's // Apply a change to a document, and add it to the document's
// history, and propagating it to all linked documents. // history, and propagating it to all linked documents.
export function makeChange(doc, change, ignoreReadOnly) { export function makeChange(doc, change, ignoreReadOnly) {
if (doc.cm) { if (doc.cm) {
if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly)
if (doc.cm.state.suppressEdits) return if (doc.cm.state.suppressEdits) return
} }
if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
change = filterChange(doc, change, true) change = filterChange(doc, change, true)
if (!change) return if (!change) return
} }
// Possibly split or suppress the update based on the presence // Possibly split or suppress the update based on the presence
// of read-only spans in its range. // of read-only spans in its range.
let split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to) let split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to)
if (split) { if (split) {
for (let i = split.length - 1; i >= 0; --i) for (let i = split.length - 1; i >= 0; --i)
makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}) makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin})
} else { } else {
makeChangeInner(doc, change) makeChangeInner(doc, change)
} }
} }
function makeChangeInner(doc, change) { function makeChangeInner(doc, change) {
if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return
let selAfter = computeSelAfterChange(doc, change) let selAfter = computeSelAfterChange(doc, change)
addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN) addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN)
makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)) makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change))
let rebased = [] let rebased = []
linkedDocs(doc, (doc, sharedHist) => { linkedDocs(doc, (doc, sharedHist) => {
if (!sharedHist && indexOf(rebased, doc.history) == -1) { if (!sharedHist && indexOf(rebased, doc.history) == -1) {
rebaseHist(doc.history, change) rebaseHist(doc.history, change)
rebased.push(doc.history) rebased.push(doc.history)
} }
makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)) makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change))
}) })
} }
// Revert a change stored in a document's history. // Revert a change stored in a document's history.
export function makeChangeFromHistory(doc, type, allowSelectionOnly) { export function makeChangeFromHistory(doc, type, allowSelectionOnly) {
let suppress = doc.cm && doc.cm.state.suppressEdits let suppress = doc.cm && doc.cm.state.suppressEdits
if (suppress && !allowSelectionOnly) return if (suppress && !allowSelectionOnly) return
let hist = doc.history, event, selAfter = doc.sel let hist = doc.history, event, selAfter = doc.sel
let source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done let source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done
// Verify that there is a useable event (so that ctrl-z won't // Verify that there is a useable event (so that ctrl-z won't
// needlessly clear selection events) // needlessly clear selection events)
let i = 0 let i = 0
for (; i < source.length; i++) { for (; i < source.length; i++) {
event = source[i] event = source[i]
if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
break break
} }
if (i == source.length) return if (i == source.length) return
hist.lastOrigin = hist.lastSelOrigin = null hist.lastOrigin = hist.lastSelOrigin = null
for (;;) { for (;;) {
event = source.pop() event = source.pop()
if (event.ranges) { if (event.ranges) {
pushSelectionToHistory(event, dest) pushSelectionToHistory(event, dest)
if (allowSelectionOnly && !event.equals(doc.sel)) { if (allowSelectionOnly && !event.equals(doc.sel)) {
setSelection(doc, event, {clearRedo: false}) setSelection(doc, event, {clearRedo: false})
return return
} }
selAfter = event selAfter = event
} else if (suppress) { } else if (suppress) {
source.push(event) source.push(event)
return return
} else break } else break
} }
// Build up a reverse change object to add to the opposite history // Build up a reverse change object to add to the opposite history
// stack (redo when undoing, and vice versa). // stack (redo when undoing, and vice versa).
let antiChanges = [] let antiChanges = []
pushSelectionToHistory(selAfter, dest) pushSelectionToHistory(selAfter, dest)
dest.push({changes: antiChanges, generation: hist.generation}) dest.push({changes: antiChanges, generation: hist.generation})
hist.generation = event.generation || ++hist.maxGeneration hist.generation = event.generation || ++hist.maxGeneration
let filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange") let filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")
for (let i = event.changes.length - 1; i >= 0; --i) { for (let i = event.changes.length - 1; i >= 0; --i) {
let change = event.changes[i] let change = event.changes[i]
change.origin = type change.origin = type
if (filter && !filterChange(doc, change, false)) { if (filter && !filterChange(doc, change, false)) {
source.length = 0 source.length = 0
return return
} }
antiChanges.push(historyChangeFromChange(doc, change)) antiChanges.push(historyChangeFromChange(doc, change))
let after = i ? computeSelAfterChange(doc, change) : lst(source) let after = i ? computeSelAfterChange(doc, change) : lst(source)
makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)) makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change))
if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}) if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)})
let rebased = [] let rebased = []
// Propagate to the linked documents // Propagate to the linked documents
linkedDocs(doc, (doc, sharedHist) => { linkedDocs(doc, (doc, sharedHist) => {
if (!sharedHist && indexOf(rebased, doc.history) == -1) { if (!sharedHist && indexOf(rebased, doc.history) == -1) {
rebaseHist(doc.history, change) rebaseHist(doc.history, change)
rebased.push(doc.history) rebased.push(doc.history)
} }
makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)) makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change))
}) })
} }
} }
// Sub-views need their line numbers shifted when text is added // Sub-views need their line numbers shifted when text is added
// above or below them in the parent document. // above or below them in the parent document.
function shiftDoc(doc, distance) { function shiftDoc(doc, distance) {
if (distance == 0) return if (distance == 0) return
doc.first += distance doc.first += distance
doc.sel = new Selection(map(doc.sel.ranges, range => new Range( doc.sel = new Selection(map(doc.sel.ranges, range => new Range(
Pos(range.anchor.line + distance, range.anchor.ch), Pos(range.anchor.line + distance, range.anchor.ch),
Pos(range.head.line + distance, range.head.ch) Pos(range.head.line + distance, range.head.ch)
)), doc.sel.primIndex) )), doc.sel.primIndex)
if (doc.cm) { if (doc.cm) {
regChange(doc.cm, doc.first, doc.first - distance, distance) regChange(doc.cm, doc.first, doc.first - distance, distance)
for (let d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) for (let d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
regLineChange(doc.cm, l, "gutter") regLineChange(doc.cm, l, "gutter")
} }
} }
// More lower-level change function, handling only a single document // More lower-level change function, handling only a single document
// (not linked ones). // (not linked ones).
function makeChangeSingleDoc(doc, change, selAfter, spans) { function makeChangeSingleDoc(doc, change, selAfter, spans) {
if (doc.cm && !doc.cm.curOp) if (doc.cm && !doc.cm.curOp)
return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans)
if (change.to.line < doc.first) { if (change.to.line < doc.first) {
shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)) shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line))
return return
} }
if (change.from.line > doc.lastLine()) return if (change.from.line > doc.lastLine()) return
// Clip the change to the size of this doc // Clip the change to the size of this doc
if (change.from.line < doc.first) { if (change.from.line < doc.first) {
let shift = change.text.length - 1 - (doc.first - change.from.line) let shift = change.text.length - 1 - (doc.first - change.from.line)
shiftDoc(doc, shift) shiftDoc(doc, shift)
change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
text: [lst(change.text)], origin: change.origin} text: [lst(change.text)], origin: change.origin}
} }
let last = doc.lastLine() let last = doc.lastLine()
if (change.to.line > last) { if (change.to.line > last) {
change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
text: [change.text[0]], origin: change.origin} text: [change.text[0]], origin: change.origin}
} }
change.removed = getBetween(doc, change.from, change.to) change.removed = getBetween(doc, change.from, change.to)
if (!selAfter) selAfter = computeSelAfterChange(doc, change) if (!selAfter) selAfter = computeSelAfterChange(doc, change)
if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans) if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans)
else updateDoc(doc, change, spans) else updateDoc(doc, change, spans)
setSelectionNoUndo(doc, selAfter, sel_dontScroll) setSelectionNoUndo(doc, selAfter, sel_dontScroll)
if (doc.cantEdit && skipAtomic(doc, Pos(doc.firstLine(), 0))) if (doc.cantEdit && skipAtomic(doc, Pos(doc.firstLine(), 0)))
doc.cantEdit = false doc.cantEdit = false
} }
// Handle the interaction of a change to a document with the editor // Handle the interaction of a change to a document with the editor
// that this document is part of. // that this document is part of.
function makeChangeSingleDocInEditor(cm, change, spans) { function makeChangeSingleDocInEditor(cm, change, spans) {
let doc = cm.doc, display = cm.display, from = change.from, to = change.to let doc = cm.doc, display = cm.display, from = change.from, to = change.to
let recomputeMaxLength = false, checkWidthStart = from.line let recomputeMaxLength = false, checkWidthStart = from.line
if (!cm.options.lineWrapping) { if (!cm.options.lineWrapping) {
checkWidthStart = lineNo(visualLine(getLine(doc, from.line))) checkWidthStart = lineNo(visualLine(getLine(doc, from.line)))
doc.iter(checkWidthStart, to.line + 1, line => { doc.iter(checkWidthStart, to.line + 1, line => {
if (line == display.maxLine) { if (line == display.maxLine) {
recomputeMaxLength = true recomputeMaxLength = true
return true return true
} }
}) })
} }
if (doc.sel.contains(change.from, change.to) > -1) if (doc.sel.contains(change.from, change.to) > -1)
signalCursorActivity(cm) signalCursorActivity(cm)
updateDoc(doc, change, spans, estimateHeight(cm)) updateDoc(doc, change, spans, estimateHeight(cm))
if (!cm.options.lineWrapping) { if (!cm.options.lineWrapping) {
doc.iter(checkWidthStart, from.line + change.text.length, line => { doc.iter(checkWidthStart, from.line + change.text.length, line => {
let len = lineLength(line) let len = lineLength(line)
if (len > display.maxLineLength) { if (len > display.maxLineLength) {
display.maxLine = line display.maxLine = line
display.maxLineLength = len display.maxLineLength = len
display.maxLineChanged = true display.maxLineChanged = true
recomputeMaxLength = false recomputeMaxLength = false
} }
}) })
if (recomputeMaxLength) cm.curOp.updateMaxLine = true if (recomputeMaxLength) cm.curOp.updateMaxLine = true
} }
retreatFrontier(doc, from.line) retreatFrontier(doc, from.line)
startWorker(cm, 400) startWorker(cm, 400)
let lendiff = change.text.length - (to.line - from.line) - 1 let lendiff = change.text.length - (to.line - from.line) - 1
// Remember that these lines changed, for updating the display // Remember that these lines changed, for updating the display
if (change.full) if (change.full)
regChange(cm) regChange(cm)
else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
regLineChange(cm, from.line, "text") regLineChange(cm, from.line, "text")
else else
regChange(cm, from.line, to.line + 1, lendiff) regChange(cm, from.line, to.line + 1, lendiff)
let changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change") let changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change")
if (changeHandler || changesHandler) { if (changeHandler || changesHandler) {
let obj = { let obj = {
from: from, to: to, from: from, to: to,
text: change.text, text: change.text,
removed: change.removed, removed: change.removed,
origin: change.origin origin: change.origin
} }
if (changeHandler) signalLater(cm, "change", cm, obj) if (changeHandler) signalLater(cm, "change", cm, obj)
if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj) if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj)
} }
cm.display.selForContextMenu = null cm.display.selForContextMenu = null
} }
export function replaceRange(doc, code, from, to, origin) { export function replaceRange(doc, code, from, to, origin) {
if (!to) to = from if (!to) to = from
if (cmp(to, from) < 0) [from, to] = [to, from] if (cmp(to, from) < 0) [from, to] = [to, from]
if (typeof code == "string") code = doc.splitLines(code) if (typeof code == "string") code = doc.splitLines(code)
makeChange(doc, {from, to, text: code, origin}) makeChange(doc, {from, to, text: code, origin})
} }
// Rebasing/resetting history to deal with externally-sourced changes // Rebasing/resetting history to deal with externally-sourced changes
function rebaseHistSelSingle(pos, from, to, diff) { function rebaseHistSelSingle(pos, from, to, diff) {
if (to < pos.line) { if (to < pos.line) {
pos.line += diff pos.line += diff
} else if (from < pos.line) { } else if (from < pos.line) {
pos.line = from pos.line = from
pos.ch = 0 pos.ch = 0
} }
} }
// Tries to rebase an array of history events given a change in the // Tries to rebase an array of history events given a change in the
// document. If the change touches the same lines as the event, the // document. If the change touches the same lines as the event, the
// event, and everything 'behind' it, is discarded. If the change is // event, and everything 'behind' it, is discarded. If the change is
// before the event, the event's positions are updated. Uses a // before the event, the event's positions are updated. Uses a
// copy-on-write scheme for the positions, to avoid having to // copy-on-write scheme for the positions, to avoid having to
// reallocate them all on every rebase, but also avoid problems with // reallocate them all on every rebase, but also avoid problems with
// shared position objects being unsafely updated. // shared position objects being unsafely updated.
function rebaseHistArray(array, from, to, diff) { function rebaseHistArray(array, from, to, diff) {
for (let i = 0; i < array.length; ++i) { for (let i = 0; i < array.length; ++i) {
let sub = array[i], ok = true let sub = array[i], ok = true
if (sub.ranges) { if (sub.ranges) {
if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true } if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true }
for (let j = 0; j < sub.ranges.length; j++) { for (let j = 0; j < sub.ranges.length; j++) {
rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff) rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff)
rebaseHistSelSingle(sub.ranges[j].head, from, to, diff) rebaseHistSelSingle(sub.ranges[j].head, from, to, diff)
} }
continue continue
} }
for (let j = 0; j < sub.changes.length; ++j) { for (let j = 0; j < sub.changes.length; ++j) {
let cur = sub.changes[j] let cur = sub.changes[j]
if (to < cur.from.line) { if (to < cur.from.line) {
cur.from = Pos(cur.from.line + diff, cur.from.ch) cur.from = Pos(cur.from.line + diff, cur.from.ch)
cur.to = Pos(cur.to.line + diff, cur.to.ch) cur.to = Pos(cur.to.line + diff, cur.to.ch)
} else if (from <= cur.to.line) { } else if (from <= cur.to.line) {
ok = false ok = false
break break
} }
} }
if (!ok) { if (!ok) {
array.splice(0, i + 1) array.splice(0, i + 1)
i = 0 i = 0
} }
} }
} }
function rebaseHist(hist, change) { function rebaseHist(hist, change) {
let from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1 let from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1
rebaseHistArray(hist.done, from, to, diff) rebaseHistArray(hist.done, from, to, diff)
rebaseHistArray(hist.undone, from, to, diff) rebaseHistArray(hist.undone, from, to, diff)
} }
// Utility for applying a change to a line by handle or number, // Utility for applying a change to a line by handle or number,
// returning the number and optionally registering the line as // returning the number and optionally registering the line as
// changed. // changed.
export function changeLine(doc, handle, changeType, op) { export function changeLine(doc, handle, changeType, op) {
let no = handle, line = handle let no = handle, line = handle
if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)) if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle))
else no = lineNo(handle) else no = lineNo(handle)
if (no == null) return null if (no == null) return null
if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType) if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType)
return line return line
} }

View file

@ -1,293 +1,293 @@
import { eltP } from "../util/dom.js" import { eltP } from "../util/dom.js"
import { eventMixin, hasHandler, on } from "../util/event.js" import { eventMixin, hasHandler, on } from "../util/event.js"
import { endOperation, operation, runInOp, startOperation } from "../display/operations.js" import { endOperation, operation, runInOp, startOperation } from "../display/operations.js"
import { clipPos, cmp, Pos } from "../line/pos.js" import { clipPos, cmp, Pos } from "../line/pos.js"
import { lineNo, updateLineHeight } from "../line/utils_line.js" import { lineNo, updateLineHeight } from "../line/utils_line.js"
import { clearLineMeasurementCacheFor, findViewForLine, textHeight } from "../measurement/position_measurement.js" import { clearLineMeasurementCacheFor, findViewForLine, textHeight } from "../measurement/position_measurement.js"
import { seeReadOnlySpans, seeCollapsedSpans } from "../line/saw_special_spans.js" import { seeReadOnlySpans, seeCollapsedSpans } from "../line/saw_special_spans.js"
import { addMarkedSpan, conflictingCollapsedRange, getMarkedSpanFor, lineIsHidden, lineLength, MarkedSpan, removeMarkedSpan, visualLine } from "../line/spans.js" import { addMarkedSpan, conflictingCollapsedRange, getMarkedSpanFor, lineIsHidden, lineLength, MarkedSpan, removeMarkedSpan, visualLine } from "../line/spans.js"
import { copyObj, indexOf, lst } from "../util/misc.js" import { copyObj, indexOf, lst } from "../util/misc.js"
import { signalLater } from "../util/operation_group.js" import { signalLater } from "../util/operation_group.js"
import { widgetHeight } from "../measurement/widgets.js" import { widgetHeight } from "../measurement/widgets.js"
import { regChange, regLineChange } from "../display/view_tracking.js" import { regChange, regLineChange } from "../display/view_tracking.js"
import { linkedDocs } from "./document_data.js" import { linkedDocs } from "./document_data.js"
import { addChangeToHistory } from "./history.js" import { addChangeToHistory } from "./history.js"
import { reCheckSelection } from "./selection_updates.js" import { reCheckSelection } from "./selection_updates.js"
// TEXTMARKERS // TEXTMARKERS
// Created with markText and setBookmark methods. A TextMarker is a // Created with markText and setBookmark methods. A TextMarker is a
// handle that can be used to clear or find a marked position in the // handle that can be used to clear or find a marked position in the
// document. Line objects hold arrays (markedSpans) containing // document. Line objects hold arrays (markedSpans) containing
// {from, to, marker} object pointing to such marker objects, and // {from, to, marker} object pointing to such marker objects, and
// indicating that such a marker is present on that line. Multiple // indicating that such a marker is present on that line. Multiple
// lines may point to the same marker when it spans across lines. // lines may point to the same marker when it spans across lines.
// The spans will have null for their from/to properties when the // The spans will have null for their from/to properties when the
// marker continues beyond the start/end of the line. Markers have // marker continues beyond the start/end of the line. Markers have
// links back to the lines they currently touch. // links back to the lines they currently touch.
// Collapsed markers have unique ids, in order to be able to order // Collapsed markers have unique ids, in order to be able to order
// them, which is needed for uniquely determining an outer marker // them, which is needed for uniquely determining an outer marker
// when they overlap (they may nest, but not partially overlap). // when they overlap (they may nest, but not partially overlap).
let nextMarkerId = 0 let nextMarkerId = 0
export class TextMarker { export class TextMarker {
constructor(doc, type) { constructor(doc, type) {
this.lines = [] this.lines = []
this.type = type this.type = type
this.doc = doc this.doc = doc
this.id = ++nextMarkerId this.id = ++nextMarkerId
} }
// Clear the marker. // Clear the marker.
clear() { clear() {
if (this.explicitlyCleared) return if (this.explicitlyCleared) return
let cm = this.doc.cm, withOp = cm && !cm.curOp let cm = this.doc.cm, withOp = cm && !cm.curOp
if (withOp) startOperation(cm) if (withOp) startOperation(cm)
if (hasHandler(this, "clear")) { if (hasHandler(this, "clear")) {
let found = this.find() let found = this.find()
if (found) signalLater(this, "clear", found.from, found.to) if (found) signalLater(this, "clear", found.from, found.to)
} }
let min = null, max = null let min = null, max = null
for (let i = 0; i < this.lines.length; ++i) { for (let i = 0; i < this.lines.length; ++i) {
let line = this.lines[i] let line = this.lines[i]
let span = getMarkedSpanFor(line.markedSpans, this) let span = getMarkedSpanFor(line.markedSpans, this)
if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text") if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text")
else if (cm) { else if (cm) {
if (span.to != null) max = lineNo(line) if (span.to != null) max = lineNo(line)
if (span.from != null) min = lineNo(line) if (span.from != null) min = lineNo(line)
} }
line.markedSpans = removeMarkedSpan(line.markedSpans, span) line.markedSpans = removeMarkedSpan(line.markedSpans, span)
if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
updateLineHeight(line, textHeight(cm.display)) updateLineHeight(line, textHeight(cm.display))
} }
if (cm && this.collapsed && !cm.options.lineWrapping) for (let i = 0; i < this.lines.length; ++i) { if (cm && this.collapsed && !cm.options.lineWrapping) for (let i = 0; i < this.lines.length; ++i) {
let visual = visualLine(this.lines[i]), len = lineLength(visual) let visual = visualLine(this.lines[i]), len = lineLength(visual)
if (len > cm.display.maxLineLength) { if (len > cm.display.maxLineLength) {
cm.display.maxLine = visual cm.display.maxLine = visual
cm.display.maxLineLength = len cm.display.maxLineLength = len
cm.display.maxLineChanged = true cm.display.maxLineChanged = true
} }
} }
if (min != null && cm && this.collapsed) regChange(cm, min, max + 1) if (min != null && cm && this.collapsed) regChange(cm, min, max + 1)
this.lines.length = 0 this.lines.length = 0
this.explicitlyCleared = true this.explicitlyCleared = true
if (this.atomic && this.doc.cantEdit) { if (this.atomic && this.doc.cantEdit) {
this.doc.cantEdit = false this.doc.cantEdit = false
if (cm) reCheckSelection(cm.doc) if (cm) reCheckSelection(cm.doc)
} }
if (cm) signalLater(cm, "markerCleared", cm, this, min, max) if (cm) signalLater(cm, "markerCleared", cm, this, min, max)
if (withOp) endOperation(cm) if (withOp) endOperation(cm)
if (this.parent) this.parent.clear() if (this.parent) this.parent.clear()
} }
// Find the position of the marker in the document. Returns a {from, // Find the position of the marker in the document. Returns a {from,
// to} object by default. Side can be passed to get a specific side // to} object by default. Side can be passed to get a specific side
// -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
// Pos objects returned contain a line object, rather than a line // Pos objects returned contain a line object, rather than a line
// number (used to prevent looking up the same line twice). // number (used to prevent looking up the same line twice).
find(side, lineObj) { find(side, lineObj) {
if (side == null && this.type == "bookmark") side = 1 if (side == null && this.type == "bookmark") side = 1
let from, to let from, to
for (let i = 0; i < this.lines.length; ++i) { for (let i = 0; i < this.lines.length; ++i) {
let line = this.lines[i] let line = this.lines[i]
let span = getMarkedSpanFor(line.markedSpans, this) let span = getMarkedSpanFor(line.markedSpans, this)
if (span.from != null) { if (span.from != null) {
from = Pos(lineObj ? line : lineNo(line), span.from) from = Pos(lineObj ? line : lineNo(line), span.from)
if (side == -1) return from if (side == -1) return from
} }
if (span.to != null) { if (span.to != null) {
to = Pos(lineObj ? line : lineNo(line), span.to) to = Pos(lineObj ? line : lineNo(line), span.to)
if (side == 1) return to if (side == 1) return to
} }
} }
return from && {from: from, to: to} return from && {from: from, to: to}
} }
// Signals that the marker's widget changed, and surrounding layout // Signals that the marker's widget changed, and surrounding layout
// should be recomputed. // should be recomputed.
changed() { changed() {
let pos = this.find(-1, true), widget = this, cm = this.doc.cm let pos = this.find(-1, true), widget = this, cm = this.doc.cm
if (!pos || !cm) return if (!pos || !cm) return
runInOp(cm, () => { runInOp(cm, () => {
let line = pos.line, lineN = lineNo(pos.line) let line = pos.line, lineN = lineNo(pos.line)
let view = findViewForLine(cm, lineN) let view = findViewForLine(cm, lineN)
if (view) { if (view) {
clearLineMeasurementCacheFor(view) clearLineMeasurementCacheFor(view)
cm.curOp.selectionChanged = cm.curOp.forceUpdate = true cm.curOp.selectionChanged = cm.curOp.forceUpdate = true
} }
cm.curOp.updateMaxLine = true cm.curOp.updateMaxLine = true
if (!lineIsHidden(widget.doc, line) && widget.height != null) { if (!lineIsHidden(widget.doc, line) && widget.height != null) {
let oldHeight = widget.height let oldHeight = widget.height
widget.height = null widget.height = null
let dHeight = widgetHeight(widget) - oldHeight let dHeight = widgetHeight(widget) - oldHeight
if (dHeight) if (dHeight)
updateLineHeight(line, line.height + dHeight) updateLineHeight(line, line.height + dHeight)
} }
signalLater(cm, "markerChanged", cm, this) signalLater(cm, "markerChanged", cm, this)
}) })
} }
attachLine(line) { attachLine(line) {
if (!this.lines.length && this.doc.cm) { if (!this.lines.length && this.doc.cm) {
let op = this.doc.cm.curOp let op = this.doc.cm.curOp
if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
(op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this) (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this)
} }
this.lines.push(line) this.lines.push(line)
} }
detachLine(line) { detachLine(line) {
this.lines.splice(indexOf(this.lines, line), 1) this.lines.splice(indexOf(this.lines, line), 1)
if (!this.lines.length && this.doc.cm) { if (!this.lines.length && this.doc.cm) {
let op = this.doc.cm.curOp let op = this.doc.cm.curOp
;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this) ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this)
} }
} }
} }
eventMixin(TextMarker) eventMixin(TextMarker)
// Create a marker, wire it up to the right lines, and // Create a marker, wire it up to the right lines, and
export function markText(doc, from, to, options, type) { export function markText(doc, from, to, options, type) {
// Shared markers (across linked documents) are handled separately // Shared markers (across linked documents) are handled separately
// (markTextShared will call out to this again, once per // (markTextShared will call out to this again, once per
// document). // document).
if (options && options.shared) return markTextShared(doc, from, to, options, type) if (options && options.shared) return markTextShared(doc, from, to, options, type)
// Ensure we are in an operation. // Ensure we are in an operation.
if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type) if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type)
let marker = new TextMarker(doc, type), diff = cmp(from, to) let marker = new TextMarker(doc, type), diff = cmp(from, to)
if (options) copyObj(options, marker, false) if (options) copyObj(options, marker, false)
// Don't connect empty markers unless clearWhenEmpty is false // Don't connect empty markers unless clearWhenEmpty is false
if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
return marker return marker
if (marker.replacedWith) { if (marker.replacedWith) {
// Showing up as a widget implies collapsed (widget replaces text) // Showing up as a widget implies collapsed (widget replaces text)
marker.collapsed = true marker.collapsed = true
marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget") marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget")
if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true") if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true")
if (options.insertLeft) marker.widgetNode.insertLeft = true if (options.insertLeft) marker.widgetNode.insertLeft = true
} }
if (marker.collapsed) { if (marker.collapsed) {
if (conflictingCollapsedRange(doc, from.line, from, to, marker) || if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
throw new Error("Inserting collapsed marker partially overlapping an existing one") throw new Error("Inserting collapsed marker partially overlapping an existing one")
seeCollapsedSpans() seeCollapsedSpans()
} }
if (marker.addToHistory) if (marker.addToHistory)
addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN) addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN)
let curLine = from.line, cm = doc.cm, updateMaxLine let curLine = from.line, cm = doc.cm, updateMaxLine
doc.iter(curLine, to.line + 1, line => { doc.iter(curLine, to.line + 1, line => {
if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
updateMaxLine = true updateMaxLine = true
if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0) if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0)
addMarkedSpan(line, new MarkedSpan(marker, addMarkedSpan(line, new MarkedSpan(marker,
curLine == from.line ? from.ch : null, curLine == from.line ? from.ch : null,
curLine == to.line ? to.ch : null), doc.cm && doc.cm.curOp) curLine == to.line ? to.ch : null), doc.cm && doc.cm.curOp)
++curLine ++curLine
}) })
// lineIsHidden depends on the presence of the spans, so needs a second pass // lineIsHidden depends on the presence of the spans, so needs a second pass
if (marker.collapsed) doc.iter(from.line, to.line + 1, line => { if (marker.collapsed) doc.iter(from.line, to.line + 1, line => {
if (lineIsHidden(doc, line)) updateLineHeight(line, 0) if (lineIsHidden(doc, line)) updateLineHeight(line, 0)
}) })
if (marker.clearOnEnter) on(marker, "beforeCursorEnter", () => marker.clear()) if (marker.clearOnEnter) on(marker, "beforeCursorEnter", () => marker.clear())
if (marker.readOnly) { if (marker.readOnly) {
seeReadOnlySpans() seeReadOnlySpans()
if (doc.history.done.length || doc.history.undone.length) if (doc.history.done.length || doc.history.undone.length)
doc.clearHistory() doc.clearHistory()
} }
if (marker.collapsed) { if (marker.collapsed) {
marker.id = ++nextMarkerId marker.id = ++nextMarkerId
marker.atomic = true marker.atomic = true
} }
if (cm) { if (cm) {
// Sync editor state // Sync editor state
if (updateMaxLine) cm.curOp.updateMaxLine = true if (updateMaxLine) cm.curOp.updateMaxLine = true
if (marker.collapsed) if (marker.collapsed)
regChange(cm, from.line, to.line + 1) regChange(cm, from.line, to.line + 1)
else if (marker.className || marker.startStyle || marker.endStyle || marker.css || else if (marker.className || marker.startStyle || marker.endStyle || marker.css ||
marker.attributes || marker.title) marker.attributes || marker.title)
for (let i = from.line; i <= to.line; i++) regLineChange(cm, i, "text") for (let i = from.line; i <= to.line; i++) regLineChange(cm, i, "text")
if (marker.atomic) reCheckSelection(cm.doc) if (marker.atomic) reCheckSelection(cm.doc)
signalLater(cm, "markerAdded", cm, marker) signalLater(cm, "markerAdded", cm, marker)
} }
return marker return marker
} }
// SHARED TEXTMARKERS // SHARED TEXTMARKERS
// A shared marker spans multiple linked documents. It is // A shared marker spans multiple linked documents. It is
// implemented as a meta-marker-object controlling multiple normal // implemented as a meta-marker-object controlling multiple normal
// markers. // markers.
export class SharedTextMarker { export class SharedTextMarker {
constructor(markers, primary) { constructor(markers, primary) {
this.markers = markers this.markers = markers
this.primary = primary this.primary = primary
for (let i = 0; i < markers.length; ++i) for (let i = 0; i < markers.length; ++i)
markers[i].parent = this markers[i].parent = this
} }
clear() { clear() {
if (this.explicitlyCleared) return if (this.explicitlyCleared) return
this.explicitlyCleared = true this.explicitlyCleared = true
for (let i = 0; i < this.markers.length; ++i) for (let i = 0; i < this.markers.length; ++i)
this.markers[i].clear() this.markers[i].clear()
signalLater(this, "clear") signalLater(this, "clear")
} }
find(side, lineObj) { find(side, lineObj) {
return this.primary.find(side, lineObj) return this.primary.find(side, lineObj)
} }
} }
eventMixin(SharedTextMarker) eventMixin(SharedTextMarker)
function markTextShared(doc, from, to, options, type) { function markTextShared(doc, from, to, options, type) {
options = copyObj(options) options = copyObj(options)
options.shared = false options.shared = false
let markers = [markText(doc, from, to, options, type)], primary = markers[0] let markers = [markText(doc, from, to, options, type)], primary = markers[0]
let widget = options.widgetNode let widget = options.widgetNode
linkedDocs(doc, doc => { linkedDocs(doc, doc => {
if (widget) options.widgetNode = widget.cloneNode(true) if (widget) options.widgetNode = widget.cloneNode(true)
markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)) markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type))
for (let i = 0; i < doc.linked.length; ++i) for (let i = 0; i < doc.linked.length; ++i)
if (doc.linked[i].isParent) return if (doc.linked[i].isParent) return
primary = lst(markers) primary = lst(markers)
}) })
return new SharedTextMarker(markers, primary) return new SharedTextMarker(markers, primary)
} }
export function findSharedMarkers(doc) { export function findSharedMarkers(doc) {
return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), m => m.parent) return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), m => m.parent)
} }
export function copySharedMarkers(doc, markers) { export function copySharedMarkers(doc, markers) {
for (let i = 0; i < markers.length; i++) { for (let i = 0; i < markers.length; i++) {
let marker = markers[i], pos = marker.find() let marker = markers[i], pos = marker.find()
let mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to) let mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to)
if (cmp(mFrom, mTo)) { if (cmp(mFrom, mTo)) {
let subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type) let subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type)
marker.markers.push(subMark) marker.markers.push(subMark)
subMark.parent = marker subMark.parent = marker
} }
} }
} }
export function detachSharedMarkers(markers) { export function detachSharedMarkers(markers) {
for (let i = 0; i < markers.length; i++) { for (let i = 0; i < markers.length; i++) {
let marker = markers[i], linked = [marker.primary.doc] let marker = markers[i], linked = [marker.primary.doc]
linkedDocs(marker.primary.doc, d => linked.push(d)) linkedDocs(marker.primary.doc, d => linked.push(d))
for (let j = 0; j < marker.markers.length; j++) { for (let j = 0; j < marker.markers.length; j++) {
let subMarker = marker.markers[j] let subMarker = marker.markers[j]
if (indexOf(linked, subMarker.doc) == -1) { if (indexOf(linked, subMarker.doc) == -1) {
subMarker.parent = null subMarker.parent = null
marker.markers.splice(j--, 1) marker.markers.splice(j--, 1)
} }
} }
} }
} }

View file

@ -1,84 +1,84 @@
import { cmp, copyPos, equalCursorPos, maxPos, minPos } from "../line/pos.js" import { cmp, copyPos, equalCursorPos, maxPos, minPos } from "../line/pos.js"
import { indexOf } from "../util/misc.js" import { indexOf } from "../util/misc.js"
// Selection objects are immutable. A new one is created every time // Selection objects are immutable. A new one is created every time
// the selection changes. A selection is one or more non-overlapping // the selection changes. A selection is one or more non-overlapping
// (and non-touching) ranges, sorted, and an integer that indicates // (and non-touching) ranges, sorted, and an integer that indicates
// which one is the primary selection (the one that's scrolled into // which one is the primary selection (the one that's scrolled into
// view, that getCursor returns, etc). // view, that getCursor returns, etc).
export class Selection { export class Selection {
constructor(ranges, primIndex) { constructor(ranges, primIndex) {
this.ranges = ranges this.ranges = ranges
this.primIndex = primIndex this.primIndex = primIndex
} }
primary() { return this.ranges[this.primIndex] } primary() { return this.ranges[this.primIndex] }
equals(other) { equals(other) {
if (other == this) return true if (other == this) return true
if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false
for (let i = 0; i < this.ranges.length; i++) { for (let i = 0; i < this.ranges.length; i++) {
let here = this.ranges[i], there = other.ranges[i] let here = this.ranges[i], there = other.ranges[i]
if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) return false if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) return false
} }
return true return true
} }
deepCopy() { deepCopy() {
let out = [] let out = []
for (let i = 0; i < this.ranges.length; i++) for (let i = 0; i < this.ranges.length; i++)
out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)) out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head))
return new Selection(out, this.primIndex) return new Selection(out, this.primIndex)
} }
somethingSelected() { somethingSelected() {
for (let i = 0; i < this.ranges.length; i++) for (let i = 0; i < this.ranges.length; i++)
if (!this.ranges[i].empty()) return true if (!this.ranges[i].empty()) return true
return false return false
} }
contains(pos, end) { contains(pos, end) {
if (!end) end = pos if (!end) end = pos
for (let i = 0; i < this.ranges.length; i++) { for (let i = 0; i < this.ranges.length; i++) {
let range = this.ranges[i] let range = this.ranges[i]
if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
return i return i
} }
return -1 return -1
} }
} }
export class Range { export class Range {
constructor(anchor, head) { constructor(anchor, head) {
this.anchor = anchor; this.head = head this.anchor = anchor; this.head = head
} }
from() { return minPos(this.anchor, this.head) } from() { return minPos(this.anchor, this.head) }
to() { return maxPos(this.anchor, this.head) } to() { return maxPos(this.anchor, this.head) }
empty() { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch } empty() { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch }
} }
// Take an unsorted, potentially overlapping set of ranges, and // Take an unsorted, potentially overlapping set of ranges, and
// build a selection out of it. 'Consumes' ranges array (modifying // build a selection out of it. 'Consumes' ranges array (modifying
// it). // it).
export function normalizeSelection(cm, ranges, primIndex) { export function normalizeSelection(cm, ranges, primIndex) {
let mayTouch = cm && cm.options.selectionsMayTouch let mayTouch = cm && cm.options.selectionsMayTouch
let prim = ranges[primIndex] let prim = ranges[primIndex]
ranges.sort((a, b) => cmp(a.from(), b.from())) ranges.sort((a, b) => cmp(a.from(), b.from()))
primIndex = indexOf(ranges, prim) primIndex = indexOf(ranges, prim)
for (let i = 1; i < ranges.length; i++) { for (let i = 1; i < ranges.length; i++) {
let cur = ranges[i], prev = ranges[i - 1] let cur = ranges[i], prev = ranges[i - 1]
let diff = cmp(prev.to(), cur.from()) let diff = cmp(prev.to(), cur.from())
if (mayTouch && !cur.empty() ? diff > 0 : diff >= 0) { if (mayTouch && !cur.empty() ? diff > 0 : diff >= 0) {
let from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()) let from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to())
let inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head let inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head
if (i <= primIndex) --primIndex if (i <= primIndex) --primIndex
ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)) ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to))
} }
} }
return new Selection(ranges, primIndex) return new Selection(ranges, primIndex)
} }
export function simpleSelection(anchor, head) { export function simpleSelection(anchor, head) {
return new Selection([new Range(anchor, head || anchor)], 0) return new Selection([new Range(anchor, head || anchor)], 0)
} }

View file

@ -1,216 +1,216 @@
import { signalLater } from "../util/operation_group.js" import { signalLater } from "../util/operation_group.js"
import { ensureCursorVisible } from "../display/scrolling.js" import { ensureCursorVisible } from "../display/scrolling.js"
import { clipPos, cmp, Pos } from "../line/pos.js" import { clipPos, cmp, Pos } from "../line/pos.js"
import { getLine } from "../line/utils_line.js" import { getLine } from "../line/utils_line.js"
import { hasHandler, signal, signalCursorActivity } from "../util/event.js" import { hasHandler, signal, signalCursorActivity } from "../util/event.js"
import { lst, sel_dontScroll } from "../util/misc.js" import { lst, sel_dontScroll } from "../util/misc.js"
import { addSelectionToHistory } from "./history.js" import { addSelectionToHistory } from "./history.js"
import { normalizeSelection, Range, Selection, simpleSelection } from "./selection.js" import { normalizeSelection, Range, Selection, simpleSelection } from "./selection.js"
// The 'scroll' parameter given to many of these indicated whether // The 'scroll' parameter given to many of these indicated whether
// the new cursor position should be scrolled into view after // the new cursor position should be scrolled into view after
// modifying the selection. // modifying the selection.
// If shift is held or the extend flag is set, extends a range to // If shift is held or the extend flag is set, extends a range to
// include a given position (and optionally a second position). // include a given position (and optionally a second position).
// Otherwise, simply returns the range between the given positions. // Otherwise, simply returns the range between the given positions.
// Used for cursor motion and such. // Used for cursor motion and such.
export function extendRange(range, head, other, extend) { export function extendRange(range, head, other, extend) {
if (extend) { if (extend) {
let anchor = range.anchor let anchor = range.anchor
if (other) { if (other) {
let posBefore = cmp(head, anchor) < 0 let posBefore = cmp(head, anchor) < 0
if (posBefore != (cmp(other, anchor) < 0)) { if (posBefore != (cmp(other, anchor) < 0)) {
anchor = head anchor = head
head = other head = other
} else if (posBefore != (cmp(head, other) < 0)) { } else if (posBefore != (cmp(head, other) < 0)) {
head = other head = other
} }
} }
return new Range(anchor, head) return new Range(anchor, head)
} else { } else {
return new Range(other || head, head) return new Range(other || head, head)
} }
} }
// Extend the primary selection range, discard the rest. // Extend the primary selection range, discard the rest.
export function extendSelection(doc, head, other, options, extend) { export function extendSelection(doc, head, other, options, extend) {
if (extend == null) extend = doc.cm && (doc.cm.display.shift || doc.extend) if (extend == null) extend = doc.cm && (doc.cm.display.shift || doc.extend)
setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options) setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options)
} }
// Extend all selections (pos is an array of selections with length // Extend all selections (pos is an array of selections with length
// equal the number of selections) // equal the number of selections)
export function extendSelections(doc, heads, options) { export function extendSelections(doc, heads, options) {
let out = [] let out = []
let extend = doc.cm && (doc.cm.display.shift || doc.extend) let extend = doc.cm && (doc.cm.display.shift || doc.extend)
for (let i = 0; i < doc.sel.ranges.length; i++) for (let i = 0; i < doc.sel.ranges.length; i++)
out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend) out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend)
let newSel = normalizeSelection(doc.cm, out, doc.sel.primIndex) let newSel = normalizeSelection(doc.cm, out, doc.sel.primIndex)
setSelection(doc, newSel, options) setSelection(doc, newSel, options)
} }
// Updates a single range in the selection. // Updates a single range in the selection.
export function replaceOneSelection(doc, i, range, options) { export function replaceOneSelection(doc, i, range, options) {
let ranges = doc.sel.ranges.slice(0) let ranges = doc.sel.ranges.slice(0)
ranges[i] = range ranges[i] = range
setSelection(doc, normalizeSelection(doc.cm, ranges, doc.sel.primIndex), options) setSelection(doc, normalizeSelection(doc.cm, ranges, doc.sel.primIndex), options)
} }
// Reset the selection to a single range. // Reset the selection to a single range.
export function setSimpleSelection(doc, anchor, head, options) { export function setSimpleSelection(doc, anchor, head, options) {
setSelection(doc, simpleSelection(anchor, head), options) setSelection(doc, simpleSelection(anchor, head), options)
} }
// Give beforeSelectionChange handlers a change to influence a // Give beforeSelectionChange handlers a change to influence a
// selection update. // selection update.
function filterSelectionChange(doc, sel, options) { function filterSelectionChange(doc, sel, options) {
let obj = { let obj = {
ranges: sel.ranges, ranges: sel.ranges,
update: function(ranges) { update: function(ranges) {
this.ranges = [] this.ranges = []
for (let i = 0; i < ranges.length; i++) for (let i = 0; i < ranges.length; i++)
this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
clipPos(doc, ranges[i].head)) clipPos(doc, ranges[i].head))
}, },
origin: options && options.origin origin: options && options.origin
} }
signal(doc, "beforeSelectionChange", doc, obj) signal(doc, "beforeSelectionChange", doc, obj)
if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj) if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj)
if (obj.ranges != sel.ranges) return normalizeSelection(doc.cm, obj.ranges, obj.ranges.length - 1) if (obj.ranges != sel.ranges) return normalizeSelection(doc.cm, obj.ranges, obj.ranges.length - 1)
else return sel else return sel
} }
export function setSelectionReplaceHistory(doc, sel, options) { export function setSelectionReplaceHistory(doc, sel, options) {
let done = doc.history.done, last = lst(done) let done = doc.history.done, last = lst(done)
if (last && last.ranges) { if (last && last.ranges) {
done[done.length - 1] = sel done[done.length - 1] = sel
setSelectionNoUndo(doc, sel, options) setSelectionNoUndo(doc, sel, options)
} else { } else {
setSelection(doc, sel, options) setSelection(doc, sel, options)
} }
} }
// Set a new selection. // Set a new selection.
export function setSelection(doc, sel, options) { export function setSelection(doc, sel, options) {
setSelectionNoUndo(doc, sel, options) setSelectionNoUndo(doc, sel, options)
addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options) addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options)
} }
export function setSelectionNoUndo(doc, sel, options) { export function setSelectionNoUndo(doc, sel, options) {
if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
sel = filterSelectionChange(doc, sel, options) sel = filterSelectionChange(doc, sel, options)
let bias = options && options.bias || let bias = options && options.bias ||
(cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1) (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1)
setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)) setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true))
if (!(options && options.scroll === false) && doc.cm && doc.cm.getOption("readOnly") != "nocursor") if (!(options && options.scroll === false) && doc.cm && doc.cm.getOption("readOnly") != "nocursor")
ensureCursorVisible(doc.cm) ensureCursorVisible(doc.cm)
} }
function setSelectionInner(doc, sel) { function setSelectionInner(doc, sel) {
if (sel.equals(doc.sel)) return if (sel.equals(doc.sel)) return
doc.sel = sel doc.sel = sel
if (doc.cm) { if (doc.cm) {
doc.cm.curOp.updateInput = 1 doc.cm.curOp.updateInput = 1
doc.cm.curOp.selectionChanged = true doc.cm.curOp.selectionChanged = true
signalCursorActivity(doc.cm) signalCursorActivity(doc.cm)
} }
signalLater(doc, "cursorActivity", doc) signalLater(doc, "cursorActivity", doc)
} }
// Verify that the selection does not partially select any atomic // Verify that the selection does not partially select any atomic
// marked ranges. // marked ranges.
export function reCheckSelection(doc) { export function reCheckSelection(doc) {
setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false)) setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false))
} }
// Return a selection that does not partially select any atomic // Return a selection that does not partially select any atomic
// ranges. // ranges.
function skipAtomicInSelection(doc, sel, bias, mayClear) { function skipAtomicInSelection(doc, sel, bias, mayClear) {
let out let out
for (let i = 0; i < sel.ranges.length; i++) { for (let i = 0; i < sel.ranges.length; i++) {
let range = sel.ranges[i] let range = sel.ranges[i]
let old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i] let old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i]
let newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear) let newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear)
let newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear) let newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear)
if (out || newAnchor != range.anchor || newHead != range.head) { if (out || newAnchor != range.anchor || newHead != range.head) {
if (!out) out = sel.ranges.slice(0, i) if (!out) out = sel.ranges.slice(0, i)
out[i] = new Range(newAnchor, newHead) out[i] = new Range(newAnchor, newHead)
} }
} }
return out ? normalizeSelection(doc.cm, out, sel.primIndex) : sel return out ? normalizeSelection(doc.cm, out, sel.primIndex) : sel
} }
function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
let line = getLine(doc, pos.line) let line = getLine(doc, pos.line)
if (line.markedSpans) for (let i = 0; i < line.markedSpans.length; ++i) { if (line.markedSpans) for (let i = 0; i < line.markedSpans.length; ++i) {
let sp = line.markedSpans[i], m = sp.marker let sp = line.markedSpans[i], m = sp.marker
// Determine if we should prevent the cursor being placed to the left/right of an atomic marker // Determine if we should prevent the cursor being placed to the left/right of an atomic marker
// Historically this was determined using the inclusiveLeft/Right option, but the new way to control it // Historically this was determined using the inclusiveLeft/Right option, but the new way to control it
// is with selectLeft/Right // is with selectLeft/Right
let preventCursorLeft = ("selectLeft" in m) ? !m.selectLeft : m.inclusiveLeft let preventCursorLeft = ("selectLeft" in m) ? !m.selectLeft : m.inclusiveLeft
let preventCursorRight = ("selectRight" in m) ? !m.selectRight : m.inclusiveRight let preventCursorRight = ("selectRight" in m) ? !m.selectRight : m.inclusiveRight
if ((sp.from == null || (preventCursorLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && if ((sp.from == null || (preventCursorLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
(sp.to == null || (preventCursorRight ? sp.to >= pos.ch : sp.to > pos.ch))) { (sp.to == null || (preventCursorRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
if (mayClear) { if (mayClear) {
signal(m, "beforeCursorEnter") signal(m, "beforeCursorEnter")
if (m.explicitlyCleared) { if (m.explicitlyCleared) {
if (!line.markedSpans) break if (!line.markedSpans) break
else {--i; continue} else {--i; continue}
} }
} }
if (!m.atomic) continue if (!m.atomic) continue
if (oldPos) { if (oldPos) {
let near = m.find(dir < 0 ? 1 : -1), diff let near = m.find(dir < 0 ? 1 : -1), diff
if (dir < 0 ? preventCursorRight : preventCursorLeft) if (dir < 0 ? preventCursorRight : preventCursorLeft)
near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null) near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null)
if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
return skipAtomicInner(doc, near, pos, dir, mayClear) return skipAtomicInner(doc, near, pos, dir, mayClear)
} }
let far = m.find(dir < 0 ? -1 : 1) let far = m.find(dir < 0 ? -1 : 1)
if (dir < 0 ? preventCursorLeft : preventCursorRight) if (dir < 0 ? preventCursorLeft : preventCursorRight)
far = movePos(doc, far, dir, far.line == pos.line ? line : null) far = movePos(doc, far, dir, far.line == pos.line ? line : null)
return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
} }
} }
return pos return pos
} }
// Ensure a given position is not inside an atomic range. // Ensure a given position is not inside an atomic range.
export function skipAtomic(doc, pos, oldPos, bias, mayClear) { export function skipAtomic(doc, pos, oldPos, bias, mayClear) {
let dir = bias || 1 let dir = bias || 1
let found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || let found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
(!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
(!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)) (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true))
if (!found) { if (!found) {
doc.cantEdit = true doc.cantEdit = true
return Pos(doc.first, 0) return Pos(doc.first, 0)
} }
return found return found
} }
function movePos(doc, pos, dir, line) { function movePos(doc, pos, dir, line) {
if (dir < 0 && pos.ch == 0) { if (dir < 0 && pos.ch == 0) {
if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1)) if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1))
else return null else return null
} else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) { } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0) if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0)
else return null else return null
} else { } else {
return new Pos(pos.line, pos.ch + dir) return new Pos(pos.line, pos.ch + dir)
} }
} }
export function selectAll(cm) { export function selectAll(cm) {
cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll) cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll)
} }

Some files were not shown because too many files have changed in this diff Show more