Initial commit
This commit is contained in:
commit
bd9559198c
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
/d/lib/
|
312
LICENSE
Normal file
312
LICENSE
Normal file
@ -0,0 +1,312 @@
|
||||
Mozilla Public License Version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor" means each individual or legal entity that creates, contributes
|
||||
to the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version" means the combination of the Contributions of others
|
||||
(if any) used by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution" means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software" means Source Code Form to which the initial Contributor
|
||||
has attached the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses" means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described in Exhibit
|
||||
B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of version
|
||||
1.1 or earlier of the License, but not also under the terms of a Secondary
|
||||
License.
|
||||
|
||||
1.6. "Executable Form" means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work" means a work that combines Covered Software with other
|
||||
material, in a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License" means this document.
|
||||
|
||||
1.9. "Licensable" means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications" means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to, deletion
|
||||
from, or modification of the contents of Covered Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor means any patent claim(s), including
|
||||
without limitation, method, process, and apparatus claims, in any patent Licensable
|
||||
by such Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import, or
|
||||
transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License" means either the GNU General Public License, Version
|
||||
2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form" means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your") means an individual or a legal entity exercising rights
|
||||
under this License. For legal entities, "You" includes any entity that controls,
|
||||
is controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or otherwise,
|
||||
or (b) ownership of more than fifty percent (50%) of the outstanding shares
|
||||
or beneficial ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive
|
||||
license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark) Licensable
|
||||
by such Contributor to use, reproduce, make available, modify, display, perform,
|
||||
distribute, and otherwise exploit its Contributions, either on an unmodified
|
||||
basis, with Modifications, or as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its Contributions or
|
||||
its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution become
|
||||
effective for each Contribution on the date the Contributor first distributes
|
||||
such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under this
|
||||
License. No additional rights or licenses will be implied from the distribution
|
||||
or licensing of Covered Software under this License. Notwithstanding Section
|
||||
2.1(b) above, no patent license is granted by a Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's modifications
|
||||
of Covered Software, or (ii) the combination of its Contributions with other
|
||||
software (except as part of its Contributor Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of its
|
||||
Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks, or
|
||||
logos of any Contributor (except as may be necessary to comply with the notice
|
||||
requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to distribute
|
||||
the Covered Software under a subsequent version of this License (see Section
|
||||
10.2) or under the terms of a Secondary License (if permitted under the terms
|
||||
of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its Contributions
|
||||
are its original creation(s) or it has sufficient rights to grant the rights
|
||||
to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under applicable
|
||||
copyright doctrines of fair use, fair dealing, or other equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any Modifications
|
||||
that You create or to which You contribute, must be under the terms of this
|
||||
License. You must inform recipients that the Source Code Form of the Covered
|
||||
Software is governed by the terms of this License, and how they can obtain
|
||||
a copy of this License. You may not attempt to alter or restrict the recipients'
|
||||
rights in the Source Code Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the Executable
|
||||
Form how they can obtain a copy of such Source Code Form by reasonable means
|
||||
in a timely manner, at a charge no more than the cost of distribution to the
|
||||
recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this License,
|
||||
or sublicense it under different terms, provided that the license for the
|
||||
Executable Form does not attempt to limit or alter the recipients' rights
|
||||
in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice, provided
|
||||
that You also comply with the requirements of this License for the Covered
|
||||
Software. If the Larger Work is a combination of Covered Software with a work
|
||||
governed by one or more Secondary Licenses, and the Covered Software is not
|
||||
Incompatible With Secondary Licenses, this License permits You to additionally
|
||||
distribute such Covered Software under the terms of such Secondary License(s),
|
||||
so that the recipient of the Larger Work may, at their option, further distribute
|
||||
the Covered Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices (including
|
||||
copyright notices, patent notices, disclaimers of warranty, or limitations
|
||||
of liability) contained within the Source Code Form of the Covered Software,
|
||||
except that You may alter any license notices to the extent required to remedy
|
||||
known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support, indemnity
|
||||
or liability obligations to one or more recipients of Covered Software. However,
|
||||
You may do so only on Your own behalf, and not on behalf of any Contributor.
|
||||
You must make it absolutely clear that any such warranty, support, indemnity,
|
||||
or liability obligation is offered by You alone, and You hereby agree to indemnify
|
||||
every Contributor for any liability incurred by such Contributor as a result
|
||||
of warranty, support, indemnity or liability terms You offer. You may include
|
||||
additional disclaimers of warranty and limitations of liability specific to
|
||||
any jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute, judicial
|
||||
order, or regulation then You must: (a) comply with the terms of this License
|
||||
to the maximum extent possible; and (b) describe the limitations and the code
|
||||
they affect. Such description must be placed in a text file included with
|
||||
all distributions of the Covered Software under this License. Except to the
|
||||
extent prohibited by statute or regulation, such description must be sufficiently
|
||||
detailed for a recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if
|
||||
You fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor are
|
||||
reinstated (a) provisionally, unless and until such Contributor explicitly
|
||||
and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor
|
||||
fails to notify You of the non-compliance by some reasonable means prior to
|
||||
60 days after You have come back into compliance. Moreover, Your grants from
|
||||
a particular Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the first
|
||||
time You have received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent infringement
|
||||
claim (excluding declaratory judgment actions, counter-claims, and cross-claims)
|
||||
alleging that a Contributor Version directly or indirectly infringes any patent,
|
||||
then the rights granted to You by any and all Contributors for the Covered
|
||||
Software under Section 2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end
|
||||
user license agreements (excluding distributors and resellers) which have
|
||||
been validly granted by You or Your distributors under this License prior
|
||||
to termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis, without
|
||||
warranty of any kind, either expressed, implied, or statutory, including,
|
||||
without limitation, warranties that the Covered Software is free of defects,
|
||||
merchantable, fit for a particular purpose or non-infringing. The entire risk
|
||||
as to the quality and performance of the Covered Software is with You. Should
|
||||
any Covered Software prove defective in any respect, You (not any Contributor)
|
||||
assume the cost of any necessary servicing, repair, or correction. This disclaimer
|
||||
of warranty constitutes an essential part of this License. No use of any Covered
|
||||
Software is authorized under this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any character
|
||||
including, without limitation, damages for lost profits, loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all other commercial
|
||||
damages or losses, even if such party shall have been informed of the possibility
|
||||
of such damages. This limitation of liability shall not apply to liability
|
||||
for death or personal injury resulting from such party's negligence to the
|
||||
extent applicable law prohibits such limitation. Some jurisdictions do not
|
||||
allow the exclusion or limitation of incidental or consequential damages,
|
||||
so this exclusion and limitation may not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of business
|
||||
and such litigation shall be governed by laws of that jurisdiction, without
|
||||
reference to its conflict-of-law provisions. Nothing in this Section shall
|
||||
prevent a party's ability to bring cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject matter
|
||||
hereof. If any provision of this License is held to be unenforceable, such
|
||||
provision shall be reformed only to the extent necessary to make it enforceable.
|
||||
Any law or regulation which provides that the language of a contract shall
|
||||
be construed against the drafter shall not be used to construe this License
|
||||
against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section 10.3,
|
||||
no one other than the license steward has the right to modify or publish new
|
||||
versions of this License. Each version will be given a distinguishing version
|
||||
number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version of
|
||||
the License under which You originally received the Covered Software, or under
|
||||
the terms of any subsequent version published by the license steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to create
|
||||
a new license for such software, you may create and use a modified version
|
||||
of this License if you rename the license and remove any references to the
|
||||
name of the license steward (except to note that such modified license differs
|
||||
from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With Secondary
|
||||
Licenses under the terms of this version of the License, the notice described
|
||||
in Exhibit B of this License must be attached. Exhibit A - Source Code Form
|
||||
License Notice
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain
|
||||
one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as defined
|
||||
by the Mozilla Public License, v. 2.0.
|
4
README.md
Normal file
4
README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# omz-docs
|
||||
|
||||
Dynamically generated documentation pages for everyone, currently running at [docs.omegazero.org](https://docs.omegazero.org).
|
||||
|
286
common/docs.css
Normal file
286
common/docs.css
Normal file
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (C) 2021 omegazero.org
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
:root{
|
||||
--topbar-background: black;
|
||||
--sidebar-background: rgb(32, 32, 32);
|
||||
--sidebar-entry-l1-background: rgb(32, 32, 32);
|
||||
--sidebar-entry-l1-hover: rgb(48, 48, 48);
|
||||
--sidebar-entry-l2-background: rgb(64, 64, 64);
|
||||
--sidebar-entry-l2-hover: rgb(80, 80, 80);
|
||||
--sidebar-entry-l3-background: rgb(128, 128, 128);
|
||||
--sidebar-entry-l3-hover: rgb(144, 144, 144);
|
||||
--sidebar-selected: rgb(0, 128, 0);
|
||||
--sidebar-selected-hover: rgb(0, 160, 0);
|
||||
--sidebar-border-color: #800;
|
||||
--sidebar-category-indentation: 15px;
|
||||
--sidebar-arrow-size: 5px;
|
||||
--sidebar-arrow-margin: 8px;
|
||||
--separator-color: #aaa;
|
||||
--content-background: #333;
|
||||
--text-color: #eee;
|
||||
--bar-text-color: var(--text-color);
|
||||
--sidebar-width: 300px;
|
||||
--topbar-height: 50px;
|
||||
--content-padding: 15px;
|
||||
--content-separator-color: gray;
|
||||
--content-code-background: rgb(40, 40, 40);
|
||||
--content-code-block-border-color: rgb(64, 64, 64);
|
||||
}
|
||||
|
||||
|
||||
body{
|
||||
margin: 0px;
|
||||
font-family: Calibri, Tahoma, Arial;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
|
||||
.bar{
|
||||
color: var(--bar-text-color);
|
||||
}
|
||||
|
||||
.bar, .bar * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.topbar{
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
background-color: var(--topbar-background);
|
||||
height: var(--topbar-height);
|
||||
line-height: var(--topbar-height);
|
||||
}
|
||||
|
||||
.sidebar{
|
||||
height: calc(100% - var(--topbar-height));
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
top: var(--topbar-height);
|
||||
left: 0px;
|
||||
background-color: var(--sidebar-background);
|
||||
border-right: 1px solid var(--sidebar-border-color);
|
||||
padding-top: 10px;
|
||||
display: table;
|
||||
|
||||
width: var(--sidebar-width);
|
||||
}
|
||||
|
||||
.logo{
|
||||
height: var(--topbar-height);
|
||||
padding: 3px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.title{
|
||||
font-size: 30px;
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
.topbar select{
|
||||
--height: 25px;
|
||||
float: right;
|
||||
height: var(--height);
|
||||
margin: calc(calc(var(--topbar-height) - var(--height)) * 0.5);
|
||||
padding-right: 20px;
|
||||
padding-left: 8px;
|
||||
border: none;
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml;utf8,<svg fill='rgb(128,128,128)' height='25' width='25' xmlns='http://www.w3.org/2000/svg'>\
|
||||
<path d='M7 10l5 5 5-5z'/><path d='M0 0h25v25H0z' fill='none'/></svg>");
|
||||
background-repeat: no-repeat;
|
||||
background-position-x: right;
|
||||
background-color: #061635;
|
||||
color: #ddd;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
#main{
|
||||
position: absolute;
|
||||
top: var(--topbar-height);
|
||||
left: var(--sidebar-width);
|
||||
width: calc(100% - var(--sidebar-width) - var(--content-padding) * 2);
|
||||
padding: var(--content-padding);
|
||||
height: calc(100% - var(--topbar-height) - var(--content-padding) * 2);
|
||||
overflow: auto;
|
||||
background-color: var(--content-background);
|
||||
}
|
||||
|
||||
#loadingBar{
|
||||
width: 0%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: #1158c7;
|
||||
height: 5px;
|
||||
transition: width .2s ease-in, opacity .1s;
|
||||
}
|
||||
|
||||
|
||||
.sidebar-entry{
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sidebar-entry:hover{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sidebar-entry-l1{
|
||||
background-color: var(--sidebar-entry-l1-background);
|
||||
font-size: 20px;
|
||||
padding: 5px 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar-entry-l2{
|
||||
background-color: var(--sidebar-entry-l2-background);
|
||||
font-size: 17px;
|
||||
padding: 3px 5px;
|
||||
margin-left: var(--sidebar-category-indentation);
|
||||
width: calc(100% - var(--sidebar-category-indentation));
|
||||
}
|
||||
|
||||
.sidebar-entry-l3{
|
||||
background-color: var(--sidebar-entry-l3-background);
|
||||
font-size: 14px;
|
||||
padding: 2px 4px;
|
||||
margin-left: calc(var(--sidebar-category-indentation) * 2);
|
||||
width: calc(100% - var(--sidebar-category-indentation) * 2);
|
||||
}
|
||||
|
||||
.sidebar-entry-l1:hover{
|
||||
background-color: var(--sidebar-entry-l1-hover);
|
||||
}
|
||||
|
||||
.sidebar-entry-l2:hover{
|
||||
background-color: var(--sidebar-entry-l2-hover);
|
||||
}
|
||||
|
||||
.sidebar-entry-l3:hover{
|
||||
background-color: var(--sidebar-entry-l3-hover);
|
||||
}
|
||||
|
||||
.sidebar-entry-selected{
|
||||
background-color: var(--sidebar-selected);
|
||||
}
|
||||
|
||||
.sidebar-entry-selected:hover{
|
||||
background-color: var(--sidebar-selected-hover);
|
||||
}
|
||||
|
||||
.sidebar-regularentry::before{
|
||||
content: " ";
|
||||
display: inline-block;
|
||||
width: var(--sidebar-arrow-size);
|
||||
margin-right: var(--sidebar-arrow-margin);
|
||||
}
|
||||
|
||||
.sidebar-collapsible::before{
|
||||
content: " ";
|
||||
display: inline-block;
|
||||
border-left: var(--sidebar-arrow-size) solid currentColor;
|
||||
border-top: var(--sidebar-arrow-size) solid transparent;
|
||||
border-bottom: var(--sidebar-arrow-size) solid transparent;
|
||||
transition: transform .1s ease-in-out;
|
||||
margin-right: var(--sidebar-arrow-margin);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.sidebar-collapsible-coll::before{
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.line{
|
||||
margin: 10px;
|
||||
width: calc(100% - 20px);
|
||||
display: block;
|
||||
padding-bottom: 1px;
|
||||
background-color: var(--separator-color);
|
||||
}
|
||||
|
||||
.sidebar .links{
|
||||
vertical-align: bottom;
|
||||
display: table-row;
|
||||
height: 1px;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sidebar .links a{
|
||||
text-decoration: none;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.sidebar .links a:hover{
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
|
||||
#main h1{
|
||||
font-size: 2.3em;
|
||||
}
|
||||
|
||||
#main h2{
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
#main h3{
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
#main h4{
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
#main h5{
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#main h6{
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
#main table{
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#main th, #main td{
|
||||
padding: 7px;
|
||||
border: 1px solid var(--content-separator-color);
|
||||
}
|
||||
|
||||
#main h1, #main h2{
|
||||
border-bottom: 1px solid var(--content-separator-color);
|
||||
}
|
||||
|
||||
#main code{
|
||||
background-color: var(--content-code-background);
|
||||
padding: 2px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#main pre code{
|
||||
padding: 10px;
|
||||
border: 1px solid var(--content-code-block-border-color);
|
||||
}
|
||||
|
||||
#main a{
|
||||
color: #8af;
|
||||
}
|
||||
|
||||
#main a:hover{
|
||||
color: #8ff;
|
||||
}
|
||||
|
||||
|
150
common/docs.js
Normal file
150
common/docs.js
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2021 omegazero.org
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Covered Software is provided under this License on an "as is" basis, without warranty of any kind,
|
||||
* either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software
|
||||
* is free of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
* The entire risk as to the quality and performance of the Covered Software is with You.
|
||||
*/
|
||||
|
||||
(function(){
|
||||
|
||||
|
||||
function init(){
|
||||
// var for backward compatibility
|
||||
var versionSelector = document.getElementById("versionSelector");
|
||||
if(versionSelector){
|
||||
versionSelector.onchange = function(){
|
||||
var name = this.children[this.selectedIndex].value; // value is URL-encoded already by PHP code
|
||||
if(name == "current"){
|
||||
var cur = window.location.href;
|
||||
var queryIndex = cur.indexOf("?");
|
||||
if(queryIndex > 0)
|
||||
cur = cur.substring(0, queryIndex);
|
||||
window.location.href = cur;
|
||||
}else
|
||||
window.location.href = "?tag=" + name;
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("popstate", windowStatePop);
|
||||
|
||||
var entries = document.getElementsByClassName("sidebar-regularentry");
|
||||
for(var el of entries){
|
||||
el.addEventListener("click", entryClick);
|
||||
}
|
||||
|
||||
var collapsible = document.getElementsByClassName("sidebar-collapsible");
|
||||
for(var el of collapsible){
|
||||
el.addEventListener("click", collapsibleClick);
|
||||
}
|
||||
|
||||
docsRoot = document.querySelector("meta[name='docsRoot']").content;
|
||||
addLinkClickListeners(document.getElementById("main"));
|
||||
}
|
||||
|
||||
function addLinkClickListeners(wrap){
|
||||
var els = wrap.getElementsByTagName("a");
|
||||
for(var el of els){
|
||||
el.addEventListener("click", entryClick);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var docsRoot;
|
||||
|
||||
function entryClick(event){
|
||||
var target = event.target;
|
||||
if(target.origin != window.location.origin || !target.pathname.startsWith(docsRoot))
|
||||
return;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
switchContent(target.href, target);
|
||||
|
||||
window.history.pushState({entryElementId: target.id}, document.title, target.href);
|
||||
}
|
||||
|
||||
var initialSelected; // the first state (when navigating to the page) is null, so need to save it below
|
||||
|
||||
function windowStatePop(event){
|
||||
switchContent(document.location.href, document.getElementById(event.state ? event.state.entryElementId : initialSelected));
|
||||
}
|
||||
|
||||
function switchContent(href, entryElement){
|
||||
var mainContentEl = document.getElementById("mainContent");
|
||||
|
||||
var error = function(str){ // no ecma6 arrow functions for backward compatibility
|
||||
mainContentEl.innerHTML = '<span style="color:red;">Error while loading content: ' + str + '</span>';
|
||||
};
|
||||
|
||||
var progressEl = document.getElementById("loadingBar");
|
||||
progressEl.style.opacity = "1";
|
||||
progressEl.style.width = "1%";
|
||||
|
||||
var selectedElements = document.getElementsByClassName("sidebar-entry-selected");
|
||||
for(var el of selectedElements){
|
||||
initialSelected = el.id;
|
||||
el.classList.remove("sidebar-entry-selected");
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.addEventListener("load", function(event){
|
||||
if(xhr.status == 200){
|
||||
mainContentEl.innerHTML = xhr.responseText;
|
||||
addLinkClickListeners(mainContentEl);
|
||||
}else{
|
||||
error("Non-200 status code: " + xhr.status);
|
||||
}
|
||||
});
|
||||
xhr.addEventListener("error", function(event){
|
||||
error("XHR request failed");
|
||||
});
|
||||
xhr.addEventListener("loadstart", function(){
|
||||
progressEl.style.width = "20%";
|
||||
});
|
||||
xhr.addEventListener("loadend", function(){
|
||||
setTimeout(function(){
|
||||
progressEl.style.opacity = "0";
|
||||
progressEl.style.width = "0%";
|
||||
}, 300);
|
||||
});
|
||||
xhr.addEventListener("progress", function(event){
|
||||
progressEl.style.width = Math.floor((event.loaded / event.total) * 80 + 20) + "%";
|
||||
});
|
||||
xhr.open("GET", href + (href.indexOf("?") >= 0 ? "&" : "?") + "contentOnly=1");
|
||||
xhr.send();
|
||||
|
||||
mainContentEl.innerHTML = "";
|
||||
|
||||
if(entryElement)
|
||||
entryElement.classList.add("sidebar-entry-selected");
|
||||
else
|
||||
console.warn("entryElement not available");
|
||||
}
|
||||
|
||||
|
||||
function collapsibleClick(event){
|
||||
var el = event.target;
|
||||
var contentEl = document.getElementById(el.id + "_content");
|
||||
if(!contentEl){
|
||||
console.warn("Cannot toggle collapsible '" + el.id + "' because content element was not found");
|
||||
return;
|
||||
}
|
||||
if(el.classList.contains("sidebar-collapsible-coll")){
|
||||
el.classList.remove("sidebar-collapsible-coll");
|
||||
contentEl.style.display = "block";
|
||||
}else{
|
||||
el.classList.add("sidebar-collapsible-coll");
|
||||
contentEl.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
window.addEventListener("load", init);
|
||||
|
||||
})();
|
||||
|
2
d/.htaccess
Normal file
2
d/.htaccess
Normal file
@ -0,0 +1,2 @@
|
||||
RewriteEngine On
|
||||
RewriteRule ^ main.php [QSA,END]
|
22
d/config-sample.php
Normal file
22
d/config-sample.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
$sources = array(
|
||||
1 => array(
|
||||
"resourceUrl" => "https://raw.githubusercontent.com/$(owner)/$(repository)/master/$(file)",
|
||||
"taggedResourceUrl" => "https://raw.githubusercontent.com/$(owner)/$(repository)/$(tag)/$(file)",
|
||||
"tagsUrl" => "https://api.github.com/repos/$(owner)/$(repository)/tags"
|
||||
)
|
||||
);
|
||||
|
||||
$docsBasePath = ".docs/";
|
||||
$metaFileName = $docsBasePath . "meta.json";
|
||||
|
||||
$cacheMaxAge = 10;
|
||||
|
||||
$htmlPurifierCacheDir = null;
|
||||
|
||||
$links = array(
|
||||
"Home Page" => "https://example.com/"
|
||||
);
|
||||
|
||||
?>
|
534
d/main.php
Normal file
534
d/main.php
Normal file
@ -0,0 +1,534 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2021 omegazero.org
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Covered Software is provided under this License on an "as is" basis, without warranty of any kind,
|
||||
* either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software
|
||||
* is free of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
* The entire risk as to the quality and performance of the Covered Software is with You.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once("config.php");
|
||||
|
||||
|
||||
$VERSION = "2.1.0";
|
||||
|
||||
|
||||
function request(string $url){
|
||||
global $VERSION;
|
||||
$startTime = microtime(true);
|
||||
|
||||
$cacheKey = "res:" . $url;
|
||||
$cacheEntry = apcu_fetch($cacheKey);
|
||||
if($cacheEntry){
|
||||
$resource = $cacheEntry;
|
||||
}else{
|
||||
$resource = new stdClass();
|
||||
$curl = curl_init($url);
|
||||
$setopt_array = array(
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
"User-Agent: omz-docs/" . $VERSION . " robot (https://docs.omegazero.org/)"
|
||||
),
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_TIMEOUT => 5
|
||||
);
|
||||
curl_setopt_array($curl, $setopt_array);
|
||||
$resource->data = curl_exec($curl);
|
||||
$resource->statusCode = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
|
||||
curl_close($curl);
|
||||
|
||||
apcu_store($cacheKey, $resource, 15);
|
||||
}
|
||||
|
||||
$res = clone $resource;
|
||||
$res->timeMs = (microtime(true) - $startTime) * 1000;
|
||||
return $res;
|
||||
}
|
||||
|
||||
function parseSubpath(string $path){
|
||||
global $sources;
|
||||
$res = new stdClass();
|
||||
|
||||
$pathparts = explode("/", $path, 4);
|
||||
$plen = count($pathparts);
|
||||
if($plen < 2)
|
||||
return null;
|
||||
$res->owner = "";
|
||||
$res->name = "";
|
||||
$res->path = "";
|
||||
$res->rootDir = "";
|
||||
$sourceNum = intval($pathparts[0]);
|
||||
if($sourceNum > count($sources)){
|
||||
return null;
|
||||
}else if($sourceNum <= 0){
|
||||
$sourceNum = 1;
|
||||
$res->owner = $pathparts[0];
|
||||
$res->name = $pathparts[1];
|
||||
$res->rootDir = "/" . $res->owner . "/" . $res->name;
|
||||
if($plen > 2)
|
||||
$res->path = $pathparts[2];
|
||||
if($plen > 3)
|
||||
$res->path .= "/" . $pathparts[3];
|
||||
}else{
|
||||
if($plen < 3)
|
||||
return null;
|
||||
$res->owner = $pathparts[1];
|
||||
$res->name = $pathparts[2];
|
||||
$res->rootDir = "/" . $sourceNum . "/" . $res->owner . "/" . $res->name;
|
||||
if($plen > 3)
|
||||
$res->path = $pathparts[3];
|
||||
}
|
||||
if(strlen($res->owner) < 1 || strlen($res->name) < 1)
|
||||
return null;
|
||||
$res->sourceNum = $sourceNum;
|
||||
$res->source = $sources[$sourceNum];
|
||||
return $res;
|
||||
}
|
||||
|
||||
function stringifySubpath(object $subpath) : string{
|
||||
if($subpath->sourceNum == 1)
|
||||
return $subpath->owner . "/" . $subpath->name . "/" . $subpath->path;
|
||||
else
|
||||
return $subpath->sourceNum . "/" . $subpath->owner . "/" . $subpath->name . "/" . $subpath->path;
|
||||
}
|
||||
|
||||
function getFileFromSource(object $subpath, string $filename) : object{
|
||||
global $gitTag;
|
||||
if($gitTag == "current")
|
||||
return request(strtr($subpath->source["resourceUrl"], array("$(owner)" => $subpath->owner, "$(repository)" => $subpath->name, "$(file)" => $filename)));
|
||||
else
|
||||
return request(strtr($subpath->source["taggedResourceUrl"], array("$(owner)" => $subpath->owner, "$(repository)" => $subpath->name, "$(tag)" => $gitTag, "$(file)" => $filename)));
|
||||
}
|
||||
|
||||
function getTagsFromSource(object $subpath) : object{
|
||||
return request(strtr($subpath->source["tagsUrl"], array("$(owner)" => $subpath->owner, "$(repository)" => $subpath->name)));
|
||||
}
|
||||
|
||||
function safeMeta(string $str) : string{
|
||||
return htmlspecialchars($str, ENT_QUOTES);
|
||||
}
|
||||
|
||||
function metadataAvailable(string $name, string $type) : bool{
|
||||
global $metadata;
|
||||
return !is_null($metadata) && isset($metadata->$name) && gettype($metadata->$name) === $type;
|
||||
}
|
||||
|
||||
|
||||
function errormsg(string $str){
|
||||
echo '<span style="color:red;font-weight:bold;font-style: italic;">' . htmlspecialchars($str) . '</span><br />';
|
||||
}
|
||||
|
||||
function errormsgconf(string $str){
|
||||
errormsg('Configuration Error: ' . $str);
|
||||
}
|
||||
|
||||
function str_starts_with(string $str, string $prefix) : bool{
|
||||
$prefixLen = strlen($prefix);
|
||||
return strlen($str) > $prefixLen && substr($str, 0, $prefixLen) == $prefix;
|
||||
}
|
||||
|
||||
|
||||
function nameToKey(string $name) : string{
|
||||
return strtr($name, " ", "_");
|
||||
}
|
||||
|
||||
class Entry{
|
||||
|
||||
public function __construct(?string $name, string $value){
|
||||
if(!is_null($name)){
|
||||
$this->name = $name;
|
||||
$this->key = nameToKey($name);
|
||||
}
|
||||
$p = explode(" ", $value);
|
||||
$this->filename = array_shift($p);
|
||||
if(count($p) > 0)
|
||||
$this->flags = $p;
|
||||
else
|
||||
$this->flags = array("resource");
|
||||
}
|
||||
|
||||
public function hasFlag($fname) : bool{
|
||||
return in_array($fname, $this->flags);
|
||||
}
|
||||
}
|
||||
|
||||
function getFilename(string $path) : ?string{
|
||||
global $metadata;
|
||||
static $aliasesSearched = array();
|
||||
if(metadataAvailable("content", "object")){
|
||||
$parts = explode("/", $path);
|
||||
$cur = $metadata->content;
|
||||
foreach($parts as $value){
|
||||
if(!is_object($cur)){
|
||||
$cur = null;
|
||||
break;
|
||||
}
|
||||
$cur_n = new stdClass();
|
||||
foreach($cur as $name => $v){
|
||||
$key = nameToKey($name);
|
||||
$cur_n->$key = $cur->$name;
|
||||
}
|
||||
$cur = $cur_n;
|
||||
if(isset($cur->$value))
|
||||
$cur = $cur->$value;
|
||||
}
|
||||
if(is_object($cur) && isset($cur->default)){
|
||||
$cur = $cur->default;
|
||||
}
|
||||
if(is_string($cur)){
|
||||
$entry = new Entry(null, $cur);
|
||||
if(str_starts_with($entry->filename, "@")){
|
||||
$alias = substr($entry->filename, 1);
|
||||
if(in_array($alias, $aliasesSearched)){
|
||||
errormsgconf("Loop in content aliases: " . $alias . " points back to itself");
|
||||
return null;
|
||||
}
|
||||
array_push($aliasesSearched, $alias);
|
||||
return getFilename($alias);
|
||||
}else if($entry->hasFlag("resource"))
|
||||
return $entry->filename;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function uncaughtException($exception){
|
||||
error_log("Uncaught Exception: " . $exception);
|
||||
ob_clean();
|
||||
http_response_code(500);
|
||||
echo "Internal Server Error";
|
||||
ob_end_flush();
|
||||
}
|
||||
|
||||
set_exception_handler('uncaughtException');
|
||||
|
||||
|
||||
ob_start();
|
||||
|
||||
$fetchTime = 0;
|
||||
|
||||
$gitTag = "current";
|
||||
$gitTagQuery = "";
|
||||
if(isset($_GET["tag"])){
|
||||
$gitTag = $_GET["tag"];
|
||||
$gitTagQuery = "?tag=" . $gitTag;
|
||||
}
|
||||
|
||||
$contentOnly = false;
|
||||
if(isset($_GET["contentOnly"]))
|
||||
$contentOnly = !!$_GET["contentOnly"];
|
||||
|
||||
$rootDir = dirname($_SERVER['SCRIPT_NAME']);
|
||||
$subpathStr = substr(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), strlen($rootDir) + 1);
|
||||
$subpath = parseSubpath($subpathStr);
|
||||
$docsRootDir = null;
|
||||
|
||||
$metadata = null;
|
||||
$metadataValid = false;
|
||||
$contentFilename = null;
|
||||
|
||||
$confinitError = false;
|
||||
|
||||
function errormsginitconf(string $str){
|
||||
global $confinitError;
|
||||
if($confinitError === false)
|
||||
$confinitError = $str;
|
||||
else
|
||||
$confinitError .= " / " . $str;
|
||||
}
|
||||
|
||||
function fetchMetadata(object $subpath){
|
||||
global $metaFileName; // defined in config.php
|
||||
global $fetchTime;
|
||||
global $metadata;
|
||||
global $metadataValid;
|
||||
global $contentFilename;
|
||||
// reset
|
||||
$metadata = null;
|
||||
$metadataValid = false;
|
||||
|
||||
$metaRes = getFileFromSource($subpath, $metaFileName);
|
||||
$fetchTime += $metaRes->timeMs;
|
||||
if($metaRes->data !== false && $metaRes->statusCode === 200){
|
||||
$metadata = json_decode($metaRes->data, false, 8);
|
||||
}else if($metaRes->statusCode === 404){
|
||||
errormsginitconf("Metadata does not exist");
|
||||
}else if($metaRes->statusCode !== 200){
|
||||
errormsginitconf("Metadata request returned status " . $metaRes->statusCode);
|
||||
}else{
|
||||
errormsginitconf("Failed to fetch metadata");
|
||||
}
|
||||
|
||||
if(is_null($metadata))
|
||||
errormsginitconf("Metadata is not valid JSON");
|
||||
|
||||
$metadataVersion = 1;
|
||||
if(metadataAvailable("version", "integer"))
|
||||
$metadataVersion = $metadata->version;
|
||||
if(!is_null($metadata)){
|
||||
if($metadataVersion != 2)
|
||||
errormsginitconf("Unsupported metadata version: " . $metadataVersion);
|
||||
else
|
||||
$metadataValid = true;
|
||||
}
|
||||
|
||||
$contentFilename = getFilename($subpath->path);
|
||||
}
|
||||
|
||||
function parseRedirect(string $str, object $subpath) : bool{
|
||||
if(!preg_match("/^([a-zA-Z0-9\-_\.]+\/?){1,2}$/", $str))
|
||||
return false;
|
||||
$parts = explode("/", $str);
|
||||
if(count($parts) > 1){
|
||||
$subpath->owner = $parts[0];
|
||||
$subpath->name = $parts[1];
|
||||
}else{
|
||||
$subpath->name = $parts[0];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!is_null($subpath)){
|
||||
$docsRootDir = $rootDir . $subpath->rootDir;
|
||||
|
||||
fetchMetadata($subpath);
|
||||
if($metadataValid){
|
||||
if(metadataAvailable("redirect", "string")){
|
||||
if(parseRedirect($metadata->redirect, $subpath)){
|
||||
header("Location: " . $rootDir . "/" . stringifySubpath($subpath), true, 307);
|
||||
}else{
|
||||
errormsginitconf("Redirect destination is invalid");
|
||||
}
|
||||
}else if(metadataAvailable("delegate", "string")){
|
||||
if(parseRedirect($metadata->delegate, $subpath)){
|
||||
fetchMetadata($subpath);
|
||||
}else{
|
||||
errormsginitconf("Delegate destination is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<?php if(!$contentOnly) : ?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/common/docs.css" />
|
||||
<script src="/common/docs.js"></script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<?php
|
||||
|
||||
if(metadataAvailable("siteTitle", "string"))
|
||||
echo "<title>" . safeMeta($metadata->siteTitle) . "</title>";
|
||||
else if(metadataAvailable("title", "string"))
|
||||
echo "<title>" . safeMeta($metadata->title) . "</title>";
|
||||
else
|
||||
echo "<title>omz-docs</title>";
|
||||
|
||||
if(metadataAvailable("siteIcon", "string"))
|
||||
echo '<link rel="icon" href="' . safeMeta($metadata->siteIcon) . '" />';
|
||||
else if(metadataAvailable("icon", "string"))
|
||||
echo '<link rel="icon" href="' . safeMeta($metadata->icon) . '" />';
|
||||
|
||||
if(metadataAvailable("meta", "object")){
|
||||
foreach($metadata->meta as $name => $value){
|
||||
echo "<meta name=\"" . safeMeta($name) . "\" content=\"" . safeMeta($value) . "\" />";
|
||||
}
|
||||
}else if(!$metadataValid){
|
||||
echo "<meta name=\"description\" content=\"This is not a valid documentation page\" />";
|
||||
}
|
||||
|
||||
echo "<meta name=\"docsRoot\" content=\"" . $docsRootDir . "\" />";
|
||||
|
||||
?>
|
||||
<!-- <meta name="omz-proxy-ssi" /> -->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="topbar" class="bar topbar">
|
||||
|
||||
<?php
|
||||
|
||||
$tags = array("current");
|
||||
|
||||
if(!is_null($subpath) && !is_null($metadata) /* only fetch tags if there is a metadata file to not try and load tags from nonexistent repository */){
|
||||
$tagsRes = getTagsFromSource($subpath);
|
||||
$fetchTime += $tagsRes->timeMs;
|
||||
if($tagsRes->data !== false && $tagsRes->statusCode === 200){
|
||||
$tagsArr = json_decode($tagsRes->data, false, 8);
|
||||
if(is_array($tagsArr)){
|
||||
foreach($tagsArr as $value){
|
||||
array_push($tags, $value->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(metadataAvailable("icon", "string"))
|
||||
echo '<img id="logo" src="' . safeMeta($metadata->icon) . '" class="logo" />';
|
||||
|
||||
if(metadataAvailable("title", "string"))
|
||||
echo '<span id="title" class="title">' . safeMeta($metadata->title) . '</span>';
|
||||
else if($metadataValid)
|
||||
errormsgconf("Missing title");
|
||||
|
||||
|
||||
echo '<select id="versionSelector">';
|
||||
foreach($tags as $name){
|
||||
echo '<option value="' . urlencode($name) . '" ' . ($gitTag == $name ? ' selected' : '') . '>' . htmlspecialchars($name) . '</option>';
|
||||
}
|
||||
echo '</select>';
|
||||
|
||||
?>
|
||||
|
||||
</div>
|
||||
<div id="sidebar" class="bar sidebar">
|
||||
|
||||
<?php
|
||||
|
||||
function addSidebarEntry(string $name, string $value, int $depth, string $base){
|
||||
global $docsRootDir;
|
||||
global $contentFilename;
|
||||
global $gitTagQuery;
|
||||
if($depth > 3){
|
||||
errormsgconf("Maximum depth exceeded: 3");
|
||||
return;
|
||||
}
|
||||
$entry = new Entry($name, $value);
|
||||
if(!$entry->hasFlag("hidden")){
|
||||
if($entry->hasFlag("line")){
|
||||
echo '<div class="line"></div>';
|
||||
}else{
|
||||
echo '<a id="sidebar_entry_' . $entry->key . '" class="sidebar-entry sidebar-entry-l' . $depth . ($entry->filename == $contentFilename ? ' sidebar-entry-selected' : '')
|
||||
. ' sidebar-regularentry" href="' . $docsRootDir . $base . $entry->key . $gitTagQuery . '">' . $entry->name . '</a>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addSidebarObject(object $obj, int $depth, string $base){
|
||||
global $docsRootDir;
|
||||
foreach($obj as $name => $value){
|
||||
if(is_string($value)){
|
||||
addSidebarEntry($name, $value, $depth, $base);
|
||||
}else if(is_object($value)){
|
||||
$key = nameToKey($name);
|
||||
$id = 'sidebar_collapsible_' . $key;
|
||||
echo '<a id="' . $id . '" class="sidebar-entry sidebar-entry-l' . $depth . ' sidebar-collapsible" href="javascript:void(0);">' . $name . '</a><div id="' . $id . '_content">';
|
||||
addSidebarObject($value, $depth + 1, $base . $key . "/");
|
||||
echo '</div>';
|
||||
}else{
|
||||
errormsgconf("Content entry '" . $name . "' has invalid value type " . gettype($value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(metadataAvailable("content", "object")){
|
||||
addSidebarObject($metadata->content, 1, "/");
|
||||
}else if($metadataValid){
|
||||
errormsgconf("content is not set or not an object");
|
||||
}else{ // empty div to push links div to bottom
|
||||
echo '<div></div>';
|
||||
}
|
||||
|
||||
|
||||
echo '<div class="links"><a href="https://docs.omegazero.org/">omz-docs v' . $VERSION . '</a>';
|
||||
foreach($links as $name => $href){
|
||||
echo ' | <a href="' . $href . '">' . $name . '</a>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
?>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="main">
|
||||
<div id="loadingBar"></div>
|
||||
<div id="mainContent">
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?php
|
||||
|
||||
if($confinitError){
|
||||
errormsgconf($confinitError);
|
||||
}else if(is_null($subpath)){
|
||||
errormsg("Invalid request path");
|
||||
}else if(is_null($contentFilename)){
|
||||
errormsg("Invalid resource");
|
||||
}else{
|
||||
$contentFilenameAbsolute = $contentFilename;
|
||||
if(!str_starts_with($contentFilenameAbsolute, "/")){
|
||||
$contentFilenameAbsolute = "/" . $docsBasePath . $contentFilenameAbsolute;
|
||||
}
|
||||
$contentRes = getFileFromSource($subpath, substr($contentFilenameAbsolute, 1));
|
||||
if($contentRes->data === false){
|
||||
errormsgconf("Failed to fetch content");
|
||||
}else if($contentRes->statusCode === 404){
|
||||
errormsgconf("Content file '" . $contentFilenameAbsolute . "' does not exist");
|
||||
}else if($contentRes->statusCode !== 200){
|
||||
errormsgconf("Content file request returned status " . $contentRes->statusCode);
|
||||
}else{
|
||||
$pd = null;
|
||||
if(file_exists("lib/ParsedownExtra.php")){
|
||||
require_once("lib/Parsedown.php");
|
||||
require_once("lib/ParsedownExtra.php");
|
||||
$pd = new ParsedownExtra();
|
||||
}else{
|
||||
require_once("lib/Parsedown.php");
|
||||
$pd = new Parsedown();
|
||||
}
|
||||
|
||||
$mdhtml = $pd->text($contentRes->data);
|
||||
|
||||
if(file_exists("lib/htmlpurifier/HTMLPurifier.standalone.php")){
|
||||
require_once("lib/htmlpurifier/HTMLPurifier.standalone.php");
|
||||
$htmlpurifierconfig = HTMLPurifier_Config::createDefault();
|
||||
if(is_null($htmlPurifierCacheDir)){
|
||||
$htmlpurifierconfig->set('Cache.DefinitionImpl', null);
|
||||
}else{
|
||||
$htmlpurifierconfig->set('Cache.SerializerPath', $htmlPurifierCacheDir);
|
||||
}
|
||||
$htmlpurifier = new HTMLPurifier($htmlpurifierconfig);
|
||||
$mdhtmlsafe = $htmlpurifier->purify($mdhtml);
|
||||
|
||||
echo $mdhtmlsafe;
|
||||
}else{
|
||||
echo $mdhtml;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
|
||||
<?php if(!$contentOnly) : ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
|
||||
header("Cache-Control: max-age=" . $cacheMaxAge);
|
||||
|
||||
$time = (microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]) * 1000 - $fetchTime;
|
||||
header("Server-Timing: docs-meta-fetch;dur=" . round($fetchTime) . ", docs-page-gen;dur=" . round($time));
|
||||
|
||||
header("Content-Length: " . ob_get_length());
|
||||
ob_end_flush();
|
||||
|
||||
?>
|
5
robots.txt
Normal file
5
robots.txt
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
User-agent: *
|
||||
|
||||
Disallow: /common/
|
||||
Disallow: /d/*?tag=
|
Loading…
x
Reference in New Issue
Block a user