Version v0.14.1
35
asset/css/awesome-icons.less
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
:root, :host {
|
||||||
|
--fa-font-regular: normal 400 1em/1 "Font Awesome 6 Free";
|
||||||
|
--fa-font-solid: normal 900 1em/1 "Font Awesome 6 Free";
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Font Awesome 6 Free';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: block;
|
||||||
|
src: url('@{iplWebAssets}/font/awesome/fa-regular-400.woff2') format('woff2'),
|
||||||
|
url('@{iplWebAssets}/font/awesome/fa-regular-400.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
.far,
|
||||||
|
.fa-regular {
|
||||||
|
font-family: 'Font Awesome 6 Free';
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Font Awesome 6 Free';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: block;
|
||||||
|
src: url('@{iplWebAssets}/font/awesome/fa-solid-900.woff2') format('woff2'),
|
||||||
|
url('@{iplWebAssets}/font/awesome/fa-solid-900.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa,
|
||||||
|
.fas,
|
||||||
|
.fa-solid {
|
||||||
|
font-family: 'Font Awesome 6 Free';
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
147
asset/css/balls.less
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
@ball-pad: 1/6em;
|
||||||
|
|
||||||
|
.ball {
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ball-size-xs {
|
||||||
|
height: 1/3em;
|
||||||
|
width: 1/3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ball-size-s {
|
||||||
|
height: 0.5em;
|
||||||
|
width: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ball-size-m {
|
||||||
|
height: 0.75em;
|
||||||
|
width: 0.75em;
|
||||||
|
line-height: 0;
|
||||||
|
|
||||||
|
i.icon:before {
|
||||||
|
font-size: .75 - @ball-pad * 2;
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ball-size-ml {
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
line-height: 0;
|
||||||
|
|
||||||
|
i.icon {
|
||||||
|
line-height: 0.3;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
font-size: 0.8 - @ball-pad * 2;
|
||||||
|
line-height: 1 - @ball-pad * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ball-size-l {
|
||||||
|
height: 1.5em;
|
||||||
|
width: 1.5em;
|
||||||
|
line-height: 1em;
|
||||||
|
|
||||||
|
i.icon:before {
|
||||||
|
font-size: 1 - @ball-pad * 2;
|
||||||
|
line-height: 1.5 - @ball-pad * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ball-size-xl {
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
|
||||||
|
i.icon:before {
|
||||||
|
line-height: 2 - @ball-pad * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ball-outline(@color) {
|
||||||
|
border: @ball-pad solid @color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ball-solid(@color) {
|
||||||
|
background-color: @color;
|
||||||
|
color: var(--default-text-color-inverted, @default-text-color-inverted);
|
||||||
|
padding: @ball-pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-ball {
|
||||||
|
.ball();
|
||||||
|
|
||||||
|
&.state-pending:not(.ball-size-l):not(.ball-size-xl) {
|
||||||
|
.ball-solid(var(--state-pending, @state-pending));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-pending.ball-size-l,
|
||||||
|
&.state-pending.ball-size-xl {
|
||||||
|
.ball-outline(var(--state-pending, @state-pending));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-up:not(.ball-size-l):not(.ball-size-xl) {
|
||||||
|
.ball-solid(var(--state-up, @state-up));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-up.ball-size-l,
|
||||||
|
&.state-up.ball-size-xl {
|
||||||
|
.ball-outline(var(--state-up, @state-up));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-down {
|
||||||
|
.ball-solid(var(--state-down, @state-down));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-ok:not(.ball-size-l):not(.ball-size-xl) {
|
||||||
|
.ball-solid(var(--state-ok, @state-ok));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-ok.ball-size-l,
|
||||||
|
&.state-ok.ball-size-xl {
|
||||||
|
.ball-outline(var(--state-ok, @state-ok));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-warning {
|
||||||
|
.ball-solid(var(--state-warning, @state-warning));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-critical {
|
||||||
|
.ball-solid(var(--state-critical, @state-critical));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-unknown {
|
||||||
|
.ball-solid(var(--state-unknown, @state-unknown));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.handled {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.icon {
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specific icon styles
|
||||||
|
&.ball-size-l i {
|
||||||
|
&.fa-sitemap:before {
|
||||||
|
font-size: 8px; // px to ignore browser min font-size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ball-size-xl i {
|
||||||
|
&.fa-sitemap:before {
|
||||||
|
font-size: .857em;
|
||||||
|
line-height: (2 - @ball-pad * 2) / .857;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
asset/css/cancel-button.less
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
.cancel-button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: baseline;
|
||||||
|
padding: .5em 1em;
|
||||||
|
|
||||||
|
.appearance(none);
|
||||||
|
.rounded-corners();
|
||||||
|
line-height: normal;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
background: var(--cancel-button-bg, @cancel-button-bg);
|
||||||
|
border: 1px solid var(--cancel-button-border-color, @cancel-button-border-color);
|
||||||
|
color: var(--cancel-button-color, @cancel-button-color);
|
||||||
|
|
||||||
|
&:focus,
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--cancel-button-hover-bg, @cancel-button-hover-bg);
|
||||||
|
color: var(--cancel-button-hover-color, @cancel-button-hover-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
background: none;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
border: 1px solid var(--control-disabled-color, @control-disabled-color);
|
||||||
|
color: var(--control-disabled-color, @control-disabled-color);
|
||||||
|
|
||||||
|
&:focus,
|
||||||
|
&:hover {
|
||||||
|
background: none;
|
||||||
|
color: var(--control-disabled-color, @control-disabled-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
88
asset/css/compat.less
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// General input styles
|
||||||
|
|
||||||
|
.icinga-controls {
|
||||||
|
.uploaded-files {
|
||||||
|
background-color: @default-input-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form.icinga-form {
|
||||||
|
.uploaded-files {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icinga-controls {
|
||||||
|
.uploaded-files {
|
||||||
|
font-size: inherit;
|
||||||
|
padding: .5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Button styles
|
||||||
|
|
||||||
|
// The `form` selector is only required to overrule the hover effect applied by Icinga Web.
|
||||||
|
// It's not required if done by Icinga Web itself, only here because this is applied earlier
|
||||||
|
// as it's part of a library.
|
||||||
|
form.icinga-controls {
|
||||||
|
button[type="submit"].remove-uploaded-file {
|
||||||
|
all: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule Element styles
|
||||||
|
|
||||||
|
.icinga-form > .schedule-element,
|
||||||
|
.icinga-form > .schedule-element > fieldset {
|
||||||
|
margin-top: 1em;
|
||||||
|
|
||||||
|
> .control-group:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icinga-form .schedule-element {
|
||||||
|
.control-group > fieldset > .weekly,
|
||||||
|
.control-group > .ordinal,
|
||||||
|
.control-group > .monthly,
|
||||||
|
.control-group > .annually {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This effectively restricts the weekly fields to always be aligned to the right,
|
||||||
|
// regardless of the using an icinga-form or not. So this should be removed once we
|
||||||
|
// have re-implemented the decorators.
|
||||||
|
.control-group > fieldset > .weekly {
|
||||||
|
margin-left: 14em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form.icinga-form .control-group {
|
||||||
|
> .monthly,
|
||||||
|
> .ordinal {
|
||||||
|
margin-right: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .ordinal.annually {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TermInput styles
|
||||||
|
|
||||||
|
form.icinga-form .control-group {
|
||||||
|
> .term-input-area {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
|
||||||
|
width: auto;
|
||||||
|
&.vertical {
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"] {
|
||||||
|
flex: unset;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
164
asset/css/controls.less
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
.pagination-control {
|
||||||
|
li > a {
|
||||||
|
color: var(--control-color, @control-color);
|
||||||
|
border-radius: .25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
li > a:hover {
|
||||||
|
background: var(--control-hover-bg, @control-hover-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.previous-page,
|
||||||
|
.next-page {
|
||||||
|
padding: .5em .25em;
|
||||||
|
|
||||||
|
i {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
i:before {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.previous-page > i {
|
||||||
|
margin-left: -.125em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.next-page > i {
|
||||||
|
margin-right: -.125em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style
|
||||||
|
|
||||||
|
.control-button {
|
||||||
|
.appearance(none);
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--control-color, @control-color);
|
||||||
|
.rounded-corners();
|
||||||
|
|
||||||
|
&:hover, &:focus, &.active {
|
||||||
|
background-color: var(--control-hover-bg, @control-hover-bg);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
color: var(--control-disabled-color, @control-disabled-color);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i.icon:before {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout
|
||||||
|
|
||||||
|
.control-button {
|
||||||
|
display: inline-block;
|
||||||
|
padding: .25em .5em;
|
||||||
|
|
||||||
|
> i.icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.icon:before {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-control {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
.form-element {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: baseline;
|
||||||
|
margin-right: .5em;
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-right: .5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-button {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-controls {
|
||||||
|
display: flex;
|
||||||
|
min-width: 100%;
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
|
||||||
|
& ~ .control-button {
|
||||||
|
margin-left: .5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
The default layout of list controls in Icinga Web
|
||||||
|
|
||||||
|
┌────────────────────────────────────────────────────────────────┐
|
||||||
|
│ .pagination-control .limit-control .sort-control │
|
||||||
|
│ <-------------------- .search-controls ----------------------> │
|
||||||
|
└────────────────────────────────────────────────────────────────┘
|
||||||
|
*/
|
||||||
|
.controls.default-layout {
|
||||||
|
.box-shadow(0, 0, 0, 1px, @controls-separator-bg);
|
||||||
|
|
||||||
|
z-index: 1; // The content may clip, this ensures the separator is always visible
|
||||||
|
& + .content {
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .pagination-control {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .sort-control,
|
||||||
|
> .limit-control {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .limit-control {
|
||||||
|
margin-right: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .search-controls {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
> :not(:only-child) {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .sort-control,
|
||||||
|
> .search-controls > .control-button:last-child {
|
||||||
|
margin-right: -.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .search-controls > .search-bar .search-suggestions {
|
||||||
|
// Suggestions should be kept at a distance from the bottom of the page
|
||||||
|
margin-bottom: 2.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .search-controls > .search-bar .filter-input-area {
|
||||||
|
label {
|
||||||
|
&::after,
|
||||||
|
input {
|
||||||
|
padding: 0 .5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
asset/css/copy-to-clipboard.less
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
.clipboard-wrapper {
|
||||||
|
position: relative;
|
||||||
|
> .copy-to-clipboard {
|
||||||
|
margin: 0.1em 0.1em 0 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.copy-to-clipboard.active {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-to-clipboard {
|
||||||
|
.appearance(none);
|
||||||
|
border: none;
|
||||||
|
opacity: 0;
|
||||||
|
background: none;
|
||||||
|
padding: 0.25em 0.5em;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover, &:focus {
|
||||||
|
opacity: 0.8;
|
||||||
|
color: var(--control-color, @control-color);
|
||||||
|
outline-offset: -2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-to-clipboard.active,
|
||||||
|
.clipboard-wrapper:hover .copy-to-clipboard.active {
|
||||||
|
&.copied {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 1s linear 3s;
|
||||||
|
}
|
||||||
|
}
|
9
asset/css/datetime-picker.less
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.flatpickr-input + .input {
|
||||||
|
padding-right: 2em;
|
||||||
|
|
||||||
|
& + .fa-calendar {
|
||||||
|
margin: .5em 1em 0 -3.5em;
|
||||||
|
padding: 0 .5em 0 1em;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
11
asset/css/empty-state.less
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.empty-state {
|
||||||
|
color: @empty-state-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state-bar {
|
||||||
|
padding: 1em;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.rounded-corners();
|
||||||
|
background-color: @empty-state-bar-bg;
|
||||||
|
}
|
40
asset/css/file-element.less
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
form .uploaded-files {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
> li:not(:last-of-type) {
|
||||||
|
margin-bottom: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[type="submit"].remove-uploaded-file {
|
||||||
|
.icon {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus, &:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// text-overflow: ellipsis layout rules, yes, exclusively
|
||||||
|
> li {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
> button[type="submit"].remove-uploaded-file {
|
||||||
|
display: inline-flex;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
width: 0;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6215
asset/css/fontawesome.css
vendored
Normal file
17
asset/css/horizontal-key-value.less
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
.horizontal-key-value {
|
||||||
|
display: flex;
|
||||||
|
padding: .25em 0;
|
||||||
|
align-items: baseline;
|
||||||
|
|
||||||
|
.key {
|
||||||
|
color: var(--default-text-color-light, @default-text-color-light);
|
||||||
|
flex: 0 0 auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 12em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
color: var(--default-text-color, @default-text-color);
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
}
|
64
asset/css/icinga-icons.less
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Icinga-Icons';
|
||||||
|
src: url('@{iplWebAssets}/font/icinga-icons/fonts/Icinga-Icons.ttf') format('truetype'),
|
||||||
|
url('@{iplWebAssets}/font/icinga-icons/fonts/Icinga-Icons.woff') format('woff'),
|
||||||
|
url('@{iplWebAssets}/font/icinga-icons/fonts/Icinga-Icons.svg') format('svg');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="iicon-"]:before, [class*=" iicon-"]:before {
|
||||||
|
/* use !important to prevent issues with browser extensions that change fonts */
|
||||||
|
font-family: 'Icinga-Icons';
|
||||||
|
speak: none;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
font-variant: normal;
|
||||||
|
text-transform: none;
|
||||||
|
line-height: 1em;
|
||||||
|
|
||||||
|
/* Better Font Rendering =========== */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iicon-certificate:before {
|
||||||
|
content: "\e906";
|
||||||
|
}
|
||||||
|
.iicon-filter-check-circle:before {
|
||||||
|
content: "\e90b";
|
||||||
|
}
|
||||||
|
.iicon-ca-check-circle:before {
|
||||||
|
content: "\e908";
|
||||||
|
}
|
||||||
|
.iicon-refresh-cert:before {
|
||||||
|
content: "\e909";
|
||||||
|
}
|
||||||
|
.iicon-th-list:before {
|
||||||
|
content: "\e90a";
|
||||||
|
}
|
||||||
|
.iicon-icinga:before {
|
||||||
|
content: "\e907";
|
||||||
|
}
|
||||||
|
.iicon-minimal:before,
|
||||||
|
.iicon-list-view-minimal:before {
|
||||||
|
content: "\e900";
|
||||||
|
}
|
||||||
|
.iicon-detailed:before,
|
||||||
|
.iicon-list-view-detailed:before {
|
||||||
|
content: "\e901";
|
||||||
|
}
|
||||||
|
.iicon-default:before,
|
||||||
|
.iicon-list-view-default:before {
|
||||||
|
content: "\e902";
|
||||||
|
}
|
||||||
|
.iicon-grid:before {
|
||||||
|
content: "\e903";
|
||||||
|
}
|
||||||
|
.iicon-bracket-open:before {
|
||||||
|
content: "\e904";
|
||||||
|
}
|
||||||
|
.iicon-bracket-close:before {
|
||||||
|
content: "\e905";
|
||||||
|
}
|
16
asset/css/icons-base.less
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
i.icon {
|
||||||
|
vertical-align: middle; // Firefox will place icons weird otherwise
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
font-style: normal;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
display: block;
|
||||||
|
min-width: 1em;
|
||||||
|
margin-right: .2em;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
}
|
85
asset/css/list/item-list.less
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// Style
|
||||||
|
|
||||||
|
.item-list {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout
|
||||||
|
|
||||||
|
.item-list {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.main {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
padding: .5em 0;
|
||||||
|
width: 0;
|
||||||
|
margin-left: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.visual {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caption {
|
||||||
|
height: 3em;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.line-clamp();
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-height: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .empty-state-bar {
|
||||||
|
margin: 0 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list.default-layout .list-item {
|
||||||
|
.title {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: baseline;
|
||||||
|
white-space: nowrap;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
margin: 0 .28125em; // 0 calculated width
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.subject {
|
||||||
|
.text-ellipsis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls .list-item:not(:last-child) {
|
||||||
|
margin-bottom: .5em;
|
||||||
|
}
|
95
asset/css/list/item-table.less
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Style
|
||||||
|
|
||||||
|
ul.item-table {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row {
|
||||||
|
color: @default-text-color-light;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
.subject {
|
||||||
|
color: @default-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @list-item-title-hover-color;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
.item-table li.page-break-follows:not(:last-of-type) {
|
||||||
|
.col {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.visual {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout
|
||||||
|
|
||||||
|
.table-row {
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.visual {
|
||||||
|
width: 2.5em;
|
||||||
|
padding: .5em 0;
|
||||||
|
margin-top: -.5em;
|
||||||
|
margin-bottom: -.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-content {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
width: 0;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
.text-ellipsis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.col {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.item-table {
|
||||||
|
display: grid;
|
||||||
|
|
||||||
|
> .table-row {
|
||||||
|
.col:not(.title) {
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.item-table {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.item-table {
|
||||||
|
> .empty-state-bar {
|
||||||
|
margin: 0 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.table-row {
|
||||||
|
display: flex;
|
||||||
|
column-gap: 1em;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
}
|
89
asset/css/list/list-item.less
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Style
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
color: @default-text-color-light;
|
||||||
|
|
||||||
|
&:not(:first-child) > .main {
|
||||||
|
border-top: 1px solid @list-item-separation-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:first-child) .visual {
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caption {
|
||||||
|
i {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: @default-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
.subject {
|
||||||
|
color: @default-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: @default-text-color;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @list-item-title-hover-color;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
.subject {
|
||||||
|
color: @list-item-title-hover-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
padding-top: .5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
.list-item.page-break-follows + .list-item {
|
||||||
|
.main {
|
||||||
|
border-top: 1px solid transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
.visual {
|
||||||
|
padding: .5em 0;
|
||||||
|
width: 2.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caption {
|
||||||
|
p {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-right: 1em;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
time {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
> * {
|
||||||
|
font-size: .857em;
|
||||||
|
line-height: 1.5*.857em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
asset/css/mixin/card.less
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.card() {
|
||||||
|
&.card {
|
||||||
|
.rounded-corners(.5em);
|
||||||
|
border: 1px solid var(--card-border-color, @card-border-color);
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: .5em;
|
||||||
|
|
||||||
|
border-bottom: 1px solid var(--card-border-color, @card-border-color);
|
||||||
|
|
||||||
|
.meta span {
|
||||||
|
font-size: 11/12em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: .5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
asset/css/mixin/mixins.less
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
.rounded-corners(@border-radius: 0.4em) {
|
||||||
|
border-radius: @border-radius;
|
||||||
|
|
||||||
|
-webkit-background-clip: padding-box;
|
||||||
|
-moz-background-clip: padding;
|
||||||
|
background-clip: padding-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appearance(@appearance) {
|
||||||
|
-webkit-appearance: @appearance;
|
||||||
|
-moz-appearance: @appearance;
|
||||||
|
-ms-appearance: @appearance;
|
||||||
|
appearance: @appearance;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-shadow(@x: 0.2em; @y: 0.2em; @blur: 0.2em; @spread: 0; @color: rgba(83, 83, 83, 0.25)) {
|
||||||
|
-webkit-box-shadow: @arguments;
|
||||||
|
-moz-box-shadow: @arguments;
|
||||||
|
box-shadow: @arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-clamp(@numOfLines: 2) when (@numOfLines > 1) {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: @numOfLines;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
.line-clamp(@numOfLines: 2) when (@numOfLines = "reset") {
|
||||||
|
display: revert;
|
||||||
|
-webkit-line-clamp: initial;
|
||||||
|
-webkit-box-orient: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-ellipsis() {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monospace-font() {
|
||||||
|
font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
|
||||||
|
}
|
31
asset/css/mixin/state-badges.less
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.state-badges() {
|
||||||
|
&.state-badges {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
li > ul > li:first-child:not(:last-child) .state-badge {
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li > ul > li:last-child:not(:first-child) .state-badge {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> li:not(:last-child) {
|
||||||
|
margin-right: .25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
li > ul > li + li {
|
||||||
|
margin-left: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
asset/css/primary-submit-btn-duplicate.less
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
Automatically set CSS class for duplicated submit buttons
|
||||||
|
used for implicit form submission that should be invisible
|
||||||
|
and not take up any space. `display: none` is not an option,
|
||||||
|
because at least Safari will then ignore the element completely
|
||||||
|
when submitting a form.
|
||||||
|
*/
|
||||||
|
.primary-submit-btn-duplicate {
|
||||||
|
border: 0;
|
||||||
|
height: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
width: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
210
asset/css/schedule-element.less
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
// Schedule form element
|
||||||
|
|
||||||
|
.schedule-element {
|
||||||
|
@input-border-radius: .25em;
|
||||||
|
|
||||||
|
.ordinal {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.radio-label {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
color: @schedule-element-fields-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-label {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: .5em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center; // To center the radio element on safari
|
||||||
|
}
|
||||||
|
|
||||||
|
.number-specifier > input[type="number"] {
|
||||||
|
width: 5em;
|
||||||
|
margin: 0 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monthly, .ordinal:not(.annually) {
|
||||||
|
padding: .5em;
|
||||||
|
margin-left: -.5em;
|
||||||
|
border: 1px solid @schedule-element-fields-border-color;
|
||||||
|
.rounded-corners(.75em);
|
||||||
|
}
|
||||||
|
|
||||||
|
.schedule-element-fields {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
.rounded-corners(.25em);
|
||||||
|
overflow: hidden;
|
||||||
|
display:flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
&.disabled { // When the "On the" radio button is checked
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
label {
|
||||||
|
color: @schedule-element-fields-disabled-color;
|
||||||
|
background-color: @schedule-element-fields-disabled-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + label {
|
||||||
|
background: @schedule-element-fields-disabled-selected-bg;
|
||||||
|
color: @schedule-element-fields-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
width: calc(100% / 7); /* default for week based cols makes sense */
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
padding: .75em 0;
|
||||||
|
background: @schedule-element-fields-bg;
|
||||||
|
color: @schedule-element-fields-color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: @schedule-element-fields-hover-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + label {
|
||||||
|
background-color: @schedule-element-fields-selected-bg;
|
||||||
|
color: @schedule-element-fields-selected-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + label:hover {
|
||||||
|
background-color: @schedule-element-fields-selected-hover-bg;
|
||||||
|
border-color: @schedule-element-fields-selected-hover-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.multiple-fields {
|
||||||
|
li:not(:last-child) label {
|
||||||
|
border-right: 1px solid @schedule-element-fields-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus + label {
|
||||||
|
box-shadow: inset 0 0 0 3px @schedule-element-fields-outline-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked:focus + label {
|
||||||
|
box-shadow: inset 0 0 0 3px @schedule-element-fields-selected-outline-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.single-fields {
|
||||||
|
li {
|
||||||
|
padding-right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li label {
|
||||||
|
.rounded-corners(.25em);
|
||||||
|
margin-right: 1px;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li label {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
outline: 3px solid @schedule-element-fields-outline-color;
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-within + .note {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + label:hover {
|
||||||
|
background-color: @schedule-element-fields-selected-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.note {
|
||||||
|
display: none;
|
||||||
|
padding: .5em;
|
||||||
|
background: @schedule-element-keyboard-note-bg;
|
||||||
|
.rounded-corners(.25em);
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 1em;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .weekly */
|
||||||
|
.weekly { }
|
||||||
|
|
||||||
|
/* .monthly styles */
|
||||||
|
.monthly {
|
||||||
|
li label {
|
||||||
|
border-top: 1px solid @schedule-element-fields-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:first-child,
|
||||||
|
li:nth-child(2),
|
||||||
|
li:nth-child(3),
|
||||||
|
li:nth-child(4),
|
||||||
|
li:nth-child(5),
|
||||||
|
li:nth-child(6),
|
||||||
|
li:nth-child(7) {
|
||||||
|
label {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* last of row should not have a border */
|
||||||
|
.schedule-element-fields li:nth-child(7n) label {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* .annually styles */
|
||||||
|
.annually {
|
||||||
|
li {
|
||||||
|
width: 25%; // 100% / 4 elements
|
||||||
|
}
|
||||||
|
|
||||||
|
li:nth-child(4n) label {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-slider-controls {
|
||||||
|
display: flex;
|
||||||
|
column-gap: 1em;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: -.6em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.schedule-recurrences {
|
||||||
|
line-height: 1.1em;
|
||||||
|
padding-top: 0.5625em;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: @schedule-element-fields-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
232
asset/css/search-bar.less
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
// Style
|
||||||
|
.search-bar {
|
||||||
|
.rounded-corners(.25em);
|
||||||
|
background: var(--searchbar-bg, @searchbar-bg);
|
||||||
|
|
||||||
|
// Reset all input styles
|
||||||
|
input, [type="button"] {
|
||||||
|
.appearance(none);
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Submit button styles
|
||||||
|
input[type=submit],
|
||||||
|
button[type=submit],
|
||||||
|
button:not([type]) {
|
||||||
|
background: var(--primary-button-bg, @primary-button-bg);
|
||||||
|
color: var(--primary-button-color, @primary-button-color);
|
||||||
|
border-top-right-radius: .25em;
|
||||||
|
border-bottom-right-radius: .25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// General input styles
|
||||||
|
input:focus {
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide the submit button, it must exist, but shouldn't be shown to the user
|
||||||
|
input[type=submit][value="hidden"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left-most search dropdown style
|
||||||
|
button.search-options {
|
||||||
|
i.icon:before {
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin-right: 0;
|
||||||
|
color: var(--control-color, @control-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
i.icon:before {
|
||||||
|
color: var(--control-disabled-color, @control-disabled-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Term styles
|
||||||
|
.filter-condition {
|
||||||
|
button {
|
||||||
|
border-radius: .4em 0 0 .4em;
|
||||||
|
background-color: var(--search-condition-remove-bg, @search-condition-remove-bg);
|
||||||
|
color: var(--search-condition-remove-color, @search-condition-remove-color);
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: .4em;
|
||||||
|
height: 100%;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
background-color: var(--searchbar-bg, @searchbar-bg);
|
||||||
|
border: .2em solid var(--search-condition-remove-bg, @search-condition-remove-bg);
|
||||||
|
border-width: 0 0 0 .2em;
|
||||||
|
border-top-left-radius: .4em;
|
||||||
|
border-bottom-left-radius: .4em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
background-color: var(--search-term-bg, @search-term-bg);
|
||||||
|
color: var(--search-term-color, @search-term-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms > .filter-condition:first-child button {
|
||||||
|
border-radius: 0 .4em .4em 0;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: .4em;
|
||||||
|
height: 100%;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
background-color: var(--searchbar-bg, @searchbar-bg);
|
||||||
|
border: .2em solid var(--search-condition-remove-bg, @search-condition-remove-bg);
|
||||||
|
border-width: 0 .2em 0 0;
|
||||||
|
border-top-right-radius: .4em;
|
||||||
|
border-bottom-right-radius: .4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logical_operator,
|
||||||
|
.grouping_operator_open,
|
||||||
|
.grouping_operator_close {
|
||||||
|
input {
|
||||||
|
.rounded-corners();
|
||||||
|
background-color: var(--search-logical-operator-bg, @search-logical-operator-bg);
|
||||||
|
color: var(--search-logical-operator-color, @search-logical-operator-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator,
|
||||||
|
.logical_operator,
|
||||||
|
.grouping_operator_open,
|
||||||
|
.grouping_operator_close {
|
||||||
|
input {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.column input {
|
||||||
|
.rounded-corners(.4em);
|
||||||
|
}
|
||||||
|
.column:not(:last-of-type),
|
||||||
|
.column.last-term {
|
||||||
|
input {
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator:last-of-type:not(.last-term) input {
|
||||||
|
.rounded-corners(.4em);
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value input {
|
||||||
|
.rounded-corners(.4em);
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlighted input {
|
||||||
|
background-color: var(--search-term-highlighted-bg, @search-term-highlighted-bg);
|
||||||
|
color: var(--search-term-highlighted-color, @search-term-highlighted-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.comma-separated {
|
||||||
|
display: inline;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
list-style-type: none;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline;
|
||||||
|
|
||||||
|
&:not(:first-of-type):before {
|
||||||
|
display: inline;
|
||||||
|
content: ', ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout
|
||||||
|
.search-bar {
|
||||||
|
height: 2em;
|
||||||
|
display: flex;
|
||||||
|
position: relative; // Required for the suggestions
|
||||||
|
|
||||||
|
button.search-options {
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-input-area {
|
||||||
|
padding: 2/12em; // 2 (px) desired / default font size (px)
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms {
|
||||||
|
.filter-chain,
|
||||||
|
.filter-condition {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-condition {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: none;
|
||||||
|
z-index: 1;
|
||||||
|
width: ~"calc(2em + 2px)";
|
||||||
|
padding: .15em .6em .15em .4em;
|
||||||
|
position: absolute;
|
||||||
|
left: ~"calc(-2em - 2px)"; // That's min-width + margin-right of an operator
|
||||||
|
line-height: 16/12; // 16 (px) desired / default font size (px)
|
||||||
|
|
||||||
|
i:before {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(._hover_delay):hover button {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .filter-condition:first-child button {
|
||||||
|
padding: .15em .4em .15em .6em;
|
||||||
|
left: auto;
|
||||||
|
right: ~"calc(-2em - 1px)"; // That's min-width + margin-left of an operator
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
&.logical_operator,
|
||||||
|
&.grouping_operator_open,
|
||||||
|
&.grouping_operator_close {
|
||||||
|
margin-left: 1px; // adds up to 2px with the previous term
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
.terms .filter-condition:hover button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-suggestions {
|
||||||
|
// 2 (px) desired / default font-size to match .filter-input outline-offset (-1px) + outline-width (3px)
|
||||||
|
margin-top: 2/12em;
|
||||||
|
}
|
||||||
|
}
|
367
asset/css/search-base.less
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
// Style
|
||||||
|
|
||||||
|
.search-bar .filter-input-area,
|
||||||
|
.term-input-area:not(.vertical) {
|
||||||
|
// Scrollbar style
|
||||||
|
|
||||||
|
// Firefox
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: var(--searchbar-scrollbar-bg, @searchbar-scrollbar-bg) transparent;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
height: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover::-webkit-scrollbar {
|
||||||
|
display: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: .25em;
|
||||||
|
background: var(--searchbar-scrollbar-bg, @searchbar-scrollbar-bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar,
|
||||||
|
.term-input-area {
|
||||||
|
[data-index] input:invalid,
|
||||||
|
[data-index] input.invalid {
|
||||||
|
background-color: var(--search-term-invalid-bg, @search-term-invalid-bg);
|
||||||
|
color: var(--search-term-invalid-color, @search-term-invalid-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-index] input:disabled {
|
||||||
|
background-color: var(--search-term-disabled-bg, @search-term-disabled-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected input {
|
||||||
|
background-color: var(--search-term-selected-bg, @search-term-selected-bg);
|
||||||
|
color: var(--search-term-selected-color, @search-term-selected-color);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-drag-initiator] {
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortable-drag > label {
|
||||||
|
border: 1px dashed var(--search-term-drag-border-color, @search-term-drag-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortable-ghost {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset:disabled .term-input-area [data-drag-initiator] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invalid-reason {
|
||||||
|
padding: .25em;
|
||||||
|
.rounded-corners(.25em);
|
||||||
|
border: 1px solid black;
|
||||||
|
font-weight: bold;
|
||||||
|
background: var(--search-term-invalid-reason-bg, @search-term-invalid-reason-bg);
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 2s, visibility 2s;
|
||||||
|
&.visible {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-suggestions {
|
||||||
|
background: var(--suggestions-bg, @suggestions-bg);
|
||||||
|
color: var(--suggestions-color, @suggestions-color);
|
||||||
|
border: 1px solid var(--suggestions-border-color, @suggestions-border-color);
|
||||||
|
border-bottom-right-radius: .5em;
|
||||||
|
border-bottom-left-radius: .5em;
|
||||||
|
|
||||||
|
> ul {
|
||||||
|
list-style-type: none;
|
||||||
|
|
||||||
|
> li {
|
||||||
|
border-top: 1px solid var(--suggestions-separation-bg, @suggestions-separation-bg);
|
||||||
|
}
|
||||||
|
> li.suggestion-title + li {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
> li:not(.default) + li.suggestion-title {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.default {
|
||||||
|
color: var(--suggestions-default-opt-color, @suggestions-default-opt-color);
|
||||||
|
font-style: italic;
|
||||||
|
|
||||||
|
[type="button"] {
|
||||||
|
background-color: var(--suggestions-default-opt-bg, @suggestions-default-opt-bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.suggestion-title {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.failure-message {
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
em {
|
||||||
|
font-weight: normal;
|
||||||
|
color: var(--suggestions-failure-message-color, @suggestions-failure-message-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nothing-to-suggest {
|
||||||
|
color: var(--suggestions-color, @suggestions-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.relation-path {
|
||||||
|
padding: 0 .2em;
|
||||||
|
background-color: var(--suggestions-relation-path-bg, @suggestions-relation-path-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="button"] {
|
||||||
|
.appearance(none);
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="button"]:focus,
|
||||||
|
[type="button"].selected {
|
||||||
|
background: var(--suggestions-focus-bg, @suggestions-focus-bg);
|
||||||
|
color: var(--suggestions-focus-color, @suggestions-focus-color);
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
.relation-path {
|
||||||
|
background-color: var(--suggestions-relation-path-focus-bg, @suggestions-relation-path-focus-bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="button"]:not(:focus):hover,
|
||||||
|
[type="button"]:not(.selected):hover {
|
||||||
|
background: var(--suggestions-hover-bg, @suggestions-hover-bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout
|
||||||
|
.search-bar .filter-input-area,
|
||||||
|
.term-input-area:not(.vertical) {
|
||||||
|
overflow: auto hidden;
|
||||||
|
overflow-x: overlay; // Not invalid, but proprietary feature by chrome/webkit
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
width: 100%;
|
||||||
|
height: ~"calc(2em + 10px)"; // Search bar height + approximate scrollbar height
|
||||||
|
|
||||||
|
// Lets inputs grow based on their contents, Inspired by https://css-tricks.com/auto-growing-inputs-textareas/
|
||||||
|
label {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 2em;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&::after,
|
||||||
|
input {
|
||||||
|
width: auto;
|
||||||
|
padding: .25em .5em;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
line-height: 20/12; // 20 (px) desired / default font size (px)
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
height: 0;
|
||||||
|
content: attr(data-label);
|
||||||
|
visibility: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0 7/12em; // 7 (px) desired / default font size (px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> label {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
|
||||||
|
&::after,
|
||||||
|
input {
|
||||||
|
max-width: none;
|
||||||
|
min-width: 8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .terms {
|
||||||
|
display: inline;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-right: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-input-area.vertical {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
|
||||||
|
@itemGap: 1px;
|
||||||
|
|
||||||
|
> .terms {
|
||||||
|
margin-top: @itemGap;
|
||||||
|
|
||||||
|
input {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> div.terms {
|
||||||
|
@termsPerRow: 2;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: @itemGap;
|
||||||
|
|
||||||
|
label {
|
||||||
|
@termWidth: 100%/@termsPerRow;
|
||||||
|
@totalGapWidthPerRow: (@termsPerRow - 1) * @itemGap;
|
||||||
|
|
||||||
|
min-width: ~"calc(@{termWidth} - (@{totalGapWidthPerRow} / @{termsPerRow}))";
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> ol.terms {
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
|
||||||
|
li:not(:first-child) {
|
||||||
|
margin-top: @itemGap;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: .25em;
|
||||||
|
|
||||||
|
> label {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
> [data-drag-initiator]::before {
|
||||||
|
font-size: 1.75em;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-input-area {
|
||||||
|
label input:focus {
|
||||||
|
@labelPad: 7/12em;
|
||||||
|
outline-width: 3px;
|
||||||
|
outline-offset: ~"calc(-@{labelPad} + 3px)";
|
||||||
|
}
|
||||||
|
|
||||||
|
&.read-only {
|
||||||
|
[data-index] {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding-left: 1.5em;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ i {
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
top: .5em;
|
||||||
|
left: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:disabled):hover + i,
|
||||||
|
&:not(:disabled):focus + i {
|
||||||
|
display: revert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.invalid-reason {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: 85%;
|
||||||
|
left: .5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-suggestions {
|
||||||
|
z-index: 2; // Required so that nothing else can overlap it (such as opaque elements and the impact overlay)
|
||||||
|
position: absolute;
|
||||||
|
overflow: auto;
|
||||||
|
min-width: 5em;
|
||||||
|
|
||||||
|
&:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
> ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
li.suggestion-title {
|
||||||
|
padding: 1.25em .625em 0 .625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.failure-message {
|
||||||
|
padding: .5em 1em;
|
||||||
|
|
||||||
|
em {
|
||||||
|
margin-right: .5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li.nothing-to-suggest {
|
||||||
|
padding: .5em 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="button"] {
|
||||||
|
padding: .5em 1em;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
&[data-class="operator"], &[data-class="logical_operator"] {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.has-details {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relation-path {
|
||||||
|
margin-left: .5em;
|
||||||
|
|
||||||
|
&::first-line {
|
||||||
|
font-size: .8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
268
asset/css/search-editor.less
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
// Style
|
||||||
|
|
||||||
|
.search-editor {
|
||||||
|
ul, ol {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button, input[type="submit"] {
|
||||||
|
.appearance(none);
|
||||||
|
background: none;
|
||||||
|
|
||||||
|
&:not(.cancel-button) {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select:not([multiple]) {
|
||||||
|
.appearance(none);
|
||||||
|
padding-right: 1.5625em;
|
||||||
|
background-image: url('@{iplWebAssets}/img/select-icon-text-color.svg');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right center;
|
||||||
|
background-size: contain;
|
||||||
|
.rounded-corners(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
i.icon:before {
|
||||||
|
color: var(--search-editor-control-color, @search-editor-control-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-initiator {
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"], select {
|
||||||
|
border: none;
|
||||||
|
background: var(--search-term-bg, @search-term-bg);
|
||||||
|
color: var(--search-term-color, @search-term-color);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(fieldset) > select {
|
||||||
|
.rounded-corners();
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset > input[data-type="column"] {
|
||||||
|
.rounded-corners(.4em 0 0 .4em);
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset > input[data-type="value"] {
|
||||||
|
.rounded-corners(0 .4em .4em 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-error {
|
||||||
|
input:invalid {
|
||||||
|
background: var(--search-term-invalid-bg, @search-term-invalid-bg);
|
||||||
|
color: var(--search-term-invalid-color, @search-term-invalid-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-errors {
|
||||||
|
color: var(--search-editor-error-color, @search-editor-error-color);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li > select:not([multiple]) {
|
||||||
|
background-color: var(--search-logical-operator-bg, @search-logical-operator-bg);
|
||||||
|
color: var(--search-logical-operator-color, @search-logical-operator-color);
|
||||||
|
.rounded-corners();
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortable-ghost {
|
||||||
|
border: dashed .2em var(--search-editor-drag-outline-color, @search-editor-drag-outline-color);
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
ul {
|
||||||
|
.rounded-corners();
|
||||||
|
.box-shadow(0, 0, .5em);
|
||||||
|
border: 1px solid var(--search-editor-context-menu-border-color, @search-editor-context-menu-border-color);
|
||||||
|
background: var(--search-editor-context-menu-bg, @search-editor-context-menu-bg);
|
||||||
|
|
||||||
|
li:not(:first-child) {
|
||||||
|
border-top: 1px solid var(--search-editor-context-menu-border-color, @search-editor-context-menu-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: var(--primary-button-bg, @primary-button-bg);
|
||||||
|
color: var(--primary-button-color, @primary-button-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add rounded corners to buttons as well, otherwise their
|
||||||
|
// background is not rounded and overlaps the list's corners
|
||||||
|
:first-child button {
|
||||||
|
.rounded-corners();
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
:last-child button {
|
||||||
|
.rounded-corners();
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
// The left pointing arrow
|
||||||
|
border-bottom: 1px solid var(--search-editor-context-menu-border-color, @search-editor-context-menu-border-color);
|
||||||
|
border-left: 1px solid var(--search-editor-context-menu-border-color, @search-editor-context-menu-border-color);
|
||||||
|
background: var(--search-editor-context-menu-bg, @search-editor-context-menu-bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover i.icon:before {
|
||||||
|
.rounded-corners();
|
||||||
|
background: var(--primary-button-bg, @primary-button-bg);
|
||||||
|
color: var(--primary-button-color, @primary-button-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"] {
|
||||||
|
.rounded-corners();
|
||||||
|
background: var(--primary-button-bg, @primary-button-bg);
|
||||||
|
color: var(--primary-button-color, @primary-button-color);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--primary-button-hover-bg, @primary-button-hover-bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout
|
||||||
|
|
||||||
|
.search-editor-opener + a.modal-opener {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-editor {
|
||||||
|
padding: 1em;
|
||||||
|
|
||||||
|
@item-spacing: .5em;
|
||||||
|
|
||||||
|
ul, ol {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
> :not(:first-child) {
|
||||||
|
margin-left: @item-spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
padding-left: 1em;
|
||||||
|
padding-bottom: @item-spacing;
|
||||||
|
|
||||||
|
> li:first-child,
|
||||||
|
> :not(.filter-chain) + li {
|
||||||
|
margin-top: @item-spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"], select {
|
||||||
|
padding: 0 .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
li > select {
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
display: flex;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
input[data-type="value"] {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
> :not(:first-child) {
|
||||||
|
margin-left: .1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input, button, select {
|
||||||
|
height: 28/12em; // Target Pixels @ default font size / default font size
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-errors {
|
||||||
|
margin-left: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.icon:before {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.5em;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
position: absolute;
|
||||||
|
right: 32/12em; // Target distance @ default font size / default font size
|
||||||
|
z-index: 1;
|
||||||
|
width: auto;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
button {
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
// The left pointing arrow
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
height: 1em;
|
||||||
|
transform: rotate(-135deg);
|
||||||
|
width: 1em;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: ((28/12)/2)-.5em; // ((First row pixels @ default font size / default font size) / 2) - own half width
|
||||||
|
right: -.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover ul {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.icon:before {
|
||||||
|
padding: ((28/18)-1)/2em; // (Container pixels / default font size) - line height / (padding-top,padding-bottom)
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button {
|
||||||
|
margin-top: 2em - @item-spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"] {
|
||||||
|
float: right;
|
||||||
|
width: 6em;
|
||||||
|
margin-top: 2em - @item-spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"]:not(:last-of-type) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
52
asset/css/state-badge.less
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
.state-badge {
|
||||||
|
.rounded-corners();
|
||||||
|
color: var(--default-text-color-inverted, @default-text-color-inverted);
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 1em;
|
||||||
|
min-width: 2em;
|
||||||
|
padding: .25em;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&.handled {
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-critical {
|
||||||
|
background-color: var(--state-critical, @state-critical);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-down {
|
||||||
|
background-color: var(--state-down, @state-down);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-ok {
|
||||||
|
background-color: var(--state-ok, @state-ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-pending {
|
||||||
|
background-color: var(--state-pending, @state-pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-unknown {
|
||||||
|
background-color: var(--state-unknown, @state-unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-up {
|
||||||
|
background-color: var(--state-up, @state-up);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-warning {
|
||||||
|
background-color: var(--state-warning, @state-warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-none {
|
||||||
|
background-color: var(--state-none, @state-none);
|
||||||
|
color: var(--default-text-color-light, @default-text-color-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a .state-badge {
|
||||||
|
&:not(.disabled):hover {
|
||||||
|
filter: brightness(80%);
|
||||||
|
}
|
||||||
|
}
|
220
asset/css/variables.less
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
RECOMMENDATION:
|
||||||
|
Please do not use the base color variables directly,
|
||||||
|
define a new variable instead that assigns the value of this base variable.
|
||||||
|
Examples:
|
||||||
|
- @base-color: red;
|
||||||
|
- @my-new-var: @base-color;
|
||||||
|
- @my-second-new-var: @base-color;
|
||||||
|
|
||||||
|
Do not use the same variable for different use cases, but define a new variable for each use case.
|
||||||
|
|
||||||
|
NOTICE:
|
||||||
|
Color vars identification:
|
||||||
|
- Vars with `-bg` suffix are background-color vars. Please use only for setting bg-color.
|
||||||
|
- Vars with `-color` suffix are color vars. Please use only for setting fg-color.
|
||||||
|
|
||||||
|
MODE SUPPORT:
|
||||||
|
The standard LESS variables represent the dark mode. The LESS detached ruleset `@iplWebLightRules`
|
||||||
|
contains CSS variables that represent the light mode. It must be used explicitly to have any effect.
|
||||||
|
If you use media queries to support modes, just call the ruleset inside your media query:
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
@iplWebLightRules();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@default-bg: #282E39;
|
||||||
|
|
||||||
|
@base-gray: #c4c4c4;
|
||||||
|
@base-gray-light: #5c5c5c;
|
||||||
|
@base-gray-lighter: #4b4b4b;
|
||||||
|
@base-gray-semilight: #888;
|
||||||
|
@base-disabled: #9a9a9a;
|
||||||
|
|
||||||
|
@base-primary-color: #00C3ED;
|
||||||
|
@base-primary-bg: #00C3ED;
|
||||||
|
@base-primary-dark: #0081a6;
|
||||||
|
@base-primary-light: fade(@base-primary-bg, 50%);
|
||||||
|
|
||||||
|
@default-text-color: #fff;
|
||||||
|
@default-text-color-light: fade(@default-text-color, 75%);
|
||||||
|
@default-text-color-inverted: @default-bg;
|
||||||
|
@default-input-bg: #404d72;
|
||||||
|
|
||||||
|
@state-ok: #44bb77;
|
||||||
|
@state-up: @state-ok;
|
||||||
|
@state-warning: #ffaa44;
|
||||||
|
@state-critical: #ff5566;
|
||||||
|
@state-down: @state-critical;
|
||||||
|
@state-pending: #77aaff;
|
||||||
|
@state-unknown: #aa44ff;
|
||||||
|
@state-none: @base-gray-light;
|
||||||
|
|
||||||
|
@primary-button-color: @default-text-color-inverted;
|
||||||
|
@primary-button-bg: @base-primary-bg;
|
||||||
|
@primary-button-hover-bg: @base-primary-dark;
|
||||||
|
|
||||||
|
@search-term-bg: @base-gray;
|
||||||
|
@search-term-color: @default-text-color-inverted;
|
||||||
|
@search-term-selected-bg: @base-disabled;
|
||||||
|
@search-term-invalid-bg: @state-critical;
|
||||||
|
@search-term-invalid-color: @default-text-color-inverted;
|
||||||
|
@search-term-invalid-reason-bg: @base-gray-lighter;
|
||||||
|
@search-term-disabled-bg: @base-disabled;
|
||||||
|
@search-term-selected-color: @base-gray-light;
|
||||||
|
@search-term-highlighted-bg: @base-primary-bg;
|
||||||
|
@search-term-highlighted-color: @default-text-color-inverted;
|
||||||
|
@search-term-drag-border-color: @base-gray;
|
||||||
|
|
||||||
|
@search-condition-remove-bg: @state-critical;
|
||||||
|
@search-condition-remove-color: @default-text-color-inverted;
|
||||||
|
|
||||||
|
@search-logical-operator-bg: @base-gray-light;
|
||||||
|
@search-logical-operator-color: @default-text-color-light;
|
||||||
|
|
||||||
|
@searchbar-bg: @default-input-bg;
|
||||||
|
@searchbar-scrollbar-bg: @base-gray-light;
|
||||||
|
|
||||||
|
@search-editor-error-color: @state-critical;
|
||||||
|
@search-editor-control-color: @base-gray-light;
|
||||||
|
@search-editor-logical-op-bg: @base-gray-light;
|
||||||
|
@search-editor-context-menu-border-color: @base-gray-light;
|
||||||
|
@search-editor-context-menu-bg: @default-bg;
|
||||||
|
@search-editor-drag-outline-color: @base-gray;
|
||||||
|
|
||||||
|
@control-color: @base-primary-color;
|
||||||
|
@control-hover-bg: @base-gray-lighter;
|
||||||
|
@control-disabled-color: @base-disabled;
|
||||||
|
@controls-separator-bg: @base-gray-lighter;
|
||||||
|
|
||||||
|
@cancel-button-bg: none;
|
||||||
|
@cancel-button-border-color: @state-critical;
|
||||||
|
@cancel-button-color: @state-critical;
|
||||||
|
@cancel-button-hover-bg: @state-critical;
|
||||||
|
@cancel-button-hover-color: @default-text-color-inverted;
|
||||||
|
|
||||||
|
@suggestions-bg: @default-bg;
|
||||||
|
@suggestions-color: @default-text-color-light;
|
||||||
|
@suggestions-focus-bg: @base-primary-bg;
|
||||||
|
@suggestions-focus-color: @default-text-color-inverted;
|
||||||
|
@suggestions-default-opt-bg: fade(@base-primary-bg, 10%);
|
||||||
|
@suggestions-default-opt-color: @default-text-color-light;
|
||||||
|
@suggestions-hover-bg: fade(@base-primary-bg, 30%);
|
||||||
|
@suggestions-border-color: @base-gray-light;
|
||||||
|
@suggestions-separation-bg: @base-gray-lighter;
|
||||||
|
@suggestions-failure-message-color: @default-text-color-light;
|
||||||
|
@suggestions-relation-path-bg: @base-gray-light;
|
||||||
|
@suggestions-relation-path-focus-bg: @base-gray;
|
||||||
|
|
||||||
|
@card-border-color: @base-gray-light;
|
||||||
|
|
||||||
|
@schedule-element-fields-bg: @default-input-bg;
|
||||||
|
@schedule-element-fields-color: @base-primary-color;
|
||||||
|
@schedule-element-fields-border-color: @base-gray-light;
|
||||||
|
@schedule-element-fields-selected-bg: @primary-button-bg;
|
||||||
|
@schedule-element-fields-selected-color: @default-text-color-inverted;
|
||||||
|
@schedule-element-fields-hover-bg: @base-primary-light;
|
||||||
|
@schedule-element-fields-outline-color: fade(@base-primary-bg, 50%);
|
||||||
|
@schedule-element-fields-selected-outline-color: fade(#fff, 50%);
|
||||||
|
@schedule-element-fields-selected-hover-bg: @primary-button-hover-bg;
|
||||||
|
@schedule-element-fields-disabled-color: @base-gray;
|
||||||
|
@schedule-element-fields-disabled-bg: @base-gray-lighter;
|
||||||
|
@schedule-element-fields-disabled-selected-bg: @base-gray-light;
|
||||||
|
@schedule-element-keyboard-note-bg: @base-gray-light;
|
||||||
|
|
||||||
|
@empty-state-color: @base-gray-semilight;
|
||||||
|
@empty-state-bar-bg: @base-gray-lighter;
|
||||||
|
|
||||||
|
@list-item-title-hover-color: @base-primary-color;
|
||||||
|
@list-item-separation-bg: @base-gray-light;
|
||||||
|
|
||||||
|
@iplWebLightRules: {
|
||||||
|
:root {
|
||||||
|
--base-gray: #819398;
|
||||||
|
--base-gray-light: #d0d3da;
|
||||||
|
--base-gray-lighter: #e8ecef;
|
||||||
|
--base-gray-semilight: #94a5a6;
|
||||||
|
--base-disabled: var(--base-gray-light);
|
||||||
|
|
||||||
|
--base-remove-bg: @state-critical;
|
||||||
|
|
||||||
|
--default-text-color: #535353;
|
||||||
|
--default-text-color-light: fade(#535353, 75%); // --default-text-color
|
||||||
|
--default-text-color-inverted: #F5F9FA;
|
||||||
|
--default-input-bg: #DEECF1;
|
||||||
|
|
||||||
|
--primary-button-color: var(--default-text-color-inverted);
|
||||||
|
--primary-button-bg: @primary-button-bg;
|
||||||
|
--primary-button-hover-bg: @primary-button-hover-bg;
|
||||||
|
|
||||||
|
--searchbar-bg: var(--default-input-bg);
|
||||||
|
--searchbar-scrollbar-bg: var(--base-gray-light);
|
||||||
|
|
||||||
|
--search-term-bg: var(--base-gray-light);
|
||||||
|
--search-term-color: var(--default-text-color);
|
||||||
|
--search-term-selected-bg: var(--base-disabled);
|
||||||
|
--search-term-invalid-bg: var(--base-remove-bg);
|
||||||
|
--search-term-invalid-color: var(--default-text-color-inverted);
|
||||||
|
--search-term-invalid-reason-bg: var(--base-gray-lighter);
|
||||||
|
--search-term-disabled-bg: var(--base-gray-light);
|
||||||
|
--search-term-selected-color: var(--base-gray);
|
||||||
|
--search-term-highlighted-bg: var(--primary-button-bg);
|
||||||
|
--search-term-highlighted-color: var(--default-text-color-inverted);
|
||||||
|
--search-term-drag-border-color: var(--base-gray);
|
||||||
|
|
||||||
|
--search-condition-remove-bg: var(--base-remove-bg);
|
||||||
|
--search-condition-remove-color: var(--default-text-color-inverted);
|
||||||
|
|
||||||
|
--search-logical-operator-bg: fade(#819398, 50%); // --base-gray
|
||||||
|
--search-logical-operator-color: var(--default-text-color-light);
|
||||||
|
|
||||||
|
--search-editor-error-color: var(--base-remove-bg);
|
||||||
|
--search-editor-control-color: var(--base-gray-light);
|
||||||
|
--search-editor-logical-op-bg: var(--base-gray-light);
|
||||||
|
--search-editor-context-menu-border-color: var(--base-gray-light);
|
||||||
|
--search-editor-context-menu-bg: var(--default-text-color-inverted);
|
||||||
|
--search-editor-drag-outline-color: var(--base-gray);
|
||||||
|
|
||||||
|
--control-color: var(--primary-button-bg);
|
||||||
|
--control-hover-bg: var(--base-gray-lighter);
|
||||||
|
--control-disabled-color: var(--base-gray-light);
|
||||||
|
|
||||||
|
--cancel-button-hover-color: var(--default-text-color-inverted);
|
||||||
|
|
||||||
|
--suggestions-bg: var(--default-text-color-inverted);
|
||||||
|
--suggestions-color: var(--default-text-color-light);
|
||||||
|
--suggestions-focus-bg: var(--primary-button-bg);
|
||||||
|
--suggestions-focus-color: var(--default-text-color-inverted);
|
||||||
|
--suggestions-default-opt-bg: fade(@primary-button-bg, 10%);
|
||||||
|
--suggestions-default-opt-color: var(--default-text-color-light);
|
||||||
|
--suggestions-hover-bg: fade(@primary-button-bg, 30%);
|
||||||
|
--suggestions-border-color: var(--base-gray-light);
|
||||||
|
--suggestions-separation-bg: var(--base-gray-lighter);
|
||||||
|
--suggestions-failure-message-color: var(--default-text-color-light);
|
||||||
|
--suggestions-relation-path-bg: var(--base-gray-lighter);
|
||||||
|
--suggestions-relation-path-focus-bg: var(--base-gray);
|
||||||
|
|
||||||
|
--card-border-color: var(--base-gray-light);
|
||||||
|
|
||||||
|
--schedule-element-fields-bg: var(--default-input-bg);
|
||||||
|
--schedule-element-fields-color: var(--base-primary-color);
|
||||||
|
--schedule-element-fields-border-color: var(--base-gray-light);
|
||||||
|
--schedule-element-fields-selected-bg: var(--primary-button-bg);
|
||||||
|
--schedule-element-fields-selected-color: var(--default-text-color-inverted);
|
||||||
|
--schedule-element-fields-hover-bg: @base-primary-light;
|
||||||
|
--schedule-element-fields-outline-color: fade(@base-primary-bg, 50%);
|
||||||
|
--schedule-element-fields-selected-outline-color: fade(#fff, 50%);
|
||||||
|
--schedule-element-fields-selected-hover-bg: var(--primary-button-hover-bg);
|
||||||
|
--schedule-element-fields-disabled-color: var(--base-gray);
|
||||||
|
--schedule-element-fields-disabled-bg: var(--base-gray-lighter);
|
||||||
|
--schedule-element-fields-disabled-selected-bg: var(--base-gray-light);
|
||||||
|
--schedule-element-keyboard-note-bg: var(--base-gray-light);
|
||||||
|
|
||||||
|
--empty-state-color: var(--base-gray-semilight);
|
||||||
|
--empty-state-bar-bg: var(--base-gray-lighter);
|
||||||
|
|
||||||
|
--list-item-title-hover-color: var(--base-primary-color);
|
||||||
|
--list-item-separation-bg: var(--base-gray-light);
|
||||||
|
}
|
||||||
|
};
|
791
asset/css/vendor/flatpickr.css
vendored
Normal file
@ -0,0 +1,791 @@
|
|||||||
|
.flatpickr-calendar {
|
||||||
|
background: transparent;
|
||||||
|
opacity: 0;
|
||||||
|
display: none;
|
||||||
|
text-align: center;
|
||||||
|
visibility: hidden;
|
||||||
|
padding: 0;
|
||||||
|
-webkit-animation: none;
|
||||||
|
animation: none;
|
||||||
|
direction: ltr;
|
||||||
|
border: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 24px;
|
||||||
|
border-radius: 5px;
|
||||||
|
position: absolute;
|
||||||
|
width: 307.875px;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-ms-touch-action: manipulation;
|
||||||
|
touch-action: manipulation;
|
||||||
|
background: #fff;
|
||||||
|
-webkit-box-shadow: 1px 0 0 #e6e6e6, -1px 0 0 #e6e6e6, 0 1px 0 #e6e6e6, 0 -1px 0 #e6e6e6, 0 3px 13px rgba(0,0,0,0.08);
|
||||||
|
box-shadow: 1px 0 0 #e6e6e6, -1px 0 0 #e6e6e6, 0 1px 0 #e6e6e6, 0 -1px 0 #e6e6e6, 0 3px 13px rgba(0,0,0,0.08);
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.open,
|
||||||
|
.flatpickr-calendar.inline {
|
||||||
|
opacity: 1;
|
||||||
|
max-height: 640px;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.open {
|
||||||
|
display: inline-block;
|
||||||
|
z-index: 99999;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.animate.open {
|
||||||
|
-webkit-animation: fpFadeInDown 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
|
animation: fpFadeInDown 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.inline {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.static {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + 2px);
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.static.open {
|
||||||
|
z-index: 999;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+1) .flatpickr-day.inRange:nth-child(7n+7) {
|
||||||
|
-webkit-box-shadow: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+2) .flatpickr-day.inRange:nth-child(7n+1) {
|
||||||
|
-webkit-box-shadow: -2px 0 0 #e6e6e6, 5px 0 0 #e6e6e6;
|
||||||
|
box-shadow: -2px 0 0 #e6e6e6, 5px 0 0 #e6e6e6;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar .hasWeeks .dayContainer,
|
||||||
|
.flatpickr-calendar .hasTime .dayContainer {
|
||||||
|
border-bottom: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar .hasWeeks .dayContainer {
|
||||||
|
border-left: 0;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.hasTime .flatpickr-time {
|
||||||
|
height: 40px;
|
||||||
|
border-top: 1px solid #e6e6e6;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.noCalendar.hasTime .flatpickr-time {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar:before,
|
||||||
|
.flatpickr-calendar:after {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
pointer-events: none;
|
||||||
|
border: solid transparent;
|
||||||
|
content: '';
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
left: 22px;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.rightMost:before,
|
||||||
|
.flatpickr-calendar.arrowRight:before,
|
||||||
|
.flatpickr-calendar.rightMost:after,
|
||||||
|
.flatpickr-calendar.arrowRight:after {
|
||||||
|
left: auto;
|
||||||
|
right: 22px;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.arrowCenter:before,
|
||||||
|
.flatpickr-calendar.arrowCenter:after {
|
||||||
|
left: 50%;
|
||||||
|
right: 50%;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar:before {
|
||||||
|
border-width: 5px;
|
||||||
|
margin: 0 -5px;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar:after {
|
||||||
|
border-width: 4px;
|
||||||
|
margin: 0 -4px;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.arrowTop:before,
|
||||||
|
.flatpickr-calendar.arrowTop:after {
|
||||||
|
bottom: 100%;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.arrowTop:before {
|
||||||
|
border-bottom-color: #e6e6e6;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.arrowTop:after {
|
||||||
|
border-bottom-color: #fff;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.arrowBottom:before,
|
||||||
|
.flatpickr-calendar.arrowBottom:after {
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.arrowBottom:before {
|
||||||
|
border-top-color: #e6e6e6;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar.arrowBottom:after {
|
||||||
|
border-top-color: #fff;
|
||||||
|
}
|
||||||
|
.flatpickr-calendar:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.flatpickr-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.flatpickr-months {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.flatpickr-months .flatpickr-month {
|
||||||
|
background: transparent;
|
||||||
|
color: rgba(0,0,0,0.9);
|
||||||
|
fill: rgba(0,0,0,0.9);
|
||||||
|
height: 34px;
|
||||||
|
line-height: 1;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-webkit-flex: 1;
|
||||||
|
-ms-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.flatpickr-months .flatpickr-prev-month,
|
||||||
|
.flatpickr-months .flatpickr-next-month {
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: 34px;
|
||||||
|
padding: 10px;
|
||||||
|
z-index: 3;
|
||||||
|
color: rgba(0,0,0,0.9);
|
||||||
|
fill: rgba(0,0,0,0.9);
|
||||||
|
}
|
||||||
|
.flatpickr-months .flatpickr-prev-month.flatpickr-disabled,
|
||||||
|
.flatpickr-months .flatpickr-next-month.flatpickr-disabled {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.flatpickr-months .flatpickr-prev-month i,
|
||||||
|
.flatpickr-months .flatpickr-next-month i {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.flatpickr-months .flatpickr-prev-month.flatpickr-prev-month,
|
||||||
|
.flatpickr-months .flatpickr-next-month.flatpickr-prev-month {
|
||||||
|
/*
|
||||||
|
/*rtl:begin:ignore*/
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
left: 0;
|
||||||
|
/*
|
||||||
|
/*rtl:end:ignore*/
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
/*rtl:begin:ignore*/
|
||||||
|
/*
|
||||||
|
/*rtl:end:ignore*/
|
||||||
|
.flatpickr-months .flatpickr-prev-month.flatpickr-next-month,
|
||||||
|
.flatpickr-months .flatpickr-next-month.flatpickr-next-month {
|
||||||
|
/*
|
||||||
|
/*rtl:begin:ignore*/
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
right: 0;
|
||||||
|
/*
|
||||||
|
/*rtl:end:ignore*/
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
/*rtl:begin:ignore*/
|
||||||
|
/*
|
||||||
|
/*rtl:end:ignore*/
|
||||||
|
.flatpickr-months .flatpickr-prev-month:hover,
|
||||||
|
.flatpickr-months .flatpickr-next-month:hover {
|
||||||
|
color: #959ea9;
|
||||||
|
}
|
||||||
|
.flatpickr-months .flatpickr-prev-month:hover svg,
|
||||||
|
.flatpickr-months .flatpickr-next-month:hover svg {
|
||||||
|
fill: #f64747;
|
||||||
|
}
|
||||||
|
.flatpickr-months .flatpickr-prev-month svg,
|
||||||
|
.flatpickr-months .flatpickr-next-month svg {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
.flatpickr-months .flatpickr-prev-month svg path,
|
||||||
|
.flatpickr-months .flatpickr-next-month svg path {
|
||||||
|
-webkit-transition: fill 0.1s;
|
||||||
|
transition: fill 0.1s;
|
||||||
|
fill: inherit;
|
||||||
|
}
|
||||||
|
.numInputWrapper {
|
||||||
|
position: relative;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.numInputWrapper input,
|
||||||
|
.numInputWrapper span {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.numInputWrapper input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.numInputWrapper input::-ms-clear {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.numInputWrapper input::-webkit-outer-spin-button,
|
||||||
|
.numInputWrapper input::-webkit-inner-spin-button {
|
||||||
|
margin: 0;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
.numInputWrapper span {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
width: 14px;
|
||||||
|
padding: 0 4px 0 2px;
|
||||||
|
height: 50%;
|
||||||
|
line-height: 50%;
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid rgba(57,57,57,0.15);
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.numInputWrapper span:hover {
|
||||||
|
background: rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.numInputWrapper span:active {
|
||||||
|
background: rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
.numInputWrapper span:after {
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.numInputWrapper span.arrowUp {
|
||||||
|
top: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
.numInputWrapper span.arrowUp:after {
|
||||||
|
border-left: 4px solid transparent;
|
||||||
|
border-right: 4px solid transparent;
|
||||||
|
border-bottom: 4px solid rgba(57,57,57,0.6);
|
||||||
|
top: 26%;
|
||||||
|
}
|
||||||
|
.numInputWrapper span.arrowDown {
|
||||||
|
top: 50%;
|
||||||
|
}
|
||||||
|
.numInputWrapper span.arrowDown:after {
|
||||||
|
border-left: 4px solid transparent;
|
||||||
|
border-right: 4px solid transparent;
|
||||||
|
border-top: 4px solid rgba(57,57,57,0.6);
|
||||||
|
top: 40%;
|
||||||
|
}
|
||||||
|
.numInputWrapper span svg {
|
||||||
|
width: inherit;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.numInputWrapper span svg path {
|
||||||
|
fill: rgba(0,0,0,0.5);
|
||||||
|
}
|
||||||
|
.numInputWrapper:hover {
|
||||||
|
background: rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
.numInputWrapper:hover span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.flatpickr-current-month {
|
||||||
|
font-size: 135%;
|
||||||
|
line-height: inherit;
|
||||||
|
font-weight: 300;
|
||||||
|
color: inherit;
|
||||||
|
position: absolute;
|
||||||
|
width: 75%;
|
||||||
|
left: 12.5%;
|
||||||
|
padding: 7.48px 0 0 0;
|
||||||
|
line-height: 1;
|
||||||
|
height: 34px;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
-webkit-transform: translate3d(0px, 0px, 0px);
|
||||||
|
transform: translate3d(0px, 0px, 0px);
|
||||||
|
}
|
||||||
|
.flatpickr-current-month span.cur-month {
|
||||||
|
font-family: inherit;
|
||||||
|
font-weight: 700;
|
||||||
|
color: inherit;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 0.5ch;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.flatpickr-current-month span.cur-month:hover {
|
||||||
|
background: rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .numInputWrapper {
|
||||||
|
width: 6ch;
|
||||||
|
width: 7ch\0;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .numInputWrapper span.arrowUp:after {
|
||||||
|
border-bottom-color: rgba(0,0,0,0.9);
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .numInputWrapper span.arrowDown:after {
|
||||||
|
border-top-color: rgba(0,0,0,0.9);
|
||||||
|
}
|
||||||
|
.flatpickr-current-month input.cur-year {
|
||||||
|
background: transparent;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: inherit;
|
||||||
|
cursor: text;
|
||||||
|
padding: 0 0 0 0.5ch;
|
||||||
|
margin: 0;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
font-weight: 300;
|
||||||
|
line-height: inherit;
|
||||||
|
height: auto;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
vertical-align: initial;
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
appearance: textfield;
|
||||||
|
}
|
||||||
|
.flatpickr-current-month input.cur-year:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.flatpickr-current-month input.cur-year[disabled],
|
||||||
|
.flatpickr-current-month input.cur-year[disabled]:hover {
|
||||||
|
font-size: 100%;
|
||||||
|
color: rgba(0,0,0,0.5);
|
||||||
|
background: transparent;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .flatpickr-monthDropdown-months {
|
||||||
|
appearance: menulist;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
font-weight: 300;
|
||||||
|
height: auto;
|
||||||
|
line-height: inherit;
|
||||||
|
margin: -1px 0 0 0;
|
||||||
|
outline: none;
|
||||||
|
padding: 0 0 0 0.5ch;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: initial;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-webkit-appearance: menulist;
|
||||||
|
-moz-appearance: menulist;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .flatpickr-monthDropdown-months:focus,
|
||||||
|
.flatpickr-current-month .flatpickr-monthDropdown-months:active {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .flatpickr-monthDropdown-months:hover {
|
||||||
|
background: rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month {
|
||||||
|
background-color: transparent;
|
||||||
|
outline: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.flatpickr-weekdays {
|
||||||
|
background: transparent;
|
||||||
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
.flatpickr-weekdays .flatpickr-weekdaycontainer {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-webkit-flex: 1;
|
||||||
|
-ms-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
span.flatpickr-weekday {
|
||||||
|
cursor: default;
|
||||||
|
font-size: 90%;
|
||||||
|
background: transparent;
|
||||||
|
color: rgba(0,0,0,0.54);
|
||||||
|
line-height: 1;
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-webkit-flex: 1;
|
||||||
|
-ms-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
.dayContainer,
|
||||||
|
.flatpickr-weeks {
|
||||||
|
padding: 1px 0 0 0;
|
||||||
|
}
|
||||||
|
.flatpickr-days {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-align: start;
|
||||||
|
-webkit-align-items: flex-start;
|
||||||
|
-ms-flex-align: start;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 307.875px;
|
||||||
|
}
|
||||||
|
.flatpickr-days:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.dayContainer {
|
||||||
|
padding: 0;
|
||||||
|
outline: 0;
|
||||||
|
text-align: left;
|
||||||
|
width: 307.875px;
|
||||||
|
min-width: 307.875px;
|
||||||
|
max-width: 307.875px;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: flex;
|
||||||
|
-webkit-flex-wrap: wrap;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
-ms-flex-wrap: wrap;
|
||||||
|
-ms-flex-pack: justify;
|
||||||
|
-webkit-justify-content: space-around;
|
||||||
|
justify-content: space-around;
|
||||||
|
-webkit-transform: translate3d(0px, 0px, 0px);
|
||||||
|
transform: translate3d(0px, 0px, 0px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.dayContainer + .dayContainer {
|
||||||
|
-webkit-box-shadow: -1px 0 0 #e6e6e6;
|
||||||
|
box-shadow: -1px 0 0 #e6e6e6;
|
||||||
|
}
|
||||||
|
.flatpickr-day {
|
||||||
|
background: none;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 150px;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #393939;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 400;
|
||||||
|
width: 14.2857143%;
|
||||||
|
-webkit-flex-basis: 14.2857143%;
|
||||||
|
-ms-flex-preferred-size: 14.2857143%;
|
||||||
|
flex-basis: 14.2857143%;
|
||||||
|
max-width: 39px;
|
||||||
|
height: 39px;
|
||||||
|
line-height: 39px;
|
||||||
|
margin: 0;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-webkit-justify-content: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.flatpickr-day.inRange,
|
||||||
|
.flatpickr-day.prevMonthDay.inRange,
|
||||||
|
.flatpickr-day.nextMonthDay.inRange,
|
||||||
|
.flatpickr-day.today.inRange,
|
||||||
|
.flatpickr-day.prevMonthDay.today.inRange,
|
||||||
|
.flatpickr-day.nextMonthDay.today.inRange,
|
||||||
|
.flatpickr-day:hover,
|
||||||
|
.flatpickr-day.prevMonthDay:hover,
|
||||||
|
.flatpickr-day.nextMonthDay:hover,
|
||||||
|
.flatpickr-day:focus,
|
||||||
|
.flatpickr-day.prevMonthDay:focus,
|
||||||
|
.flatpickr-day.nextMonthDay:focus {
|
||||||
|
cursor: pointer;
|
||||||
|
outline: 0;
|
||||||
|
background: #e6e6e6;
|
||||||
|
border-color: #e6e6e6;
|
||||||
|
}
|
||||||
|
.flatpickr-day.today {
|
||||||
|
border-color: #959ea9;
|
||||||
|
}
|
||||||
|
.flatpickr-day.today:hover,
|
||||||
|
.flatpickr-day.today:focus {
|
||||||
|
border-color: #959ea9;
|
||||||
|
background: #959ea9;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.flatpickr-day.selected,
|
||||||
|
.flatpickr-day.startRange,
|
||||||
|
.flatpickr-day.endRange,
|
||||||
|
.flatpickr-day.selected.inRange,
|
||||||
|
.flatpickr-day.startRange.inRange,
|
||||||
|
.flatpickr-day.endRange.inRange,
|
||||||
|
.flatpickr-day.selected:focus,
|
||||||
|
.flatpickr-day.startRange:focus,
|
||||||
|
.flatpickr-day.endRange:focus,
|
||||||
|
.flatpickr-day.selected:hover,
|
||||||
|
.flatpickr-day.startRange:hover,
|
||||||
|
.flatpickr-day.endRange:hover,
|
||||||
|
.flatpickr-day.selected.prevMonthDay,
|
||||||
|
.flatpickr-day.startRange.prevMonthDay,
|
||||||
|
.flatpickr-day.endRange.prevMonthDay,
|
||||||
|
.flatpickr-day.selected.nextMonthDay,
|
||||||
|
.flatpickr-day.startRange.nextMonthDay,
|
||||||
|
.flatpickr-day.endRange.nextMonthDay {
|
||||||
|
background: #569ff7;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #569ff7;
|
||||||
|
}
|
||||||
|
.flatpickr-day.selected.startRange,
|
||||||
|
.flatpickr-day.startRange.startRange,
|
||||||
|
.flatpickr-day.endRange.startRange {
|
||||||
|
border-radius: 50px 0 0 50px;
|
||||||
|
}
|
||||||
|
.flatpickr-day.selected.endRange,
|
||||||
|
.flatpickr-day.startRange.endRange,
|
||||||
|
.flatpickr-day.endRange.endRange {
|
||||||
|
border-radius: 0 50px 50px 0;
|
||||||
|
}
|
||||||
|
.flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n+1)),
|
||||||
|
.flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n+1)),
|
||||||
|
.flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n+1)) {
|
||||||
|
-webkit-box-shadow: -10px 0 0 #569ff7;
|
||||||
|
box-shadow: -10px 0 0 #569ff7;
|
||||||
|
}
|
||||||
|
.flatpickr-day.selected.startRange.endRange,
|
||||||
|
.flatpickr-day.startRange.startRange.endRange,
|
||||||
|
.flatpickr-day.endRange.startRange.endRange {
|
||||||
|
border-radius: 50px;
|
||||||
|
}
|
||||||
|
.flatpickr-day.inRange {
|
||||||
|
border-radius: 0;
|
||||||
|
-webkit-box-shadow: -5px 0 0 #e6e6e6, 5px 0 0 #e6e6e6;
|
||||||
|
box-shadow: -5px 0 0 #e6e6e6, 5px 0 0 #e6e6e6;
|
||||||
|
}
|
||||||
|
.flatpickr-day.flatpickr-disabled,
|
||||||
|
.flatpickr-day.flatpickr-disabled:hover,
|
||||||
|
.flatpickr-day.prevMonthDay,
|
||||||
|
.flatpickr-day.nextMonthDay,
|
||||||
|
.flatpickr-day.notAllowed,
|
||||||
|
.flatpickr-day.notAllowed.prevMonthDay,
|
||||||
|
.flatpickr-day.notAllowed.nextMonthDay {
|
||||||
|
color: rgba(57,57,57,0.3);
|
||||||
|
background: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.flatpickr-day.flatpickr-disabled,
|
||||||
|
.flatpickr-day.flatpickr-disabled:hover {
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: rgba(57,57,57,0.1);
|
||||||
|
}
|
||||||
|
.flatpickr-day.week.selected {
|
||||||
|
border-radius: 0;
|
||||||
|
-webkit-box-shadow: -5px 0 0 #569ff7, 5px 0 0 #569ff7;
|
||||||
|
box-shadow: -5px 0 0 #569ff7, 5px 0 0 #569ff7;
|
||||||
|
}
|
||||||
|
.flatpickr-day.hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.rangeMode .flatpickr-day {
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
.flatpickr-weekwrapper {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.flatpickr-weekwrapper .flatpickr-weeks {
|
||||||
|
padding: 0 12px;
|
||||||
|
-webkit-box-shadow: 1px 0 0 #e6e6e6;
|
||||||
|
box-shadow: 1px 0 0 #e6e6e6;
|
||||||
|
}
|
||||||
|
.flatpickr-weekwrapper .flatpickr-weekday {
|
||||||
|
float: none;
|
||||||
|
width: 100%;
|
||||||
|
line-height: 28px;
|
||||||
|
}
|
||||||
|
.flatpickr-weekwrapper span.flatpickr-day,
|
||||||
|
.flatpickr-weekwrapper span.flatpickr-day:hover {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: none;
|
||||||
|
color: rgba(57,57,57,0.3);
|
||||||
|
background: transparent;
|
||||||
|
cursor: default;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.flatpickr-innerContainer {
|
||||||
|
display: block;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.flatpickr-rContainer {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.flatpickr-time {
|
||||||
|
text-align: center;
|
||||||
|
outline: 0;
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
line-height: 40px;
|
||||||
|
max-height: 40px;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.flatpickr-time:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.flatpickr-time .numInputWrapper {
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-webkit-flex: 1;
|
||||||
|
-ms-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
width: 40%;
|
||||||
|
height: 40px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.flatpickr-time .numInputWrapper span.arrowUp:after {
|
||||||
|
border-bottom-color: #393939;
|
||||||
|
}
|
||||||
|
.flatpickr-time .numInputWrapper span.arrowDown:after {
|
||||||
|
border-top-color: #393939;
|
||||||
|
}
|
||||||
|
.flatpickr-time.hasSeconds .numInputWrapper {
|
||||||
|
width: 26%;
|
||||||
|
}
|
||||||
|
.flatpickr-time.time24hr .numInputWrapper {
|
||||||
|
width: 49%;
|
||||||
|
}
|
||||||
|
.flatpickr-time input {
|
||||||
|
background: transparent;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: #393939;
|
||||||
|
font-size: 14px;
|
||||||
|
position: relative;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
appearance: textfield;
|
||||||
|
}
|
||||||
|
.flatpickr-time input.flatpickr-hour {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.flatpickr-time input.flatpickr-minute,
|
||||||
|
.flatpickr-time input.flatpickr-second {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.flatpickr-time input:focus {
|
||||||
|
outline: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.flatpickr-time .flatpickr-time-separator,
|
||||||
|
.flatpickr-time .flatpickr-am-pm {
|
||||||
|
height: inherit;
|
||||||
|
float: left;
|
||||||
|
line-height: inherit;
|
||||||
|
color: #393939;
|
||||||
|
font-weight: bold;
|
||||||
|
width: 2%;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-align-self: center;
|
||||||
|
-ms-flex-item-align: center;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
.flatpickr-time .flatpickr-am-pm {
|
||||||
|
outline: 0;
|
||||||
|
width: 18%;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.flatpickr-time input:hover,
|
||||||
|
.flatpickr-time .flatpickr-am-pm:hover,
|
||||||
|
.flatpickr-time input:focus,
|
||||||
|
.flatpickr-time .flatpickr-am-pm:focus {
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
.flatpickr-input[readonly] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
@-webkit-keyframes fpFadeInDown {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transform: translate3d(0, -20px, 0);
|
||||||
|
transform: translate3d(0, -20px, 0);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transform: translate3d(0, 0, 0);
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fpFadeInDown {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transform: translate3d(0, -20px, 0);
|
||||||
|
transform: translate3d(0, -20px, 0);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transform: translate3d(0, 0, 0);
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
327
asset/css/vendor/flatpickr.vars.less
vendored
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
/**
|
||||||
|
* This file's only purpose is to make the flatpickr themeable. DO NOT add ANY custom style here!
|
||||||
|
* Also, DO NOT re-arrange the CSS blocks to make them more LESS like. They're based off of the
|
||||||
|
* pre-compiled flatpickr.css file and so can easily identified when updating to a new version.
|
||||||
|
*
|
||||||
|
* Non-standard LESS variables were added to allow usage of CSS variables. All of them hold a
|
||||||
|
* value calculated by LESS functions. If not temporarily stored in another LESS variable,
|
||||||
|
* they wouldn't be available to CSS variable usage.
|
||||||
|
*
|
||||||
|
* Latest state from version: v4.6.9
|
||||||
|
*/
|
||||||
|
|
||||||
|
@fp-calendarBackground: #ffffff;
|
||||||
|
@fp-calendarBorderColor: #e6e6e6;
|
||||||
|
|
||||||
|
@fp-arrowColor: fadeout(@fp-dayForeground, 40%); // Non-standard variable
|
||||||
|
@fp-arrow_hover_color: #f64747;
|
||||||
|
|
||||||
|
@fp-monthForeground: fadeout(black, 10%);
|
||||||
|
@fp-monthBackground: transparent;
|
||||||
|
|
||||||
|
@fp-weekdaysBackground: transparent;
|
||||||
|
@fp-weekdaysForeground: fadeout(black, 46%);
|
||||||
|
@fp-weekNumberForeground: fadeout(@fp-dayForeground, 70%); // Non-standard variable
|
||||||
|
|
||||||
|
@fp-dayForeground: #393939;
|
||||||
|
@fp-dayHoverBackground: #e6e6e6;
|
||||||
|
@fp-disabledDayForeground: fadeout(@fp-dayForeground, 90%); // Non-standard variable
|
||||||
|
@fp-outsideRangeDayForeground: @fp-weekNumberForeground; // Non-standard variable
|
||||||
|
@fp-selectedDayBackground: #569FF7;
|
||||||
|
@fp-todayColor: #959ea9;
|
||||||
|
|
||||||
|
@fp-timeHoverBg: lighten(@fp-dayHoverBackground, 3); // Non-standard variable
|
||||||
|
|
||||||
|
@fp-invertedBg: black;
|
||||||
|
@fp-hoverInvertedBg: fadeout(@fp-invertedBg, 95%); // Non-standard variable
|
||||||
|
|
||||||
|
@fp-numChooserSvgFillColor: fadeout(@fp-monthForeground, 50%); // Non-standard variable
|
||||||
|
@fp-hoverNumChooserBg: fadeout(@fp-invertedBg, 90%); // Non-standard variable
|
||||||
|
@fp-numChooserBorderColor: fadeout(@fp-dayForeground, 85%); // Non-standard variable
|
||||||
|
|
||||||
|
.icinga-datetime-picker {
|
||||||
|
&.flatpickr-calendar {
|
||||||
|
background: @fp-calendarBackground;
|
||||||
|
background: var(--fp-calendarBackground, @fp-calendarBackground);
|
||||||
|
box-shadow: 1px 0 0 @fp-calendarBorderColor,
|
||||||
|
-1px 0 0 @fp-calendarBorderColor,
|
||||||
|
0 1px 0 @fp-calendarBorderColor,
|
||||||
|
0 -1px 0 @fp-calendarBorderColor,
|
||||||
|
0 3px 13px fadeout(black, 92%);
|
||||||
|
box-shadow: 1px 0 0 var(--fp-calendarBorderColor, @fp-calendarBorderColor),
|
||||||
|
-1px 0 0 var(--fp-calendarBorderColor, @fp-calendarBorderColor),
|
||||||
|
0 1px 0 var(--fp-calendarBorderColor, @fp-calendarBorderColor),
|
||||||
|
0 -1px 0 var(--fp-calendarBorderColor, @fp-calendarBorderColor),
|
||||||
|
0 3px 13px fadeout(black, 92%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.flatpickr-calendar.arrowTop:before {
|
||||||
|
border-bottom-color: @fp-calendarBorderColor;
|
||||||
|
border-bottom-color: var(--fp-calendarBorderColor, @fp-calendarBorderColor);
|
||||||
|
}
|
||||||
|
&.flatpickr-calendar.arrowTop:after {
|
||||||
|
border-bottom-color: @fp-calendarBackground;
|
||||||
|
border-bottom-color: var(--fp-calendarBackground, @fp-calendarBackground);
|
||||||
|
}
|
||||||
|
&.flatpickr-calendar.arrowBottom:before {
|
||||||
|
border-top-color: @fp-calendarBorderColor;
|
||||||
|
border-top-color: var(--fp-calendarBorderColor, @fp-calendarBorderColor);
|
||||||
|
}
|
||||||
|
&.flatpickr-calendar.arrowBottom:after {
|
||||||
|
border-top-color: @fp-calendarBackground;
|
||||||
|
border-top-color: var(--fp-calendarBackground, @fp-calendarBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.flatpickr-calendar.hasTime .flatpickr-time {
|
||||||
|
border-top-color: @fp-calendarBorderColor;
|
||||||
|
border-top-color: var(--fp-calendarBorderColor, @fp-calendarBorderColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dayContainer + .dayContainer {
|
||||||
|
-webkit-box-shadow: -1px 0 0 @fp-calendarBorderColor;
|
||||||
|
-webkit-box-shadow: -1px 0 0 var(--fp-calendarBorderColor, @fp-calendarBorderColor);
|
||||||
|
box-shadow: -1px 0 0 @fp-calendarBorderColor;
|
||||||
|
box-shadow: -1px 0 0 var(--fp-calendarBorderColor, @fp-calendarBorderColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-day {
|
||||||
|
color: @fp-dayForeground;
|
||||||
|
color: var(--fp-dayForeground, @fp-dayForeground);
|
||||||
|
}
|
||||||
|
.flatpickr-day.today {
|
||||||
|
border-color: @fp-todayColor;
|
||||||
|
border-color: var(--fp-todayColor, @fp-todayColor);
|
||||||
|
}
|
||||||
|
.flatpickr-day.today:hover,
|
||||||
|
.flatpickr-day.today:focus {
|
||||||
|
border-color: @fp-todayColor;
|
||||||
|
border-color: var(--fp-todayColor, @fp-todayColor);
|
||||||
|
background: @fp-todayColor;
|
||||||
|
background: var(--fp-todayColor, @fp-todayColor);
|
||||||
|
color: @fp-calendarBackground;
|
||||||
|
color: var(--fp-calendarBackground, @fp-calendarBackground);
|
||||||
|
}
|
||||||
|
.flatpickr-day.selected,
|
||||||
|
.flatpickr-day.startRange,
|
||||||
|
.flatpickr-day.endRange,
|
||||||
|
.flatpickr-day.selected.inRange,
|
||||||
|
.flatpickr-day.startRange.inRange,
|
||||||
|
.flatpickr-day.endRange.inRange,
|
||||||
|
.flatpickr-day.selected:focus,
|
||||||
|
.flatpickr-day.startRange:focus,
|
||||||
|
.flatpickr-day.endRange:focus,
|
||||||
|
.flatpickr-day.selected:hover,
|
||||||
|
.flatpickr-day.startRange:hover,
|
||||||
|
.flatpickr-day.endRange:hover,
|
||||||
|
.flatpickr-day.selected.prevMonthDay,
|
||||||
|
.flatpickr-day.startRange.prevMonthDay,
|
||||||
|
.flatpickr-day.endRange.prevMonthDay,
|
||||||
|
.flatpickr-day.selected.nextMonthDay,
|
||||||
|
.flatpickr-day.startRange.nextMonthDay,
|
||||||
|
.flatpickr-day.endRange.nextMonthDay {
|
||||||
|
color: @fp-calendarBackground;
|
||||||
|
color: var(--fp-calendarBackground, @fp-calendarBackground);
|
||||||
|
}
|
||||||
|
.flatpickr-day.inRange,
|
||||||
|
.flatpickr-day.prevMonthDay.inRange,
|
||||||
|
.flatpickr-day.nextMonthDay.inRange,
|
||||||
|
.flatpickr-day.today.inRange,
|
||||||
|
.flatpickr-day.prevMonthDay.today.inRange,
|
||||||
|
.flatpickr-day.nextMonthDay.today.inRange,
|
||||||
|
.flatpickr-day:hover,
|
||||||
|
.flatpickr-day.prevMonthDay:hover,
|
||||||
|
.flatpickr-day.nextMonthDay:hover,
|
||||||
|
.flatpickr-day:focus,
|
||||||
|
.flatpickr-day.nextMonthDay:focus {
|
||||||
|
background: @fp-dayHoverBackground;
|
||||||
|
background: var(--fp-dayHoverBackground, @fp-dayHoverBackground);
|
||||||
|
border-color: @fp-dayHoverBackground;
|
||||||
|
border-color: var(--fp-dayHoverBackground, @fp-dayHoverBackground);
|
||||||
|
}
|
||||||
|
.flatpickr-day.inRange {
|
||||||
|
-webkit-box-shadow: -5px 0 0 @fp-dayHoverBackground, 5px 0 0 @fp-dayHoverBackground;
|
||||||
|
-webkit-box-shadow: -5px 0 0 var(--fp-dayHoverBackground, @fp-dayHoverBackground),
|
||||||
|
5px 0 0 var(--fp-dayHoverBackground, @fp-dayHoverBackground);
|
||||||
|
box-shadow: -5px 0 0 @fp-dayHoverBackground, 5px 0 0 @fp-dayHoverBackground;
|
||||||
|
box-shadow: -5px 0 0 var(--fp-dayHoverBackground, @fp-dayHoverBackground),
|
||||||
|
5px 0 0 var(--fp-dayHoverBackground, @fp-dayHoverBackground);
|
||||||
|
}
|
||||||
|
.flatpickr-day.prevMonthDay,
|
||||||
|
.flatpickr-day.nextMonthDay,
|
||||||
|
.flatpickr-day.notAllowed,
|
||||||
|
.flatpickr-day.notAllowed.prevMonthDay,
|
||||||
|
.flatpickr-day.notAllowed.nextMonthDay {
|
||||||
|
color: @fp-outsideRangeDayForeground;
|
||||||
|
color: var(--fp-outsideRangeDayForeground, @fp-outsideRangeDayForeground);
|
||||||
|
}
|
||||||
|
.flatpickr-day.flatpickr-disabled,
|
||||||
|
.flatpickr-day.flatpickr-disabled:hover {
|
||||||
|
color: @fp-disabledDayForeground;
|
||||||
|
color: var(--fp-disabledDayForeground, @fp-disabledDayForeground);
|
||||||
|
}
|
||||||
|
.flatpickr-day.selected,
|
||||||
|
.flatpickr-day.startRange,
|
||||||
|
.flatpickr-day.endRange,
|
||||||
|
.flatpickr-day.selected.inRange,
|
||||||
|
.flatpickr-day.startRange.inRange,
|
||||||
|
.flatpickr-day.endRange.inRange,
|
||||||
|
.flatpickr-day.selected:focus,
|
||||||
|
.flatpickr-day.startRange:focus,
|
||||||
|
.flatpickr-day.endRange:focus,
|
||||||
|
.flatpickr-day.selected:hover,
|
||||||
|
.flatpickr-day.startRange:hover,
|
||||||
|
.flatpickr-day.endRange:hover,
|
||||||
|
.flatpickr-day.selected.prevMonthDay,
|
||||||
|
.flatpickr-day.startRange.prevMonthDay,
|
||||||
|
.flatpickr-day.endRange.prevMonthDay,
|
||||||
|
.flatpickr-day.selected.nextMonthDay,
|
||||||
|
.flatpickr-day.startRange.nextMonthDay,
|
||||||
|
.flatpickr-day.endRange.nextMonthDay {
|
||||||
|
background: @fp-selectedDayBackground;
|
||||||
|
background: var(--fp-selectedDayBackground, @fp-selectedDayBackground);
|
||||||
|
border-color: @fp-selectedDayBackground;
|
||||||
|
border-color: var(--fp-selectedDayBackground, @fp-selectedDayBackground);
|
||||||
|
}
|
||||||
|
.flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n+1)),
|
||||||
|
.flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n+1)),
|
||||||
|
.flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n+1)) {
|
||||||
|
-webkit-box-shadow: -10px 0 0 @fp-selectedDayBackground;
|
||||||
|
-webkit-box-shadow: -10px 0 0 var(--fp-selectedDayBackground, @fp-selectedDayBackground);
|
||||||
|
box-shadow: -10px 0 0 @fp-selectedDayBackground;
|
||||||
|
box-shadow: -10px 0 0 var(--fp-selectedDayBackground, @fp-selectedDayBackground);
|
||||||
|
}
|
||||||
|
.flatpickr-day.week.selected {
|
||||||
|
-webkit-box-shadow: -5px 0 0 @fp-selectedDayBackground, 5px 0 0 @fp-selectedDayBackground;
|
||||||
|
-webkit-box-shadow: -5px 0 0 var(--fp-selectedDayBackground, @fp-selectedDayBackground),
|
||||||
|
5px 0 0 var(--fp-selectedDayBackground, @fp-selectedDayBackground);
|
||||||
|
box-shadow: -5px 0 0 @fp-selectedDayBackground, 5px 0 0 @fp-selectedDayBackground;
|
||||||
|
box-shadow: -5px 0 0 var(--fp-selectedDayBackground, @fp-selectedDayBackground),
|
||||||
|
5px 0 0 var(--fp-selectedDayBackground, @fp-selectedDayBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-weekwrapper .flatpickr-weeks {
|
||||||
|
-webkit-box-shadow: 1px 0 0 @fp-calendarBorderColor;
|
||||||
|
-webkit-box-shadow: 1px 0 0 var(--fp-calendarBorderColor, @fp-calendarBorderColor);
|
||||||
|
box-shadow: 1px 0 0 @fp-calendarBorderColor;
|
||||||
|
box-shadow: 1px 0 0 var(--fp-calendarBorderColor, @fp-calendarBorderColor);
|
||||||
|
}
|
||||||
|
.flatpickr-weekwrapper span.flatpickr-day,
|
||||||
|
.flatpickr-weekwrapper span.flatpickr-day:hover {
|
||||||
|
color: @fp-weekNumberForeground;
|
||||||
|
color: var(--fp-weekNumberForeground, @fp-weekNumberForeground);
|
||||||
|
}
|
||||||
|
.flatpickr-weekdays {
|
||||||
|
background: @fp-weekdaysBackground;
|
||||||
|
background: var(--fp-weekdaysBackground, @fp-weekdaysBackground);
|
||||||
|
}
|
||||||
|
span.flatpickr-weekday {
|
||||||
|
background: @fp-monthBackground;
|
||||||
|
background: var(--fp-monthBackground, @fp-monthBackground);
|
||||||
|
color: @fp-weekdaysForeground;
|
||||||
|
color: var(--fp-weekdaysForeground, @fp-weekdaysForeground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-months .flatpickr-month {
|
||||||
|
background: @fp-monthBackground;
|
||||||
|
background: var(--fp-monthBackground, @fp-monthBackground);
|
||||||
|
color: @fp-monthForeground;
|
||||||
|
color: var(--fp-monthForeground, @fp-monthForeground);
|
||||||
|
fill: @fp-monthForeground;
|
||||||
|
fill: var(--fp-monthForeground, @fp-monthForeground);
|
||||||
|
}
|
||||||
|
.flatpickr-months .flatpickr-prev-month,
|
||||||
|
.flatpickr-months .flatpickr-next-month {
|
||||||
|
color: @fp-monthForeground;
|
||||||
|
color: var(--fp-monthForeground, @fp-monthForeground);
|
||||||
|
fill: @fp-monthForeground;
|
||||||
|
fill: var(--fp-monthForeground, @fp-monthForeground);
|
||||||
|
}
|
||||||
|
.flatpickr-months .flatpickr-prev-month:hover,
|
||||||
|
.flatpickr-months .flatpickr-next-month:hover {
|
||||||
|
color: @fp-todayColor;
|
||||||
|
color: var(--fp-todayColor, @fp-todayColor);
|
||||||
|
}
|
||||||
|
.flatpickr-months .flatpickr-prev-month:hover svg,
|
||||||
|
.flatpickr-months .flatpickr-next-month:hover svg {
|
||||||
|
fill: @fp-arrow_hover_color;
|
||||||
|
fill: var(--fp-arrow_hover_color, @fp-arrow_hover_color);
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .flatpickr-monthDropdown-months {
|
||||||
|
background: @fp-monthBackground;
|
||||||
|
background: var(--fp-monthBackground, @fp-monthBackground);
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month {
|
||||||
|
background-color: @fp-monthBackground;
|
||||||
|
background-color: var(--fp-monthBackground, @fp-monthBackground);
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .numInputWrapper span.arrowUp:after {
|
||||||
|
border-bottom-color: @fp-monthForeground;
|
||||||
|
border-bottom-color: var(--fp-monthForeground, @fp-monthForeground);
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .numInputWrapper span.arrowDown:after {
|
||||||
|
border-top-color: @fp-monthForeground;
|
||||||
|
border-top-color: var(--fp-monthForeground, @fp-monthForeground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.numInputWrapper span {
|
||||||
|
border-color: @fp-numChooserBorderColor;
|
||||||
|
border-color: var(--fp-numChooserBorderColor, @fp-numChooserBorderColor);
|
||||||
|
}
|
||||||
|
.numInputWrapper span:hover {
|
||||||
|
background: @fp-hoverNumChooserBg;
|
||||||
|
background: var(--fp-hoverNumChooserBg, @fp-hoverNumChooserBg);
|
||||||
|
}
|
||||||
|
.numInputWrapper span:active {
|
||||||
|
background: @fp-hoverNumChooserBg;
|
||||||
|
background: var(--fp-hoverNumChooserBg, @fp-hoverNumChooserBg);
|
||||||
|
}
|
||||||
|
.numInputWrapper span svg path {
|
||||||
|
fill: @fp-numChooserSvgFillColor;
|
||||||
|
fill: var(--fp-numChooserSvgFillColor, @fp-numChooserSvgFillColor);
|
||||||
|
}
|
||||||
|
.numInputWrapper span.arrowUp:after {
|
||||||
|
border-bottom-color: @fp-arrowColor;
|
||||||
|
border-bottom-color: var(--fp-arrowColor, @fp-arrowColor);
|
||||||
|
}
|
||||||
|
.numInputWrapper span.arrowDown:after {
|
||||||
|
border-top-color: @fp-arrowColor;
|
||||||
|
border-top-color: var(--fp-arrowColor, @fp-arrowColor);
|
||||||
|
}
|
||||||
|
.numInputWrapper:hover {
|
||||||
|
background: @fp-hoverInvertedBg;
|
||||||
|
background: var(--fp-hoverInvertedBg, @fp-hoverInvertedBg);
|
||||||
|
}
|
||||||
|
.flatpickr-current-month span.cur-month:hover {
|
||||||
|
background: @fp-hoverInvertedBg;
|
||||||
|
background: var(--fp-hoverInvertedBg, @fp-hoverInvertedBg);
|
||||||
|
}
|
||||||
|
.flatpickr-current-month .flatpickr-monthDropdown-months:hover {
|
||||||
|
background: @fp-hoverInvertedBg;
|
||||||
|
background: var(--fp-hoverInvertedBg, @fp-hoverInvertedBg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-time input:hover,
|
||||||
|
.flatpickr-time .flatpickr-am-pm:hover,
|
||||||
|
.flatpickr-time input:focus,
|
||||||
|
.flatpickr-time .flatpickr-am-pm:focus {
|
||||||
|
background: @fp-timeHoverBg;
|
||||||
|
background: var(--fp-timeHoverBg, @fp-timeHoverBg);
|
||||||
|
}
|
||||||
|
.flatpickr-time .numInputWrapper span.arrowUp:after {
|
||||||
|
border-bottom-color: @fp-dayForeground;
|
||||||
|
border-bottom-color: var(--fp-dayForeground, @fp-dayForeground);
|
||||||
|
}
|
||||||
|
.flatpickr-time .numInputWrapper span.arrowDown:after {
|
||||||
|
border-top-color: @fp-dayForeground;
|
||||||
|
border-top-color: var(--fp-dayForeground, @fp-dayForeground);
|
||||||
|
}
|
||||||
|
.flatpickr-time input {
|
||||||
|
color: @fp-dayForeground;
|
||||||
|
color: var(--fp-dayForeground, @fp-dayForeground);
|
||||||
|
}
|
||||||
|
.flatpickr-time .flatpickr-time-separator,
|
||||||
|
.flatpickr-time .flatpickr-am-pm {
|
||||||
|
color: @fp-dayForeground;
|
||||||
|
color: var(--fp-dayForeground, @fp-dayForeground);
|
||||||
|
}
|
||||||
|
}
|
17
asset/css/vertical-key-value.less
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
.vertical-key-value {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: .75;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
.key {
|
||||||
|
font-size: 10/12em;
|
||||||
|
color: var(--default-text-color-light, @default-text-color-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
color: var(--default-text-color, @default-text-color);
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
161
asset/js/notjQuery.js
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
define(function () {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
class notjQuery {
|
||||||
|
/**
|
||||||
|
* Create a new notjQuery object
|
||||||
|
*
|
||||||
|
* @param {Element} element
|
||||||
|
*/
|
||||||
|
constructor(element) {
|
||||||
|
if (! element) {
|
||||||
|
throw new Error("Can't create a notjQuery object for `" + element + "`");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an event listener to the element
|
||||||
|
*
|
||||||
|
* @param {string} type
|
||||||
|
* @param {string} selector
|
||||||
|
* @param {function} handler
|
||||||
|
* @param {object} context
|
||||||
|
*/
|
||||||
|
on(type, selector, handler, context = null) {
|
||||||
|
if (typeof selector === 'function') {
|
||||||
|
context = handler;
|
||||||
|
handler = selector;
|
||||||
|
selector = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selector === null) {
|
||||||
|
this.element.addEventListener(type, e => {
|
||||||
|
if (type === 'focusin' && e.target.receivesCustomFocus) {
|
||||||
|
// Ignore native focus event if a custom one follows
|
||||||
|
if (e instanceof FocusEvent) {
|
||||||
|
delete e.target.receivesCustomFocus;
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context === null) {
|
||||||
|
handler.apply(e.currentTarget, [e]);
|
||||||
|
} else {
|
||||||
|
handler.apply(context, [e]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.element.addEventListener(type, e => {
|
||||||
|
if (type === 'focusin' && e.target.receivesCustomFocus) {
|
||||||
|
// Ignore native focus event if a custom one follows
|
||||||
|
if (e instanceof FocusEvent) {
|
||||||
|
delete e.target.receivesCustomFocus;
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(e, 'currentTarget', { value: e.currentTarget, writable: true });
|
||||||
|
|
||||||
|
let currentParent = e.currentTarget.parentNode;
|
||||||
|
for (let target = e.target; target && target !== currentParent; target = target.parentNode) {
|
||||||
|
if (target.matches(selector)) {
|
||||||
|
e.currentTarget = target;
|
||||||
|
if (context === null) {
|
||||||
|
handler.apply(target, [e]);
|
||||||
|
} else {
|
||||||
|
handler.apply(context, [e]);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger a custom event on the element, asynchronously
|
||||||
|
*
|
||||||
|
* The event will bubble and is not cancelable.
|
||||||
|
*
|
||||||
|
* @param {string} type
|
||||||
|
* @param {{}} detail
|
||||||
|
*/
|
||||||
|
trigger(type, detail = null) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.dispatchEvent(new CustomEvent(type, {
|
||||||
|
cancelable: true, // TODO: this should depend on whether it's a native or custom event
|
||||||
|
bubbles: true,
|
||||||
|
detail: detail
|
||||||
|
}));
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Focus the element
|
||||||
|
*
|
||||||
|
* Any other option than `preventScroll` is used as `event.detail`.
|
||||||
|
*
|
||||||
|
* @param {{}} options
|
||||||
|
*/
|
||||||
|
focus(options = {}) {
|
||||||
|
let { preventScroll = false, ...data } = options;
|
||||||
|
|
||||||
|
const hasData = Object.keys(data).length > 0;
|
||||||
|
if (hasData) {
|
||||||
|
this.element.receivesCustomFocus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put separately on the event loop because focus() forces layout.
|
||||||
|
setTimeout(() => this.element.focus({ preventScroll: preventScroll }), 0);
|
||||||
|
|
||||||
|
if (hasData) {
|
||||||
|
this.trigger('focusin', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the element string as DOM Element
|
||||||
|
*
|
||||||
|
* @param {string} html
|
||||||
|
* @return {Element}
|
||||||
|
*/
|
||||||
|
static render(html) {
|
||||||
|
if (typeof html !== 'string') {
|
||||||
|
throw new Error("Can\'t render `" + html + "`");
|
||||||
|
}
|
||||||
|
|
||||||
|
let template = document.createElement('template');
|
||||||
|
template.innerHTML = html;
|
||||||
|
return template.content.firstChild;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a notjQuery object for the given element
|
||||||
|
*
|
||||||
|
* @param {Element} element
|
||||||
|
* @return {notjQuery}
|
||||||
|
*/
|
||||||
|
let factory = function (element) {
|
||||||
|
return new notjQuery(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the static methods on the factory
|
||||||
|
for (let name of Object.getOwnPropertyNames(notjQuery)) {
|
||||||
|
if (['length', 'prototype', 'name'].includes(name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(factory, name, {
|
||||||
|
value: notjQuery[name]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return factory;
|
||||||
|
});
|
3721
asset/js/vendor/Sortable.js
vendored
Normal file
2
asset/js/vendor/Sortable.min.js
vendored
Normal file
2705
asset/js/vendor/flatpickr.js
vendored
Normal file
2
asset/js/vendor/flatpickr.min.js
vendored
Normal file
62
asset/js/vendor/flatpickr/l10n/ar.js
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
|
typeof define === 'function' && define.icinga ? define(["exports"], factory) :
|
||||||
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ar = {}));
|
||||||
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
|
var fp = typeof window !== "undefined" && window.flatpickr !== undefined
|
||||||
|
? window.flatpickr
|
||||||
|
: {
|
||||||
|
l10ns: {},
|
||||||
|
};
|
||||||
|
var Arabic = {
|
||||||
|
weekdays: {
|
||||||
|
shorthand: ["أحد", "اثنين", "ثلاثاء", "أربعاء", "خميس", "جمعة", "سبت"],
|
||||||
|
longhand: [
|
||||||
|
"الأحد",
|
||||||
|
"الاثنين",
|
||||||
|
"الثلاثاء",
|
||||||
|
"الأربعاء",
|
||||||
|
"الخميس",
|
||||||
|
"الجمعة",
|
||||||
|
"السبت",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
months: {
|
||||||
|
shorthand: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
|
||||||
|
longhand: [
|
||||||
|
"يناير",
|
||||||
|
"فبراير",
|
||||||
|
"مارس",
|
||||||
|
"أبريل",
|
||||||
|
"مايو",
|
||||||
|
"يونيو",
|
||||||
|
"يوليو",
|
||||||
|
"أغسطس",
|
||||||
|
"سبتمبر",
|
||||||
|
"أكتوبر",
|
||||||
|
"نوفمبر",
|
||||||
|
"ديسمبر",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
firstDayOfWeek: 6,
|
||||||
|
rangeSeparator: " إلى ",
|
||||||
|
weekAbbreviation: "Wk",
|
||||||
|
scrollTitle: "قم بالتمرير للزيادة",
|
||||||
|
toggleTitle: "اضغط للتبديل",
|
||||||
|
amPM: ["ص", "م"],
|
||||||
|
yearAriaLabel: "سنة",
|
||||||
|
monthAriaLabel: "شهر",
|
||||||
|
hourAriaLabel: "ساعة",
|
||||||
|
minuteAriaLabel: "دقيقة",
|
||||||
|
time_24hr: false,
|
||||||
|
};
|
||||||
|
fp.l10ns.ar = Arabic;
|
||||||
|
var ar = fp.l10ns;
|
||||||
|
|
||||||
|
exports.Arabic = Arabic;
|
||||||
|
exports.default = ar;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
})));
|
70
asset/js/vendor/flatpickr/l10n/de.js
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
|
typeof define === 'function' && define.icinga ? define(["exports"], factory) :
|
||||||
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.de = {}));
|
||||||
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
|
var fp = typeof window !== "undefined" && window.flatpickr !== undefined
|
||||||
|
? window.flatpickr
|
||||||
|
: {
|
||||||
|
l10ns: {},
|
||||||
|
};
|
||||||
|
var German = {
|
||||||
|
weekdays: {
|
||||||
|
shorthand: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
|
||||||
|
longhand: [
|
||||||
|
"Sonntag",
|
||||||
|
"Montag",
|
||||||
|
"Dienstag",
|
||||||
|
"Mittwoch",
|
||||||
|
"Donnerstag",
|
||||||
|
"Freitag",
|
||||||
|
"Samstag",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
months: {
|
||||||
|
shorthand: [
|
||||||
|
"Jan",
|
||||||
|
"Feb",
|
||||||
|
"Mär",
|
||||||
|
"Apr",
|
||||||
|
"Mai",
|
||||||
|
"Jun",
|
||||||
|
"Jul",
|
||||||
|
"Aug",
|
||||||
|
"Sep",
|
||||||
|
"Okt",
|
||||||
|
"Nov",
|
||||||
|
"Dez",
|
||||||
|
],
|
||||||
|
longhand: [
|
||||||
|
"Januar",
|
||||||
|
"Februar",
|
||||||
|
"März",
|
||||||
|
"April",
|
||||||
|
"Mai",
|
||||||
|
"Juni",
|
||||||
|
"Juli",
|
||||||
|
"August",
|
||||||
|
"September",
|
||||||
|
"Oktober",
|
||||||
|
"November",
|
||||||
|
"Dezember",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
firstDayOfWeek: 1,
|
||||||
|
weekAbbreviation: "KW",
|
||||||
|
rangeSeparator: " bis ",
|
||||||
|
scrollTitle: "Zum Ändern scrollen",
|
||||||
|
toggleTitle: "Zum Umschalten klicken",
|
||||||
|
time_24hr: true,
|
||||||
|
};
|
||||||
|
fp.l10ns.de = German;
|
||||||
|
var de = fp.l10ns;
|
||||||
|
|
||||||
|
exports.German = German;
|
||||||
|
exports.default = de;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
})));
|
70
asset/js/vendor/flatpickr/l10n/es.js
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
|
typeof define === 'function' && define.icinga ? define(["exports"], factory) :
|
||||||
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.es = {}));
|
||||||
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
|
var fp = typeof window !== "undefined" && window.flatpickr !== undefined
|
||||||
|
? window.flatpickr
|
||||||
|
: {
|
||||||
|
l10ns: {},
|
||||||
|
};
|
||||||
|
var Spanish = {
|
||||||
|
weekdays: {
|
||||||
|
shorthand: ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb"],
|
||||||
|
longhand: [
|
||||||
|
"Domingo",
|
||||||
|
"Lunes",
|
||||||
|
"Martes",
|
||||||
|
"Miércoles",
|
||||||
|
"Jueves",
|
||||||
|
"Viernes",
|
||||||
|
"Sábado",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
months: {
|
||||||
|
shorthand: [
|
||||||
|
"Ene",
|
||||||
|
"Feb",
|
||||||
|
"Mar",
|
||||||
|
"Abr",
|
||||||
|
"May",
|
||||||
|
"Jun",
|
||||||
|
"Jul",
|
||||||
|
"Ago",
|
||||||
|
"Sep",
|
||||||
|
"Oct",
|
||||||
|
"Nov",
|
||||||
|
"Dic",
|
||||||
|
],
|
||||||
|
longhand: [
|
||||||
|
"Enero",
|
||||||
|
"Febrero",
|
||||||
|
"Marzo",
|
||||||
|
"Abril",
|
||||||
|
"Mayo",
|
||||||
|
"Junio",
|
||||||
|
"Julio",
|
||||||
|
"Agosto",
|
||||||
|
"Septiembre",
|
||||||
|
"Octubre",
|
||||||
|
"Noviembre",
|
||||||
|
"Diciembre",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
ordinal: function () {
|
||||||
|
return "º";
|
||||||
|
},
|
||||||
|
firstDayOfWeek: 1,
|
||||||
|
rangeSeparator: " a ",
|
||||||
|
time_24hr: true,
|
||||||
|
};
|
||||||
|
fp.l10ns.es = Spanish;
|
||||||
|
var es = fp.l10ns;
|
||||||
|
|
||||||
|
exports.Spanish = Spanish;
|
||||||
|
exports.default = es;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
})));
|
69
asset/js/vendor/flatpickr/l10n/fi.js
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
|
typeof define === 'function' && define.icinga ? define(["exports"], factory) :
|
||||||
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.fi = {}));
|
||||||
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
|
var fp = typeof window !== "undefined" && window.flatpickr !== undefined
|
||||||
|
? window.flatpickr
|
||||||
|
: {
|
||||||
|
l10ns: {},
|
||||||
|
};
|
||||||
|
var Finnish = {
|
||||||
|
firstDayOfWeek: 1,
|
||||||
|
weekdays: {
|
||||||
|
shorthand: ["su", "ma", "ti", "ke", "to", "pe", "la"],
|
||||||
|
longhand: [
|
||||||
|
"sunnuntai",
|
||||||
|
"maanantai",
|
||||||
|
"tiistai",
|
||||||
|
"keskiviikko",
|
||||||
|
"torstai",
|
||||||
|
"perjantai",
|
||||||
|
"lauantai",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
months: {
|
||||||
|
shorthand: [
|
||||||
|
"tammi",
|
||||||
|
"helmi",
|
||||||
|
"maalis",
|
||||||
|
"huhti",
|
||||||
|
"touko",
|
||||||
|
"kesä",
|
||||||
|
"heinä",
|
||||||
|
"elo",
|
||||||
|
"syys",
|
||||||
|
"loka",
|
||||||
|
"marras",
|
||||||
|
"joulu",
|
||||||
|
],
|
||||||
|
longhand: [
|
||||||
|
"tammikuu",
|
||||||
|
"helmikuu",
|
||||||
|
"maaliskuu",
|
||||||
|
"huhtikuu",
|
||||||
|
"toukokuu",
|
||||||
|
"kesäkuu",
|
||||||
|
"heinäkuu",
|
||||||
|
"elokuu",
|
||||||
|
"syyskuu",
|
||||||
|
"lokakuu",
|
||||||
|
"marraskuu",
|
||||||
|
"joulukuu",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
ordinal: function () {
|
||||||
|
return ".";
|
||||||
|
},
|
||||||
|
time_24hr: true,
|
||||||
|
};
|
||||||
|
fp.l10ns.fi = Finnish;
|
||||||
|
var fi = fp.l10ns;
|
||||||
|
|
||||||
|
exports.Finnish = Finnish;
|
||||||
|
exports.default = fi;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
})));
|
75
asset/js/vendor/flatpickr/l10n/fr.js
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
|
typeof define === 'function' && define.icinga ? define(["exports"], factory) :
|
||||||
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.fr = {}));
|
||||||
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
|
var fp = typeof window !== "undefined" && window.flatpickr !== undefined
|
||||||
|
? window.flatpickr
|
||||||
|
: {
|
||||||
|
l10ns: {},
|
||||||
|
};
|
||||||
|
var French = {
|
||||||
|
firstDayOfWeek: 1,
|
||||||
|
weekdays: {
|
||||||
|
shorthand: ["dim", "lun", "mar", "mer", "jeu", "ven", "sam"],
|
||||||
|
longhand: [
|
||||||
|
"dimanche",
|
||||||
|
"lundi",
|
||||||
|
"mardi",
|
||||||
|
"mercredi",
|
||||||
|
"jeudi",
|
||||||
|
"vendredi",
|
||||||
|
"samedi",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
months: {
|
||||||
|
shorthand: [
|
||||||
|
"janv",
|
||||||
|
"févr",
|
||||||
|
"mars",
|
||||||
|
"avr",
|
||||||
|
"mai",
|
||||||
|
"juin",
|
||||||
|
"juil",
|
||||||
|
"août",
|
||||||
|
"sept",
|
||||||
|
"oct",
|
||||||
|
"nov",
|
||||||
|
"déc",
|
||||||
|
],
|
||||||
|
longhand: [
|
||||||
|
"janvier",
|
||||||
|
"février",
|
||||||
|
"mars",
|
||||||
|
"avril",
|
||||||
|
"mai",
|
||||||
|
"juin",
|
||||||
|
"juillet",
|
||||||
|
"août",
|
||||||
|
"septembre",
|
||||||
|
"octobre",
|
||||||
|
"novembre",
|
||||||
|
"décembre",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
ordinal: function (nth) {
|
||||||
|
if (nth > 1)
|
||||||
|
return "";
|
||||||
|
return "er";
|
||||||
|
},
|
||||||
|
rangeSeparator: " au ",
|
||||||
|
weekAbbreviation: "Sem",
|
||||||
|
scrollTitle: "Défiler pour augmenter la valeur",
|
||||||
|
toggleTitle: "Cliquer pour basculer",
|
||||||
|
time_24hr: true,
|
||||||
|
};
|
||||||
|
fp.l10ns.fr = French;
|
||||||
|
var fr = fp.l10ns;
|
||||||
|
|
||||||
|
exports.French = French;
|
||||||
|
exports.default = fr;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
})));
|
71
asset/js/vendor/flatpickr/l10n/it.js
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
|
typeof define === 'function' && define.icinga ? define(["exports"], factory) :
|
||||||
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.it = {}));
|
||||||
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
|
var fp = typeof window !== "undefined" && window.flatpickr !== undefined
|
||||||
|
? window.flatpickr
|
||||||
|
: {
|
||||||
|
l10ns: {},
|
||||||
|
};
|
||||||
|
var Italian = {
|
||||||
|
weekdays: {
|
||||||
|
shorthand: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"],
|
||||||
|
longhand: [
|
||||||
|
"Domenica",
|
||||||
|
"Lunedì",
|
||||||
|
"Martedì",
|
||||||
|
"Mercoledì",
|
||||||
|
"Giovedì",
|
||||||
|
"Venerdì",
|
||||||
|
"Sabato",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
months: {
|
||||||
|
shorthand: [
|
||||||
|
"Gen",
|
||||||
|
"Feb",
|
||||||
|
"Mar",
|
||||||
|
"Apr",
|
||||||
|
"Mag",
|
||||||
|
"Giu",
|
||||||
|
"Lug",
|
||||||
|
"Ago",
|
||||||
|
"Set",
|
||||||
|
"Ott",
|
||||||
|
"Nov",
|
||||||
|
"Dic",
|
||||||
|
],
|
||||||
|
longhand: [
|
||||||
|
"Gennaio",
|
||||||
|
"Febbraio",
|
||||||
|
"Marzo",
|
||||||
|
"Aprile",
|
||||||
|
"Maggio",
|
||||||
|
"Giugno",
|
||||||
|
"Luglio",
|
||||||
|
"Agosto",
|
||||||
|
"Settembre",
|
||||||
|
"Ottobre",
|
||||||
|
"Novembre",
|
||||||
|
"Dicembre",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
firstDayOfWeek: 1,
|
||||||
|
ordinal: function () { return "°"; },
|
||||||
|
rangeSeparator: " al ",
|
||||||
|
weekAbbreviation: "Se",
|
||||||
|
scrollTitle: "Scrolla per aumentare",
|
||||||
|
toggleTitle: "Clicca per cambiare",
|
||||||
|
time_24hr: true,
|
||||||
|
};
|
||||||
|
fp.l10ns.it = Italian;
|
||||||
|
var it = fp.l10ns;
|
||||||
|
|
||||||
|
exports.Italian = Italian;
|
||||||
|
exports.default = it;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
})));
|
71
asset/js/vendor/flatpickr/l10n/ja.js
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
|
typeof define === 'function' && define.icinga ? define(["exports"], factory) :
|
||||||
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ja = {}));
|
||||||
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
|
var fp = typeof window !== "undefined" && window.flatpickr !== undefined
|
||||||
|
? window.flatpickr
|
||||||
|
: {
|
||||||
|
l10ns: {},
|
||||||
|
};
|
||||||
|
var Japanese = {
|
||||||
|
weekdays: {
|
||||||
|
shorthand: ["日", "月", "火", "水", "木", "金", "土"],
|
||||||
|
longhand: [
|
||||||
|
"日曜日",
|
||||||
|
"月曜日",
|
||||||
|
"火曜日",
|
||||||
|
"水曜日",
|
||||||
|
"木曜日",
|
||||||
|
"金曜日",
|
||||||
|
"土曜日",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
months: {
|
||||||
|
shorthand: [
|
||||||
|
"1月",
|
||||||
|
"2月",
|
||||||
|
"3月",
|
||||||
|
"4月",
|
||||||
|
"5月",
|
||||||
|
"6月",
|
||||||
|
"7月",
|
||||||
|
"8月",
|
||||||
|
"9月",
|
||||||
|
"10月",
|
||||||
|
"11月",
|
||||||
|
"12月",
|
||||||
|
],
|
||||||
|
longhand: [
|
||||||
|
"1月",
|
||||||
|
"2月",
|
||||||
|
"3月",
|
||||||
|
"4月",
|
||||||
|
"5月",
|
||||||
|
"6月",
|
||||||
|
"7月",
|
||||||
|
"8月",
|
||||||
|
"9月",
|
||||||
|
"10月",
|
||||||
|
"11月",
|
||||||
|
"12月",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
time_24hr: true,
|
||||||
|
rangeSeparator: " から ",
|
||||||
|
monthAriaLabel: "月",
|
||||||
|
amPM: ["午前", "午後"],
|
||||||
|
yearAriaLabel: "年",
|
||||||
|
hourAriaLabel: "時間",
|
||||||
|
minuteAriaLabel: "分",
|
||||||
|
};
|
||||||
|
fp.l10ns.ja = Japanese;
|
||||||
|
var ja = fp.l10ns;
|
||||||
|
|
||||||
|
exports.Japanese = Japanese;
|
||||||
|
exports.default = ja;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
})));
|
66
asset/js/vendor/flatpickr/l10n/pt.js
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
|
typeof define === 'function' && define.icinga ? define(["exports"], factory) :
|
||||||
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.pt = {}));
|
||||||
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
|
var fp = typeof window !== "undefined" && window.flatpickr !== undefined
|
||||||
|
? window.flatpickr
|
||||||
|
: {
|
||||||
|
l10ns: {},
|
||||||
|
};
|
||||||
|
var Portuguese = {
|
||||||
|
weekdays: {
|
||||||
|
shorthand: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"],
|
||||||
|
longhand: [
|
||||||
|
"Domingo",
|
||||||
|
"Segunda-feira",
|
||||||
|
"Terça-feira",
|
||||||
|
"Quarta-feira",
|
||||||
|
"Quinta-feira",
|
||||||
|
"Sexta-feira",
|
||||||
|
"Sábado",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
months: {
|
||||||
|
shorthand: [
|
||||||
|
"Jan",
|
||||||
|
"Fev",
|
||||||
|
"Mar",
|
||||||
|
"Abr",
|
||||||
|
"Mai",
|
||||||
|
"Jun",
|
||||||
|
"Jul",
|
||||||
|
"Ago",
|
||||||
|
"Set",
|
||||||
|
"Out",
|
||||||
|
"Nov",
|
||||||
|
"Dez",
|
||||||
|
],
|
||||||
|
longhand: [
|
||||||
|
"Janeiro",
|
||||||
|
"Fevereiro",
|
||||||
|
"Março",
|
||||||
|
"Abril",
|
||||||
|
"Maio",
|
||||||
|
"Junho",
|
||||||
|
"Julho",
|
||||||
|
"Agosto",
|
||||||
|
"Setembro",
|
||||||
|
"Outubro",
|
||||||
|
"Novembro",
|
||||||
|
"Dezembro",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
rangeSeparator: " até ",
|
||||||
|
time_24hr: true,
|
||||||
|
};
|
||||||
|
fp.l10ns.pt = Portuguese;
|
||||||
|
var pt = fp.l10ns;
|
||||||
|
|
||||||
|
exports.Portuguese = Portuguese;
|
||||||
|
exports.default = pt;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
})));
|
75
asset/js/vendor/flatpickr/l10n/ru.js
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
|
typeof define === 'function' && define.icinga ? define(["exports"], factory) :
|
||||||
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ru = {}));
|
||||||
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
|
var fp = typeof window !== "undefined" && window.flatpickr !== undefined
|
||||||
|
? window.flatpickr
|
||||||
|
: {
|
||||||
|
l10ns: {},
|
||||||
|
};
|
||||||
|
var Russian = {
|
||||||
|
weekdays: {
|
||||||
|
shorthand: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
|
||||||
|
longhand: [
|
||||||
|
"Воскресенье",
|
||||||
|
"Понедельник",
|
||||||
|
"Вторник",
|
||||||
|
"Среда",
|
||||||
|
"Четверг",
|
||||||
|
"Пятница",
|
||||||
|
"Суббота",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
months: {
|
||||||
|
shorthand: [
|
||||||
|
"Янв",
|
||||||
|
"Фев",
|
||||||
|
"Март",
|
||||||
|
"Апр",
|
||||||
|
"Май",
|
||||||
|
"Июнь",
|
||||||
|
"Июль",
|
||||||
|
"Авг",
|
||||||
|
"Сен",
|
||||||
|
"Окт",
|
||||||
|
"Ноя",
|
||||||
|
"Дек",
|
||||||
|
],
|
||||||
|
longhand: [
|
||||||
|
"Январь",
|
||||||
|
"Февраль",
|
||||||
|
"Март",
|
||||||
|
"Апрель",
|
||||||
|
"Май",
|
||||||
|
"Июнь",
|
||||||
|
"Июль",
|
||||||
|
"Август",
|
||||||
|
"Сентябрь",
|
||||||
|
"Октябрь",
|
||||||
|
"Ноябрь",
|
||||||
|
"Декабрь",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
firstDayOfWeek: 1,
|
||||||
|
ordinal: function () {
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
rangeSeparator: " — ",
|
||||||
|
weekAbbreviation: "Нед.",
|
||||||
|
scrollTitle: "Прокрутите для увеличения",
|
||||||
|
toggleTitle: "Нажмите для переключения",
|
||||||
|
amPM: ["ДП", "ПП"],
|
||||||
|
yearAriaLabel: "Год",
|
||||||
|
time_24hr: true,
|
||||||
|
};
|
||||||
|
fp.l10ns.ru = Russian;
|
||||||
|
var ru = fp.l10ns;
|
||||||
|
|
||||||
|
exports.Russian = Russian;
|
||||||
|
exports.default = ru;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
})));
|
66
asset/js/vendor/flatpickr/l10n/uk.js
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
|
typeof define === 'function' && define.icinga ? define(["exports"], factory) :
|
||||||
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.uk = {}));
|
||||||
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
|
var fp = typeof window !== "undefined" && window.flatpickr !== undefined
|
||||||
|
? window.flatpickr
|
||||||
|
: {
|
||||||
|
l10ns: {},
|
||||||
|
};
|
||||||
|
var Ukrainian = {
|
||||||
|
firstDayOfWeek: 1,
|
||||||
|
weekdays: {
|
||||||
|
shorthand: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
|
||||||
|
longhand: [
|
||||||
|
"Неділя",
|
||||||
|
"Понеділок",
|
||||||
|
"Вівторок",
|
||||||
|
"Середа",
|
||||||
|
"Четвер",
|
||||||
|
"П'ятниця",
|
||||||
|
"Субота",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
months: {
|
||||||
|
shorthand: [
|
||||||
|
"Січ",
|
||||||
|
"Лют",
|
||||||
|
"Бер",
|
||||||
|
"Кві",
|
||||||
|
"Тра",
|
||||||
|
"Чер",
|
||||||
|
"Лип",
|
||||||
|
"Сер",
|
||||||
|
"Вер",
|
||||||
|
"Жов",
|
||||||
|
"Лис",
|
||||||
|
"Гру",
|
||||||
|
],
|
||||||
|
longhand: [
|
||||||
|
"Січень",
|
||||||
|
"Лютий",
|
||||||
|
"Березень",
|
||||||
|
"Квітень",
|
||||||
|
"Травень",
|
||||||
|
"Червень",
|
||||||
|
"Липень",
|
||||||
|
"Серпень",
|
||||||
|
"Вересень",
|
||||||
|
"Жовтень",
|
||||||
|
"Листопад",
|
||||||
|
"Грудень",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
time_24hr: true,
|
||||||
|
};
|
||||||
|
fp.l10ns.uk = Ukrainian;
|
||||||
|
var uk = fp.l10ns;
|
||||||
|
|
||||||
|
exports.Ukrainian = Ukrainian;
|
||||||
|
exports.default = uk;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
})));
|
1074
asset/js/widget/BaseInput.js
Normal file
750
asset/js/widget/Completer.js
Normal file
@ -0,0 +1,750 @@
|
|||||||
|
define(["../notjQuery"], function ($) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
class Completer {
|
||||||
|
constructor(input, instrumented = false) {
|
||||||
|
this.input = input;
|
||||||
|
this.instrumented = instrumented;
|
||||||
|
this.selectionStartInput = null;
|
||||||
|
this.selectionActive = false;
|
||||||
|
this.mouseSelectionActive = false;
|
||||||
|
this.nextSuggestion = null;
|
||||||
|
this.activeSuggestion = null;
|
||||||
|
this.suggestionKiller = null;
|
||||||
|
this.completedInput = null;
|
||||||
|
this.completedValue = null;
|
||||||
|
this.completedData = null;
|
||||||
|
this._termSuggestions = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get termSuggestions() {
|
||||||
|
if (this._termSuggestions === null) {
|
||||||
|
this._termSuggestions = document.querySelector(this.input.dataset.termSuggestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._termSuggestions;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(to = null) {
|
||||||
|
// Form submissions
|
||||||
|
$(this.input.form).on('submit', this.onSubmit, this);
|
||||||
|
|
||||||
|
// User interactions
|
||||||
|
$(this.termSuggestions).on('focusout', '[type="button"]', this.onFocusOut, this);
|
||||||
|
$(this.termSuggestions).on('click', '[type="button"]', this.onSuggestionClick, this);
|
||||||
|
$(this.termSuggestions).on('keydown', '[type="button"]', this.onSuggestionKeyDown, this);
|
||||||
|
|
||||||
|
if (this.selectionEnabled()) {
|
||||||
|
$(this.termSuggestions).on('keyup', '[type="button"]', this.onSuggestionKeyUp, this);
|
||||||
|
$(this.termSuggestions).on('mouseover', '[type="button"]', this.onSuggestionMouseOver, this);
|
||||||
|
$(this.termSuggestions).on('mousedown', '[type="button"]', this.onSuggestionMouseDown, this);
|
||||||
|
$(this.termSuggestions).on('mouseup', '[type="button"]', this.onSuggestionsMouseUp, this);
|
||||||
|
$(this.termSuggestions).on('mouseleave', this.onSuggestionsMouseLeave, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.instrumented) {
|
||||||
|
if (to !== null) {
|
||||||
|
$(to).on('focusout', 'input[type="text"]', this.onFocusOut, this);
|
||||||
|
$(to).on('keydown', 'input[type="text"]', this.onKeyDown, this);
|
||||||
|
$(to).on('complete', 'input[type="text"]', this.onComplete, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(this.input).on('complete', this.onComplete, this);
|
||||||
|
} else {
|
||||||
|
$(this.input).on('input', this.onInput, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(this.input).on('focusout', this.onFocusOut, this);
|
||||||
|
$(this.input).on('keydown', this.onKeyDown, this);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh(input, bindTo = null) {
|
||||||
|
if (input === this.input) {
|
||||||
|
// If the DOM node is still the same, nothing has changed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._termSuggestions = null;
|
||||||
|
this.abort();
|
||||||
|
|
||||||
|
this.input = input;
|
||||||
|
this.bind(bindTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.abort();
|
||||||
|
this.hideSuggestions();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this._termSuggestions = null;
|
||||||
|
this.input = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSuggestions(html) {
|
||||||
|
let template = document.createElement('template');
|
||||||
|
template.innerHTML = html;
|
||||||
|
|
||||||
|
return template.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
showSuggestions(suggestions, input) {
|
||||||
|
this.termSuggestions.innerHTML = '';
|
||||||
|
this.termSuggestions.appendChild(suggestions);
|
||||||
|
this.termSuggestions.style.display = '';
|
||||||
|
|
||||||
|
let containingBlock = this.termSuggestions.offsetParent || document.body;
|
||||||
|
let containingBlockRect = containingBlock.getBoundingClientRect();
|
||||||
|
let inputRect = input.getBoundingClientRect();
|
||||||
|
let inputPosX = inputRect.left - containingBlockRect.left;
|
||||||
|
let inputPosY = inputRect.bottom - containingBlockRect.top;
|
||||||
|
let suggestionWidth = this.termSuggestions.offsetWidth;
|
||||||
|
|
||||||
|
let maxAvailableHeight = document.body.clientHeight - inputRect.bottom;
|
||||||
|
let localMarginBottom = window.getComputedStyle(this.termSuggestions).marginBottom;
|
||||||
|
|
||||||
|
this.termSuggestions.style.top = `${ inputPosY }px`;
|
||||||
|
this.termSuggestions.style.maxHeight = `calc(${maxAvailableHeight}px - ${localMarginBottom})`;
|
||||||
|
if (inputPosX + suggestionWidth > containingBlockRect.right - containingBlockRect.left) {
|
||||||
|
this.termSuggestions.style.left =
|
||||||
|
`${ containingBlockRect.right - containingBlockRect.left - suggestionWidth }px`;
|
||||||
|
} else {
|
||||||
|
this.termSuggestions.style.left = `${ inputPosX }px`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hasSuggestions() {
|
||||||
|
return this.termSuggestions.childNodes.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hideSuggestions() {
|
||||||
|
if (this.nextSuggestion !== null || this.activeSuggestion !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.suggestionKiller !== null) {
|
||||||
|
// onFocusOut initiates this timer in order to hide the suggestions if the user
|
||||||
|
// doesn't navigate them. Since it does this by checking after a short interval
|
||||||
|
// if the focus is inside the suggestions, the interval has to be long enough to
|
||||||
|
// have a chance to detect the focus. `focusout` runs before `blur` and `focus`,
|
||||||
|
// so this may lead to a race condition which is addressed by the timeout. Though,
|
||||||
|
// to not close the newly opened suggestions of the next input the timer has to
|
||||||
|
// be cancelled here since it's purpose is already fulfilled.
|
||||||
|
clearTimeout(this.suggestionKiller);
|
||||||
|
this.suggestionKiller = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.termSuggestions.style.display = 'none';
|
||||||
|
this.termSuggestions.innerHTML = '';
|
||||||
|
|
||||||
|
this.completedInput = null;
|
||||||
|
this.completedValue = null;
|
||||||
|
this.completedData = null;
|
||||||
|
|
||||||
|
this.endSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareCompletionData(input, data = null) {
|
||||||
|
if (data === null) {
|
||||||
|
data = { term: { ...input.dataset } };
|
||||||
|
data.term.label = input.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = data.term.label;
|
||||||
|
data.term.search = value;
|
||||||
|
data.term.label = this.addWildcards(value);
|
||||||
|
|
||||||
|
if (input.parentElement instanceof HTMLFieldSetElement) {
|
||||||
|
for (let element of input.parentElement.elements) {
|
||||||
|
if (element !== input
|
||||||
|
&& element.name !== input.name + '-search'
|
||||||
|
&& (element.name.substr(-7) === '-search'
|
||||||
|
|| typeof input.form[element.name + '-search'] === 'undefined')
|
||||||
|
) {
|
||||||
|
// Make sure we'll use a key that the server can understand..
|
||||||
|
let dataName = element.name;
|
||||||
|
if (dataName.substr(-7) === '-search') {
|
||||||
|
dataName = dataName.substr(0, dataName.length - 7);
|
||||||
|
}
|
||||||
|
if (dataName.substr(0, input.parentElement.name.length) === input.parentElement.name) {
|
||||||
|
dataName = dataName.substr(input.parentElement.name.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! dataName in data || element.value) {
|
||||||
|
data[dataName] = element.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [value, data];
|
||||||
|
}
|
||||||
|
|
||||||
|
addWildcards(value) {
|
||||||
|
if (! value) {
|
||||||
|
return '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.slice(0, 1) !== '*' && value.slice(-1) !== '*') {
|
||||||
|
return '*' + value + '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
abort() {
|
||||||
|
if (this.activeSuggestion !== null) {
|
||||||
|
this.activeSuggestion.abort();
|
||||||
|
this.activeSuggestion = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.nextSuggestion !== null) {
|
||||||
|
clearTimeout(this.nextSuggestion);
|
||||||
|
this.nextSuggestion = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestCompletion(input, data, trigger = 'user') {
|
||||||
|
this.abort();
|
||||||
|
|
||||||
|
this.nextSuggestion = setTimeout(() => {
|
||||||
|
let req = new XMLHttpRequest();
|
||||||
|
req.open('POST', this.input.dataset.suggestUrl, true);
|
||||||
|
req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||||
|
req.setRequestHeader('Content-Type', 'application/json');
|
||||||
|
|
||||||
|
if (typeof icinga !== 'undefined') {
|
||||||
|
let windowId = icinga.ui.getWindowId();
|
||||||
|
let containerId = icinga.ui.getUniqueContainerId(this.termSuggestions);
|
||||||
|
if (containerId) {
|
||||||
|
req.setRequestHeader('X-Icinga-WindowId', windowId + '_' + containerId);
|
||||||
|
} else {
|
||||||
|
req.setRequestHeader('X-Icinga-WindowId', windowId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req.addEventListener('loadend', () => {
|
||||||
|
if (req.readyState > 0) {
|
||||||
|
if (req.responseText) {
|
||||||
|
let suggestions = this.renderSuggestions(req.responseText);
|
||||||
|
if (trigger === 'script') {
|
||||||
|
// If the suggestions are to be displayed due to a scripted event,
|
||||||
|
// show them only if the completed input is still focused..
|
||||||
|
if (document.activeElement === input) {
|
||||||
|
this.showSuggestions(suggestions, input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.showSuggestions(suggestions, input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.hideSuggestions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.activeSuggestion = null;
|
||||||
|
this.nextSuggestion = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
req.send(JSON.stringify(data));
|
||||||
|
|
||||||
|
this.activeSuggestion = req;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
suggest(input, value, data = {}) {
|
||||||
|
if (this.instrumented) {
|
||||||
|
if (! Object.keys(data).length) {
|
||||||
|
data = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(input).trigger('suggestion', data);
|
||||||
|
} else {
|
||||||
|
input.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete(input, value, data) {
|
||||||
|
$(input).focus({ scripted: true });
|
||||||
|
|
||||||
|
if (this.instrumented) {
|
||||||
|
if (! Object.keys(data).length) {
|
||||||
|
data = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(input).trigger('completion', data);
|
||||||
|
} else {
|
||||||
|
input.value = value;
|
||||||
|
|
||||||
|
for (let name in data) {
|
||||||
|
let dataElement = input.form[input.name + '-' + name];
|
||||||
|
if (typeof dataElement !== 'undefined') {
|
||||||
|
if (dataElement instanceof RadioNodeList) {
|
||||||
|
dataElement = dataElement[dataElement.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
dataElement.value = data[name];
|
||||||
|
} else if (name === 'title') {
|
||||||
|
input.title = data[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hideSuggestions();
|
||||||
|
}
|
||||||
|
|
||||||
|
moveToSuggestion(backwards = false, stopAtEdge = false) {
|
||||||
|
let focused = this.termSuggestions.querySelector('[type="button"]:focus');
|
||||||
|
let inputs = Array.from(this.termSuggestions.querySelectorAll('[type="button"]'));
|
||||||
|
|
||||||
|
let input;
|
||||||
|
if (focused !== null) {
|
||||||
|
let sibling = inputs[backwards ? inputs.indexOf(focused) - 1 : inputs.indexOf(focused) + 1];
|
||||||
|
if (sibling) {
|
||||||
|
input = sibling;
|
||||||
|
} else if (stopAtEdge) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
input = this.completedInput;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
input = inputs[backwards ? inputs.length - 1 : 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$(input).focus();
|
||||||
|
|
||||||
|
if (! stopAtEdge && this.completedValue !== null) {
|
||||||
|
if (input === this.completedInput) {
|
||||||
|
this.suggest(this.completedInput, this.completedValue);
|
||||||
|
} else {
|
||||||
|
this.suggest(this.completedInput, input.value, { ...input.dataset });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
isBeingCompleted(input, activeElement = null) {
|
||||||
|
if (activeElement === null) {
|
||||||
|
activeElement = document.activeElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return input === this.completedInput && this.hasSuggestions()
|
||||||
|
&& (! activeElement || input === activeElement || this.termSuggestions.contains(activeElement));
|
||||||
|
}
|
||||||
|
|
||||||
|
selectionEnabled() {
|
||||||
|
return this.instrumented && 'withMultiCompletion' in this.input.dataset;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectionAllowed() {
|
||||||
|
return this.completedInput === this.input && this.selectionEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
startSelection(input) {
|
||||||
|
this.selectionActive = true;
|
||||||
|
this.selectionStartInput = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSelectionActive() {
|
||||||
|
return this.selectionActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
endSelection() {
|
||||||
|
this.selectionStartInput = null;
|
||||||
|
this.selectionActive = false;
|
||||||
|
this.mouseSelectionActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectSuggestion(input) {
|
||||||
|
input.classList.add('selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
deselectSuggestion(input) {
|
||||||
|
input.classList.remove('selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleSelection(input) {
|
||||||
|
input.classList.toggle('selected');
|
||||||
|
let selected = input.classList.contains('selected');
|
||||||
|
if (selected && ! this.isSelectionActive()) {
|
||||||
|
this.startSelection(input);
|
||||||
|
$(input).focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! selected && input === this.selectionStartInput) {
|
||||||
|
this.selectionStartInput = this.termSuggestions.querySelector('[type="button"].selected');
|
||||||
|
if (! this.selectionStartInput) {
|
||||||
|
this.endSelection();
|
||||||
|
$(this.input).focus();
|
||||||
|
} else {
|
||||||
|
$(this.selectionStartInput).focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSelectedSuggestion(input) {
|
||||||
|
return input.classList.contains('selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
getSelectedSuggestions() {
|
||||||
|
return this.termSuggestions.querySelectorAll('[type="button"].selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelection() {
|
||||||
|
if (! this.isSelectionActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const selectedInput of this.getSelectedSuggestions()) {
|
||||||
|
this.deselectSuggestion(selectedInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.endSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeySelection(input, newInput) {
|
||||||
|
if (! this.isSelectionActive()) {
|
||||||
|
this.startSelection(input);
|
||||||
|
this.selectSuggestion(input);
|
||||||
|
this.selectSuggestion(newInput);
|
||||||
|
this.suggest(this.completedInput, '');
|
||||||
|
} else if (this.isSelectedSuggestion(newInput)) {
|
||||||
|
this.deselectSuggestion(input);
|
||||||
|
} else {
|
||||||
|
this.selectSuggestion(newInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startMouseSelection(input) {
|
||||||
|
this.startSelection(input);
|
||||||
|
this.mouseSelectionActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
isMouseSelectionActive() {
|
||||||
|
return this.mouseSelectionActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
finishMouseSelection() {
|
||||||
|
if (! this.mouseSelectionActive) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mouseSelectionActive = false;
|
||||||
|
this.selectSuggestion(this.selectionStartInput);
|
||||||
|
|
||||||
|
let selectionFound = false;
|
||||||
|
let selectionCandidates = [];
|
||||||
|
for (const input of this.termSuggestions.querySelectorAll('[type="button"]')) {
|
||||||
|
if (input.classList.contains('selected')) {
|
||||||
|
if (selectionFound) {
|
||||||
|
for (const candidate of selectionCandidates) {
|
||||||
|
this.selectSuggestion(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectionCandidates = [];
|
||||||
|
} else {
|
||||||
|
selectionFound = true;
|
||||||
|
}
|
||||||
|
} else if (selectionFound) {
|
||||||
|
selectionCandidates.push(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listeners
|
||||||
|
*/
|
||||||
|
|
||||||
|
onSubmit(event) {
|
||||||
|
if (! event.detail || ! event.detail.submittedBy) {
|
||||||
|
// Reset all states, the user is about to navigate away
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocusOut(event) {
|
||||||
|
if (this.completedInput === null) {
|
||||||
|
// If there are multiple instances of Completer bound to the same suggestion container
|
||||||
|
// all of them try to handle the event. Though, only one of them is responsible and
|
||||||
|
// that's the one which has a completed input set.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = event.target;
|
||||||
|
let completedInput = this.completedInput;
|
||||||
|
this.suggestionKiller = setTimeout(() => {
|
||||||
|
if (completedInput !== this.completedInput) {
|
||||||
|
// Don't hide another input's suggestions
|
||||||
|
} else if (document.activeElement !== completedInput
|
||||||
|
&& ! this.termSuggestions.contains(document.activeElement)
|
||||||
|
) {
|
||||||
|
// Hide the suggestions if the user doesn't navigate them
|
||||||
|
if (input !== completedInput) {
|
||||||
|
// Restore input if a suggestion lost focus
|
||||||
|
this.suggest(completedInput, this.completedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hideSuggestions();
|
||||||
|
}
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionMouseDown(event) {
|
||||||
|
if (! this.selectionAllowed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.ctrlKey || event.metaKey) {
|
||||||
|
// onSuggestionClick only toggles the suggestion's selection and should
|
||||||
|
// be the only one who decides which other suggestion should be focused
|
||||||
|
event.preventDefault();
|
||||||
|
} else {
|
||||||
|
this.clearSelection();
|
||||||
|
this.startMouseSelection(event.target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionsMouseUp(event) {
|
||||||
|
if (! event.ctrlKey && ! event.metaKey) {
|
||||||
|
this.finishMouseSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionsMouseLeave(_) {
|
||||||
|
this.finishMouseSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionMouseOver(event) {
|
||||||
|
if (this.isMouseSelectionActive()) {
|
||||||
|
this.selectSuggestion(event.target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionKeyUp(event) {
|
||||||
|
if (this.completedInput === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = event.target;
|
||||||
|
|
||||||
|
switch (event.key) {
|
||||||
|
case 'Shift':
|
||||||
|
if (this.isSelectionActive()) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (input === this.selectionStartInput && this.getSelectedSuggestions().length === 1) {
|
||||||
|
this.deselectSuggestion(input);
|
||||||
|
this.endSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionKeyDown(event) {
|
||||||
|
if (this.completedInput === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let newInput;
|
||||||
|
let input = event.target;
|
||||||
|
let allowSelection = event.shiftKey && this.selectionAllowed();
|
||||||
|
|
||||||
|
switch (event.key) {
|
||||||
|
case 'Escape':
|
||||||
|
$(this.completedInput).focus({ scripted: true });
|
||||||
|
this.suggest(this.completedInput, this.completedValue);
|
||||||
|
this.clearSelection();
|
||||||
|
break;
|
||||||
|
case 'Tab':
|
||||||
|
event.preventDefault();
|
||||||
|
this.moveToSuggestion(event.shiftKey);
|
||||||
|
break;
|
||||||
|
case 'ArrowLeft':
|
||||||
|
case 'ArrowUp':
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
newInput = this.moveToSuggestion(true, allowSelection);
|
||||||
|
if (allowSelection) {
|
||||||
|
if (newInput !== null) {
|
||||||
|
this.handleKeySelection(input, newInput);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'ArrowRight':
|
||||||
|
case 'ArrowDown':
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
newInput = this.moveToSuggestion(false, allowSelection);
|
||||||
|
if (allowSelection) {
|
||||||
|
if (newInput !== null) {
|
||||||
|
this.handleKeySelection(input, newInput);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionClick(event) {
|
||||||
|
if (this.completedInput === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.ctrlKey || event.metaKey) {
|
||||||
|
if (this.selectionAllowed()) {
|
||||||
|
this.toggleSelection(event.target);
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
} else if (this.isSelectionActive() && this.isSelectedSuggestion(event.target)) {
|
||||||
|
let terms = [];
|
||||||
|
for (const suggestion of this.getSelectedSuggestions()) {
|
||||||
|
terms.push({ ...suggestion.dataset });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.complete(this.completedInput, null, { type: 'terms', terms: terms });
|
||||||
|
} else {
|
||||||
|
let input = event.currentTarget;
|
||||||
|
|
||||||
|
this.complete(this.completedInput, input.value, { ...input.dataset });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown(event) {
|
||||||
|
let suggestions;
|
||||||
|
|
||||||
|
switch (event.key) {
|
||||||
|
case ' ':
|
||||||
|
if (this.instrumented) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = event.target;
|
||||||
|
|
||||||
|
if (! input.value) {
|
||||||
|
if (input.minLength <= 0) {
|
||||||
|
let [value, data] = this.prepareCompletionData(input);
|
||||||
|
this.completedInput = input;
|
||||||
|
this.completedValue = value;
|
||||||
|
this.completedData = data;
|
||||||
|
this.requestCompletion(input, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'Tab':
|
||||||
|
suggestions = this.termSuggestions.querySelectorAll('[type="button"]');
|
||||||
|
if (suggestions.length === 1) {
|
||||||
|
event.preventDefault();
|
||||||
|
let input = event.target;
|
||||||
|
let suggestion = suggestions[0];
|
||||||
|
|
||||||
|
this.complete(input, suggestion.value, { ...suggestion.dataset });
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'Enter':
|
||||||
|
let defaultSuggestion = this.termSuggestions.querySelector('.default > [type="button"]');
|
||||||
|
if (defaultSuggestion !== null) {
|
||||||
|
event.preventDefault();
|
||||||
|
let input = event.target;
|
||||||
|
|
||||||
|
this.complete(input, defaultSuggestion.value, { ...defaultSuggestion.dataset });
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'Escape':
|
||||||
|
if (this.hasSuggestions()) {
|
||||||
|
this.hideSuggestions()
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'ArrowUp':
|
||||||
|
suggestions = this.termSuggestions.querySelectorAll('[type="button"]');
|
||||||
|
if (suggestions.length) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.moveToSuggestion(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'ArrowDown':
|
||||||
|
suggestions = this.termSuggestions.querySelectorAll('[type="button"]');
|
||||||
|
if (suggestions.length) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.moveToSuggestion();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (/[A-Z]/.test(event.key.charAt(0)) || event.key === '"') {
|
||||||
|
// Ignore control keys not resulting in new input data
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let typedSuggestion = this.termSuggestions.querySelector(`[value="${ event.key }"]`);
|
||||||
|
if (typedSuggestion !== null) {
|
||||||
|
this.hideSuggestions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onInput(event) {
|
||||||
|
let input = event.target;
|
||||||
|
|
||||||
|
if (input.minLength > 0 && input.value.length < input.minLength) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the input's value as search value. This ensures that if the user doesn't
|
||||||
|
// choose a suggestion, an up2date contextual value will be transmitted with
|
||||||
|
// completion requests and the server can properly identify a new value upon submit
|
||||||
|
input.dataset.search = input.value;
|
||||||
|
if (typeof input.form[input.name + '-search'] !== 'undefined') {
|
||||||
|
let dataElement = input.form[input.name + '-search'];
|
||||||
|
if (dataElement instanceof RadioNodeList) {
|
||||||
|
dataElement = dataElement[dataElement.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
dataElement.value = input.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
let [value, data] = this.prepareCompletionData(input);
|
||||||
|
this.completedInput = input;
|
||||||
|
this.completedValue = value;
|
||||||
|
this.completedData = data;
|
||||||
|
this.requestCompletion(input, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
onComplete(event) {
|
||||||
|
let input = event.target;
|
||||||
|
let { trigger = 'user' , ...detail } = event.detail;
|
||||||
|
|
||||||
|
let [value, data] = this.prepareCompletionData(input, detail);
|
||||||
|
this.completedInput = input;
|
||||||
|
this.completedValue = value;
|
||||||
|
this.completedData = data;
|
||||||
|
|
||||||
|
if (typeof data.suggestions !== 'undefined') {
|
||||||
|
this.showSuggestions(data.suggestions, input);
|
||||||
|
} else {
|
||||||
|
this.requestCompletion(input, data, trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Completer;
|
||||||
|
});
|
49
asset/js/widget/CopyToClipboard.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
define(["../notjQuery"], function ($) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
class CopyToClipboard {
|
||||||
|
constructor(button)
|
||||||
|
{
|
||||||
|
button.classList.add('active');
|
||||||
|
button.removeAttribute('tabindex');
|
||||||
|
$(button).on('click', null, this.onClick, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick(event)
|
||||||
|
{
|
||||||
|
let button = event.currentTarget;
|
||||||
|
let clipboardSource = button.parentElement.querySelector("[data-clipboard-source]");
|
||||||
|
let copyText;
|
||||||
|
|
||||||
|
if (clipboardSource) {
|
||||||
|
copyText = clipboardSource.innerText;
|
||||||
|
} else {
|
||||||
|
throw new Error('Clipboard source is required but not provided');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
navigator.clipboard.writeText(copyText).then(() => {
|
||||||
|
let previousHtml = button.innerHTML;
|
||||||
|
button.innerText = button.dataset.copiedLabel;
|
||||||
|
button.classList.add('copied');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// after 4 second, reset it.
|
||||||
|
button.classList.remove('copied');
|
||||||
|
button.innerHTML = previousHtml;
|
||||||
|
}, 4000);
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error('Failed to copy: ', err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error('Copy to clipboard requires HTTPS connection');
|
||||||
|
}
|
||||||
|
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CopyToClipboard;
|
||||||
|
});
|
1521
asset/js/widget/FilterInput.js
Normal file
81
asset/js/widget/SearchBar.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
define(["../notjQuery"], function ($) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
class SearchBar {
|
||||||
|
constructor(form) {
|
||||||
|
this.form = form;
|
||||||
|
this.filterInput = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind() {
|
||||||
|
$(this.form.parentNode).on('click', '[data-search-editor-url]', this.onOpenerClick, this);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh(form) {
|
||||||
|
if (form === this.form) {
|
||||||
|
// If the DOM node is still the same, nothing has changed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.form = form;
|
||||||
|
this.bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.form = null;
|
||||||
|
this.filterInput = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
setFilterInput(filterInput) {
|
||||||
|
this.filterInput = filterInput;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpenerClick(event) {
|
||||||
|
let opener = event.currentTarget;
|
||||||
|
let editorUrl = opener.dataset.searchEditorUrl;
|
||||||
|
let filterQueryString = this.filterInput.getQueryString();
|
||||||
|
let layout = document.getElementById('layout');
|
||||||
|
|
||||||
|
editorUrl += (editorUrl.indexOf('?') > -1 ? '&' : '?') + filterQueryString;
|
||||||
|
|
||||||
|
// Disable pointer events to block further function calls
|
||||||
|
opener.style.pointerEvents = 'none';
|
||||||
|
|
||||||
|
let observer = new MutationObserver((mutations) => {
|
||||||
|
for (let mutation of mutations) {
|
||||||
|
if (mutation.type === 'childList') {
|
||||||
|
mutation.removedNodes.forEach((node) => {
|
||||||
|
// Remove the pointerEvent none style to make the button clickable again
|
||||||
|
// after the modal has been removed
|
||||||
|
if (node.id === 'modal') {
|
||||||
|
opener.style.pointerEvents = '';
|
||||||
|
observer.disconnect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(layout, {childList: true});
|
||||||
|
|
||||||
|
// The search editor should open in a modal. We simulate a click on an anchor
|
||||||
|
// appropriately prepared so that Icinga Web 2 will handle it natively.
|
||||||
|
let a = document.createElement('a');
|
||||||
|
a.classList.add('modal-opener');
|
||||||
|
a.href = editorUrl;
|
||||||
|
a.dataset.noIcingaAjax = '';
|
||||||
|
a.dataset.icingaModal = '';
|
||||||
|
|
||||||
|
opener.parentNode.insertBefore(a, opener.nextSibling);
|
||||||
|
a.click();
|
||||||
|
a.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SearchBar;
|
||||||
|
});
|
79
asset/js/widget/SearchEditor.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
define(["../notjQuery", "../vendor/Sortable"], function ($, Sortable) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
class SearchEditor {
|
||||||
|
constructor(form) {
|
||||||
|
this.form = form;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind() {
|
||||||
|
$(this.form).on('end', this.onRuleDropped, this);
|
||||||
|
|
||||||
|
this.form.querySelectorAll('ol').forEach(sortable => {
|
||||||
|
let options = {
|
||||||
|
scroll: true,
|
||||||
|
group: 'rules',
|
||||||
|
direction: 'vertical',
|
||||||
|
invertSwap: true,
|
||||||
|
handle: '.drag-initiator'
|
||||||
|
};
|
||||||
|
|
||||||
|
Sortable.create(sortable, options);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh(form) {
|
||||||
|
if (form === this.form) {
|
||||||
|
// If the DOM node is still the same, nothing has changed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.form = form;
|
||||||
|
this.bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.form = null;
|
||||||
|
this.filterInput = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
onRuleDropped(event) {
|
||||||
|
if (event.to === event.from && event.newIndex === event.oldIndex) {
|
||||||
|
// The user dropped the rule at its previous position
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let placement = 'before';
|
||||||
|
let neighbour = event.to.querySelector(':scope > :nth-child(' + (event.newIndex + 2) + ')');
|
||||||
|
if (! neighbour) {
|
||||||
|
// User dropped the rule at the end of a group
|
||||||
|
placement = 'after';
|
||||||
|
neighbour = event.to.querySelector(':scope > :nth-child(' + event.newIndex + ')')
|
||||||
|
if (! neighbour) {
|
||||||
|
// User dropped the rule into an empty group
|
||||||
|
placement = 'to';
|
||||||
|
neighbour = event.to.closest('[id]');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's a submit element, the very first one, otherwise Icinga Web 2 sends another "structural-change"
|
||||||
|
this.form.insertBefore(
|
||||||
|
$.render(
|
||||||
|
'<input type="hidden" name="structural-change[1]" value="' + placement + ':' + neighbour.id + '">'
|
||||||
|
),
|
||||||
|
this.form.firstChild
|
||||||
|
);
|
||||||
|
this.form.insertBefore(
|
||||||
|
$.render('<input type="submit" name="structural-change[0]" value="move-rule:' + event.item.id + '">'),
|
||||||
|
this.form.firstChild
|
||||||
|
);
|
||||||
|
|
||||||
|
$(this.form).trigger('submit');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SearchEditor;
|
||||||
|
});
|
331
asset/js/widget/TermInput.js
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
define(["../notjQuery", "../vendor/Sortable", "BaseInput"], function ($, Sortable, BaseInput) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
class TermInput extends BaseInput {
|
||||||
|
constructor(input) {
|
||||||
|
super(input);
|
||||||
|
|
||||||
|
this.separator = this.input.dataset.termSeparator || ' ';
|
||||||
|
this.ordered = 'maintainTermOrder' in this.input.dataset;
|
||||||
|
this.readOnly = 'readOnlyTerms' in this.input.dataset;
|
||||||
|
this.ignoreSpaceUntil = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind() {
|
||||||
|
super.bind();
|
||||||
|
|
||||||
|
if (this.readOnly) {
|
||||||
|
$(this.termContainer).on('click', '[data-index] > input', this.onTermClick, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.ordered) {
|
||||||
|
$(this.termContainer).on('end', this.onDrop, this);
|
||||||
|
|
||||||
|
Sortable.create(this.termContainer, {
|
||||||
|
scroll: true,
|
||||||
|
direction: 'vertical',
|
||||||
|
handle: '[data-drag-initiator]'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Compatibility only. Remove as soon as possible once Web 2.12 (?) is out.
|
||||||
|
// Or upon any other update which lets Web trigger a real submit upon auto submit.
|
||||||
|
$(this.input.form).on('change', 'select.autosubmit', this.onSubmit, this);
|
||||||
|
$(this.input.form).on('change', 'input.autosubmit', this.onSubmit, this);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
super.reset();
|
||||||
|
|
||||||
|
this.ignoreSpaceUntil = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerTerm(termData, termIndex = null) {
|
||||||
|
termIndex = super.registerTerm(termData, termIndex);
|
||||||
|
|
||||||
|
if (this.readOnly) {
|
||||||
|
const label = this.termContainer.querySelector(`[data-index="${ termIndex }"]`);
|
||||||
|
if (label) {
|
||||||
|
// The label only exists in DOM at this time if it was transmitted
|
||||||
|
// by the server. So it's safe to assume that it needs validation
|
||||||
|
this.validate(label.firstChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return termIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
readPartialTerm(input) {
|
||||||
|
let value = super.readPartialTerm(input);
|
||||||
|
if (value && this.ignoreSpaceUntil && value[0] === this.ignoreSpaceUntil) {
|
||||||
|
value = value.slice(1);
|
||||||
|
if (value.slice(-1) === this.ignoreSpaceUntil) {
|
||||||
|
value = value.slice(0, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
writePartialTerm(value, input) {
|
||||||
|
if (this.ignoreSpaceUntil !== null && this.ignoreSpaceSince === 0) {
|
||||||
|
value = this.ignoreSpaceUntil + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.writePartialTerm(value, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
readFullTerm(input, termIndex = null) {
|
||||||
|
let termData = super.readFullTerm(input, termIndex);
|
||||||
|
if (termData && this.ignoreSpaceUntil !== null && input.value[0] === this.ignoreSpaceUntil) {
|
||||||
|
if (input.value.slice(-1) !== this.ignoreSpaceUntil || input.value.length < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ignoreSpaceUntil = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return termData;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasSyntaxError(input) {
|
||||||
|
if ((typeof input === 'undefined' || input === this.input) && this.ignoreSpaceUntil !== null) {
|
||||||
|
if (this.input.value === this.ignoreSpaceUntil) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.hasSyntaxError(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkValidity(input) {
|
||||||
|
if (! this.readOnly) {
|
||||||
|
return super.checkValidity(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Readonly terms don't participate in constraint validation, so we have to do it ourselves
|
||||||
|
return ! (input.pattern && ! input.value.match(input.pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
reportValidity(element) {
|
||||||
|
if (! this.readOnly) {
|
||||||
|
return super.reportValidity(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once invalid, it stays invalid since it's readonly
|
||||||
|
element.classList.add('invalid');
|
||||||
|
if (element.dataset.invalidMsg) {
|
||||||
|
const reason = element.parentNode.querySelector(':scope > .invalid-reason');
|
||||||
|
if (! reason.matches('.visible')) {
|
||||||
|
element.title = element.dataset.invalidMsg;
|
||||||
|
reason.textContent = element.dataset.invalidMsg;
|
||||||
|
reason.classList.add('visible');
|
||||||
|
setTimeout(() => reason.classList.remove('visible'), 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
termsToQueryString(terms) {
|
||||||
|
let quoted = [];
|
||||||
|
for (const termData of terms) {
|
||||||
|
let search = this.encodeTerm(termData).search;
|
||||||
|
if (search.indexOf(this.separator) >= 0) {
|
||||||
|
search = '"' + termData.search + '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
quoted.push(search);
|
||||||
|
}
|
||||||
|
|
||||||
|
return quoted.join(this.separator).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
addRenderedTerm(label) {
|
||||||
|
if (! this.ordered) {
|
||||||
|
return super.addRenderedTerm(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
const listItem = document.createElement('li');
|
||||||
|
listItem.appendChild(label);
|
||||||
|
listItem.appendChild($.render('<i data-drag-initiator class="icon fa-bars fa"></i>'));
|
||||||
|
this.termContainer.appendChild(listItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
insertRenderedTerm(label) {
|
||||||
|
if (! this.ordered) {
|
||||||
|
return super.insertRenderedTerm(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
const termIndex = Number(label.dataset.index);
|
||||||
|
const nextListItemLabel = this.termContainer.querySelector(`[data-index="${ termIndex + 1 }"]`);
|
||||||
|
const nextListItem = nextListItemLabel?.parentNode || null;
|
||||||
|
const listItem = document.createElement('li');
|
||||||
|
listItem.appendChild(label);
|
||||||
|
listItem.appendChild($.render('<i data-drag-initiator class="icon fa-bars fa"></i>'));
|
||||||
|
this.termContainer.insertBefore(listItem, nextListItem);
|
||||||
|
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeRenderedTerm(label) {
|
||||||
|
if (! this.ordered) {
|
||||||
|
return super.removeRenderedTerm(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
label.parentNode.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
complete(input, data) {
|
||||||
|
data.exclude = this.usedTerms.map(termData => termData.search);
|
||||||
|
|
||||||
|
super.complete(input, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTerm(termData, termIndex) {
|
||||||
|
const label = super.renderTerm(termData, termIndex);
|
||||||
|
|
||||||
|
if (this.readOnly) {
|
||||||
|
label.firstChild.readOnly = true;
|
||||||
|
label.appendChild($.render('<i class="icon fa-trash fa"></i>'));
|
||||||
|
label.appendChild($.render('<span class="invalid-reason"></span>'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listeners
|
||||||
|
*/
|
||||||
|
|
||||||
|
onTermClick(event) {
|
||||||
|
let termIndex = Number(event.target.parentNode.dataset.index);
|
||||||
|
this.removeTerm(event.target.parentNode);
|
||||||
|
this.moveFocusForward(termIndex - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDrop(event) {
|
||||||
|
if (event.to === event.from && event.newIndex === event.oldIndex) {
|
||||||
|
// The user dropped the term at its previous position
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The item is the list item, not the term's label
|
||||||
|
const label = event.item.firstChild;
|
||||||
|
|
||||||
|
// Remove the term from the internal map, but not the DOM, as it's been moved already
|
||||||
|
const termData = this.removeTerm(label, false);
|
||||||
|
delete label.dataset.index; // Which is why we have to take it out of the equation for now
|
||||||
|
|
||||||
|
let newIndex = 0; // event.newIndex is intentionally not used, as we have our own indexing
|
||||||
|
if (event.item.previousSibling) {
|
||||||
|
newIndex = Number(event.item.previousSibling.firstChild.dataset.index) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is essentially insertTerm() with custom DOM manipulation
|
||||||
|
this.reIndexTerms(newIndex, 1, true); // Free up the new index
|
||||||
|
this.registerTerm(termData, newIndex); // Re-register the term with the new index
|
||||||
|
label.dataset.index = `${ newIndex }`; // Update the DOM, we didn't do that during removal
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(event) {
|
||||||
|
super.onSubmit(event);
|
||||||
|
|
||||||
|
this.ignoreSpaceUntil = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
onInput(event) {
|
||||||
|
let label = event.target.parentNode;
|
||||||
|
if (label.dataset.index >= 0) {
|
||||||
|
super.onInput(event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = event.target;
|
||||||
|
let firstChar = input.value[0];
|
||||||
|
|
||||||
|
if (this.ignoreSpaceUntil !== null) {
|
||||||
|
// Reset if the user changes/removes the source char
|
||||||
|
if (firstChar !== this.ignoreSpaceUntil) {
|
||||||
|
this.ignoreSpaceUntil = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.ignoreSpaceUntil === null && (firstChar === "'" || firstChar === '"')) {
|
||||||
|
this.ignoreSpaceUntil = firstChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onInput(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown(event) {
|
||||||
|
super.onKeyDown(event);
|
||||||
|
if (event.defaultPrevented) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let label = event.target.parentNode;
|
||||||
|
if (label.dataset.index >= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key !== this.separator && event.key !== 'Enter') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let addedTerms = this.exchangeTerm();
|
||||||
|
if (Object.keys(addedTerms).length) {
|
||||||
|
this.togglePlaceholder();
|
||||||
|
event.preventDefault();
|
||||||
|
this.autoSubmit(this.input, 'exchange', { terms: addedTerms });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyUp(event) {
|
||||||
|
super.onKeyUp(event);
|
||||||
|
|
||||||
|
let label = event.target.parentNode;
|
||||||
|
if (label.dataset.index >= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.ignoreSpaceUntil !== null) {
|
||||||
|
// Reset if the user changes/removes the source char
|
||||||
|
let value = event.target.value;
|
||||||
|
if (value[this.ignoreSpaceSince] !== this.ignoreSpaceUntil) {
|
||||||
|
this.ignoreSpaceUntil = null;
|
||||||
|
this.ignoreSpaceSince = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = event.target;
|
||||||
|
switch (event.key) {
|
||||||
|
case '"':
|
||||||
|
case "'":
|
||||||
|
if (this.ignoreSpaceUntil === null) {
|
||||||
|
this.ignoreSpaceUntil = event.key;
|
||||||
|
this.ignoreSpaceSince = input.selectionStart - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onButtonClick(event) {
|
||||||
|
if (! this.hasSyntaxError()) {
|
||||||
|
let addedTerms = this.exchangeTerm();
|
||||||
|
if (Object.keys(addedTerms).length) {
|
||||||
|
this.togglePlaceholder();
|
||||||
|
event.preventDefault();
|
||||||
|
this.autoSubmit(this.input, 'exchange', { terms: addedTerms });
|
||||||
|
this.ignoreSpaceUntil = null;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onButtonClick(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TermInput;
|
||||||
|
});
|
BIN
asset/static/font/awesome/fa-brands-400.ttf
Normal file
BIN
asset/static/font/awesome/fa-brands-400.woff2
Normal file
BIN
asset/static/font/awesome/fa-regular-400.ttf
Normal file
BIN
asset/static/font/awesome/fa-regular-400.woff2
Normal file
BIN
asset/static/font/awesome/fa-solid-900.ttf
Normal file
BIN
asset/static/font/awesome/fa-solid-900.woff2
Normal file
BIN
asset/static/font/awesome/fa-v4compatibility.ttf
Normal file
BIN
asset/static/font/awesome/fa-v4compatibility.woff2
Normal file
7
asset/static/font/icinga-icons/Read Me.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Open *demo.html* to see a list of all the glyphs in your font along with their codes/ligatures.
|
||||||
|
|
||||||
|
To use the generated font in desktop programs, you can install the TTF font. In order to copy the character associated with each icon, refer to the text box at the bottom right corner of each glyph in demo.html. The character inside this text box may be invisible; but it can still be copied. See this guide for more info: https://icomoon.io/#docs/local-fonts
|
||||||
|
|
||||||
|
You won't need any of the files located under the *demo-files* directory when including the generated font in your own projects.
|
||||||
|
|
||||||
|
You can import *selection.json* back to the IcoMoon app using the *Import Icons* button (or via Main Menu → Manage Projects) to retrieve your icon selection.
|
22
asset/static/font/icinga-icons/fonts/Icinga-Icons.svg
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<metadata>Generated by IcoMoon</metadata>
|
||||||
|
<defs>
|
||||||
|
<font id="Icinga-Icons" horiz-adv-x="1024">
|
||||||
|
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
||||||
|
<missing-glyph horiz-adv-x="1024" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="512" d="" />
|
||||||
|
<glyph unicode="" glyph-name="list-view-minimal" d="M192.009 831.995c0-35.361-28.665-64.026-64.026-64.026s-64.026 28.665-64.026 64.026c0 35.361 28.665 64.026 64.026 64.026s64.026-28.665 64.026-64.026zM192.009 639.671c0-35.361-28.665-64.026-64.026-64.026s-64.026 28.665-64.026 64.026c0 35.361 28.665 64.026 64.026 64.026s64.026-28.665 64.026-64.026zM192.009 447.671c0-35.361-28.665-64.026-64.026-64.026s-64.026 28.665-64.026 64.026c0 35.361 28.665 64.026 64.026 64.026s64.026-28.665 64.026-64.026zM320.006 863.997h640.004v-64.005h-640.004v64.005zM320.006 479.674h640.004v-64.005h-640.004v64.005zM320.006 671.674h640.004v-64.005h-640.004v64.005zM320.006 287.674h640.004v-64.005h-640.004v64.005zM320.006 95.674h640.004v-64.005h-640.004v64.005zM192.009 255.348c0-35.361-28.665-64.026-64.026-64.026s-64.026 28.665-64.026 64.026c0 35.361 28.665 64.026 64.026 64.026s64.026-28.665 64.026-64.026zM192.009 63.671c0-35.361-28.665-64.026-64.026-64.026s-64.026 28.665-64.026 64.026c0 35.361 28.665 64.026 64.026 64.026s64.026-28.665 64.026-64.026z" />
|
||||||
|
<glyph unicode="" glyph-name="list-view-detailed" d="M320.007 831.679h639.993v-191.358h-639.993v191.358zM320.007 575.997h639.993v-63.992h-639.993v63.992zM256.014 736.317c0-53.041-42.998-96.039-96.039-96.039s-96.039 42.998-96.039 96.039c0 53.041 42.998 96.039 96.039 96.039s96.039-42.998 96.039-96.039zM256.014 287.992c0-53.041-42.998-96.039-96.039-96.039s-96.039 42.998-96.039 96.039c0 53.041 42.998 96.039 96.039 96.039s96.039-42.998 96.039-96.039zM320.007 384.004h639.993v-192.005h-639.993v192.005zM320.007 128.005h639.993v-63.992h-639.993v63.992z" />
|
||||||
|
<glyph unicode="" glyph-name="list-view-default" d="M256.015 767.992c0-53.041-42.998-96.039-96.039-96.039s-96.039 42.998-96.039 96.039c0 53.041 42.998 96.039 96.039 96.039s96.039-42.998 96.039-96.039zM384.001 864h576.002v-192.008h-576.002v192.008zM384.001 543.998h576.002v-192.008h-576.002v192.008zM384.001 223.998h576.002v-192.008h-576.002v192.008zM256.015 447.99c0-53.041-42.998-96.039-96.039-96.039s-96.039 42.998-96.039 96.039c0 53.041 42.998 96.039 96.039 96.039s96.039-42.998 96.039-96.039zM256.015 127.99c0-53.041-42.998-96.039-96.039-96.039s-96.039 42.998-96.039 96.039c0 53.041 42.998 96.039 96.039 96.039s96.039-42.998 96.039-96.039z" />
|
||||||
|
<glyph unicode="" glyph-name="grid" d="M64.059 48.925v274.364c0 14.39 4.781 25.902 14.342 35.495s21.035 14.39 35.377 15.349h273.451c13.386 0 24.859-4.797 35.377-15.349s15.298-22.064 14.342-35.495v-274.364c0-13.43-4.781-24.942-14.342-34.535s-21.035-14.39-35.377-14.39h-273.451c-14.342 0-25.815 4.797-35.377 14.39s-14.342 21.105-14.342 34.535zM64.059 572.711v274.364c0 13.43 4.781 24.942 14.342 34.535s21.035 14.39 35.377 14.39h273.451c13.386 0 24.859-4.797 35.377-14.39s15.298-21.105 14.342-34.535v-274.364c0-14.39-4.781-25.902-14.342-35.495s-21.035-14.39-35.377-15.349h-273.451c-13.386 0-24.859 4.797-35.377 15.349s-15.298 22.064-14.342 35.495zM148.197 83.461h204.61v205.293h-204.61v-205.293zM148.197 607.247h204.61v204.334h-204.61v-204.334zM587.058 48.925v274.364c0 14.39 4.781 25.902 14.342 35.495s21.035 14.39 35.377 15.349h273.451c13.386 0 24.859-4.797 35.377-15.349s15.298-22.064 14.342-35.495v-274.364c0-13.43-4.781-24.942-14.342-34.535s-21.035-14.39-35.377-14.39h-273.451c-13.386 0-24.859 4.797-35.377 14.39s-15.298 21.105-14.342 34.535zM587.058 572.711v274.364c0 13.43 4.781 24.942 14.342 34.535s21.035 14.39 35.377 14.39h273.451c14.342 0 25.815-4.797 35.377-14.39s14.342-21.105 14.342-34.535v-274.364c0-14.39-4.781-25.902-14.342-35.495s-21.035-14.39-35.377-15.349h-273.451c-13.386 0-24.859 4.797-35.377 15.349s-15.298 22.064-14.342 35.495zM671.197 83.461h205.566v205.293h-205.566v-205.293zM671.197 607.247h205.566v204.334h-205.566v-204.334z" />
|
||||||
|
<glyph unicode="" glyph-name="bracket-open" d="M473.568 179.2c0-59.098 44.467-107.789 101.76-114.432l6.682-0.576 6.758-0.192h-153.6l-6.758 0.192c-58.253 3.379-104.87 49.997-108.25 108.25l-0.192 6.758v537.6l0.192 6.758c3.226 55.91 46.349 101.107 101.299 107.635l6.95 0.614 6.758 0.192h153.6l-6.758-0.192c-55.91-3.226-101.107-46.349-107.635-101.299l-0.614-6.95-0.192-6.758v-537.6z" />
|
||||||
|
<glyph unicode="" glyph-name="bracket-close" d="M447.136 179.2c0-59.098-44.467-107.789-101.76-114.432l-6.682-0.576-6.758-0.192h153.6l6.758 0.192c58.253 3.379 104.87 49.997 108.25 108.25l0.192 6.758v537.6l-0.192 6.758c-3.226 55.91-46.349 101.107-101.299 107.635l-6.95 0.614-6.758 0.192h-153.6l6.758-0.192c55.91-3.226 101.107-46.349 107.635-101.299l0.614-6.95 0.192-6.758v-537.6z" />
|
||||||
|
<glyph unicode="" glyph-name="certificate" d="M64 960h896c35.328 0 64-28.672 64-64v-640c0-35.328-28.672-64-64-64h-350.72v64h350.72v640h-896v-640h33.28v-64h-33.28c-35.328 0-64 28.672-64 64v640c0 35.328 28.672 64 64 64zM576.048 478.878c0-123.698-100.277-223.976-223.976-223.976s-223.976 100.277-223.976 223.976c0 123.698 100.277 223.976 223.976 223.976s223.976-100.277 223.976-223.976zM511.488 239.104l64-303.104-224.32 128-223.168-128 64 303.488c45.76-30.656 100.8-48.576 160-48.576 58.944 0 113.792 17.728 159.488 48.192zM896 768c0 16.96-6.784 33.28-18.752 45.248-12.032 12.032-28.288 18.752-45.248 18.752-71.040 0-185.024 0-256 0-17.024 0-33.28-6.72-45.248-18.752-12.032-11.968-18.752-28.288-18.752-45.248s6.72-33.28 18.752-45.248c11.968-12.032 28.224-18.752 45.248-18.752 70.976 0 184.96 0 256 0 16.96 0 33.216 6.72 45.248 18.752 11.968 11.968 18.752 28.288 18.752 45.248zM896 576c0 16.96-6.784 33.28-18.752 45.248-12.032 12.032-28.288 18.752-45.248 18.752-71.040 0-57.024 0-128 0-17.024 0-33.28-6.72-45.248-18.752-12.032-11.968-18.752-28.288-18.752-45.248s6.72-33.28 18.752-45.248c11.968-12.032 28.224-18.752 45.248-18.752 70.976 0 56.96 0 128 0 16.96 0 33.216 6.72 45.248 18.752 11.968 11.968 18.752 28.288 18.752 45.248z" />
|
||||||
|
<glyph unicode="" glyph-name="icinga" d="M574.496 878.589l45.262-8.286-149.128-422.304-45.261 8.286 149.126 422.304zM896.001 590.671v-29.341l-379.111-128.001-9.78 29.341 388.891 128.001zM656 192v-43.787l-164.906 224.295 41.812 23.571 123.093-204.079zM205.566 114.412l-27.131 27.175 205.565 242.414 63.999-13.589-242.434-255.999zM192.001 639.999l-38.798 52.36 308.952-225.624-28.309-38.763-241.845 212.028zM576.418 959.103c75.061 0 136.002-60.94 136.002-136s-60.941-136-136.002-136c-75.058 0-135.999 60.94-135.999 136s60.941 136 135.999 136zM911.998 687.103c61.815 0 111.999-50.187 111.999-112 0-61.816-50.185-112-111.999-112s-111.999 50.184-111.999 112c0 61.813 50.185 112 111.999 112zM656 240.002c44.154 0 80.002-35.85 80.002-80.001 0-44.155-35.848-80.001-80.002-80.001-44.15 0-79.998 35.846-79.998 80.001 0 44.151 35.848 80.001 79.998 80.001zM143.999 224.001c79.478 0 144.002-64.526 144.002-144.002s-64.524-143.999-144.002-143.999c-79.475 0-143.999 64.524-143.999 143.999s64.524 144.002 143.999 144.002zM139.048 768.978c52.984 0 96.001-43.016 96.001-96.001 0-52.982-43.018-95.998-96.001-95.998s-95.998 43.016-95.998 95.998c0 52.985 43.014 96.001 95.998 96.001zM448 640.294c105.968 0 192-86.034 192-192.001s-86.032-191.999-192-191.999c-105.968 0-192 86.032-192 191.999s86.032 192.001 192 192.001z" />
|
||||||
|
<glyph unicode="" glyph-name="ca-circle-check" d="M177.038 352.521c-5.88-0.539-12.299-0.833-19.306-0.833-22.54 0-43.317 4.018-62.378 12.103-19.061 8.036-35.672 19.453-49.883 34.202-14.259 14.749-25.382 32.34-33.418 52.725s-12.103 43.072-12.103 68.013c0 24.941 4.165 47.727 12.495 68.405s19.6 38.22 33.81 52.725c14.21 14.504 30.968 25.48 50.324 33.026 19.306 7.497 40.23 11.27 62.77 11.27 20.384 0 40.671-3.92 60.761-11.711 20.139-7.742 36.358-19.159 48.707-34.202l-48.266-52.333c-6.468 10.241-15.043 17.591-25.774 22.148s-22.001 6.86-33.81 6.86c-11.809 0-22.932-2.401-33.418-7.252-10.437-4.851-19.453-11.515-26.95-20.139-7.497-8.575-13.279-18.767-17.297-30.576s-6.076-24.696-6.076-38.613c0-13.965 2.058-26.999 6.076-39.054 4.018-12.103 9.8-22.295 17.297-30.576 7.497-8.33 16.219-14.896 26.166-19.747 9.898-4.802 21.070-7.252 33.369-7.252 13.965 0 26.313 2.989 37.044 8.869 8.575 4.851 15.827 11.025 21.756 18.522l-41.896-96.58zM484.864 365.888l-18.752 49.408h-123.2l-23.296-63.616h-82.944l132.8 321.984h74.88l90.688-222.4c-21.632-25.92-38.336-54.336-50.176-85.376zM405.696 587.52l-40.192-110.272h79.68l-39.488 110.272zM1024 254.976c-2.176-72.512-27.456-132.992-75.84-181.504-48.384-48.576-108.672-73.344-180.992-74.496-72.256 1.152-132.288 25.92-180.096 74.496-47.808 48.512-72.832 108.992-75.072 181.504 2.24 72.512 27.264 133.056 75.072 181.568s107.84 73.344 180.096 74.432c72.32-1.088 132.608-25.92 180.992-74.432s73.664-109.056 75.84-181.568zM966.144 378.752c-0.512 0.704-1.088 1.344-1.728 1.92-22.656 22.72-59.52 22.72-82.176 0l-80.448-80.32-33.024-76.608c0 0-25.6 65.728-25.6 65.728l-29.312 29.312c-22.656 22.656-59.52 22.656-82.176 0-22.72-22.72-22.72-59.52 0-82.24l94.272-94.272c11.2-11.2 25.856-16.832 40.512-16.96 0.448 0 0.896 0 1.28 0 14.656 0.192 29.248 5.824 40.384 16.96l156.224 156.224c22.016 22.016 22.656 57.472 1.792 80.256z" />
|
||||||
|
<glyph unicode="" glyph-name="refresh-cert" d="M319.936 512h384v-257.088h-384v257.088zM383.936 544v96c0 35.328 28.672 64 64 64h128c35.328 0 64-28.672 64-64v-96h-256zM575.936 640h-128v-96h128v96zM192.448 235.136c68.864-103.168 186.368-171.136 319.552-171.136 141.568 0 265.344 76.8 331.904 190.912h142.4c-76.288-187.008-260.032-318.912-474.304-318.912-180.544 0-339.392 93.632-430.592 235.008l-81.536-47.104 2.112 324.096 281.472-160.384-91.008-52.48zM833.472 657.92c-68.544 104.832-187.008 174.080-321.472 174.080-167.040 0-309.376-106.944-362.112-256h-133.76c56.896 220.736 257.472 384 495.872 384 181.824 0 341.632-94.976 432.448-237.952l79.68 45.952-2.112-324.096-281.472 160.384 92.928 53.632z" />
|
||||||
|
<glyph unicode="" glyph-name="th-list" d="M64.491 172.602c0-19.125 6.694-35.381 20.081-48.768s29.644-20.081 48.768-20.081h30.6c19.125 0 35.381 6.694 48.768 20.081s20.081 29.644 20.081 48.768c0 19.125-6.694 35.381-20.081 48.768s-29.644 20.081-48.768 20.081h-30.6c-19.125 0-35.381-6.694-48.768-20.081s-20.081-29.644-20.081-48.768zM64.491 448c0-19.125 6.694-35.381 20.081-48.768s29.644-20.081 48.768-20.081h30.6c19.125 0 35.381 6.694 48.768 20.081s20.081 29.644 20.081 48.768c0 19.125-6.694 35.381-20.081 48.768s-29.644 20.081-48.768 20.081h-30.6c-19.125 0-35.381-6.694-48.768-20.081s-20.081-29.644-20.081-48.768zM64.491 723.398c0-19.125 6.694-35.381 20.081-48.768s29.644-20.081 48.768-20.081h30.6c19.125 0 35.381 6.694 48.768 20.081s20.081 29.644 20.081 48.768c0 19.125-6.694 35.381-20.081 48.768s-29.644 20.081-48.768 20.081h-30.6c-19.125 0-35.381-6.694-48.768-20.081s-20.081-29.644-20.081-48.768zM288.252 172.602c0-19.125 6.694-35.381 20.081-48.768s29.644-20.081 48.768-20.081h534.54c19.125 0 35.381 6.694 48.768 20.081s20.081 29.644 20.081 48.768c0 19.125-6.694 35.381-20.081 48.768s-29.644 20.081-48.768 20.081h-534.54c-19.125 0-35.381-6.694-48.768-20.081s-20.081-29.644-20.081-48.768zM288.252 448c0-19.125 6.694-35.381 20.081-48.768s29.644-20.081 48.768-20.081h534.54c19.125 0 35.381 6.694 48.768 20.081s20.081 29.644 20.081 48.768c0 19.125-6.694 35.381-20.081 48.768s-29.644 20.081-48.768 20.081h-534.54c-19.125 0-35.381-6.694-48.768-20.081s-20.081-29.644-20.081-48.768zM288.252 723.398c0-19.125 6.694-35.381 20.081-48.768s29.644-20.081 48.768-20.081h534.54c19.125 0 35.381 6.694 48.768 20.081s20.081 29.644 20.081 48.768c0 19.125-6.694 35.381-20.081 48.768s-29.644 20.081-48.768 20.081h-534.54c-19.125 0-35.381-6.694-48.768-20.081s-20.081-29.644-20.081-48.768z" />
|
||||||
|
<glyph unicode="" glyph-name="filter-check-circle" d="M7.232 869.504c11.776 24.896 36.672 40.704 64.192 40.704h768c27.584 0 52.48-15.808 64.192-40.704s8.192-54.208-9.216-75.52l-189.376-231.488c-142.592-29.312-249.6-155.392-249.6-306.496 0-48.704 11.2-94.912 31.104-136-2.816 1.408-5.696 3.2-8.32 5.184l-113.792 85.312c-14.4 10.688-22.784 27.52-22.784 45.504v140.608l-325.312 397.504c-17.216 21.184-20.992 50.688-9.088 75.392zM1024 254.976c-2.176-72.512-27.456-132.992-75.84-181.504-48.384-48.576-108.672-73.344-180.992-74.496-72.256 1.152-132.288 25.92-180.096 74.496-47.808 48.512-72.832 108.992-75.072 181.504 2.24 72.512 27.264 133.056 75.072 181.568s107.84 73.344 180.096 74.432c72.32-1.088 132.608-25.92 180.992-74.432s73.664-109.056 75.84-181.568zM966.144 378.752c-0.512 0.704-1.088 1.344-1.728 1.92-22.656 22.72-59.52 22.72-82.176 0l-80.448-80.32-33.024-76.608c0 0-25.6 65.728-25.6 65.728l-29.312 29.312c-22.656 22.656-59.52 22.656-82.176 0-22.72-22.72-22.72-59.52 0-82.24l94.272-94.272c11.2-11.2 25.856-16.832 40.512-16.96 0.448 0 0.896 0 1.28 0 14.656 0.192 29.248 5.824 40.384 16.96l156.224 156.224c22.016 22.016 22.656 57.472 1.792 80.256z" />
|
||||||
|
</font></defs></svg>
|
After Width: | Height: | Size: 13 KiB |
BIN
asset/static/font/icinga-icons/fonts/Icinga-Icons.ttf
Normal file
BIN
asset/static/font/icinga-icons/fonts/Icinga-Icons.woff
Normal file
1
asset/static/font/icinga-icons/selection.json
Normal file
14
asset/static/font/icinga-icons/src/bracket-close.svg
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-120,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,120,134)">
|
||||||
|
<rect id="bracket-close" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<g id="bracket-close1" serif:id="bracket-close">
|
||||||
|
<g transform="matrix(2.4,0,0,2.4,20.746,8)">
|
||||||
|
<path d="M3,17C3,18.539 1.842,19.807 0.35,19.98L0.176,19.995L0,20L4,20L4.176,19.995C5.693,19.907 6.907,18.693 6.995,17.176L7,17L7,3L6.995,2.824C6.911,1.368 5.788,0.191 4.357,0.021L4.176,0.005L4,0L0,0L0.176,0.005C1.632,0.089 2.809,1.212 2.979,2.643L2.995,2.824L3,3L3,17Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
14
asset/static/font/icinga-icons/src/bracket-open.svg
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-100,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,100,134)">
|
||||||
|
<rect id="bracket-open" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<g id="bracket-open1" serif:id="bracket-open">
|
||||||
|
<g transform="matrix(-2.4,0,0,2.4,36.846,8)">
|
||||||
|
<path d="M3,17C3,18.539 1.842,19.807 0.35,19.98L0.176,19.995L0,20L4,20L4.176,19.995C5.693,19.907 6.907,18.693 6.995,17.176L7,17L7,3L6.995,2.824C6.911,1.368 5.788,0.191 4.357,0.021L4.176,0.005L4,0L0,0L0.176,0.005C1.632,0.089 2.809,1.212 2.979,2.643L2.995,2.824L3,3L3,17Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
20
asset/static/font/icinga-icons/src/ca-check-circle.svg
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-216,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,216,134)">
|
||||||
|
<rect id="filter-circle-check" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<g id="filter-circle-check1" serif:id="filter-circle-check">
|
||||||
|
<g transform="matrix(3.06254,0,0,3.06254,-937.661,-403.905)">
|
||||||
|
<path d="M309.784,144.283C309.664,144.294 309.533,144.3 309.39,144.3C308.93,144.3 308.506,144.218 308.117,144.053C307.728,143.889 307.389,143.656 307.099,143.355C306.808,143.054 306.581,142.695 306.417,142.279C306.253,141.863 306.17,141.4 306.17,140.891C306.17,140.382 306.255,139.917 306.425,139.495C306.595,139.073 306.825,138.715 307.115,138.419C307.405,138.123 307.747,137.899 308.142,137.745C308.536,137.592 308.963,137.515 309.423,137.515C309.839,137.515 310.253,137.595 310.663,137.754C311.074,137.912 311.405,138.145 311.657,138.452L310.672,139.52C310.54,139.311 310.365,139.161 310.146,139.068C309.927,138.975 309.697,138.928 309.456,138.928C309.215,138.928 308.988,138.977 308.774,139.076C308.561,139.175 308.377,139.311 308.224,139.487C308.071,139.662 307.953,139.87 307.871,140.111C307.789,140.352 307.747,140.615 307.747,140.899C307.747,141.184 307.789,141.45 307.871,141.696C307.953,141.943 308.071,142.151 308.224,142.32C308.377,142.49 308.555,142.624 308.758,142.723C308.96,142.821 309.188,142.871 309.439,142.871C309.724,142.871 309.976,142.81 310.195,142.69C310.37,142.591 310.518,142.465 310.639,142.312L309.784,144.283Z" style="fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,-1224.68,-536)">
|
||||||
|
<path d="M313.746,143.283L313.453,142.511L311.528,142.511L311.164,143.505L309.868,143.505L311.943,138.474L313.113,138.474L314.53,141.949C314.192,142.354 313.931,142.798 313.746,143.283ZM312.509,139.82L311.881,141.543L313.126,141.543L312.509,139.82Z" style="fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,-1224.68,-536)">
|
||||||
|
<path d="M322.17,145.016C322.136,146.149 321.741,147.094 320.985,147.852C320.229,148.611 319.287,148.998 318.157,149.016C317.028,148.998 316.09,148.611 315.343,147.852C314.596,147.094 314.205,146.149 314.17,145.016C314.205,143.883 314.596,142.937 315.343,142.179C316.09,141.421 317.028,141.033 318.157,141.016C319.287,141.033 320.229,141.421 320.985,142.179C321.741,142.937 322.136,143.883 322.17,145.016ZM321.266,143.082C321.258,143.071 321.249,143.061 321.239,143.052C320.885,142.697 320.309,142.697 319.955,143.052L318.698,144.307L318.182,145.504C318.182,145.504 317.782,144.477 317.782,144.477L317.324,144.019C316.97,143.665 316.394,143.665 316.04,144.019C315.685,144.374 315.685,144.949 316.04,145.304L317.513,146.777C317.688,146.952 317.917,147.04 318.146,147.042C318.153,147.042 318.16,147.042 318.166,147.042C318.395,147.039 318.623,146.951 318.797,146.777L321.238,144.336C321.582,143.992 321.592,143.438 321.266,143.082Z" style="fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.4 KiB |
26
asset/static/font/icinga-icons/src/certificate.svg
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-242,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,242,134)">
|
||||||
|
<rect id="certificate" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<g id="certificate1" serif:id="certificate">
|
||||||
|
<g transform="matrix(4,0,0,4,-1329.92,-536)">
|
||||||
|
<path d="M333.48,134L347.48,134C348.032,134 348.48,134.448 348.48,135L348.48,145C348.48,145.552 348.032,146 347.48,146L342,146L342,145L347.48,145L347.48,135L333.48,135L333.48,145L334,145L334,146L333.48,146C332.928,146 332.48,145.552 332.48,145L332.48,135C332.48,134.448 332.928,134 333.48,134Z"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4.32185,0,0,4.32185,-1439.2,-580.832)">
|
||||||
|
<circle cx="338.097" cy="141.352" r="3.239"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,-1329.92,-536)">
|
||||||
|
<path d="M340.472,145.264L341.472,150L337.967,148L334.48,150L335.48,145.258C336.195,145.737 337.055,146.017 337.98,146.017C338.901,146.017 339.758,145.74 340.472,145.264Z" style="fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,-1329.92,-536)">
|
||||||
|
<path d="M346.48,137C346.48,136.735 346.374,136.48 346.187,136.293C345.999,136.105 345.745,136 345.48,136C344.37,136 342.589,136 341.48,136C341.214,136 340.96,136.105 340.773,136.293C340.585,136.48 340.48,136.735 340.48,137C340.48,137.265 340.585,137.52 340.773,137.707C340.96,137.895 341.214,138 341.48,138C342.589,138 344.37,138 345.48,138C345.745,138 345.999,137.895 346.187,137.707C346.374,137.52 346.48,137.265 346.48,137Z"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,-1329.92,-524)">
|
||||||
|
<path d="M346.48,137C346.48,136.735 346.374,136.48 346.187,136.293C345.999,136.105 345.745,136 345.48,136C344.37,136 344.589,136 343.48,136C343.214,136 342.96,136.105 342.773,136.293C342.585,136.48 342.48,136.735 342.48,137C342.48,137.265 342.585,137.52 342.773,137.707C342.96,137.895 343.214,138 343.48,138C344.589,138 344.37,138 345.48,138C345.745,138 345.999,137.895 346.187,137.707C346.374,137.52 346.48,137.265 346.48,137Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
17
asset/static/font/icinga-icons/src/filter-check-circle.svg
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-162,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,162,134)">
|
||||||
|
<rect id="filter-circle-check" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<g id="filter-circle-check1" serif:id="filter-circle-check">
|
||||||
|
<g transform="matrix(4,0,0,4,-1008,-536)">
|
||||||
|
<path d="M252.113,135.414C252.297,135.025 252.686,134.778 253.116,134.778L265.116,134.778C265.547,134.778 265.936,135.025 266.119,135.414C266.302,135.803 266.247,136.261 265.975,136.594L263.016,140.211C260.788,140.669 259.116,142.639 259.116,145C259.116,145.761 259.291,146.483 259.602,147.125C259.558,147.103 259.513,147.075 259.472,147.044L257.694,145.711C257.469,145.544 257.338,145.281 257.338,145L257.338,142.803L252.255,136.592C251.986,136.261 251.927,135.8 252.113,135.414Z" style="fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,-1224.68,-536)">
|
||||||
|
<path d="M322.17,145.016C322.136,146.149 321.741,147.094 320.985,147.852C320.229,148.611 319.287,148.998 318.157,149.016C317.028,148.998 316.09,148.611 315.343,147.852C314.596,147.094 314.205,146.149 314.17,145.016C314.205,143.883 314.596,142.937 315.343,142.179C316.09,141.421 317.028,141.033 318.157,141.016C319.287,141.033 320.229,141.421 320.985,142.179C321.741,142.937 322.136,143.883 322.17,145.016ZM321.266,143.082C321.258,143.071 321.249,143.061 321.239,143.052C320.885,142.697 320.309,142.697 319.955,143.052L318.698,144.307L318.182,145.504C318.182,145.504 317.782,144.477 317.782,144.477L317.324,144.019C316.97,143.665 316.394,143.665 316.04,144.019C315.685,144.374 315.685,144.949 316.04,145.304L317.513,146.777C317.688,146.952 317.917,147.04 318.146,147.042C318.153,147.042 318.16,147.042 318.166,147.042C318.395,147.039 318.623,146.951 318.797,146.777L321.238,144.336C321.582,143.992 321.592,143.438 321.266,143.082Z" style="fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
49
asset/static/font/icinga-icons/src/icinga.svg
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-140,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,140,134)">
|
||||||
|
<rect id="icinga" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<clipPath id="_clip1">
|
||||||
|
<rect id="icinga1" serif:id="icinga" x="0" y="0" width="64" height="64"/>
|
||||||
|
</clipPath>
|
||||||
|
<g clip-path="url(#_clip1)">
|
||||||
|
<g transform="matrix(0.028493,0,0,0.028493,1.07196,0)">
|
||||||
|
<g transform="matrix(4,0,0,4,0,0)">
|
||||||
|
<path d="M305.637,44.644L330.458,49.188L248.679,280.771L223.859,276.227L305.637,44.644Z"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,0,0)">
|
||||||
|
<path d="M481.944,202.533L481.944,218.623L274.047,288.816L268.684,272.726L481.944,202.533Z"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,0,0)">
|
||||||
|
<path d="M350.332,421.156L350.332,445.168L259.901,322.169L282.83,309.243L350.332,421.156Z"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,0,0)">
|
||||||
|
<path d="M103.323,463.704L88.445,448.802L201.173,315.867L236.269,323.319L103.323,463.704Z"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,0,0)">
|
||||||
|
<path d="M95.884,175.482L74.608,146.769L244.031,270.497L228.507,291.754L95.884,175.482Z"/>
|
||||||
|
</g>
|
||||||
|
<g id="Orb-1" serif:id="Orb 1" transform="matrix(6.01058,0,0,6.08489,-684.883,1.9677)">
|
||||||
|
<path d="M318.047,0C345.44,0 367.68,21.968 367.68,49.026C367.68,76.084 345.44,98.052 318.047,98.052C290.655,98.052 268.415,76.084 268.415,49.026C268.415,21.968 290.655,0 318.047,0Z"/>
|
||||||
|
</g>
|
||||||
|
<g id="Orb-2" serif:id="Orb 2" transform="matrix(6.2603,0,0,6.3377,-1189.12,-493.419)">
|
||||||
|
<path d="M503.488,172.306C525.147,172.306 542.731,189.676 542.731,211.07C542.731,232.465 525.147,249.834 503.488,249.834C481.829,249.834 464.245,232.465 464.245,211.07C464.245,189.676 481.829,172.306 503.488,172.306Z"/>
|
||||||
|
</g>
|
||||||
|
<g id="Orb-3" serif:id="Orb 3" transform="matrix(9.01966,0,0,9.13117,-1337.13,-2229.08)">
|
||||||
|
<path d="M303.61,417.078C314.348,417.078 323.066,425.69 323.066,436.296C323.066,446.903 314.348,455.514 303.61,455.514C292.873,455.514 284.155,446.903 284.155,436.296C284.155,425.69 292.873,417.078 303.61,417.078Z"/>
|
||||||
|
</g>
|
||||||
|
<g id="Orb-4" serif:id="Orb 4" transform="matrix(4.93841,0,0,4.99946,-37.6219,-561.24)">
|
||||||
|
<path d="M63.961,435.181C99.263,435.181 127.923,463.492 127.923,498.362C127.923,533.232 99.263,561.542 63.961,561.542C28.66,561.542 0,533.232 0,498.362C0,463.492 28.66,435.181 63.961,435.181Z"/>
|
||||||
|
</g>
|
||||||
|
<g id="Orb-5" serif:id="Orb 5" transform="matrix(6.84016,0,0,6.92473,-189.854,-460.346)">
|
||||||
|
<path d="M66.846,126.988C83.837,126.988 97.632,140.614 97.632,157.398C97.632,174.181 83.837,187.807 66.846,187.807C49.855,187.807 36.061,174.181 36.061,157.398C36.061,140.614 49.855,126.988 66.846,126.988Z"/>
|
||||||
|
</g>
|
||||||
|
<g id="Orb-Center" serif:id="Orb Center" transform="matrix(4.34182,0,0,4.3955,19.5912,-110.981)">
|
||||||
|
<path d="M213.156,184.794C266.692,184.794 310.156,227.728 310.156,280.61C310.156,333.492 266.692,376.425 213.156,376.425C159.62,376.425 116.156,333.492 116.156,280.61C116.156,227.728 159.62,184.794 213.156,184.794Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.0 KiB |
37
asset/static/font/icinga-icons/src/list-view-default.svg
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-40,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,40,134)">
|
||||||
|
<rect id="list-view-default" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<clipPath id="_clip1">
|
||||||
|
<rect id="list-view-default1" serif:id="list-view-default" x="0" y="0" width="64" height="64"/>
|
||||||
|
</clipPath>
|
||||||
|
<g clip-path="url(#_clip1)">
|
||||||
|
<g id="_16-list-view-default" serif:id="16/list-view-default" transform="matrix(1.02005,0,0,1.02005,-2.30518,-1.16359)">
|
||||||
|
<g transform="matrix(3.92139,0,0,3.92139,2.25988,-492.954)">
|
||||||
|
<rect x="0" y="126" width="16" height="16" style="fill:none;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(5.76344,0,0,5.76344,-25.17,-51.3628)">
|
||||||
|
<circle cx="6.46" cy="11.151" r="1.021"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.802102,0,0,0.961081,-54.422,-3.54908)">
|
||||||
|
<rect x="100" y="11" width="44" height="12.241"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.802102,0,0,0.961081,-54.422,16.0579)">
|
||||||
|
<rect x="100" y="11" width="44" height="12.241"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.802102,0,0,0.961081,-54.422,35.6648)">
|
||||||
|
<rect x="100" y="11" width="44" height="12.241"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(5.76344,0,0,5.76344,-25.17,-31.7558)">
|
||||||
|
<circle cx="6.46" cy="11.151" r="1.021"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(5.76344,0,0,5.76344,-25.17,-12.1489)">
|
||||||
|
<circle cx="6.46" cy="11.151" r="1.021"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
34
asset/static/font/icinga-icons/src/list-view-detailed.svg
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-20,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,20,134)">
|
||||||
|
<rect id="list-view-detailed" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<g id="list-view-detailed1" serif:id="list-view-detailed">
|
||||||
|
<g id="_16-list-view-detailed" serif:id="16/list-view-detailed">
|
||||||
|
<g transform="matrix(4,0,0,4,0,-504)">
|
||||||
|
<rect x="0" y="126" width="16" height="16" style="fill:none;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.00393,0,0,1.07437,1.27514,2.18191)">
|
||||||
|
<rect x="18.652" y="5.434" width="39.843" height="11.132"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.00393,0,0,1.03883,1.27514,14.5728)">
|
||||||
|
<rect x="18.652" y="9.075" width="39.843" height="3.85"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(5.87898,0,0,5.87898,-27.9798,-51.5763)">
|
||||||
|
<circle cx="6.46" cy="11.151" r="1.021"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(5.87898,0,0,5.87898,-27.9798,-23.556)">
|
||||||
|
<circle cx="6.46" cy="11.151" r="1.021"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.00393,0,0,1.078,1.27514,30.1419)">
|
||||||
|
<rect x="18.652" y="5.434" width="39.843" height="11.132"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.00393,0,0,1.03533,1.27513,42.6113)">
|
||||||
|
<rect x="18.652" y="9.068" width="39.843" height="3.863"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
46
asset/static/font/icinga-icons/src/list-view-minimal.svg
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,0,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,0,134)">
|
||||||
|
<rect id="list-view-minimal" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<g id="list-view-minimal1" serif:id="list-view-minimal">
|
||||||
|
<g id="_16-list-view-minimal" serif:id="16/list-view-minimal">
|
||||||
|
<g transform="matrix(4,0,0,4,0,-504)">
|
||||||
|
<rect x="0" y="126" width="16" height="16" style="fill:none;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(3.91932,0,0,3.91932,-17.3199,-35.704)">
|
||||||
|
<circle cx="6.46" cy="11.151" r="1.021"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(3.91932,0,0,3.91932,-17.3199,-23.6838)">
|
||||||
|
<circle cx="6.46" cy="11.151" r="1.021"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(3.91932,0,0,3.91932,-17.3199,-11.6838)">
|
||||||
|
<circle cx="6.46" cy="11.151" r="1.021"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.02326,0,0,0.6611,-1.44408,0.727897)">
|
||||||
|
<rect x="20.957" y="7.975" width="39.091" height="6.051"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.02326,0,0,0.6611,-1.44408,24.7481)">
|
||||||
|
<rect x="20.957" y="7.975" width="39.091" height="6.051"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.02326,0,0,0.6611,-1.44408,12.7481)">
|
||||||
|
<rect x="20.957" y="7.975" width="39.091" height="6.051"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.02326,0,0,0.6611,-1.44408,36.7481)">
|
||||||
|
<rect x="20.957" y="7.975" width="39.091" height="6.051"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.02326,0,0,0.6611,-1.44408,48.7481)">
|
||||||
|
<rect x="20.957" y="7.975" width="39.091" height="6.051"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(3.91932,0,0,3.91932,-17.3199,0.336422)">
|
||||||
|
<circle cx="6.46" cy="11.151" r="1.021"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(3.91932,0,0,3.91932,-17.3199,12.3162)">
|
||||||
|
<circle cx="6.46" cy="11.151" r="1.021"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
23
asset/static/font/icinga-icons/src/refresh-cert.svg
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-268,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,268,134)">
|
||||||
|
<rect id="refresh-cert" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<clipPath id="_clip1">
|
||||||
|
<rect id="refresh-cert1" serif:id="refresh-cert" x="0" y="0" width="64" height="64"/>
|
||||||
|
</clipPath>
|
||||||
|
<g clip-path="url(#_clip1)">
|
||||||
|
<g transform="matrix(4,0,0,4,-1435.16,-536)">
|
||||||
|
<rect x="363.789" y="141" width="6" height="4.017" style="fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,-1435.16,-536)">
|
||||||
|
<path d="M364.789,140.5L364.789,139C364.789,138.448 365.237,138 365.789,138L367.789,138C368.341,138 368.789,138.448 368.789,139L368.789,140.5L364.789,140.5ZM367.789,139L365.789,139L365.789,140.5L367.789,140.5L367.789,139Z"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(4,0,0,4,-1432,-536)">
|
||||||
|
<path d="M361.007,145.326C362.083,146.938 363.919,148 366,148C368.212,148 370.146,146.8 371.186,145.017L373.411,145.017C372.219,147.939 369.348,150 366,150C363.179,150 360.697,148.537 359.272,146.328L357.998,147.064L358.031,142L362.429,144.506L361.007,145.326ZM371.023,138.72C369.952,137.082 368.101,136 366,136C363.39,136 361.166,137.671 360.342,140L358.252,140C359.141,136.551 362.275,134 366,134C368.841,134 371.338,135.484 372.757,137.718L374.002,137L373.969,142.064L369.571,139.558L371.023,138.72Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
22
asset/static/font/icinga-icons/src/th-list.svg
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-80,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,80,134)">
|
||||||
|
<rect id="th-list" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<clipPath id="_clip1">
|
||||||
|
<rect id="th-list1" serif:id="th-list" x="0" y="0" width="64" height="64"/>
|
||||||
|
</clipPath>
|
||||||
|
<g clip-path="url(#_clip1)">
|
||||||
|
<g id="th-list2" serif:id="th-list">
|
||||||
|
<g transform="matrix(5.33333,0,0,5.33333,-563.593,-880)">
|
||||||
|
<rect x="105.674" y="165" width="12" height="12" style="fill:none;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(59.7652,0,0,59.7652,4.03068,52.9178)">
|
||||||
|
<path d="M0,-0.062C0,-0.042 0.007,-0.025 0.021,-0.011C0.035,0.003 0.052,0.01 0.072,0.01L0.104,0.01C0.124,0.01 0.141,0.003 0.155,-0.011C0.169,-0.025 0.176,-0.042 0.176,-0.062C0.176,-0.082 0.169,-0.099 0.155,-0.113C0.141,-0.127 0.124,-0.134 0.104,-0.134L0.072,-0.134C0.052,-0.134 0.035,-0.127 0.021,-0.113C0.007,-0.099 0,-0.082 0,-0.062ZM0,-0.35C0,-0.33 0.007,-0.313 0.021,-0.299C0.035,-0.285 0.052,-0.278 0.072,-0.278L0.104,-0.278C0.124,-0.278 0.141,-0.285 0.155,-0.299C0.169,-0.313 0.176,-0.33 0.176,-0.35C0.176,-0.37 0.169,-0.387 0.155,-0.401C0.141,-0.415 0.124,-0.422 0.104,-0.422L0.072,-0.422C0.052,-0.422 0.035,-0.415 0.021,-0.401C0.007,-0.387 0,-0.37 0,-0.35ZM0,-0.638C0,-0.618 0.007,-0.601 0.021,-0.587C0.035,-0.573 0.052,-0.566 0.072,-0.566L0.104,-0.566C0.124,-0.566 0.141,-0.573 0.155,-0.587C0.169,-0.601 0.176,-0.618 0.176,-0.638C0.176,-0.658 0.169,-0.675 0.155,-0.689C0.141,-0.703 0.124,-0.71 0.104,-0.71L0.072,-0.71C0.052,-0.71 0.035,-0.703 0.021,-0.689C0.007,-0.675 0,-0.658 0,-0.638ZM0.234,-0.062C0.234,-0.042 0.241,-0.025 0.255,-0.011C0.269,0.003 0.286,0.01 0.306,0.01L0.865,0.01C0.885,0.01 0.902,0.003 0.916,-0.011C0.93,-0.025 0.937,-0.042 0.937,-0.062C0.937,-0.082 0.93,-0.099 0.916,-0.113C0.902,-0.127 0.885,-0.134 0.865,-0.134L0.306,-0.134C0.286,-0.134 0.269,-0.127 0.255,-0.113C0.241,-0.099 0.234,-0.082 0.234,-0.062ZM0.234,-0.35C0.234,-0.33 0.241,-0.313 0.255,-0.299C0.269,-0.285 0.286,-0.278 0.306,-0.278L0.865,-0.278C0.885,-0.278 0.902,-0.285 0.916,-0.299C0.93,-0.313 0.937,-0.33 0.937,-0.35C0.937,-0.37 0.93,-0.387 0.916,-0.401C0.902,-0.415 0.885,-0.422 0.865,-0.422L0.306,-0.422C0.286,-0.422 0.269,-0.415 0.255,-0.401C0.241,-0.387 0.234,-0.37 0.234,-0.35ZM0.234,-0.638C0.234,-0.618 0.241,-0.601 0.255,-0.587C0.269,-0.573 0.286,-0.566 0.306,-0.566L0.865,-0.566C0.885,-0.566 0.902,-0.573 0.916,-0.587C0.93,-0.601 0.937,-0.618 0.937,-0.638C0.937,-0.658 0.93,-0.675 0.916,-0.689C0.902,-0.703 0.885,-0.71 0.865,-0.71L0.306,-0.71C0.286,-0.71 0.269,-0.703 0.255,-0.689C0.241,-0.675 0.234,-0.658 0.234,-0.638Z" style="fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
21
asset/static/font/icinga-icons/src/th-thumb-empty.svg
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-60,-134)">
|
||||||
|
<g transform="matrix(0.25,0,0,0.25,60,134)">
|
||||||
|
<rect id="grid" x="0" y="0" width="64" height="64" style="fill:none;"/>
|
||||||
|
<g id="grid1" serif:id="grid">
|
||||||
|
<g>
|
||||||
|
<g transform="matrix(5.33333,0,0,5.33333,-320,-880)">
|
||||||
|
<g>
|
||||||
|
<rect x="60" y="165" width="12" height="12" style="fill:none;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(59.7577,0,0,59.9572,4.01886,52.985)">
|
||||||
|
<path d="M0,0.066L0,-0.22C0,-0.235 0.005,-0.247 0.015,-0.257C0.025,-0.267 0.037,-0.272 0.052,-0.273L0.338,-0.273C0.352,-0.273 0.364,-0.268 0.375,-0.257C0.386,-0.246 0.391,-0.234 0.39,-0.22L0.39,0.066C0.39,0.08 0.385,0.092 0.375,0.102C0.365,0.112 0.353,0.117 0.338,0.117L0.052,0.117C0.037,0.117 0.025,0.112 0.015,0.102C0.005,0.092 0,0.08 0,0.066ZM0,-0.48L0,-0.766C0,-0.78 0.005,-0.792 0.015,-0.802C0.025,-0.812 0.037,-0.817 0.052,-0.817L0.338,-0.817C0.352,-0.817 0.364,-0.812 0.375,-0.802C0.386,-0.792 0.391,-0.78 0.39,-0.766L0.39,-0.48C0.39,-0.465 0.385,-0.453 0.375,-0.443C0.365,-0.433 0.353,-0.428 0.338,-0.427L0.052,-0.427C0.038,-0.427 0.026,-0.432 0.015,-0.443C0.004,-0.454 -0.001,-0.466 0,-0.48ZM0.088,0.03L0.302,0.03L0.302,-0.184L0.088,-0.184L0.088,0.03ZM0.088,-0.516L0.302,-0.516L0.302,-0.729L0.088,-0.729L0.088,-0.516ZM0.547,0.066L0.547,-0.22C0.547,-0.235 0.552,-0.247 0.562,-0.257C0.572,-0.267 0.584,-0.272 0.599,-0.273L0.885,-0.273C0.899,-0.273 0.911,-0.268 0.922,-0.257C0.933,-0.246 0.938,-0.234 0.937,-0.22L0.937,0.066C0.937,0.08 0.932,0.092 0.922,0.102C0.912,0.112 0.9,0.117 0.885,0.117L0.599,0.117C0.585,0.117 0.573,0.112 0.562,0.102C0.551,0.092 0.546,0.08 0.547,0.066ZM0.547,-0.48L0.547,-0.766C0.547,-0.78 0.552,-0.792 0.562,-0.802C0.572,-0.812 0.584,-0.817 0.599,-0.817L0.885,-0.817C0.9,-0.817 0.912,-0.812 0.922,-0.802C0.932,-0.792 0.937,-0.78 0.937,-0.766L0.937,-0.48C0.937,-0.465 0.932,-0.453 0.922,-0.443C0.912,-0.433 0.9,-0.428 0.885,-0.427L0.599,-0.427C0.585,-0.427 0.573,-0.432 0.562,-0.443C0.551,-0.454 0.546,-0.466 0.547,-0.48ZM0.635,0.03L0.85,0.03L0.85,-0.184L0.635,-0.184L0.635,0.03ZM0.635,-0.516L0.85,-0.516L0.85,-0.729L0.635,-0.729L0.635,-0.516Z" style="fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
62
asset/static/font/icinga-icons/style.css
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Icinga-Icons';
|
||||||
|
src:
|
||||||
|
url('fonts/Icinga-Icons.ttf?xnw9vw') format('truetype'),
|
||||||
|
url('fonts/Icinga-Icons.woff?xnw9vw') format('woff'),
|
||||||
|
url('fonts/Icinga-Icons.svg?xnw9vw#Icinga-Icons') format('svg');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="iicon-"], [class*=" iicon-"] {
|
||||||
|
/* use !important to prevent issues with browser extensions that change fonts */
|
||||||
|
font-family: 'Icinga-Icons' !important;
|
||||||
|
speak: never;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
font-variant: normal;
|
||||||
|
text-transform: none;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
/* Better Font Rendering =========== */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iicon-certificate:before {
|
||||||
|
content: "\e906";
|
||||||
|
}
|
||||||
|
.iicon-filter-check-circle:before {
|
||||||
|
content: "\e90b";
|
||||||
|
}
|
||||||
|
.iicon-ca-check-circle:before {
|
||||||
|
content: "\e908";
|
||||||
|
}
|
||||||
|
.iicon-refresh-cert:before {
|
||||||
|
content: "\e909";
|
||||||
|
}
|
||||||
|
.iicon-th-list:before {
|
||||||
|
content: "\e90a";
|
||||||
|
}
|
||||||
|
.iicon-icinga:before {
|
||||||
|
content: "\e907";
|
||||||
|
}
|
||||||
|
.iicon-list-view-minimal:before {
|
||||||
|
content: "\e900";
|
||||||
|
}
|
||||||
|
.iicon-list-view-detailed:before {
|
||||||
|
content: "\e901";
|
||||||
|
}
|
||||||
|
.iicon-list-view-default:before {
|
||||||
|
content: "\e902";
|
||||||
|
}
|
||||||
|
.iicon-grid:before {
|
||||||
|
content: "\e903";
|
||||||
|
}
|
||||||
|
.iicon-bracket-open:before {
|
||||||
|
content: "\e904";
|
||||||
|
}
|
||||||
|
.iicon-bracket-close:before {
|
||||||
|
content: "\e905";
|
||||||
|
}
|
1
asset/static/img/select-icon-text-color.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="32" viewBox="0 0 24 32" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m5.20126707.78766623 4.45386238 4.20402191c.16721345.15783356.16291017.40979541-.00961164.56277256-.081158.0719638-.18974398.11220597-.3027668.11220597h-8.90772462c-.24025844 0-.43502639-.17818569-.43502639-.39798892 0-.10340014.04398717-.20274128.12264801-.27698961l4.45386234-4.20402191c.16721345-.15783357.44262326-.16177048.61514507-.00879333.00325382.00288518.00645805.00581661.00961165.00879333z" fill="#282E39" transform="matrix(1 0 0 -1 7 20.666667)"/></svg>
|
After Width: | Height: | Size: 559 B |
1
asset/static/img/select-icon.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="32" viewBox="0 0 24 32" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m5.20126707.78766623 4.45386238 4.20402191c.16721345.15783356.16291017.40979541-.00961164.56277256-.081158.0719638-.18974398.11220597-.3027668.11220597h-8.90772462c-.24025844 0-.43502639-.17818569-.43502639-.39798892 0-.10340014.04398717-.20274128.12264801-.27698961l4.45386234-4.20402191c.16721345-.15783357.44262326-.16177048.61514507-.00879333.00325382.00288518.00645805.00581661.00961165.00879333z" fill="#00c3ed" transform="matrix(1 0 0 -1 7 20.666667)"/></svg>
|
After Width: | Height: | Size: 558 B |
1775
composer.lock
generated
Normal file
25
vendor/autoload.php
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
if (PHP_VERSION_ID < 50600) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, $err);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo $err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trigger_error(
|
||||||
|
$err,
|
||||||
|
E_USER_ERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
|
return ComposerAutoloaderInit20d4022bc196691807f55d4a47c06474::getLoader();
|
20
vendor/brick/math/LICENSE
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2013-present Benjamin Morel
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
35
vendor/brick/math/composer.json
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "brick/math",
|
||||||
|
"description": "Arbitrary-precision arithmetic library",
|
||||||
|
"type": "library",
|
||||||
|
"keywords": [
|
||||||
|
"Brick",
|
||||||
|
"Math",
|
||||||
|
"Arbitrary-precision",
|
||||||
|
"Arithmetic",
|
||||||
|
"BigInteger",
|
||||||
|
"BigDecimal",
|
||||||
|
"BigRational",
|
||||||
|
"Bignum"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1 || ^8.0",
|
||||||
|
"ext-json": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",
|
||||||
|
"php-coveralls/php-coveralls": "^2.2",
|
||||||
|
"vimeo/psalm": "4.9.2"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Brick\\Math\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Brick\\Math\\Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
895
vendor/brick/math/src/BigDecimal.php
vendored
Normal file
@ -0,0 +1,895 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math;
|
||||||
|
|
||||||
|
use Brick\Math\Exception\DivisionByZeroException;
|
||||||
|
use Brick\Math\Exception\MathException;
|
||||||
|
use Brick\Math\Exception\NegativeNumberException;
|
||||||
|
use Brick\Math\Internal\Calculator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immutable, arbitrary-precision signed decimal numbers.
|
||||||
|
*
|
||||||
|
* @psalm-immutable
|
||||||
|
*/
|
||||||
|
final class BigDecimal extends BigNumber
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The unscaled value of this decimal number.
|
||||||
|
*
|
||||||
|
* This is a string of digits with an optional leading minus sign.
|
||||||
|
* No leading zero must be present.
|
||||||
|
* No leading minus sign must be present if the value is 0.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The scale (number of digits after the decimal point) of this decimal number.
|
||||||
|
*
|
||||||
|
* This must be zero or more.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $scale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protected constructor. Use a factory method to obtain an instance.
|
||||||
|
*
|
||||||
|
* @param string $value The unscaled value, validated.
|
||||||
|
* @param int $scale The scale, validated.
|
||||||
|
*/
|
||||||
|
protected function __construct(string $value, int $scale = 0)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
$this->scale = $scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a BigDecimal of the given value.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $value
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*
|
||||||
|
* @throws MathException If the value cannot be converted to a BigDecimal.
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function of($value) : BigNumber
|
||||||
|
{
|
||||||
|
return parent::of($value)->toBigDecimal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a BigDecimal from an unscaled value and a scale.
|
||||||
|
*
|
||||||
|
* Example: `(12345, 3)` will result in the BigDecimal `12.345`.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $value The unscaled value. Must be convertible to a BigInteger.
|
||||||
|
* @param int $scale The scale of the number, positive or zero.
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If the scale is negative.
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function ofUnscaledValue($value, int $scale = 0) : BigDecimal
|
||||||
|
{
|
||||||
|
if ($scale < 0) {
|
||||||
|
throw new \InvalidArgumentException('The scale cannot be negative.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BigDecimal((string) BigInteger::of($value), $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a BigDecimal representing zero, with a scale of zero.
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function zero() : BigDecimal
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @psalm-suppress ImpureStaticVariable
|
||||||
|
* @var BigDecimal|null $zero
|
||||||
|
*/
|
||||||
|
static $zero;
|
||||||
|
|
||||||
|
if ($zero === null) {
|
||||||
|
$zero = new BigDecimal('0');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a BigDecimal representing one, with a scale of zero.
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function one() : BigDecimal
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @psalm-suppress ImpureStaticVariable
|
||||||
|
* @var BigDecimal|null $one
|
||||||
|
*/
|
||||||
|
static $one;
|
||||||
|
|
||||||
|
if ($one === null) {
|
||||||
|
$one = new BigDecimal('1');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $one;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a BigDecimal representing ten, with a scale of zero.
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function ten() : BigDecimal
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @psalm-suppress ImpureStaticVariable
|
||||||
|
* @var BigDecimal|null $ten
|
||||||
|
*/
|
||||||
|
static $ten;
|
||||||
|
|
||||||
|
if ($ten === null) {
|
||||||
|
$ten = new BigDecimal('10');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ten;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sum of this number and the given one.
|
||||||
|
*
|
||||||
|
* The result has a scale of `max($this->scale, $that->scale)`.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigDecimal.
|
||||||
|
*
|
||||||
|
* @return BigDecimal The result.
|
||||||
|
*
|
||||||
|
* @throws MathException If the number is not valid, or is not convertible to a BigDecimal.
|
||||||
|
*/
|
||||||
|
public function plus($that) : BigDecimal
|
||||||
|
{
|
||||||
|
$that = BigDecimal::of($that);
|
||||||
|
|
||||||
|
if ($that->value === '0' && $that->scale <= $this->scale) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->value === '0' && $this->scale <= $that->scale) {
|
||||||
|
return $that;
|
||||||
|
}
|
||||||
|
|
||||||
|
[$a, $b] = $this->scaleValues($this, $that);
|
||||||
|
|
||||||
|
$value = Calculator::get()->add($a, $b);
|
||||||
|
$scale = $this->scale > $that->scale ? $this->scale : $that->scale;
|
||||||
|
|
||||||
|
return new BigDecimal($value, $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the difference of this number and the given one.
|
||||||
|
*
|
||||||
|
* The result has a scale of `max($this->scale, $that->scale)`.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigDecimal.
|
||||||
|
*
|
||||||
|
* @return BigDecimal The result.
|
||||||
|
*
|
||||||
|
* @throws MathException If the number is not valid, or is not convertible to a BigDecimal.
|
||||||
|
*/
|
||||||
|
public function minus($that) : BigDecimal
|
||||||
|
{
|
||||||
|
$that = BigDecimal::of($that);
|
||||||
|
|
||||||
|
if ($that->value === '0' && $that->scale <= $this->scale) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
[$a, $b] = $this->scaleValues($this, $that);
|
||||||
|
|
||||||
|
$value = Calculator::get()->sub($a, $b);
|
||||||
|
$scale = $this->scale > $that->scale ? $this->scale : $that->scale;
|
||||||
|
|
||||||
|
return new BigDecimal($value, $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the product of this number and the given one.
|
||||||
|
*
|
||||||
|
* The result has a scale of `$this->scale + $that->scale`.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigDecimal.
|
||||||
|
*
|
||||||
|
* @return BigDecimal The result.
|
||||||
|
*
|
||||||
|
* @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal.
|
||||||
|
*/
|
||||||
|
public function multipliedBy($that) : BigDecimal
|
||||||
|
{
|
||||||
|
$that = BigDecimal::of($that);
|
||||||
|
|
||||||
|
if ($that->value === '1' && $that->scale === 0) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->value === '1' && $this->scale === 0) {
|
||||||
|
return $that;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = Calculator::get()->mul($this->value, $that->value);
|
||||||
|
$scale = $this->scale + $that->scale;
|
||||||
|
|
||||||
|
return new BigDecimal($value, $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the result of the division of this number by the given one, at the given scale.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The divisor.
|
||||||
|
* @param int|null $scale The desired scale, or null to use the scale of this number.
|
||||||
|
* @param int $roundingMode An optional rounding mode.
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If the scale or rounding mode is invalid.
|
||||||
|
* @throws MathException If the number is invalid, is zero, or rounding was necessary.
|
||||||
|
*/
|
||||||
|
public function dividedBy($that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||||
|
{
|
||||||
|
$that = BigDecimal::of($that);
|
||||||
|
|
||||||
|
if ($that->isZero()) {
|
||||||
|
throw DivisionByZeroException::divisionByZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($scale === null) {
|
||||||
|
$scale = $this->scale;
|
||||||
|
} elseif ($scale < 0) {
|
||||||
|
throw new \InvalidArgumentException('Scale cannot be negative.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($that->value === '1' && $that->scale === 0 && $scale === $this->scale) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
$p = $this->valueWithMinScale($that->scale + $scale);
|
||||||
|
$q = $that->valueWithMinScale($this->scale - $scale);
|
||||||
|
|
||||||
|
$result = Calculator::get()->divRound($p, $q, $roundingMode);
|
||||||
|
|
||||||
|
return new BigDecimal($result, $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the exact result of the division of this number by the given one.
|
||||||
|
*
|
||||||
|
* The scale of the result is automatically calculated to fit all the fraction digits.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
|
||||||
|
*
|
||||||
|
* @return BigDecimal The result.
|
||||||
|
*
|
||||||
|
* @throws MathException If the divisor is not a valid number, is not convertible to a BigDecimal, is zero,
|
||||||
|
* or the result yields an infinite number of digits.
|
||||||
|
*/
|
||||||
|
public function exactlyDividedBy($that) : BigDecimal
|
||||||
|
{
|
||||||
|
$that = BigDecimal::of($that);
|
||||||
|
|
||||||
|
if ($that->value === '0') {
|
||||||
|
throw DivisionByZeroException::divisionByZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
[, $b] = $this->scaleValues($this, $that);
|
||||||
|
|
||||||
|
$d = \rtrim($b, '0');
|
||||||
|
$scale = \strlen($b) - \strlen($d);
|
||||||
|
|
||||||
|
$calculator = Calculator::get();
|
||||||
|
|
||||||
|
foreach ([5, 2] as $prime) {
|
||||||
|
for (;;) {
|
||||||
|
$lastDigit = (int) $d[-1];
|
||||||
|
|
||||||
|
if ($lastDigit % $prime !== 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$d = $calculator->divQ($d, (string) $prime);
|
||||||
|
$scale++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->dividedBy($that, $scale)->stripTrailingZeros();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this number exponentiated to the given value.
|
||||||
|
*
|
||||||
|
* The result has a scale of `$this->scale * $exponent`.
|
||||||
|
*
|
||||||
|
* @param int $exponent The exponent.
|
||||||
|
*
|
||||||
|
* @return BigDecimal The result.
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
|
||||||
|
*/
|
||||||
|
public function power(int $exponent) : BigDecimal
|
||||||
|
{
|
||||||
|
if ($exponent === 0) {
|
||||||
|
return BigDecimal::one();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($exponent === 1) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($exponent < 0 || $exponent > Calculator::MAX_POWER) {
|
||||||
|
throw new \InvalidArgumentException(\sprintf(
|
||||||
|
'The exponent %d is not in the range 0 to %d.',
|
||||||
|
$exponent,
|
||||||
|
Calculator::MAX_POWER
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BigDecimal(Calculator::get()->pow($this->value, $exponent), $this->scale * $exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quotient of the division of this number by this given one.
|
||||||
|
*
|
||||||
|
* The quotient has a scale of `0`.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
|
||||||
|
*
|
||||||
|
* @return BigDecimal The quotient.
|
||||||
|
*
|
||||||
|
* @throws MathException If the divisor is not a valid decimal number, or is zero.
|
||||||
|
*/
|
||||||
|
public function quotient($that) : BigDecimal
|
||||||
|
{
|
||||||
|
$that = BigDecimal::of($that);
|
||||||
|
|
||||||
|
if ($that->isZero()) {
|
||||||
|
throw DivisionByZeroException::divisionByZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
$p = $this->valueWithMinScale($that->scale);
|
||||||
|
$q = $that->valueWithMinScale($this->scale);
|
||||||
|
|
||||||
|
$quotient = Calculator::get()->divQ($p, $q);
|
||||||
|
|
||||||
|
return new BigDecimal($quotient, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the remainder of the division of this number by this given one.
|
||||||
|
*
|
||||||
|
* The remainder has a scale of `max($this->scale, $that->scale)`.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
|
||||||
|
*
|
||||||
|
* @return BigDecimal The remainder.
|
||||||
|
*
|
||||||
|
* @throws MathException If the divisor is not a valid decimal number, or is zero.
|
||||||
|
*/
|
||||||
|
public function remainder($that) : BigDecimal
|
||||||
|
{
|
||||||
|
$that = BigDecimal::of($that);
|
||||||
|
|
||||||
|
if ($that->isZero()) {
|
||||||
|
throw DivisionByZeroException::divisionByZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
$p = $this->valueWithMinScale($that->scale);
|
||||||
|
$q = $that->valueWithMinScale($this->scale);
|
||||||
|
|
||||||
|
$remainder = Calculator::get()->divR($p, $q);
|
||||||
|
|
||||||
|
$scale = $this->scale > $that->scale ? $this->scale : $that->scale;
|
||||||
|
|
||||||
|
return new BigDecimal($remainder, $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quotient and remainder of the division of this number by the given one.
|
||||||
|
*
|
||||||
|
* The quotient has a scale of `0`, and the remainder has a scale of `max($this->scale, $that->scale)`.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
|
||||||
|
*
|
||||||
|
* @return BigDecimal[] An array containing the quotient and the remainder.
|
||||||
|
*
|
||||||
|
* @throws MathException If the divisor is not a valid decimal number, or is zero.
|
||||||
|
*/
|
||||||
|
public function quotientAndRemainder($that) : array
|
||||||
|
{
|
||||||
|
$that = BigDecimal::of($that);
|
||||||
|
|
||||||
|
if ($that->isZero()) {
|
||||||
|
throw DivisionByZeroException::divisionByZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
$p = $this->valueWithMinScale($that->scale);
|
||||||
|
$q = $that->valueWithMinScale($this->scale);
|
||||||
|
|
||||||
|
[$quotient, $remainder] = Calculator::get()->divQR($p, $q);
|
||||||
|
|
||||||
|
$scale = $this->scale > $that->scale ? $this->scale : $that->scale;
|
||||||
|
|
||||||
|
$quotient = new BigDecimal($quotient, 0);
|
||||||
|
$remainder = new BigDecimal($remainder, $scale);
|
||||||
|
|
||||||
|
return [$quotient, $remainder];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the square root of this number, rounded down to the given number of decimals.
|
||||||
|
*
|
||||||
|
* @param int $scale
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If the scale is negative.
|
||||||
|
* @throws NegativeNumberException If this number is negative.
|
||||||
|
*/
|
||||||
|
public function sqrt(int $scale) : BigDecimal
|
||||||
|
{
|
||||||
|
if ($scale < 0) {
|
||||||
|
throw new \InvalidArgumentException('Scale cannot be negative.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->value === '0') {
|
||||||
|
return new BigDecimal('0', $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->value[0] === '-') {
|
||||||
|
throw new NegativeNumberException('Cannot calculate the square root of a negative number.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $this->value;
|
||||||
|
$addDigits = 2 * $scale - $this->scale;
|
||||||
|
|
||||||
|
if ($addDigits > 0) {
|
||||||
|
// add zeros
|
||||||
|
$value .= \str_repeat('0', $addDigits);
|
||||||
|
} elseif ($addDigits < 0) {
|
||||||
|
// trim digits
|
||||||
|
if (-$addDigits >= \strlen($this->value)) {
|
||||||
|
// requesting a scale too low, will always yield a zero result
|
||||||
|
return new BigDecimal('0', $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = \substr($value, 0, $addDigits);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = Calculator::get()->sqrt($value);
|
||||||
|
|
||||||
|
return new BigDecimal($value, $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this BigDecimal with the decimal point moved $n places to the left.
|
||||||
|
*
|
||||||
|
* @param int $n
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*/
|
||||||
|
public function withPointMovedLeft(int $n) : BigDecimal
|
||||||
|
{
|
||||||
|
if ($n === 0) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($n < 0) {
|
||||||
|
return $this->withPointMovedRight(-$n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BigDecimal($this->value, $this->scale + $n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this BigDecimal with the decimal point moved $n places to the right.
|
||||||
|
*
|
||||||
|
* @param int $n
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*/
|
||||||
|
public function withPointMovedRight(int $n) : BigDecimal
|
||||||
|
{
|
||||||
|
if ($n === 0) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($n < 0) {
|
||||||
|
return $this->withPointMovedLeft(-$n);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $this->value;
|
||||||
|
$scale = $this->scale - $n;
|
||||||
|
|
||||||
|
if ($scale < 0) {
|
||||||
|
if ($value !== '0') {
|
||||||
|
$value .= \str_repeat('0', -$scale);
|
||||||
|
}
|
||||||
|
$scale = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BigDecimal($value, $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this BigDecimal with any trailing zeros removed from the fractional part.
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*/
|
||||||
|
public function stripTrailingZeros() : BigDecimal
|
||||||
|
{
|
||||||
|
if ($this->scale === 0) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
$trimmedValue = \rtrim($this->value, '0');
|
||||||
|
|
||||||
|
if ($trimmedValue === '') {
|
||||||
|
return BigDecimal::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
$trimmableZeros = \strlen($this->value) - \strlen($trimmedValue);
|
||||||
|
|
||||||
|
if ($trimmableZeros === 0) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($trimmableZeros > $this->scale) {
|
||||||
|
$trimmableZeros = $this->scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = \substr($this->value, 0, -$trimmableZeros);
|
||||||
|
$scale = $this->scale - $trimmableZeros;
|
||||||
|
|
||||||
|
return new BigDecimal($value, $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the absolute value of this number.
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*/
|
||||||
|
public function abs() : BigDecimal
|
||||||
|
{
|
||||||
|
return $this->isNegative() ? $this->negated() : $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the negated value of this number.
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*/
|
||||||
|
public function negated() : BigDecimal
|
||||||
|
{
|
||||||
|
return new BigDecimal(Calculator::get()->neg($this->value), $this->scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function compareTo($that) : int
|
||||||
|
{
|
||||||
|
$that = BigNumber::of($that);
|
||||||
|
|
||||||
|
if ($that instanceof BigInteger) {
|
||||||
|
$that = $that->toBigDecimal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($that instanceof BigDecimal) {
|
||||||
|
[$a, $b] = $this->scaleValues($this, $that);
|
||||||
|
|
||||||
|
return Calculator::get()->cmp($a, $b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return - $that->compareTo($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getSign() : int
|
||||||
|
{
|
||||||
|
return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return BigInteger
|
||||||
|
*/
|
||||||
|
public function getUnscaledValue() : BigInteger
|
||||||
|
{
|
||||||
|
return BigInteger::create($this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getScale() : int
|
||||||
|
{
|
||||||
|
return $this->scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representing the integral part of this decimal number.
|
||||||
|
*
|
||||||
|
* Example: `-123.456` => `-123`.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getIntegralPart() : string
|
||||||
|
{
|
||||||
|
if ($this->scale === 0) {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $this->getUnscaledValueWithLeadingZeros();
|
||||||
|
|
||||||
|
return \substr($value, 0, -$this->scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representing the fractional part of this decimal number.
|
||||||
|
*
|
||||||
|
* If the scale is zero, an empty string is returned.
|
||||||
|
*
|
||||||
|
* Examples: `-123.456` => '456', `123` => ''.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFractionalPart() : string
|
||||||
|
{
|
||||||
|
if ($this->scale === 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $this->getUnscaledValueWithLeadingZeros();
|
||||||
|
|
||||||
|
return \substr($value, -$this->scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this decimal number has a non-zero fractional part.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasNonZeroFractionalPart() : bool
|
||||||
|
{
|
||||||
|
return $this->getFractionalPart() !== \str_repeat('0', $this->scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toBigInteger() : BigInteger
|
||||||
|
{
|
||||||
|
$zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0);
|
||||||
|
|
||||||
|
return BigInteger::create($zeroScaleDecimal->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toBigDecimal() : BigDecimal
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toBigRational() : BigRational
|
||||||
|
{
|
||||||
|
$numerator = BigInteger::create($this->value);
|
||||||
|
$denominator = BigInteger::create('1' . \str_repeat('0', $this->scale));
|
||||||
|
|
||||||
|
return BigRational::create($numerator, $denominator, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||||
|
{
|
||||||
|
if ($scale === $this->scale) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toInt() : int
|
||||||
|
{
|
||||||
|
return $this->toBigInteger()->toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toFloat() : float
|
||||||
|
{
|
||||||
|
return (float) (string) $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
if ($this->scale === 0) {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $this->getUnscaledValueWithLeadingZeros();
|
||||||
|
|
||||||
|
return \substr($value, 0, -$this->scale) . '.' . \substr($value, -$this->scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is required for serializing the object and SHOULD NOT be accessed directly.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @return array{value: string, scale: int}
|
||||||
|
*/
|
||||||
|
public function __serialize(): array
|
||||||
|
{
|
||||||
|
return ['value' => $this->value, 'scale' => $this->scale];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is only here to allow unserializing the object and cannot be accessed directly.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
* @psalm-suppress RedundantPropertyInitializationCheck
|
||||||
|
*
|
||||||
|
* @param array{value: string, scale: int} $data
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws \LogicException
|
||||||
|
*/
|
||||||
|
public function __unserialize(array $data): void
|
||||||
|
{
|
||||||
|
if (isset($this->value)) {
|
||||||
|
throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->value = $data['value'];
|
||||||
|
$this->scale = $data['scale'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is required by interface Serializable and SHOULD NOT be accessed directly.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function serialize() : string
|
||||||
|
{
|
||||||
|
return $this->value . ':' . $this->scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is only here to implement interface Serializable and cannot be accessed directly.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
* @psalm-suppress RedundantPropertyInitializationCheck
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws \LogicException
|
||||||
|
*/
|
||||||
|
public function unserialize($value) : void
|
||||||
|
{
|
||||||
|
if (isset($this->value)) {
|
||||||
|
throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
|
||||||
|
}
|
||||||
|
|
||||||
|
[$value, $scale] = \explode(':', $value);
|
||||||
|
|
||||||
|
$this->value = $value;
|
||||||
|
$this->scale = (int) $scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the internal values of the given decimal numbers on the same scale.
|
||||||
|
*
|
||||||
|
* @param BigDecimal $x The first decimal number.
|
||||||
|
* @param BigDecimal $y The second decimal number.
|
||||||
|
*
|
||||||
|
* @return array{string, string} The scaled integer values of $x and $y.
|
||||||
|
*/
|
||||||
|
private function scaleValues(BigDecimal $x, BigDecimal $y) : array
|
||||||
|
{
|
||||||
|
$a = $x->value;
|
||||||
|
$b = $y->value;
|
||||||
|
|
||||||
|
if ($b !== '0' && $x->scale > $y->scale) {
|
||||||
|
$b .= \str_repeat('0', $x->scale - $y->scale);
|
||||||
|
} elseif ($a !== '0' && $x->scale < $y->scale) {
|
||||||
|
$a .= \str_repeat('0', $y->scale - $x->scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$a, $b];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $scale
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function valueWithMinScale(int $scale) : string
|
||||||
|
{
|
||||||
|
$value = $this->value;
|
||||||
|
|
||||||
|
if ($this->value !== '0' && $scale > $this->scale) {
|
||||||
|
$value .= \str_repeat('0', $scale - $this->scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds leading zeros if necessary to the unscaled value to represent the full decimal number.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getUnscaledValueWithLeadingZeros() : string
|
||||||
|
{
|
||||||
|
$value = $this->value;
|
||||||
|
$targetLength = $this->scale + 1;
|
||||||
|
$negative = ($value[0] === '-');
|
||||||
|
$length = \strlen($value);
|
||||||
|
|
||||||
|
if ($negative) {
|
||||||
|
$length--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($length >= $targetLength) {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($negative) {
|
||||||
|
$value = \substr($value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT);
|
||||||
|
|
||||||
|
if ($negative) {
|
||||||
|
$value = '-' . $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
1184
vendor/brick/math/src/BigInteger.php
vendored
Normal file
572
vendor/brick/math/src/BigNumber.php
vendored
Normal file
@ -0,0 +1,572 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math;
|
||||||
|
|
||||||
|
use Brick\Math\Exception\DivisionByZeroException;
|
||||||
|
use Brick\Math\Exception\MathException;
|
||||||
|
use Brick\Math\Exception\NumberFormatException;
|
||||||
|
use Brick\Math\Exception\RoundingNecessaryException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common interface for arbitrary-precision rational numbers.
|
||||||
|
*
|
||||||
|
* @psalm-immutable
|
||||||
|
*/
|
||||||
|
abstract class BigNumber implements \Serializable, \JsonSerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The regular expression used to parse integer, decimal and rational numbers.
|
||||||
|
*/
|
||||||
|
private const PARSE_REGEXP =
|
||||||
|
'/^' .
|
||||||
|
'(?<sign>[\-\+])?' .
|
||||||
|
'(?:' .
|
||||||
|
'(?:' .
|
||||||
|
'(?<integral>[0-9]+)?' .
|
||||||
|
'(?<point>\.)?' .
|
||||||
|
'(?<fractional>[0-9]+)?' .
|
||||||
|
'(?:[eE](?<exponent>[\-\+]?[0-9]+))?' .
|
||||||
|
')|(?:' .
|
||||||
|
'(?<numerator>[0-9]+)' .
|
||||||
|
'\/?' .
|
||||||
|
'(?<denominator>[0-9]+)' .
|
||||||
|
')' .
|
||||||
|
')' .
|
||||||
|
'$/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a BigNumber of the given value.
|
||||||
|
*
|
||||||
|
* The concrete return type is dependent on the given value, with the following rules:
|
||||||
|
*
|
||||||
|
* - BigNumber instances are returned as is
|
||||||
|
* - integer numbers are returned as BigInteger
|
||||||
|
* - floating point numbers are converted to a string then parsed as such
|
||||||
|
* - strings containing a `/` character are returned as BigRational
|
||||||
|
* - strings containing a `.` character or using an exponential notation are returned as BigDecimal
|
||||||
|
* - strings containing only digits with an optional leading `+` or `-` sign are returned as BigInteger
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $value
|
||||||
|
*
|
||||||
|
* @return BigNumber
|
||||||
|
*
|
||||||
|
* @throws NumberFormatException If the format of the number is not valid.
|
||||||
|
* @throws DivisionByZeroException If the value represents a rational number with a denominator of zero.
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function of($value) : BigNumber
|
||||||
|
{
|
||||||
|
if ($value instanceof BigNumber) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_int($value)) {
|
||||||
|
return new BigInteger((string) $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @psalm-suppress RedundantCastGivenDocblockType We cannot trust the untyped $value here! */
|
||||||
|
$value = \is_float($value) ? self::floatToString($value) : (string) $value;
|
||||||
|
|
||||||
|
$throw = static function() use ($value) : void {
|
||||||
|
throw new NumberFormatException(\sprintf(
|
||||||
|
'The given value "%s" does not represent a valid number.',
|
||||||
|
$value
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) {
|
||||||
|
$throw();
|
||||||
|
}
|
||||||
|
|
||||||
|
$getMatch = static function(string $value) use ($matches) : ?string {
|
||||||
|
return isset($matches[$value]) && $matches[$value] !== '' ? $matches[$value] : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
$sign = $getMatch('sign');
|
||||||
|
$numerator = $getMatch('numerator');
|
||||||
|
$denominator = $getMatch('denominator');
|
||||||
|
|
||||||
|
if ($numerator !== null) {
|
||||||
|
assert($denominator !== null);
|
||||||
|
|
||||||
|
if ($sign !== null) {
|
||||||
|
$numerator = $sign . $numerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
$numerator = self::cleanUp($numerator);
|
||||||
|
$denominator = self::cleanUp($denominator);
|
||||||
|
|
||||||
|
if ($denominator === '0') {
|
||||||
|
throw DivisionByZeroException::denominatorMustNotBeZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BigRational(
|
||||||
|
new BigInteger($numerator),
|
||||||
|
new BigInteger($denominator),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$point = $getMatch('point');
|
||||||
|
$integral = $getMatch('integral');
|
||||||
|
$fractional = $getMatch('fractional');
|
||||||
|
$exponent = $getMatch('exponent');
|
||||||
|
|
||||||
|
if ($integral === null && $fractional === null) {
|
||||||
|
$throw();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($integral === null) {
|
||||||
|
$integral = '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($point !== null || $exponent !== null) {
|
||||||
|
$fractional = ($fractional ?? '');
|
||||||
|
$exponent = ($exponent !== null) ? (int) $exponent : 0;
|
||||||
|
|
||||||
|
if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) {
|
||||||
|
throw new NumberFormatException('Exponent too large.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$unscaledValue = self::cleanUp(($sign ?? ''). $integral . $fractional);
|
||||||
|
|
||||||
|
$scale = \strlen($fractional) - $exponent;
|
||||||
|
|
||||||
|
if ($scale < 0) {
|
||||||
|
if ($unscaledValue !== '0') {
|
||||||
|
$unscaledValue .= \str_repeat('0', - $scale);
|
||||||
|
}
|
||||||
|
$scale = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BigDecimal($unscaledValue, $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
$integral = self::cleanUp(($sign ?? '') . $integral);
|
||||||
|
|
||||||
|
return new BigInteger($integral);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safely converts float to string, avoiding locale-dependent issues.
|
||||||
|
*
|
||||||
|
* @see https://github.com/brick/math/pull/20
|
||||||
|
*
|
||||||
|
* @param float $float
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
* @psalm-suppress ImpureFunctionCall
|
||||||
|
*/
|
||||||
|
private static function floatToString(float $float) : string
|
||||||
|
{
|
||||||
|
$currentLocale = \setlocale(LC_NUMERIC, '0');
|
||||||
|
\setlocale(LC_NUMERIC, 'C');
|
||||||
|
|
||||||
|
$result = (string) $float;
|
||||||
|
|
||||||
|
\setlocale(LC_NUMERIC, $currentLocale);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy method to access protected constructors from sibling classes.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @param mixed ...$args The arguments to the constructor.
|
||||||
|
*
|
||||||
|
* @return static
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
* @psalm-suppress TooManyArguments
|
||||||
|
* @psalm-suppress UnsafeInstantiation
|
||||||
|
*/
|
||||||
|
protected static function create(... $args) : BigNumber
|
||||||
|
{
|
||||||
|
return new static(... $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum of the given values.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible
|
||||||
|
* to an instance of the class this method is called on.
|
||||||
|
*
|
||||||
|
* @return static The minimum value.
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If no values are given.
|
||||||
|
* @throws MathException If an argument is not valid.
|
||||||
|
*
|
||||||
|
* @psalm-suppress LessSpecificReturnStatement
|
||||||
|
* @psalm-suppress MoreSpecificReturnType
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function min(...$values) : BigNumber
|
||||||
|
{
|
||||||
|
$min = null;
|
||||||
|
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$value = static::of($value);
|
||||||
|
|
||||||
|
if ($min === null || $value->isLessThan($min)) {
|
||||||
|
$min = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($min === null) {
|
||||||
|
throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $min;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum of the given values.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible
|
||||||
|
* to an instance of the class this method is called on.
|
||||||
|
*
|
||||||
|
* @return static The maximum value.
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If no values are given.
|
||||||
|
* @throws MathException If an argument is not valid.
|
||||||
|
*
|
||||||
|
* @psalm-suppress LessSpecificReturnStatement
|
||||||
|
* @psalm-suppress MoreSpecificReturnType
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function max(...$values) : BigNumber
|
||||||
|
{
|
||||||
|
$max = null;
|
||||||
|
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$value = static::of($value);
|
||||||
|
|
||||||
|
if ($max === null || $value->isGreaterThan($max)) {
|
||||||
|
$max = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($max === null) {
|
||||||
|
throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sum of the given values.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string ...$values The numbers to add. All the numbers need to be convertible
|
||||||
|
* to an instance of the class this method is called on.
|
||||||
|
*
|
||||||
|
* @return static The sum.
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If no values are given.
|
||||||
|
* @throws MathException If an argument is not valid.
|
||||||
|
*
|
||||||
|
* @psalm-suppress LessSpecificReturnStatement
|
||||||
|
* @psalm-suppress MoreSpecificReturnType
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function sum(...$values) : BigNumber
|
||||||
|
{
|
||||||
|
/** @var BigNumber|null $sum */
|
||||||
|
$sum = null;
|
||||||
|
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$value = static::of($value);
|
||||||
|
|
||||||
|
$sum = $sum === null ? $value : self::add($sum, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($sum === null) {
|
||||||
|
throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds two BigNumber instances in the correct order to avoid a RoundingNecessaryException.
|
||||||
|
*
|
||||||
|
* @todo This could be better resolved by creating an abstract protected method in BigNumber, and leaving to
|
||||||
|
* concrete classes the responsibility to perform the addition themselves or delegate it to the given number,
|
||||||
|
* depending on their ability to perform the operation. This will also require a version bump because we're
|
||||||
|
* potentially breaking custom BigNumber implementations (if any...)
|
||||||
|
*
|
||||||
|
* @param BigNumber $a
|
||||||
|
* @param BigNumber $b
|
||||||
|
*
|
||||||
|
* @return BigNumber
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
private static function add(BigNumber $a, BigNumber $b) : BigNumber
|
||||||
|
{
|
||||||
|
if ($a instanceof BigRational) {
|
||||||
|
return $a->plus($b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($b instanceof BigRational) {
|
||||||
|
return $b->plus($a);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a instanceof BigDecimal) {
|
||||||
|
return $a->plus($b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($b instanceof BigDecimal) {
|
||||||
|
return $b->plus($a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var BigInteger $a */
|
||||||
|
|
||||||
|
return $a->plus($b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes optional leading zeros and + sign from the given number.
|
||||||
|
*
|
||||||
|
* @param string $number The number, validated as a non-empty string of digits with optional leading sign.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
private static function cleanUp(string $number) : string
|
||||||
|
{
|
||||||
|
$firstChar = $number[0];
|
||||||
|
|
||||||
|
if ($firstChar === '+' || $firstChar === '-') {
|
||||||
|
$number = \substr($number, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$number = \ltrim($number, '0');
|
||||||
|
|
||||||
|
if ($number === '') {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($firstChar === '-') {
|
||||||
|
return '-' . $number;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this number is equal to the given one.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isEqualTo($that) : bool
|
||||||
|
{
|
||||||
|
return $this->compareTo($that) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this number is strictly lower than the given one.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isLessThan($that) : bool
|
||||||
|
{
|
||||||
|
return $this->compareTo($that) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this number is lower than or equal to the given one.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isLessThanOrEqualTo($that) : bool
|
||||||
|
{
|
||||||
|
return $this->compareTo($that) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this number is strictly greater than the given one.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isGreaterThan($that) : bool
|
||||||
|
{
|
||||||
|
return $this->compareTo($that) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this number is greater than or equal to the given one.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isGreaterThanOrEqualTo($that) : bool
|
||||||
|
{
|
||||||
|
return $this->compareTo($that) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this number equals zero.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isZero() : bool
|
||||||
|
{
|
||||||
|
return $this->getSign() === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this number is strictly negative.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isNegative() : bool
|
||||||
|
{
|
||||||
|
return $this->getSign() < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this number is negative or zero.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isNegativeOrZero() : bool
|
||||||
|
{
|
||||||
|
return $this->getSign() <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this number is strictly positive.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isPositive() : bool
|
||||||
|
{
|
||||||
|
return $this->getSign() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this number is positive or zero.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isPositiveOrZero() : bool
|
||||||
|
{
|
||||||
|
return $this->getSign() >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sign of this number.
|
||||||
|
*
|
||||||
|
* @return int -1 if the number is negative, 0 if zero, 1 if positive.
|
||||||
|
*/
|
||||||
|
abstract public function getSign() : int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares this number to the given one.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that
|
||||||
|
*
|
||||||
|
* @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`.
|
||||||
|
*
|
||||||
|
* @throws MathException If the number is not valid.
|
||||||
|
*/
|
||||||
|
abstract public function compareTo($that) : int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this number to a BigInteger.
|
||||||
|
*
|
||||||
|
* @return BigInteger The converted number.
|
||||||
|
*
|
||||||
|
* @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding.
|
||||||
|
*/
|
||||||
|
abstract public function toBigInteger() : BigInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this number to a BigDecimal.
|
||||||
|
*
|
||||||
|
* @return BigDecimal The converted number.
|
||||||
|
*
|
||||||
|
* @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding.
|
||||||
|
*/
|
||||||
|
abstract public function toBigDecimal() : BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this number to a BigRational.
|
||||||
|
*
|
||||||
|
* @return BigRational The converted number.
|
||||||
|
*/
|
||||||
|
abstract public function toBigRational() : BigRational;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this number to a BigDecimal with the given scale, using rounding if necessary.
|
||||||
|
*
|
||||||
|
* @param int $scale The scale of the resulting `BigDecimal`.
|
||||||
|
* @param int $roundingMode A `RoundingMode` constant.
|
||||||
|
*
|
||||||
|
* @return BigDecimal
|
||||||
|
*
|
||||||
|
* @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding.
|
||||||
|
* This only applies when RoundingMode::UNNECESSARY is used.
|
||||||
|
*/
|
||||||
|
abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the exact value of this number as a native integer.
|
||||||
|
*
|
||||||
|
* If this number cannot be converted to a native integer without losing precision, an exception is thrown.
|
||||||
|
* Note that the acceptable range for an integer depends on the platform and differs for 32-bit and 64-bit.
|
||||||
|
*
|
||||||
|
* @return int The converted value.
|
||||||
|
*
|
||||||
|
* @throws MathException If this number cannot be exactly converted to a native integer.
|
||||||
|
*/
|
||||||
|
abstract public function toInt() : int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an approximation of this number as a floating-point value.
|
||||||
|
*
|
||||||
|
* Note that this method can discard information as the precision of a floating-point value
|
||||||
|
* is inherently limited.
|
||||||
|
*
|
||||||
|
* If the number is greater than the largest representable floating point number, positive infinity is returned.
|
||||||
|
* If the number is less than the smallest representable floating point number, negative infinity is returned.
|
||||||
|
*
|
||||||
|
* @return float The converted value.
|
||||||
|
*/
|
||||||
|
abstract public function toFloat() : float;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of this number.
|
||||||
|
*
|
||||||
|
* The output of this method can be parsed by the `of()` factory method;
|
||||||
|
* this will yield an object equal to this one, without any information loss.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract public function __toString() : string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function jsonSerialize() : string
|
||||||
|
{
|
||||||
|
return $this->__toString();
|
||||||
|
}
|
||||||
|
}
|
523
vendor/brick/math/src/BigRational.php
vendored
Normal file
@ -0,0 +1,523 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math;
|
||||||
|
|
||||||
|
use Brick\Math\Exception\DivisionByZeroException;
|
||||||
|
use Brick\Math\Exception\MathException;
|
||||||
|
use Brick\Math\Exception\NumberFormatException;
|
||||||
|
use Brick\Math\Exception\RoundingNecessaryException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An arbitrarily large rational number.
|
||||||
|
*
|
||||||
|
* This class is immutable.
|
||||||
|
*
|
||||||
|
* @psalm-immutable
|
||||||
|
*/
|
||||||
|
final class BigRational extends BigNumber
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The numerator.
|
||||||
|
*
|
||||||
|
* @var BigInteger
|
||||||
|
*/
|
||||||
|
private $numerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The denominator. Always strictly positive.
|
||||||
|
*
|
||||||
|
* @var BigInteger
|
||||||
|
*/
|
||||||
|
private $denominator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protected constructor. Use a factory method to obtain an instance.
|
||||||
|
*
|
||||||
|
* @param BigInteger $numerator The numerator.
|
||||||
|
* @param BigInteger $denominator The denominator.
|
||||||
|
* @param bool $checkDenominator Whether to check the denominator for negative and zero.
|
||||||
|
*
|
||||||
|
* @throws DivisionByZeroException If the denominator is zero.
|
||||||
|
*/
|
||||||
|
protected function __construct(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator)
|
||||||
|
{
|
||||||
|
if ($checkDenominator) {
|
||||||
|
if ($denominator->isZero()) {
|
||||||
|
throw DivisionByZeroException::denominatorMustNotBeZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($denominator->isNegative()) {
|
||||||
|
$numerator = $numerator->negated();
|
||||||
|
$denominator = $denominator->negated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->numerator = $numerator;
|
||||||
|
$this->denominator = $denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a BigRational of the given value.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $value
|
||||||
|
*
|
||||||
|
* @return BigRational
|
||||||
|
*
|
||||||
|
* @throws MathException If the value cannot be converted to a BigRational.
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function of($value) : BigNumber
|
||||||
|
{
|
||||||
|
return parent::of($value)->toBigRational();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a BigRational out of a numerator and a denominator.
|
||||||
|
*
|
||||||
|
* If the denominator is negative, the signs of both the numerator and the denominator
|
||||||
|
* will be inverted to ensure that the denominator is always positive.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $numerator The numerator. Must be convertible to a BigInteger.
|
||||||
|
* @param BigNumber|int|float|string $denominator The denominator. Must be convertible to a BigInteger.
|
||||||
|
*
|
||||||
|
* @return BigRational
|
||||||
|
*
|
||||||
|
* @throws NumberFormatException If an argument does not represent a valid number.
|
||||||
|
* @throws RoundingNecessaryException If an argument represents a non-integer number.
|
||||||
|
* @throws DivisionByZeroException If the denominator is zero.
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function nd($numerator, $denominator) : BigRational
|
||||||
|
{
|
||||||
|
$numerator = BigInteger::of($numerator);
|
||||||
|
$denominator = BigInteger::of($denominator);
|
||||||
|
|
||||||
|
return new BigRational($numerator, $denominator, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a BigRational representing zero.
|
||||||
|
*
|
||||||
|
* @return BigRational
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function zero() : BigRational
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @psalm-suppress ImpureStaticVariable
|
||||||
|
* @var BigRational|null $zero
|
||||||
|
*/
|
||||||
|
static $zero;
|
||||||
|
|
||||||
|
if ($zero === null) {
|
||||||
|
$zero = new BigRational(BigInteger::zero(), BigInteger::one(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a BigRational representing one.
|
||||||
|
*
|
||||||
|
* @return BigRational
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function one() : BigRational
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @psalm-suppress ImpureStaticVariable
|
||||||
|
* @var BigRational|null $one
|
||||||
|
*/
|
||||||
|
static $one;
|
||||||
|
|
||||||
|
if ($one === null) {
|
||||||
|
$one = new BigRational(BigInteger::one(), BigInteger::one(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $one;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a BigRational representing ten.
|
||||||
|
*
|
||||||
|
* @return BigRational
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function ten() : BigRational
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @psalm-suppress ImpureStaticVariable
|
||||||
|
* @var BigRational|null $ten
|
||||||
|
*/
|
||||||
|
static $ten;
|
||||||
|
|
||||||
|
if ($ten === null) {
|
||||||
|
$ten = new BigRational(BigInteger::ten(), BigInteger::one(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ten;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return BigInteger
|
||||||
|
*/
|
||||||
|
public function getNumerator() : BigInteger
|
||||||
|
{
|
||||||
|
return $this->numerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return BigInteger
|
||||||
|
*/
|
||||||
|
public function getDenominator() : BigInteger
|
||||||
|
{
|
||||||
|
return $this->denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quotient of the division of the numerator by the denominator.
|
||||||
|
*
|
||||||
|
* @return BigInteger
|
||||||
|
*/
|
||||||
|
public function quotient() : BigInteger
|
||||||
|
{
|
||||||
|
return $this->numerator->quotient($this->denominator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the remainder of the division of the numerator by the denominator.
|
||||||
|
*
|
||||||
|
* @return BigInteger
|
||||||
|
*/
|
||||||
|
public function remainder() : BigInteger
|
||||||
|
{
|
||||||
|
return $this->numerator->remainder($this->denominator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quotient and remainder of the division of the numerator by the denominator.
|
||||||
|
*
|
||||||
|
* @return BigInteger[]
|
||||||
|
*/
|
||||||
|
public function quotientAndRemainder() : array
|
||||||
|
{
|
||||||
|
return $this->numerator->quotientAndRemainder($this->denominator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sum of this number and the given one.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The number to add.
|
||||||
|
*
|
||||||
|
* @return BigRational The result.
|
||||||
|
*
|
||||||
|
* @throws MathException If the number is not valid.
|
||||||
|
*/
|
||||||
|
public function plus($that) : BigRational
|
||||||
|
{
|
||||||
|
$that = BigRational::of($that);
|
||||||
|
|
||||||
|
$numerator = $this->numerator->multipliedBy($that->denominator);
|
||||||
|
$numerator = $numerator->plus($that->numerator->multipliedBy($this->denominator));
|
||||||
|
$denominator = $this->denominator->multipliedBy($that->denominator);
|
||||||
|
|
||||||
|
return new BigRational($numerator, $denominator, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the difference of this number and the given one.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The number to subtract.
|
||||||
|
*
|
||||||
|
* @return BigRational The result.
|
||||||
|
*
|
||||||
|
* @throws MathException If the number is not valid.
|
||||||
|
*/
|
||||||
|
public function minus($that) : BigRational
|
||||||
|
{
|
||||||
|
$that = BigRational::of($that);
|
||||||
|
|
||||||
|
$numerator = $this->numerator->multipliedBy($that->denominator);
|
||||||
|
$numerator = $numerator->minus($that->numerator->multipliedBy($this->denominator));
|
||||||
|
$denominator = $this->denominator->multipliedBy($that->denominator);
|
||||||
|
|
||||||
|
return new BigRational($numerator, $denominator, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the product of this number and the given one.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The multiplier.
|
||||||
|
*
|
||||||
|
* @return BigRational The result.
|
||||||
|
*
|
||||||
|
* @throws MathException If the multiplier is not a valid number.
|
||||||
|
*/
|
||||||
|
public function multipliedBy($that) : BigRational
|
||||||
|
{
|
||||||
|
$that = BigRational::of($that);
|
||||||
|
|
||||||
|
$numerator = $this->numerator->multipliedBy($that->numerator);
|
||||||
|
$denominator = $this->denominator->multipliedBy($that->denominator);
|
||||||
|
|
||||||
|
return new BigRational($numerator, $denominator, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the result of the division of this number by the given one.
|
||||||
|
*
|
||||||
|
* @param BigNumber|int|float|string $that The divisor.
|
||||||
|
*
|
||||||
|
* @return BigRational The result.
|
||||||
|
*
|
||||||
|
* @throws MathException If the divisor is not a valid number, or is zero.
|
||||||
|
*/
|
||||||
|
public function dividedBy($that) : BigRational
|
||||||
|
{
|
||||||
|
$that = BigRational::of($that);
|
||||||
|
|
||||||
|
$numerator = $this->numerator->multipliedBy($that->denominator);
|
||||||
|
$denominator = $this->denominator->multipliedBy($that->numerator);
|
||||||
|
|
||||||
|
return new BigRational($numerator, $denominator, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this number exponentiated to the given value.
|
||||||
|
*
|
||||||
|
* @param int $exponent The exponent.
|
||||||
|
*
|
||||||
|
* @return BigRational The result.
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
|
||||||
|
*/
|
||||||
|
public function power(int $exponent) : BigRational
|
||||||
|
{
|
||||||
|
if ($exponent === 0) {
|
||||||
|
$one = BigInteger::one();
|
||||||
|
|
||||||
|
return new BigRational($one, $one, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($exponent === 1) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BigRational(
|
||||||
|
$this->numerator->power($exponent),
|
||||||
|
$this->denominator->power($exponent),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the reciprocal of this BigRational.
|
||||||
|
*
|
||||||
|
* The reciprocal has the numerator and denominator swapped.
|
||||||
|
*
|
||||||
|
* @return BigRational
|
||||||
|
*
|
||||||
|
* @throws DivisionByZeroException If the numerator is zero.
|
||||||
|
*/
|
||||||
|
public function reciprocal() : BigRational
|
||||||
|
{
|
||||||
|
return new BigRational($this->denominator, $this->numerator, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the absolute value of this BigRational.
|
||||||
|
*
|
||||||
|
* @return BigRational
|
||||||
|
*/
|
||||||
|
public function abs() : BigRational
|
||||||
|
{
|
||||||
|
return new BigRational($this->numerator->abs(), $this->denominator, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the negated value of this BigRational.
|
||||||
|
*
|
||||||
|
* @return BigRational
|
||||||
|
*/
|
||||||
|
public function negated() : BigRational
|
||||||
|
{
|
||||||
|
return new BigRational($this->numerator->negated(), $this->denominator, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the simplified value of this BigRational.
|
||||||
|
*
|
||||||
|
* @return BigRational
|
||||||
|
*/
|
||||||
|
public function simplified() : BigRational
|
||||||
|
{
|
||||||
|
$gcd = $this->numerator->gcd($this->denominator);
|
||||||
|
|
||||||
|
$numerator = $this->numerator->quotient($gcd);
|
||||||
|
$denominator = $this->denominator->quotient($gcd);
|
||||||
|
|
||||||
|
return new BigRational($numerator, $denominator, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function compareTo($that) : int
|
||||||
|
{
|
||||||
|
return $this->minus($that)->getSign();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getSign() : int
|
||||||
|
{
|
||||||
|
return $this->numerator->getSign();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toBigInteger() : BigInteger
|
||||||
|
{
|
||||||
|
$simplified = $this->simplified();
|
||||||
|
|
||||||
|
if (! $simplified->denominator->isEqualTo(1)) {
|
||||||
|
throw new RoundingNecessaryException('This rational number cannot be represented as an integer value without rounding.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $simplified->numerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toBigDecimal() : BigDecimal
|
||||||
|
{
|
||||||
|
return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toBigRational() : BigRational
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||||
|
{
|
||||||
|
return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toInt() : int
|
||||||
|
{
|
||||||
|
return $this->toBigInteger()->toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toFloat() : float
|
||||||
|
{
|
||||||
|
return $this->numerator->toFloat() / $this->denominator->toFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
$numerator = (string) $this->numerator;
|
||||||
|
$denominator = (string) $this->denominator;
|
||||||
|
|
||||||
|
if ($denominator === '1') {
|
||||||
|
return $numerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->numerator . '/' . $this->denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is required for serializing the object and SHOULD NOT be accessed directly.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @return array{numerator: BigInteger, denominator: BigInteger}
|
||||||
|
*/
|
||||||
|
public function __serialize(): array
|
||||||
|
{
|
||||||
|
return ['numerator' => $this->numerator, 'denominator' => $this->denominator];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is only here to allow unserializing the object and cannot be accessed directly.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
* @psalm-suppress RedundantPropertyInitializationCheck
|
||||||
|
*
|
||||||
|
* @param array{numerator: BigInteger, denominator: BigInteger} $data
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws \LogicException
|
||||||
|
*/
|
||||||
|
public function __unserialize(array $data): void
|
||||||
|
{
|
||||||
|
if (isset($this->numerator)) {
|
||||||
|
throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->numerator = $data['numerator'];
|
||||||
|
$this->denominator = $data['denominator'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is required by interface Serializable and SHOULD NOT be accessed directly.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function serialize() : string
|
||||||
|
{
|
||||||
|
return $this->numerator . '/' . $this->denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is only here to implement interface Serializable and cannot be accessed directly.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
* @psalm-suppress RedundantPropertyInitializationCheck
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws \LogicException
|
||||||
|
*/
|
||||||
|
public function unserialize($value) : void
|
||||||
|
{
|
||||||
|
if (isset($this->numerator)) {
|
||||||
|
throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
|
||||||
|
}
|
||||||
|
|
||||||
|
[$numerator, $denominator] = \explode('/', $value);
|
||||||
|
|
||||||
|
$this->numerator = BigInteger::of($numerator);
|
||||||
|
$this->denominator = BigInteger::of($denominator);
|
||||||
|
}
|
||||||
|
}
|
41
vendor/brick/math/src/Exception/DivisionByZeroException.php
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when a division by zero occurs.
|
||||||
|
*/
|
||||||
|
class DivisionByZeroException extends MathException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return DivisionByZeroException
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function divisionByZero() : DivisionByZeroException
|
||||||
|
{
|
||||||
|
return new self('Division by zero.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return DivisionByZeroException
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function modulusMustNotBeZero() : DivisionByZeroException
|
||||||
|
{
|
||||||
|
return new self('The modulus must not be zero.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return DivisionByZeroException
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function denominatorMustNotBeZero() : DivisionByZeroException
|
||||||
|
{
|
||||||
|
return new self('The denominator of a rational number cannot be zero.');
|
||||||
|
}
|
||||||
|
}
|
27
vendor/brick/math/src/Exception/IntegerOverflowException.php
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math\Exception;
|
||||||
|
|
||||||
|
use Brick\Math\BigInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when an integer overflow occurs.
|
||||||
|
*/
|
||||||
|
class IntegerOverflowException extends MathException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param BigInteger $value
|
||||||
|
*
|
||||||
|
* @return IntegerOverflowException
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function toIntOverflow(BigInteger $value) : IntegerOverflowException
|
||||||
|
{
|
||||||
|
$message = '%s is out of range %d to %d and cannot be represented as an integer.';
|
||||||
|
|
||||||
|
return new self(\sprintf($message, (string) $value, PHP_INT_MIN, PHP_INT_MAX));
|
||||||
|
}
|
||||||
|
}
|
14
vendor/brick/math/src/Exception/MathException.php
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all math exceptions.
|
||||||
|
*
|
||||||
|
* This class is abstract to ensure that only fine-grained exceptions are thrown throughout the code.
|
||||||
|
*/
|
||||||
|
class MathException extends \RuntimeException
|
||||||
|
{
|
||||||
|
}
|
12
vendor/brick/math/src/Exception/NegativeNumberException.php
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when attempting to perform an unsupported operation, such as a square root, on a negative number.
|
||||||
|
*/
|
||||||
|
class NegativeNumberException extends MathException
|
||||||
|
{
|
||||||
|
}
|
35
vendor/brick/math/src/Exception/NumberFormatException.php
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when attempting to create a number from a string with an invalid format.
|
||||||
|
*/
|
||||||
|
class NumberFormatException extends MathException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string $char The failing character.
|
||||||
|
*
|
||||||
|
* @return NumberFormatException
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function charNotInAlphabet(string $char) : self
|
||||||
|
{
|
||||||
|
$ord = \ord($char);
|
||||||
|
|
||||||
|
if ($ord < 32 || $ord > 126) {
|
||||||
|
$char = \strtoupper(\dechex($ord));
|
||||||
|
|
||||||
|
if ($ord < 10) {
|
||||||
|
$char = '0' . $char;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$char = '"' . $char . '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self(sprintf('Char %s is not a valid character in the given alphabet.', $char));
|
||||||
|
}
|
||||||
|
}
|
21
vendor/brick/math/src/Exception/RoundingNecessaryException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when a number cannot be represented at the requested scale without rounding.
|
||||||
|
*/
|
||||||
|
class RoundingNecessaryException extends MathException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return RoundingNecessaryException
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
public static function roundingNecessary() : RoundingNecessaryException
|
||||||
|
{
|
||||||
|
return new self('Rounding is necessary to represent the result of the operation at this scale.');
|
||||||
|
}
|
||||||
|
}
|
756
vendor/brick/math/src/Internal/Calculator.php
vendored
Normal file
@ -0,0 +1,756 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math\Internal;
|
||||||
|
|
||||||
|
use Brick\Math\Exception\RoundingNecessaryException;
|
||||||
|
use Brick\Math\RoundingMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs basic operations on arbitrary size integers.
|
||||||
|
*
|
||||||
|
* Unless otherwise specified, all parameters must be validated as non-empty strings of digits,
|
||||||
|
* without leading zero, and with an optional leading minus sign if the number is not zero.
|
||||||
|
*
|
||||||
|
* Any other parameter format will lead to undefined behaviour.
|
||||||
|
* All methods must return strings respecting this format, unless specified otherwise.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @psalm-immutable
|
||||||
|
*/
|
||||||
|
abstract class Calculator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The maximum exponent value allowed for the pow() method.
|
||||||
|
*/
|
||||||
|
public const MAX_POWER = 1000000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The alphabet for converting from and to base 2 to 36, lowercase.
|
||||||
|
*/
|
||||||
|
public const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Calculator instance in use.
|
||||||
|
*
|
||||||
|
* @var Calculator|null
|
||||||
|
*/
|
||||||
|
private static $instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Calculator instance to use.
|
||||||
|
*
|
||||||
|
* An instance is typically set only in unit tests: the autodetect is usually the best option.
|
||||||
|
*
|
||||||
|
* @param Calculator|null $calculator The calculator instance, or NULL to revert to autodetect.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
final public static function set(?Calculator $calculator) : void
|
||||||
|
{
|
||||||
|
self::$instance = $calculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Calculator instance to use.
|
||||||
|
*
|
||||||
|
* If none has been explicitly set, the fastest available implementation will be returned.
|
||||||
|
*
|
||||||
|
* @return Calculator
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
* @psalm-suppress ImpureStaticProperty
|
||||||
|
*/
|
||||||
|
final public static function get() : Calculator
|
||||||
|
{
|
||||||
|
if (self::$instance === null) {
|
||||||
|
/** @psalm-suppress ImpureMethodCall */
|
||||||
|
self::$instance = self::detect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fastest available Calculator implementation.
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*
|
||||||
|
* @return Calculator
|
||||||
|
*/
|
||||||
|
private static function detect() : Calculator
|
||||||
|
{
|
||||||
|
if (\extension_loaded('gmp')) {
|
||||||
|
return new Calculator\GmpCalculator();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\extension_loaded('bcmath')) {
|
||||||
|
return new Calculator\BcMathCalculator();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Calculator\NativeCalculator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the sign & digits of the operands.
|
||||||
|
*
|
||||||
|
* @param string $a The first operand.
|
||||||
|
* @param string $b The second operand.
|
||||||
|
*
|
||||||
|
* @return array{bool, bool, string, string} Whether $a and $b are negative, followed by their digits.
|
||||||
|
*/
|
||||||
|
final protected function init(string $a, string $b) : array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
$aNeg = ($a[0] === '-'),
|
||||||
|
$bNeg = ($b[0] === '-'),
|
||||||
|
|
||||||
|
$aNeg ? \substr($a, 1) : $a,
|
||||||
|
$bNeg ? \substr($b, 1) : $b,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the absolute value of a number.
|
||||||
|
*
|
||||||
|
* @param string $n The number.
|
||||||
|
*
|
||||||
|
* @return string The absolute value.
|
||||||
|
*/
|
||||||
|
final public function abs(string $n) : string
|
||||||
|
{
|
||||||
|
return ($n[0] === '-') ? \substr($n, 1) : $n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Negates a number.
|
||||||
|
*
|
||||||
|
* @param string $n The number.
|
||||||
|
*
|
||||||
|
* @return string The negated value.
|
||||||
|
*/
|
||||||
|
final public function neg(string $n) : string
|
||||||
|
{
|
||||||
|
if ($n === '0') {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($n[0] === '-') {
|
||||||
|
return \substr($n, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '-' . $n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two numbers.
|
||||||
|
*
|
||||||
|
* @param string $a The first number.
|
||||||
|
* @param string $b The second number.
|
||||||
|
*
|
||||||
|
* @return int [-1, 0, 1] If the first number is less than, equal to, or greater than the second number.
|
||||||
|
*/
|
||||||
|
final public function cmp(string $a, string $b) : int
|
||||||
|
{
|
||||||
|
[$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
|
||||||
|
|
||||||
|
if ($aNeg && ! $bNeg) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bNeg && ! $aNeg) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$aLen = \strlen($aDig);
|
||||||
|
$bLen = \strlen($bDig);
|
||||||
|
|
||||||
|
if ($aLen < $bLen) {
|
||||||
|
$result = -1;
|
||||||
|
} elseif ($aLen > $bLen) {
|
||||||
|
$result = 1;
|
||||||
|
} else {
|
||||||
|
$result = $aDig <=> $bDig;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $aNeg ? -$result : $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds two numbers.
|
||||||
|
*
|
||||||
|
* @param string $a The augend.
|
||||||
|
* @param string $b The addend.
|
||||||
|
*
|
||||||
|
* @return string The sum.
|
||||||
|
*/
|
||||||
|
abstract public function add(string $a, string $b) : string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtracts two numbers.
|
||||||
|
*
|
||||||
|
* @param string $a The minuend.
|
||||||
|
* @param string $b The subtrahend.
|
||||||
|
*
|
||||||
|
* @return string The difference.
|
||||||
|
*/
|
||||||
|
abstract public function sub(string $a, string $b) : string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplies two numbers.
|
||||||
|
*
|
||||||
|
* @param string $a The multiplicand.
|
||||||
|
* @param string $b The multiplier.
|
||||||
|
*
|
||||||
|
* @return string The product.
|
||||||
|
*/
|
||||||
|
abstract public function mul(string $a, string $b) : string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quotient of the division of two numbers.
|
||||||
|
*
|
||||||
|
* @param string $a The dividend.
|
||||||
|
* @param string $b The divisor, must not be zero.
|
||||||
|
*
|
||||||
|
* @return string The quotient.
|
||||||
|
*/
|
||||||
|
abstract public function divQ(string $a, string $b) : string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the remainder of the division of two numbers.
|
||||||
|
*
|
||||||
|
* @param string $a The dividend.
|
||||||
|
* @param string $b The divisor, must not be zero.
|
||||||
|
*
|
||||||
|
* @return string The remainder.
|
||||||
|
*/
|
||||||
|
abstract public function divR(string $a, string $b) : string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quotient and remainder of the division of two numbers.
|
||||||
|
*
|
||||||
|
* @param string $a The dividend.
|
||||||
|
* @param string $b The divisor, must not be zero.
|
||||||
|
*
|
||||||
|
* @return string[] An array containing the quotient and remainder.
|
||||||
|
*/
|
||||||
|
abstract public function divQR(string $a, string $b) : array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exponentiates a number.
|
||||||
|
*
|
||||||
|
* @param string $a The base number.
|
||||||
|
* @param int $e The exponent, validated as an integer between 0 and MAX_POWER.
|
||||||
|
*
|
||||||
|
* @return string The power.
|
||||||
|
*/
|
||||||
|
abstract public function pow(string $a, int $e) : string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $a
|
||||||
|
* @param string $b The modulus; must not be zero.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function mod(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return $this->divR($this->add($this->divR($a, $b), $b), $b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the modular multiplicative inverse of $x modulo $m.
|
||||||
|
*
|
||||||
|
* If $x has no multiplicative inverse mod m, this method must return null.
|
||||||
|
*
|
||||||
|
* This method can be overridden by the concrete implementation if the underlying library has built-in support.
|
||||||
|
*
|
||||||
|
* @param string $x
|
||||||
|
* @param string $m The modulus; must not be negative or zero.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function modInverse(string $x, string $m) : ?string
|
||||||
|
{
|
||||||
|
if ($m === '1') {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
$modVal = $x;
|
||||||
|
|
||||||
|
if ($x[0] === '-' || ($this->cmp($this->abs($x), $m) >= 0)) {
|
||||||
|
$modVal = $this->mod($x, $m);
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = '0';
|
||||||
|
$y = '0';
|
||||||
|
$g = $this->gcdExtended($modVal, $m, $x, $y);
|
||||||
|
|
||||||
|
if ($g !== '1') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->mod($this->add($this->mod($x, $m), $m), $m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raises a number into power with modulo.
|
||||||
|
*
|
||||||
|
* @param string $base The base number; must be positive or zero.
|
||||||
|
* @param string $exp The exponent; must be positive or zero.
|
||||||
|
* @param string $mod The modulus; must be strictly positive.
|
||||||
|
*
|
||||||
|
* @return string The power.
|
||||||
|
*/
|
||||||
|
abstract public function modPow(string $base, string $exp, string $mod) : string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the greatest common divisor of the two numbers.
|
||||||
|
*
|
||||||
|
* This method can be overridden by the concrete implementation if the underlying library
|
||||||
|
* has built-in support for GCD calculations.
|
||||||
|
*
|
||||||
|
* @param string $a The first number.
|
||||||
|
* @param string $b The second number.
|
||||||
|
*
|
||||||
|
* @return string The GCD, always positive, or zero if both arguments are zero.
|
||||||
|
*/
|
||||||
|
public function gcd(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
if ($a === '0') {
|
||||||
|
return $this->abs($b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($b === '0') {
|
||||||
|
return $this->abs($a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->gcd($b, $this->divR($a, $b));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function gcdExtended(string $a, string $b, string &$x, string &$y) : string
|
||||||
|
{
|
||||||
|
if ($a === '0') {
|
||||||
|
$x = '0';
|
||||||
|
$y = '1';
|
||||||
|
|
||||||
|
return $b;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x1 = '0';
|
||||||
|
$y1 = '0';
|
||||||
|
|
||||||
|
$gcd = $this->gcdExtended($this->mod($b, $a), $a, $x1, $y1);
|
||||||
|
|
||||||
|
$x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1));
|
||||||
|
$y = $x1;
|
||||||
|
|
||||||
|
return $gcd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the square root of the given number, rounded down.
|
||||||
|
*
|
||||||
|
* The result is the largest x such that x² ≤ n.
|
||||||
|
* The input MUST NOT be negative.
|
||||||
|
*
|
||||||
|
* @param string $n The number.
|
||||||
|
*
|
||||||
|
* @return string The square root.
|
||||||
|
*/
|
||||||
|
abstract public function sqrt(string $n) : string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a number from an arbitrary base.
|
||||||
|
*
|
||||||
|
* This method can be overridden by the concrete implementation if the underlying library
|
||||||
|
* has built-in support for base conversion.
|
||||||
|
*
|
||||||
|
* @param string $number The number, positive or zero, non-empty, case-insensitively validated for the given base.
|
||||||
|
* @param int $base The base of the number, validated from 2 to 36.
|
||||||
|
*
|
||||||
|
* @return string The converted number, following the Calculator conventions.
|
||||||
|
*/
|
||||||
|
public function fromBase(string $number, int $base) : string
|
||||||
|
{
|
||||||
|
return $this->fromArbitraryBase(\strtolower($number), self::ALPHABET, $base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a number to an arbitrary base.
|
||||||
|
*
|
||||||
|
* This method can be overridden by the concrete implementation if the underlying library
|
||||||
|
* has built-in support for base conversion.
|
||||||
|
*
|
||||||
|
* @param string $number The number to convert, following the Calculator conventions.
|
||||||
|
* @param int $base The base to convert to, validated from 2 to 36.
|
||||||
|
*
|
||||||
|
* @return string The converted number, lowercase.
|
||||||
|
*/
|
||||||
|
public function toBase(string $number, int $base) : string
|
||||||
|
{
|
||||||
|
$negative = ($number[0] === '-');
|
||||||
|
|
||||||
|
if ($negative) {
|
||||||
|
$number = \substr($number, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$number = $this->toArbitraryBase($number, self::ALPHABET, $base);
|
||||||
|
|
||||||
|
if ($negative) {
|
||||||
|
return '-' . $number;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a non-negative number in an arbitrary base using a custom alphabet, to base 10.
|
||||||
|
*
|
||||||
|
* @param string $number The number to convert, validated as a non-empty string,
|
||||||
|
* containing only chars in the given alphabet/base.
|
||||||
|
* @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum.
|
||||||
|
* @param int $base The base of the number, validated from 2 to alphabet length.
|
||||||
|
*
|
||||||
|
* @return string The number in base 10, following the Calculator conventions.
|
||||||
|
*/
|
||||||
|
final public function fromArbitraryBase(string $number, string $alphabet, int $base) : string
|
||||||
|
{
|
||||||
|
// remove leading "zeros"
|
||||||
|
$number = \ltrim($number, $alphabet[0]);
|
||||||
|
|
||||||
|
if ($number === '') {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// optimize for "one"
|
||||||
|
if ($number === $alphabet[1]) {
|
||||||
|
return '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = '0';
|
||||||
|
$power = '1';
|
||||||
|
|
||||||
|
$base = (string) $base;
|
||||||
|
|
||||||
|
for ($i = \strlen($number) - 1; $i >= 0; $i--) {
|
||||||
|
$index = \strpos($alphabet, $number[$i]);
|
||||||
|
|
||||||
|
if ($index !== 0) {
|
||||||
|
$result = $this->add($result, ($index === 1)
|
||||||
|
? $power
|
||||||
|
: $this->mul($power, (string) $index)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i !== 0) {
|
||||||
|
$power = $this->mul($power, $base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a non-negative number to an arbitrary base using a custom alphabet.
|
||||||
|
*
|
||||||
|
* @param string $number The number to convert, positive or zero, following the Calculator conventions.
|
||||||
|
* @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum.
|
||||||
|
* @param int $base The base to convert to, validated from 2 to alphabet length.
|
||||||
|
*
|
||||||
|
* @return string The converted number in the given alphabet.
|
||||||
|
*/
|
||||||
|
final public function toArbitraryBase(string $number, string $alphabet, int $base) : string
|
||||||
|
{
|
||||||
|
if ($number === '0') {
|
||||||
|
return $alphabet[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$base = (string) $base;
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
while ($number !== '0') {
|
||||||
|
[$number, $remainder] = $this->divQR($number, $base);
|
||||||
|
$remainder = (int) $remainder;
|
||||||
|
|
||||||
|
$result .= $alphabet[$remainder];
|
||||||
|
}
|
||||||
|
|
||||||
|
return \strrev($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a rounded division.
|
||||||
|
*
|
||||||
|
* Rounding is performed when the remainder of the division is not zero.
|
||||||
|
*
|
||||||
|
* @param string $a The dividend.
|
||||||
|
* @param string $b The divisor, must not be zero.
|
||||||
|
* @param int $roundingMode The rounding mode.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If the rounding mode is invalid.
|
||||||
|
* @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary.
|
||||||
|
*/
|
||||||
|
final public function divRound(string $a, string $b, int $roundingMode) : string
|
||||||
|
{
|
||||||
|
[$quotient, $remainder] = $this->divQR($a, $b);
|
||||||
|
|
||||||
|
$hasDiscardedFraction = ($remainder !== '0');
|
||||||
|
$isPositiveOrZero = ($a[0] === '-') === ($b[0] === '-');
|
||||||
|
|
||||||
|
$discardedFractionSign = function() use ($remainder, $b) : int {
|
||||||
|
$r = $this->abs($this->mul($remainder, '2'));
|
||||||
|
$b = $this->abs($b);
|
||||||
|
|
||||||
|
return $this->cmp($r, $b);
|
||||||
|
};
|
||||||
|
|
||||||
|
$increment = false;
|
||||||
|
|
||||||
|
switch ($roundingMode) {
|
||||||
|
case RoundingMode::UNNECESSARY:
|
||||||
|
if ($hasDiscardedFraction) {
|
||||||
|
throw RoundingNecessaryException::roundingNecessary();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RoundingMode::UP:
|
||||||
|
$increment = $hasDiscardedFraction;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RoundingMode::DOWN:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RoundingMode::CEILING:
|
||||||
|
$increment = $hasDiscardedFraction && $isPositiveOrZero;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RoundingMode::FLOOR:
|
||||||
|
$increment = $hasDiscardedFraction && ! $isPositiveOrZero;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RoundingMode::HALF_UP:
|
||||||
|
$increment = $discardedFractionSign() >= 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RoundingMode::HALF_DOWN:
|
||||||
|
$increment = $discardedFractionSign() > 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RoundingMode::HALF_CEILING:
|
||||||
|
$increment = $isPositiveOrZero ? $discardedFractionSign() >= 0 : $discardedFractionSign() > 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RoundingMode::HALF_FLOOR:
|
||||||
|
$increment = $isPositiveOrZero ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RoundingMode::HALF_EVEN:
|
||||||
|
$lastDigit = (int) $quotient[-1];
|
||||||
|
$lastDigitIsEven = ($lastDigit % 2 === 0);
|
||||||
|
$increment = $lastDigitIsEven ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException('Invalid rounding mode.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($increment) {
|
||||||
|
return $this->add($quotient, $isPositiveOrZero ? '1' : '-1');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $quotient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates bitwise AND of two numbers.
|
||||||
|
*
|
||||||
|
* This method can be overridden by the concrete implementation if the underlying library
|
||||||
|
* has built-in support for bitwise operations.
|
||||||
|
*
|
||||||
|
* @param string $a
|
||||||
|
* @param string $b
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function and(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return $this->bitwise('and', $a, $b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates bitwise OR of two numbers.
|
||||||
|
*
|
||||||
|
* This method can be overridden by the concrete implementation if the underlying library
|
||||||
|
* has built-in support for bitwise operations.
|
||||||
|
*
|
||||||
|
* @param string $a
|
||||||
|
* @param string $b
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function or(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return $this->bitwise('or', $a, $b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates bitwise XOR of two numbers.
|
||||||
|
*
|
||||||
|
* This method can be overridden by the concrete implementation if the underlying library
|
||||||
|
* has built-in support for bitwise operations.
|
||||||
|
*
|
||||||
|
* @param string $a
|
||||||
|
* @param string $b
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function xor(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return $this->bitwise('xor', $a, $b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a bitwise operation on a decimal number.
|
||||||
|
*
|
||||||
|
* @param string $operator The operator to use, must be "and", "or" or "xor".
|
||||||
|
* @param string $a The left operand.
|
||||||
|
* @param string $b The right operand.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function bitwise(string $operator, string $a, string $b) : string
|
||||||
|
{
|
||||||
|
[$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
|
||||||
|
|
||||||
|
$aBin = $this->toBinary($aDig);
|
||||||
|
$bBin = $this->toBinary($bDig);
|
||||||
|
|
||||||
|
$aLen = \strlen($aBin);
|
||||||
|
$bLen = \strlen($bBin);
|
||||||
|
|
||||||
|
if ($aLen > $bLen) {
|
||||||
|
$bBin = \str_repeat("\x00", $aLen - $bLen) . $bBin;
|
||||||
|
} elseif ($bLen > $aLen) {
|
||||||
|
$aBin = \str_repeat("\x00", $bLen - $aLen) . $aBin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($aNeg) {
|
||||||
|
$aBin = $this->twosComplement($aBin);
|
||||||
|
}
|
||||||
|
if ($bNeg) {
|
||||||
|
$bBin = $this->twosComplement($bBin);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($operator) {
|
||||||
|
case 'and':
|
||||||
|
$value = $aBin & $bBin;
|
||||||
|
$negative = ($aNeg and $bNeg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'or':
|
||||||
|
$value = $aBin | $bBin;
|
||||||
|
$negative = ($aNeg or $bNeg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'xor':
|
||||||
|
$value = $aBin ^ $bBin;
|
||||||
|
$negative = ($aNeg xor $bNeg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException('Invalid bitwise operator.');
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($negative) {
|
||||||
|
$value = $this->twosComplement($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->toDecimal($value);
|
||||||
|
|
||||||
|
return $negative ? $this->neg($result) : $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $number A positive, binary number.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function twosComplement(string $number) : string
|
||||||
|
{
|
||||||
|
$xor = \str_repeat("\xff", \strlen($number));
|
||||||
|
|
||||||
|
$number ^= $xor;
|
||||||
|
|
||||||
|
for ($i = \strlen($number) - 1; $i >= 0; $i--) {
|
||||||
|
$byte = \ord($number[$i]);
|
||||||
|
|
||||||
|
if (++$byte !== 256) {
|
||||||
|
$number[$i] = \chr($byte);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$number[$i] = "\x00";
|
||||||
|
|
||||||
|
if ($i === 0) {
|
||||||
|
$number = "\x01" . $number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a decimal number to a binary string.
|
||||||
|
*
|
||||||
|
* @param string $number The number to convert, positive or zero, only digits.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function toBinary(string $number) : string
|
||||||
|
{
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
while ($number !== '0') {
|
||||||
|
[$number, $remainder] = $this->divQR($number, '256');
|
||||||
|
$result .= \chr((int) $remainder);
|
||||||
|
}
|
||||||
|
|
||||||
|
return \strrev($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the positive decimal representation of a binary number.
|
||||||
|
*
|
||||||
|
* @param string $bytes The bytes representing the number.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function toDecimal(string $bytes) : string
|
||||||
|
{
|
||||||
|
$result = '0';
|
||||||
|
$power = '1';
|
||||||
|
|
||||||
|
for ($i = \strlen($bytes) - 1; $i >= 0; $i--) {
|
||||||
|
$index = \ord($bytes[$i]);
|
||||||
|
|
||||||
|
if ($index !== 0) {
|
||||||
|
$result = $this->add($result, ($index === 1)
|
||||||
|
? $power
|
||||||
|
: $this->mul($power, (string) $index)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i !== 0) {
|
||||||
|
$power = $this->mul($power, '256');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
116
vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php
vendored
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math\Internal\Calculator;
|
||||||
|
|
||||||
|
use Brick\Math\Internal\Calculator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculator implementation built around the bcmath library.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @psalm-immutable
|
||||||
|
*/
|
||||||
|
class BcMathCalculator extends Calculator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function add(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \bcadd($a, $b, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function sub(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \bcsub($a, $b, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function mul(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \bcmul($a, $b, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @psalm-suppress InvalidNullableReturnType
|
||||||
|
* @psalm-suppress NullableReturnStatement
|
||||||
|
*/
|
||||||
|
public function divQ(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \bcdiv($a, $b, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @psalm-suppress InvalidNullableReturnType
|
||||||
|
* @psalm-suppress NullableReturnStatement
|
||||||
|
*/
|
||||||
|
public function divR(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
if (version_compare(PHP_VERSION, '7.2') >= 0) {
|
||||||
|
return \bcmod($a, $b, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return \bcmod($a, $b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function divQR(string $a, string $b) : array
|
||||||
|
{
|
||||||
|
$q = \bcdiv($a, $b, 0);
|
||||||
|
|
||||||
|
if (version_compare(PHP_VERSION, '7.2') >= 0) {
|
||||||
|
$r = \bcmod($a, $b, 0);
|
||||||
|
} else {
|
||||||
|
$r = \bcmod($a, $b);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert($q !== null);
|
||||||
|
assert($r !== null);
|
||||||
|
|
||||||
|
return [$q, $r];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function pow(string $a, int $e) : string
|
||||||
|
{
|
||||||
|
return \bcpow($a, (string) $e, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @psalm-suppress InvalidNullableReturnType
|
||||||
|
* @psalm-suppress NullableReturnStatement
|
||||||
|
*/
|
||||||
|
public function modPow(string $base, string $exp, string $mod) : string
|
||||||
|
{
|
||||||
|
return \bcpowmod($base, $exp, $mod, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @psalm-suppress NullableReturnStatement
|
||||||
|
* @psalm-suppress InvalidNullableReturnType
|
||||||
|
*/
|
||||||
|
public function sqrt(string $n) : string
|
||||||
|
{
|
||||||
|
return \bcsqrt($n, 0);
|
||||||
|
}
|
||||||
|
}
|
156
vendor/brick/math/src/Internal/Calculator/GmpCalculator.php
vendored
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math\Internal\Calculator;
|
||||||
|
|
||||||
|
use Brick\Math\Internal\Calculator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculator implementation built around the GMP library.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @psalm-immutable
|
||||||
|
*/
|
||||||
|
class GmpCalculator extends Calculator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function add(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_add($a, $b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function sub(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_sub($a, $b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function mul(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_mul($a, $b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function divQ(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_div_q($a, $b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function divR(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_div_r($a, $b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function divQR(string $a, string $b) : array
|
||||||
|
{
|
||||||
|
[$q, $r] = \gmp_div_qr($a, $b);
|
||||||
|
|
||||||
|
return [
|
||||||
|
\gmp_strval($q),
|
||||||
|
\gmp_strval($r)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function pow(string $a, int $e) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_pow($a, $e));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function modInverse(string $x, string $m) : ?string
|
||||||
|
{
|
||||||
|
$result = \gmp_invert($x, $m);
|
||||||
|
|
||||||
|
if ($result === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return \gmp_strval($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function modPow(string $base, string $exp, string $mod) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_powm($base, $exp, $mod));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function gcd(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_gcd($a, $b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function fromBase(string $number, int $base) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_init($number, $base));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function toBase(string $number, int $base) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval($number, $base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function and(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_and($a, $b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function or(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_or($a, $b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function xor(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_xor($a, $b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function sqrt(string $n) : string
|
||||||
|
{
|
||||||
|
return \gmp_strval(\gmp_sqrt($n));
|
||||||
|
}
|
||||||
|
}
|
634
vendor/brick/math/src/Internal/Calculator/NativeCalculator.php
vendored
Normal file
@ -0,0 +1,634 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math\Internal\Calculator;
|
||||||
|
|
||||||
|
use Brick\Math\Internal\Calculator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculator implementation using only native PHP code.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @psalm-immutable
|
||||||
|
*/
|
||||||
|
class NativeCalculator extends Calculator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The max number of digits the platform can natively add, subtract, multiply or divide without overflow.
|
||||||
|
* For multiplication, this represents the max sum of the lengths of both operands.
|
||||||
|
*
|
||||||
|
* For addition, it is assumed that an extra digit can hold a carry (1) without overflowing.
|
||||||
|
* Example: 32-bit: max number 1,999,999,999 (9 digits + carry)
|
||||||
|
* 64-bit: max number 1,999,999,999,999,999,999 (18 digits + carry)
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $maxDigits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
switch (PHP_INT_SIZE) {
|
||||||
|
case 4:
|
||||||
|
$this->maxDigits = 9;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
$this->maxDigits = 18;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function add(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @psalm-var numeric-string $a
|
||||||
|
* @psalm-var numeric-string $b
|
||||||
|
*/
|
||||||
|
$result = $a + $b;
|
||||||
|
|
||||||
|
if (is_int($result)) {
|
||||||
|
return (string) $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a === '0') {
|
||||||
|
return $b;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($b === '0') {
|
||||||
|
return $a;
|
||||||
|
}
|
||||||
|
|
||||||
|
[$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
|
||||||
|
|
||||||
|
$result = $aNeg === $bNeg ? $this->doAdd($aDig, $bDig) : $this->doSub($aDig, $bDig);
|
||||||
|
|
||||||
|
if ($aNeg) {
|
||||||
|
$result = $this->neg($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function sub(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return $this->add($a, $this->neg($b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function mul(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @psalm-var numeric-string $a
|
||||||
|
* @psalm-var numeric-string $b
|
||||||
|
*/
|
||||||
|
$result = $a * $b;
|
||||||
|
|
||||||
|
if (is_int($result)) {
|
||||||
|
return (string) $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a === '0' || $b === '0') {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a === '1') {
|
||||||
|
return $b;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($b === '1') {
|
||||||
|
return $a;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a === '-1') {
|
||||||
|
return $this->neg($b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($b === '-1') {
|
||||||
|
return $this->neg($a);
|
||||||
|
}
|
||||||
|
|
||||||
|
[$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
|
||||||
|
|
||||||
|
$result = $this->doMul($aDig, $bDig);
|
||||||
|
|
||||||
|
if ($aNeg !== $bNeg) {
|
||||||
|
$result = $this->neg($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function divQ(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
return $this->divQR($a, $b)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function divR(string $a, string $b): string
|
||||||
|
{
|
||||||
|
return $this->divQR($a, $b)[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function divQR(string $a, string $b) : array
|
||||||
|
{
|
||||||
|
if ($a === '0') {
|
||||||
|
return ['0', '0'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a === $b) {
|
||||||
|
return ['1', '0'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($b === '1') {
|
||||||
|
return [$a, '0'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($b === '-1') {
|
||||||
|
return [$this->neg($a), '0'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @psalm-var numeric-string $a */
|
||||||
|
$na = $a * 1; // cast to number
|
||||||
|
|
||||||
|
if (is_int($na)) {
|
||||||
|
/** @psalm-var numeric-string $b */
|
||||||
|
$nb = $b * 1;
|
||||||
|
|
||||||
|
if (is_int($nb)) {
|
||||||
|
// the only division that may overflow is PHP_INT_MIN / -1,
|
||||||
|
// which cannot happen here as we've already handled a divisor of -1 above.
|
||||||
|
$r = $na % $nb;
|
||||||
|
$q = ($na - $r) / $nb;
|
||||||
|
|
||||||
|
assert(is_int($q));
|
||||||
|
|
||||||
|
return [
|
||||||
|
(string) $q,
|
||||||
|
(string) $r
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
|
||||||
|
|
||||||
|
[$q, $r] = $this->doDiv($aDig, $bDig);
|
||||||
|
|
||||||
|
if ($aNeg !== $bNeg) {
|
||||||
|
$q = $this->neg($q);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($aNeg) {
|
||||||
|
$r = $this->neg($r);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$q, $r];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function pow(string $a, int $e) : string
|
||||||
|
{
|
||||||
|
if ($e === 0) {
|
||||||
|
return '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($e === 1) {
|
||||||
|
return $a;
|
||||||
|
}
|
||||||
|
|
||||||
|
$odd = $e % 2;
|
||||||
|
$e -= $odd;
|
||||||
|
|
||||||
|
$aa = $this->mul($a, $a);
|
||||||
|
|
||||||
|
/** @psalm-suppress PossiblyInvalidArgument We're sure that $e / 2 is an int now */
|
||||||
|
$result = $this->pow($aa, $e / 2);
|
||||||
|
|
||||||
|
if ($odd === 1) {
|
||||||
|
$result = $this->mul($result, $a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Algorithm from: https://www.geeksforgeeks.org/modular-exponentiation-power-in-modular-arithmetic/
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function modPow(string $base, string $exp, string $mod) : string
|
||||||
|
{
|
||||||
|
// special case: the algorithm below fails with 0 power 0 mod 1 (returns 1 instead of 0)
|
||||||
|
if ($base === '0' && $exp === '0' && $mod === '1') {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case: the algorithm below fails with power 0 mod 1 (returns 1 instead of 0)
|
||||||
|
if ($exp === '0' && $mod === '1') {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = $base;
|
||||||
|
|
||||||
|
$res = '1';
|
||||||
|
|
||||||
|
// numbers are positive, so we can use remainder instead of modulo
|
||||||
|
$x = $this->divR($x, $mod);
|
||||||
|
|
||||||
|
while ($exp !== '0') {
|
||||||
|
if (in_array($exp[-1], ['1', '3', '5', '7', '9'])) { // odd
|
||||||
|
$res = $this->divR($this->mul($res, $x), $mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
$exp = $this->divQ($exp, '2');
|
||||||
|
$x = $this->divR($this->mul($x, $x), $mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapted from https://cp-algorithms.com/num_methods/roots_newton.html
|
||||||
|
*
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function sqrt(string $n) : string
|
||||||
|
{
|
||||||
|
if ($n === '0') {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// initial approximation
|
||||||
|
$x = \str_repeat('9', \intdiv(\strlen($n), 2) ?: 1);
|
||||||
|
|
||||||
|
$decreased = false;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
$nx = $this->divQ($this->add($x, $this->divQ($n, $x)), '2');
|
||||||
|
|
||||||
|
if ($x === $nx || $this->cmp($nx, $x) > 0 && $decreased) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$decreased = $this->cmp($nx, $x) < 0;
|
||||||
|
$x = $nx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the addition of two non-signed large integers.
|
||||||
|
*
|
||||||
|
* @param string $a The first operand.
|
||||||
|
* @param string $b The second operand.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function doAdd(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
[$a, $b, $length] = $this->pad($a, $b);
|
||||||
|
|
||||||
|
$carry = 0;
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) {
|
||||||
|
$blockLength = $this->maxDigits;
|
||||||
|
|
||||||
|
if ($i < 0) {
|
||||||
|
$blockLength += $i;
|
||||||
|
/** @psalm-suppress LoopInvalidation */
|
||||||
|
$i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @psalm-var numeric-string $blockA */
|
||||||
|
$blockA = \substr($a, $i, $blockLength);
|
||||||
|
|
||||||
|
/** @psalm-var numeric-string $blockB */
|
||||||
|
$blockB = \substr($b, $i, $blockLength);
|
||||||
|
|
||||||
|
$sum = (string) ($blockA + $blockB + $carry);
|
||||||
|
$sumLength = \strlen($sum);
|
||||||
|
|
||||||
|
if ($sumLength > $blockLength) {
|
||||||
|
$sum = \substr($sum, 1);
|
||||||
|
$carry = 1;
|
||||||
|
} else {
|
||||||
|
if ($sumLength < $blockLength) {
|
||||||
|
$sum = \str_repeat('0', $blockLength - $sumLength) . $sum;
|
||||||
|
}
|
||||||
|
$carry = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $sum . $result;
|
||||||
|
|
||||||
|
if ($i === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($carry === 1) {
|
||||||
|
$result = '1' . $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the subtraction of two non-signed large integers.
|
||||||
|
*
|
||||||
|
* @param string $a The first operand.
|
||||||
|
* @param string $b The second operand.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function doSub(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
if ($a === $b) {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that we always subtract to a positive result: biggest minus smallest.
|
||||||
|
$cmp = $this->doCmp($a, $b);
|
||||||
|
|
||||||
|
$invert = ($cmp === -1);
|
||||||
|
|
||||||
|
if ($invert) {
|
||||||
|
$c = $a;
|
||||||
|
$a = $b;
|
||||||
|
$b = $c;
|
||||||
|
}
|
||||||
|
|
||||||
|
[$a, $b, $length] = $this->pad($a, $b);
|
||||||
|
|
||||||
|
$carry = 0;
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
$complement = 10 ** $this->maxDigits;
|
||||||
|
|
||||||
|
for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) {
|
||||||
|
$blockLength = $this->maxDigits;
|
||||||
|
|
||||||
|
if ($i < 0) {
|
||||||
|
$blockLength += $i;
|
||||||
|
/** @psalm-suppress LoopInvalidation */
|
||||||
|
$i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @psalm-var numeric-string $blockA */
|
||||||
|
$blockA = \substr($a, $i, $blockLength);
|
||||||
|
|
||||||
|
/** @psalm-var numeric-string $blockB */
|
||||||
|
$blockB = \substr($b, $i, $blockLength);
|
||||||
|
|
||||||
|
$sum = $blockA - $blockB - $carry;
|
||||||
|
|
||||||
|
if ($sum < 0) {
|
||||||
|
$sum += $complement;
|
||||||
|
$carry = 1;
|
||||||
|
} else {
|
||||||
|
$carry = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sum = (string) $sum;
|
||||||
|
$sumLength = \strlen($sum);
|
||||||
|
|
||||||
|
if ($sumLength < $blockLength) {
|
||||||
|
$sum = \str_repeat('0', $blockLength - $sumLength) . $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $sum . $result;
|
||||||
|
|
||||||
|
if ($i === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carry cannot be 1 when the loop ends, as a > b
|
||||||
|
assert($carry === 0);
|
||||||
|
|
||||||
|
$result = \ltrim($result, '0');
|
||||||
|
|
||||||
|
if ($invert) {
|
||||||
|
$result = $this->neg($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the multiplication of two non-signed large integers.
|
||||||
|
*
|
||||||
|
* @param string $a The first operand.
|
||||||
|
* @param string $b The second operand.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function doMul(string $a, string $b) : string
|
||||||
|
{
|
||||||
|
$x = \strlen($a);
|
||||||
|
$y = \strlen($b);
|
||||||
|
|
||||||
|
$maxDigits = \intdiv($this->maxDigits, 2);
|
||||||
|
$complement = 10 ** $maxDigits;
|
||||||
|
|
||||||
|
$result = '0';
|
||||||
|
|
||||||
|
for ($i = $x - $maxDigits;; $i -= $maxDigits) {
|
||||||
|
$blockALength = $maxDigits;
|
||||||
|
|
||||||
|
if ($i < 0) {
|
||||||
|
$blockALength += $i;
|
||||||
|
/** @psalm-suppress LoopInvalidation */
|
||||||
|
$i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$blockA = (int) \substr($a, $i, $blockALength);
|
||||||
|
|
||||||
|
$line = '';
|
||||||
|
$carry = 0;
|
||||||
|
|
||||||
|
for ($j = $y - $maxDigits;; $j -= $maxDigits) {
|
||||||
|
$blockBLength = $maxDigits;
|
||||||
|
|
||||||
|
if ($j < 0) {
|
||||||
|
$blockBLength += $j;
|
||||||
|
/** @psalm-suppress LoopInvalidation */
|
||||||
|
$j = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$blockB = (int) \substr($b, $j, $blockBLength);
|
||||||
|
|
||||||
|
$mul = $blockA * $blockB + $carry;
|
||||||
|
$value = $mul % $complement;
|
||||||
|
$carry = ($mul - $value) / $complement;
|
||||||
|
|
||||||
|
$value = (string) $value;
|
||||||
|
$value = \str_pad($value, $maxDigits, '0', STR_PAD_LEFT);
|
||||||
|
|
||||||
|
$line = $value . $line;
|
||||||
|
|
||||||
|
if ($j === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($carry !== 0) {
|
||||||
|
$line = $carry . $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
$line = \ltrim($line, '0');
|
||||||
|
|
||||||
|
if ($line !== '') {
|
||||||
|
$line .= \str_repeat('0', $x - $blockALength - $i);
|
||||||
|
$result = $this->add($result, $line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the division of two non-signed large integers.
|
||||||
|
*
|
||||||
|
* @param string $a The first operand.
|
||||||
|
* @param string $b The second operand.
|
||||||
|
*
|
||||||
|
* @return string[] The quotient and remainder.
|
||||||
|
*/
|
||||||
|
private function doDiv(string $a, string $b) : array
|
||||||
|
{
|
||||||
|
$cmp = $this->doCmp($a, $b);
|
||||||
|
|
||||||
|
if ($cmp === -1) {
|
||||||
|
return ['0', $a];
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = \strlen($a);
|
||||||
|
$y = \strlen($b);
|
||||||
|
|
||||||
|
// we now know that a >= b && x >= y
|
||||||
|
|
||||||
|
$q = '0'; // quotient
|
||||||
|
$r = $a; // remainder
|
||||||
|
$z = $y; // focus length, always $y or $y+1
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
$focus = \substr($a, 0, $z);
|
||||||
|
|
||||||
|
$cmp = $this->doCmp($focus, $b);
|
||||||
|
|
||||||
|
if ($cmp === -1) {
|
||||||
|
if ($z === $x) { // remainder < dividend
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$z++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$zeros = \str_repeat('0', $x - $z);
|
||||||
|
|
||||||
|
$q = $this->add($q, '1' . $zeros);
|
||||||
|
$a = $this->sub($a, $b . $zeros);
|
||||||
|
|
||||||
|
$r = $a;
|
||||||
|
|
||||||
|
if ($r === '0') { // remainder == 0
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = \strlen($a);
|
||||||
|
|
||||||
|
if ($x < $y) { // remainder < dividend
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$z = $y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$q, $r];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two non-signed large numbers.
|
||||||
|
*
|
||||||
|
* @param string $a The first operand.
|
||||||
|
* @param string $b The second operand.
|
||||||
|
*
|
||||||
|
* @return int [-1, 0, 1]
|
||||||
|
*/
|
||||||
|
private function doCmp(string $a, string $b) : int
|
||||||
|
{
|
||||||
|
$x = \strlen($a);
|
||||||
|
$y = \strlen($b);
|
||||||
|
|
||||||
|
$cmp = $x <=> $y;
|
||||||
|
|
||||||
|
if ($cmp !== 0) {
|
||||||
|
return $cmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return \strcmp($a, $b) <=> 0; // enforce [-1, 0, 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pads the left of one of the given numbers with zeros if necessary to make both numbers the same length.
|
||||||
|
*
|
||||||
|
* The numbers must only consist of digits, without leading minus sign.
|
||||||
|
*
|
||||||
|
* @param string $a The first operand.
|
||||||
|
* @param string $b The second operand.
|
||||||
|
*
|
||||||
|
* @return array{string, string, int}
|
||||||
|
*/
|
||||||
|
private function pad(string $a, string $b) : array
|
||||||
|
{
|
||||||
|
$x = \strlen($a);
|
||||||
|
$y = \strlen($b);
|
||||||
|
|
||||||
|
if ($x > $y) {
|
||||||
|
$b = \str_repeat('0', $x - $y) . $b;
|
||||||
|
|
||||||
|
return [$a, $b, $x];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($x < $y) {
|
||||||
|
$a = \str_repeat('0', $y - $x) . $a;
|
||||||
|
|
||||||
|
return [$a, $b, $y];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$a, $b, $x];
|
||||||
|
}
|
||||||
|
}
|
107
vendor/brick/math/src/RoundingMode.php
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Brick\Math;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies a rounding behavior for numerical operations capable of discarding precision.
|
||||||
|
*
|
||||||
|
* Each rounding mode indicates how the least significant returned digit of a rounded result
|
||||||
|
* is to be calculated. If fewer digits are returned than the digits needed to represent the
|
||||||
|
* exact numerical result, the discarded digits will be referred to as the discarded fraction
|
||||||
|
* regardless the digits' contribution to the value of the number. In other words, considered
|
||||||
|
* as a numerical value, the discarded fraction could have an absolute value greater than one.
|
||||||
|
*/
|
||||||
|
final class RoundingMode
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Private constructor. This class is not instantiable.
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the requested operation has an exact result, hence no rounding is necessary.
|
||||||
|
*
|
||||||
|
* If this rounding mode is specified on an operation that yields a result that
|
||||||
|
* cannot be represented at the requested scale, a RoundingNecessaryException is thrown.
|
||||||
|
*/
|
||||||
|
public const UNNECESSARY = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds away from zero.
|
||||||
|
*
|
||||||
|
* Always increments the digit prior to a nonzero discarded fraction.
|
||||||
|
* Note that this rounding mode never decreases the magnitude of the calculated value.
|
||||||
|
*/
|
||||||
|
public const UP = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds towards zero.
|
||||||
|
*
|
||||||
|
* Never increments the digit prior to a discarded fraction (i.e., truncates).
|
||||||
|
* Note that this rounding mode never increases the magnitude of the calculated value.
|
||||||
|
*/
|
||||||
|
public const DOWN = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds towards positive infinity.
|
||||||
|
*
|
||||||
|
* If the result is positive, behaves as for UP; if negative, behaves as for DOWN.
|
||||||
|
* Note that this rounding mode never decreases the calculated value.
|
||||||
|
*/
|
||||||
|
public const CEILING = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds towards negative infinity.
|
||||||
|
*
|
||||||
|
* If the result is positive, behave as for DOWN; if negative, behave as for UP.
|
||||||
|
* Note that this rounding mode never increases the calculated value.
|
||||||
|
*/
|
||||||
|
public const FLOOR = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
|
||||||
|
*
|
||||||
|
* Behaves as for UP if the discarded fraction is >= 0.5; otherwise, behaves as for DOWN.
|
||||||
|
* Note that this is the rounding mode commonly taught at school.
|
||||||
|
*/
|
||||||
|
public const HALF_UP = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
|
||||||
|
*
|
||||||
|
* Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves as for DOWN.
|
||||||
|
*/
|
||||||
|
public const HALF_DOWN = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards positive infinity.
|
||||||
|
*
|
||||||
|
* If the result is positive, behaves as for HALF_UP; if negative, behaves as for HALF_DOWN.
|
||||||
|
*/
|
||||||
|
public const HALF_CEILING = 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards negative infinity.
|
||||||
|
*
|
||||||
|
* If the result is positive, behaves as for HALF_DOWN; if negative, behaves as for HALF_UP.
|
||||||
|
*/
|
||||||
|
public const HALF_FLOOR = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor.
|
||||||
|
*
|
||||||
|
* Behaves as for HALF_UP if the digit to the left of the discarded fraction is odd;
|
||||||
|
* behaves as for HALF_DOWN if it's even.
|
||||||
|
*
|
||||||
|
* Note that this is the rounding mode that statistically minimizes
|
||||||
|
* cumulative error when applied repeatedly over a sequence of calculations.
|
||||||
|
* It is sometimes known as "Banker's rounding", and is chiefly used in the USA.
|
||||||
|
*/
|
||||||
|
public const HALF_EVEN = 9;
|
||||||
|
}
|
579
vendor/composer/ClassLoader.php
vendored
Normal file
@ -0,0 +1,579 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||||
|
*
|
||||||
|
* $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
*
|
||||||
|
* // register classes with namespaces
|
||||||
|
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||||
|
* $loader->add('Symfony', __DIR__.'/framework');
|
||||||
|
*
|
||||||
|
* // activate the autoloader
|
||||||
|
* $loader->register();
|
||||||
|
*
|
||||||
|
* // to enable searching the include path (eg. for PEAR packages)
|
||||||
|
* $loader->setUseIncludePath(true);
|
||||||
|
*
|
||||||
|
* In this example, if you try to use a class in the Symfony\Component
|
||||||
|
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||||
|
* the autoloader will first look for the class under the component/
|
||||||
|
* directory, and it will then fallback to the framework/ directory if not
|
||||||
|
* found before giving up.
|
||||||
|
*
|
||||||
|
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
* @see https://www.php-fig.org/psr/psr-0/
|
||||||
|
* @see https://www.php-fig.org/psr/psr-4/
|
||||||
|
*/
|
||||||
|
class ClassLoader
|
||||||
|
{
|
||||||
|
/** @var \Closure(string):void */
|
||||||
|
private static $includeFile;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $vendorDir;
|
||||||
|
|
||||||
|
// PSR-4
|
||||||
|
/**
|
||||||
|
* @var array<string, array<string, int>>
|
||||||
|
*/
|
||||||
|
private $prefixLengthsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var array<string, list<string>>
|
||||||
|
*/
|
||||||
|
private $prefixDirsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr4 = array();
|
||||||
|
|
||||||
|
// PSR-0
|
||||||
|
/**
|
||||||
|
* List of PSR-0 prefixes
|
||||||
|
*
|
||||||
|
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||||
|
*
|
||||||
|
* @var array<string, array<string, list<string>>>
|
||||||
|
*/
|
||||||
|
private $prefixesPsr0 = array();
|
||||||
|
/**
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr0 = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $useIncludePath = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
private $classMap = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $classMapAuthoritative = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, bool>
|
||||||
|
*/
|
||||||
|
private $missingClasses = array();
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $apcuPrefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, self>
|
||||||
|
*/
|
||||||
|
private static $registeredLoaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|null $vendorDir
|
||||||
|
*/
|
||||||
|
public function __construct($vendorDir = null)
|
||||||
|
{
|
||||||
|
$this->vendorDir = $vendorDir;
|
||||||
|
self::initializeIncludeClosure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, list<string>>
|
||||||
|
*/
|
||||||
|
public function getPrefixes()
|
||||||
|
{
|
||||||
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, list<string>>
|
||||||
|
*/
|
||||||
|
public function getPrefixesPsr4()
|
||||||
|
{
|
||||||
|
return $this->prefixDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirs()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirsPsr4()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string> Array of classname => path
|
||||||
|
*/
|
||||||
|
public function getClassMap()
|
||||||
|
{
|
||||||
|
return $this->classMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, string> $classMap Class to filename map
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addClassMap(array $classMap)
|
||||||
|
{
|
||||||
|
if ($this->classMap) {
|
||||||
|
$this->classMap = array_merge($this->classMap, $classMap);
|
||||||
|
} else {
|
||||||
|
$this->classMap = $classMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix, either
|
||||||
|
* appending or prepending to the ones previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param list<string>|string $paths The PSR-0 root directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function add($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
$paths = (array) $paths;
|
||||||
|
if (!$prefix) {
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->fallbackDirsPsr0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$this->fallbackDirsPsr0,
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$first = $prefix[0];
|
||||||
|
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($prepend) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->prefixesPsr0[$first][$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$this->prefixesPsr0[$first][$prefix],
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace, either
|
||||||
|
* appending or prepending to the ones previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param list<string>|string $paths The PSR-4 base directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addPsr4($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
$paths = (array) $paths;
|
||||||
|
if (!$prefix) {
|
||||||
|
// Register directories for the root namespace.
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->fallbackDirsPsr4
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$this->fallbackDirsPsr4,
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||||
|
// Register directories for a new namespace.
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||||
|
} elseif ($prepend) {
|
||||||
|
// Prepend directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->prefixDirsPsr4[$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Append directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$this->prefixDirsPsr4[$prefix],
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix,
|
||||||
|
* replacing any others previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param list<string>|string $paths The PSR-0 base directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr0 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace,
|
||||||
|
* replacing any others previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param list<string>|string $paths The PSR-4 base directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setPsr4($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr4 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns on searching the include path for class files.
|
||||||
|
*
|
||||||
|
* @param bool $useIncludePath
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUseIncludePath($useIncludePath)
|
||||||
|
{
|
||||||
|
$this->useIncludePath = $useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to check if the autoloader uses the include path to check
|
||||||
|
* for classes.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUseIncludePath()
|
||||||
|
{
|
||||||
|
return $this->useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns off searching the prefix and fallback directories for classes
|
||||||
|
* that have not been registered with the class map.
|
||||||
|
*
|
||||||
|
* @param bool $classMapAuthoritative
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||||
|
{
|
||||||
|
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should class lookup fail if not found in the current class map?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isClassMapAuthoritative()
|
||||||
|
{
|
||||||
|
return $this->classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||||
|
*
|
||||||
|
* @param string|null $apcuPrefix
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setApcuPrefix($apcuPrefix)
|
||||||
|
{
|
||||||
|
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getApcuPrefix()
|
||||||
|
{
|
||||||
|
return $this->apcuPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @param bool $prepend Whether to prepend the autoloader or not
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register($prepend = false)
|
||||||
|
{
|
||||||
|
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||||
|
|
||||||
|
if (null === $this->vendorDir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prepend) {
|
||||||
|
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||||
|
} else {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unregister()
|
||||||
|
{
|
||||||
|
spl_autoload_unregister(array($this, 'loadClass'));
|
||||||
|
|
||||||
|
if (null !== $this->vendorDir) {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given class or interface.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
* @return true|null True if loaded, null otherwise
|
||||||
|
*/
|
||||||
|
public function loadClass($class)
|
||||||
|
{
|
||||||
|
if ($file = $this->findFile($class)) {
|
||||||
|
$includeFile = self::$includeFile;
|
||||||
|
$includeFile($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the path to the file where the class is defined.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
*
|
||||||
|
* @return string|false The path if found, false otherwise
|
||||||
|
*/
|
||||||
|
public function findFile($class)
|
||||||
|
{
|
||||||
|
// class map lookup
|
||||||
|
if (isset($this->classMap[$class])) {
|
||||||
|
return $this->classMap[$class];
|
||||||
|
}
|
||||||
|
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||||
|
if ($hit) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
|
// Search for Hack files if we are running on HHVM
|
||||||
|
if (false === $file && defined('HHVM_VERSION')) {
|
||||||
|
$file = $this->findFileWithExtension($class, '.hh');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
apcu_add($this->apcuPrefix.$class, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $file) {
|
||||||
|
// Remember that this class does not exist.
|
||||||
|
$this->missingClasses[$class] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||||
|
*
|
||||||
|
* @return array<string, self>
|
||||||
|
*/
|
||||||
|
public static function getRegisteredLoaders()
|
||||||
|
{
|
||||||
|
return self::$registeredLoaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
* @param string $ext
|
||||||
|
* @return string|false
|
||||||
|
*/
|
||||||
|
private function findFileWithExtension($class, $ext)
|
||||||
|
{
|
||||||
|
// PSR-4 lookup
|
||||||
|
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
|
||||||
|
$first = $class[0];
|
||||||
|
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||||
|
$subPath = $class;
|
||||||
|
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||||
|
$subPath = substr($subPath, 0, $lastPos);
|
||||||
|
$search = $subPath . '\\';
|
||||||
|
if (isset($this->prefixDirsPsr4[$search])) {
|
||||||
|
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||||
|
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||||
|
if (file_exists($file = $dir . $pathEnd)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-4 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 lookup
|
||||||
|
if (false !== $pos = strrpos($class, '\\')) {
|
||||||
|
// namespaced class name
|
||||||
|
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||||
|
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||||
|
} else {
|
||||||
|
// PEAR-like class name
|
||||||
|
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->prefixesPsr0[$first])) {
|
||||||
|
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||||
|
if (0 === strpos($class, $prefix)) {
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 include paths.
|
||||||
|
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function initializeIncludeClosure()
|
||||||
|
{
|
||||||
|
if (self::$includeFile !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope isolated include.
|
||||||
|
*
|
||||||
|
* Prevents access to $this/self from included files.
|
||||||
|
*
|
||||||
|
* @param string $file
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
self::$includeFile = \Closure::bind(static function($file) {
|
||||||
|
include $file;
|
||||||
|
}, null, null);
|
||||||
|
}
|
||||||
|
}
|