From 09fc8f8c76848ee053831d2e1c86aec6fdd2d468 Mon Sep 17 00:00:00 2001 From: zunaidahmed96 <123038546+zunaidahmed96@users.noreply.github.com> Date: Sun, 25 Feb 2024 23:01:57 +0000 Subject: [PATCH] Latest build deployed. --- .mapping.json | 1 + Discrete-Math-with-SageMath.html | 263 + OOP.html | 273 + _static/pretext/css/banner_crc.css | 336 ++ _static/pretext/css/banner_default.css | 141 + _static/pretext/css/banner_wide.css | 20 + _static/pretext/css/catalog.css | 94 + _static/pretext/css/colors_blue_green.css | 118 + _static/pretext/css/colors_blue_grey.css | 74 + _static/pretext/css/colors_blue_red.css | 72 + _static/pretext/css/colors_blue_red_dark.css | 130 + _static/pretext/css/colors_bluegreen_grey.css | 119 + _static/pretext/css/colors_brown_gold.css | 37 + .../pretext/css/colors_darkmartiansands.css | 74 + _static/pretext/css/colors_default.css | 82 + .../pretext/css/colors_focused_gray_aqua.css | 47 + _static/pretext/css/colors_focused_light.css | 44 + _static/pretext/css/colors_green_blue.css | 72 + _static/pretext/css/colors_green_plum.css | 72 + _static/pretext/css/colors_maroon_grey.css | 37 + _static/pretext/css/colors_martiansands.css | 74 + _static/pretext/css/colors_orange_navy.css | 72 + .../pretext/css/colors_pastel_blue_orange.css | 32 + _static/pretext/css/colors_red_blue.css | 35 + _static/pretext/css/colors_ruby_amethyst.css | 72 + _static/pretext/css/colors_ruby_emerald.css | 72 + _static/pretext/css/colors_ruby_turquoise.css | 72 + _static/pretext/css/edit.css | 493 ++ _static/pretext/css/epub.css | 58 + _static/pretext/css/features.css | 324 ++ _static/pretext/css/kindle.css | 103 + _static/pretext/css/knowls_default.css | 230 + _static/pretext/css/navbar_crc.css | 358 ++ _static/pretext/css/navbar_default.css | 194 + _static/pretext/css/navbar_wide.css | 39 + _static/pretext/css/pretext.css | 1151 ++++ _static/pretext/css/pretext_add_on.css | 3178 +++++++++++ _static/pretext/css/pretext_search.css | 173 + _static/pretext/css/reveal.css | 75 + _static/pretext/css/setcolors.css | 452 ++ _static/pretext/css/shell_crc.css | 408 ++ _static/pretext/css/shell_default.css | 260 + _static/pretext/css/shell_min.css | 273 + _static/pretext/css/shell_wide.css | 350 ++ _static/pretext/css/style_default.css | 332 ++ _static/pretext/css/style_oscarlevin.css | 471 ++ _static/pretext/css/style_soundwriting.css | 156 + _static/pretext/css/style_wide.css | 225 + _static/pretext/css/toc_crc.css | 276 + _static/pretext/css/toc_default.css | 274 + _static/pretext/css/toc_min.css | 144 + _static/pretext/css/toc_wide.css | 36 + _static/pretext/css/webwork.css | 72 + _static/pretext/js/answer.js | 552 ++ _static/pretext/js/edit.js | 4988 +++++++++++++++++ _static/pretext/js/highlight.js | 480 ++ _static/pretext/js/instructor.js | 131 + _static/pretext/js/lib/jquery.espy.min.js | 195 + _static/pretext/js/lib/jquery.min.js | 2 + _static/pretext/js/lib/jquery.sticky.js | 161 + _static/pretext/js/lib/knowl.js | 216 + _static/pretext/js/lib/mathjaxknowl.js | 110 + _static/pretext/js/lib/mathjaxknowl3.js | 48 + _static/pretext/js/login.js | 322 ++ .../pretext-webwork/2.16/pretext-webwork.js | 752 +++ .../pretext-webwork/2.17/pretext-webwork.js | 1057 ++++ .../pretext-webwork/2.18/pretext-webwork.js | 1057 ++++ _static/pretext/js/pretext.js | 165 + _static/pretext/js/pretext_add_on.js | 984 ++++ _static/pretext/js/pretext_search.js | 307 + _static/pretext/js/ptx_search.js | 112 + _static/pretext/js/user_preferences.js | 510 ++ about-sage.html | 276 + backmatter-2.html | 245 + backmatter.html | 242 + cardinality.html | 274 + ch-combinatorics.html | 257 + ch-functions.html | 260 + ch-getting-started.html | 266 + ch-logic.html | 261 + ch-relations.html | 263 + ch-set-theory.html | 261 + creating-sets.html | 289 + data-types.html | 331 ++ debugging.html | 291 + digraphs.html | 271 + documentation.html | 247 + equivalence.html | 358 ++ frontmatter-2.html | 247 + frontmatter.html | 250 + generated/.web_assets.pkl | 1 + index.html | 20 + intro-relations.html | 330 ++ iteration.html | 244 + lunr-pretext-search-index.js | 455 ++ partial-order.html | 316 ++ printing.html | 279 + relations-on-a-set.html | 275 + sage-browser.html | 262 + sec-combinatorics.html | 287 + sec-functions.html | 281 + sec-logical-operation.html | 296 + sec-operation-on-sets.html | 353 ++ sec-recursion.html | 295 + sec-tautology.html | 284 + sec-truth-table.html | 266 + 106 files changed, 33922 insertions(+) create mode 100644 .mapping.json create mode 100644 Discrete-Math-with-SageMath.html create mode 100644 OOP.html create mode 100644 _static/pretext/css/banner_crc.css create mode 100644 _static/pretext/css/banner_default.css create mode 100644 _static/pretext/css/banner_wide.css create mode 100644 _static/pretext/css/catalog.css create mode 100644 _static/pretext/css/colors_blue_green.css create mode 100644 _static/pretext/css/colors_blue_grey.css create mode 100644 _static/pretext/css/colors_blue_red.css create mode 100644 _static/pretext/css/colors_blue_red_dark.css create mode 100644 _static/pretext/css/colors_bluegreen_grey.css create mode 100644 _static/pretext/css/colors_brown_gold.css create mode 100644 _static/pretext/css/colors_darkmartiansands.css create mode 100644 _static/pretext/css/colors_default.css create mode 100644 _static/pretext/css/colors_focused_gray_aqua.css create mode 100644 _static/pretext/css/colors_focused_light.css create mode 100644 _static/pretext/css/colors_green_blue.css create mode 100644 _static/pretext/css/colors_green_plum.css create mode 100644 _static/pretext/css/colors_maroon_grey.css create mode 100644 _static/pretext/css/colors_martiansands.css create mode 100644 _static/pretext/css/colors_orange_navy.css create mode 100644 _static/pretext/css/colors_pastel_blue_orange.css create mode 100644 _static/pretext/css/colors_red_blue.css create mode 100644 _static/pretext/css/colors_ruby_amethyst.css create mode 100644 _static/pretext/css/colors_ruby_emerald.css create mode 100644 _static/pretext/css/colors_ruby_turquoise.css create mode 100644 _static/pretext/css/edit.css create mode 100644 _static/pretext/css/epub.css create mode 100644 _static/pretext/css/features.css create mode 100644 _static/pretext/css/kindle.css create mode 100644 _static/pretext/css/knowls_default.css create mode 100644 _static/pretext/css/navbar_crc.css create mode 100644 _static/pretext/css/navbar_default.css create mode 100644 _static/pretext/css/navbar_wide.css create mode 100644 _static/pretext/css/pretext.css create mode 100644 _static/pretext/css/pretext_add_on.css create mode 100644 _static/pretext/css/pretext_search.css create mode 100644 _static/pretext/css/reveal.css create mode 100644 _static/pretext/css/setcolors.css create mode 100644 _static/pretext/css/shell_crc.css create mode 100644 _static/pretext/css/shell_default.css create mode 100644 _static/pretext/css/shell_min.css create mode 100644 _static/pretext/css/shell_wide.css create mode 100644 _static/pretext/css/style_default.css create mode 100644 _static/pretext/css/style_oscarlevin.css create mode 100644 _static/pretext/css/style_soundwriting.css create mode 100644 _static/pretext/css/style_wide.css create mode 100644 _static/pretext/css/toc_crc.css create mode 100644 _static/pretext/css/toc_default.css create mode 100644 _static/pretext/css/toc_min.css create mode 100644 _static/pretext/css/toc_wide.css create mode 100644 _static/pretext/css/webwork.css create mode 100644 _static/pretext/js/answer.js create mode 100644 _static/pretext/js/edit.js create mode 100644 _static/pretext/js/highlight.js create mode 100644 _static/pretext/js/instructor.js create mode 100644 _static/pretext/js/lib/jquery.espy.min.js create mode 100644 _static/pretext/js/lib/jquery.min.js create mode 100644 _static/pretext/js/lib/jquery.sticky.js create mode 100644 _static/pretext/js/lib/knowl.js create mode 100644 _static/pretext/js/lib/mathjaxknowl.js create mode 100644 _static/pretext/js/lib/mathjaxknowl3.js create mode 100644 _static/pretext/js/login.js create mode 100644 _static/pretext/js/pretext-webwork/2.16/pretext-webwork.js create mode 100644 _static/pretext/js/pretext-webwork/2.17/pretext-webwork.js create mode 100644 _static/pretext/js/pretext-webwork/2.18/pretext-webwork.js create mode 100644 _static/pretext/js/pretext.js create mode 100644 _static/pretext/js/pretext_add_on.js create mode 100644 _static/pretext/js/pretext_search.js create mode 100644 _static/pretext/js/ptx_search.js create mode 100644 _static/pretext/js/user_preferences.js create mode 100644 about-sage.html create mode 100644 backmatter-2.html create mode 100644 backmatter.html create mode 100644 cardinality.html create mode 100644 ch-combinatorics.html create mode 100644 ch-functions.html create mode 100644 ch-getting-started.html create mode 100644 ch-logic.html create mode 100644 ch-relations.html create mode 100644 ch-set-theory.html create mode 100644 creating-sets.html create mode 100644 data-types.html create mode 100644 debugging.html create mode 100644 digraphs.html create mode 100644 documentation.html create mode 100644 equivalence.html create mode 100644 frontmatter-2.html create mode 100644 frontmatter.html create mode 100644 generated/.web_assets.pkl create mode 100644 index.html create mode 100644 intro-relations.html create mode 100644 iteration.html create mode 100644 lunr-pretext-search-index.js create mode 100644 partial-order.html create mode 100644 printing.html create mode 100644 relations-on-a-set.html create mode 100644 sage-browser.html create mode 100644 sec-combinatorics.html create mode 100644 sec-functions.html create mode 100644 sec-logical-operation.html create mode 100644 sec-operation-on-sets.html create mode 100644 sec-recursion.html create mode 100644 sec-tautology.html create mode 100644 sec-truth-table.html diff --git a/.mapping.json b/.mapping.json new file mode 100644 index 0000000..8671759 --- /dev/null +++ b/.mapping.json @@ -0,0 +1 @@ +{"source/main.ptx": ["Discrete-Math-with-SageMath"], "source/frontmatter.ptx": ["frontmatter"], "source/getting-started/ch-getting-started.ptx": ["ch-getting-started"], "source/getting-started/sec-intro-to-sage.ptx": ["about-sage"], "source/getting-started/sec-printing.ptx": ["printing"], "source/getting-started/sec-OOP.ptx": ["OOP"], "source/getting-started/sec-data-types.ptx": ["data-types"], "source/getting-started/sec-iteration.ptx": ["iteration"], "source/getting-started/sec-debugging.ptx": ["debugging"], "source/getting-started/sec-documentation.ptx": ["documentation"], "source/getting-started/sec-sage-browser.ptx": ["sage-browser"], "source/set-theory/ch-set-theory.ptx": ["ch-set-theory"], "source/set-theory/sec-creating-sets.ptx": ["creating-sets"], "source/set-theory/sec-cardinality.ptx": ["cardinality"], "source/set-theory/sec-operation-on-sets.ptx": ["sec-operation-on-sets"], "source/combinatorics/ch-combinatorics.ptx": ["ch-combinatorics"], "source/combinatorics/sec-combinatorics.ptx": ["sec-combinatorics"], "source/logic/ch-logic.ptx": ["ch-logic"], "source/logic/sec-logical-operation.ptx": ["sec-logical-operation"], "source/logic/sec-truth-table.ptx": ["sec-truth-table"], "source/logic/sec-tautology.ptx": ["sec-tautology"], "source/relations/ch-relations.ptx": ["ch-relations"], "source/relations/sec-intro-relations.ptx": ["intro-relations"], "source/relations/sec-relations-on-a-set.ptx": ["relations-on-a-set"], "source/relations/sec-digraphs.ptx": ["digraphs"], "source/relations/sec-equivalence.ptx": ["equivalence"], "source/relations/sec-partial-order.ptx": ["partial-order"], "source/functions/ch-functions.ptx": ["ch-functions"], "source/functions/sec-functions.ptx": ["sec-functions"], "source/functions/sec-recursion.ptx": ["sec-recursion"], "source/backmatter.ptx": ["backmatter"]} \ No newline at end of file diff --git a/Discrete-Math-with-SageMath.html b/Discrete-Math-with-SageMath.html new file mode 100644 index 0000000..35ac63a --- /dev/null +++ b/Discrete-Math-with-SageMath.html @@ -0,0 +1,263 @@ + + + + + + + + + + +Discrete Math with SageMath + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
+
+

Discrete Math with SageMath: Learn math with open-source software

+ +
+
+
+
+
+
+
+ + + diff --git a/OOP.html b/OOP.html new file mode 100644 index 0000000..ff78f12 --- /dev/null +++ b/OOP.html @@ -0,0 +1,273 @@ + + + + + + + + + + +Object Oriented Programming + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
+
+

Discrete Math with SageMath: Learn math with open-source software

+ +
+
+
+
+

+Section 1.3 Object Oriented Programming +

+
What is an object? Almost everything in Sage and Python for that matter is an object! More specifically an object is an instance of a class.
+
A class provides a template or blueprint for creating objects and defines the attributes (properties) and methods (behaviors) that those objects can have.
+
This might not mean too much right now and it will be more clear as we explore what is known as object-oriented programming. Just know that SageMath has different ways of representing and working with data. We can create an object by typing something into our Sage Worksheet or the cells on this page.
+
+Dot notation is a feature in object-oriented programming. Here is an example of dot notation. There are many more examples of this in Sage. Dot notation is used to access attributes and methods of an object. We can also pass in arguments to this method to specify the number of digits we want to round to.
+
+
Sage supports different ways of accomplishing the same task.
+
+
+
+ + + diff --git a/_static/pretext/css/banner_crc.css b/_static/pretext/css/banner_crc.css new file mode 100644 index 0000000..c3db460 --- /dev/null +++ b/_static/pretext/css/banner_crc.css @@ -0,0 +1,336 @@ +/*** Some PreTeXt overrides ***/ +/* +@media (min-width: 801px) { + .title-container .title { + font-size: unset; + font-weight: unset; + } +} +*/ +.ptx-masthead .title-container > .heading { + line-height: unset; +} +/* +.ptx-masthead .title-container > .heading { + font-family: unset; + font-weight: unset; + font-size: unset; + line-height: unset; + color: unset; +} +*/ +.ptx-masthead .byline { + margin: unset; + font-size: unset; + line-height: unset; + font-family: unset; +} + +.ptx-masthead .ptx-banner { + border-top: 1px solid transparent; + border-bottom: none; + overflow: hidden; + padding-top: 0.625em; + padding-bottom: 1.125em; +} + +.ptx-content .summary-links a { + display: block; + padding: .6em; + text-decoration: none; + font-family: "Open Sans", sans-serif; + font-size: 1em; + font-weight: 600; + border-radius: 5px; +} + +.ptx-content .summary-links a .codenumber { + color: var(--bluegreen) +} + +.ptx-content .summary-links a .title { + font-weight: 600; +} + +.ptx-content .summary-links a:hover { + color: #fff; + background: var(--bluegreen); +} + +.ptx-content .summary-links ul, +.ptx-content .summary-links ul li { + display: grid; + list-style-type: none; + min-width: 300px; + padding-inline-start: 0px; + font-family: "Open Sans", sans-serif; + justify-items: stretch; + margin: 2px auto 3px auto; +} + + +.ptx-content .summary-links > ul { + // text-align: left; +} + +@media screen and (min-width: 600px) { + .ptx-content .summary-links ul, + .ptx-content .summary-links ul li { + width: 60vw; + max-width: 500px; + } +} + +@media screen and (min-width: 700px) { + .ptx-content .summary-links ul, + .ptx-content .summary-links ul li { + width: 55vw; + max-width: 500px; + } +} + +@media screen and (min-width: 800px) { + .ptx-content .summary-links ul, + .ptx-content .summary-links ul li { + width: 49vw; + max-width: 500px; + } +} +/*** End PreTeXt overrides ***/ + + + +.ptx-masthead .title-container { + font-size: 1em; + padding-left: 9.68px; + overflow: hidden; +} + +@media screen and (max-width: 480px) { + .ptx-masthead .title-container { + padding: 0; + text-align: center; + } +} + +.ptx-masthead .title-container > .heading { + margin: 0; + font-size: 2em; +} + +.ptx-masthead .title-container > .heading.hide-type .type { + display: none; +} +.ptx-masthead .title-container > .heading.hide-codenumber .codenumber { + display: none; +} +.ptx-masthead .title-container > .heading.hide-title .title { + display: none; +} + +/* +@media screen and (max-width: 480px) { + .ptx-masthead .title-container > .heading { + font-size: 1.5em; + line-height: 1.25em; + margin: 0; + margin-bottom: 0.41667em; + } +} + + +.ptx-masthead .title-container > .heading a { + color: #932919; + background: none; + text-decoration: none; +} + + + +.ptx-masthead .title-container > .heading a:active { + color: #3572a0; +} +*/ + +.ptx-masthead .title-container > .heading .subtitle { + font-weight: normal; +} + + +@media screen and (max-width: 800px) { + .ptx-masthead .title-container > .heading .subtitle { + /* Force the subtitle onto a separate line */ + display: block; + /* De-emphasize relative to main title */ + color: #595959; + /* Remove colon */ + } + .ptx-masthead .title-container > .heading .subtitle:before { + content: normal; + } +} + + +.ptx-masthead .byline { + color: #333333; + font-size: 1.2em; + font-weight: normal; + margin: 0; + min-height: inherit; +} + + + +@media screen and (max-width: 480px) { + .ptx-masthead .byline { + margin-top: 0; + font-size: 1em; + line-height: 1.25em; + } +} + + + + +.ptx-masthead .byline a { + color: #333333; +} +.ptx-masthead .byline a:active { + color: #3572a0; +} + + +.ptx-masthead .ptx-banner .title-container .heading { + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +/* .ptx-masthead-banner */ +.ptx-masthead .ptx-banner { /* maybe .ptx-masthead > .ptx-banner? */ + max-width: 904px; + display: grid; + grid-gap: 1em; + grid-template-columns: 50px 1fr; + grid-template-areas: + "ptx-logobox ptx-title-byline-box"; + background-color: #fff; /* #fafafa; */ + padding: 0px 20px 0px 20px; +/* + justify-self: stretch; +*/ + +} + +.title-container .title { + color: var(--bodytitle); +} + +.title-container .subtitle { + color: var(--bodysubtitle); +} + +/* Adjust font sizes by screen sizes */ +/* Phones */ +.title-container { + margin-top: 0px; +} + +.title-container .title { + font-size: .6em; + font-weight: 600; +} + +.title-container .subtitle { + font-weight: normal; + font-size: .5em; +} + + + +/* Larger than mobile */ +@media (min-width: 400px) { + + .title-container { + margin-top: 0px; + } + + .title-container .title { + font-size: .7em; + font-weight: 600; + } + + .title-container .subtitle { + font-weight: normal; + font-size: .6em; + } + + +} + +/* Larger than phablet (also point when grid becomes active) */ +@media (min-width: 550px) { + + .title-container { + margin-top: 3px; + } + + .title-container .title { + font-size: .9em; + font-weight: 600; + } + + .title-container .subtitle { + font-weight: normal; + font-size: .7em; + } + + +} + +/* Large screens */ +@media (min-width: 801px) { + + .title-container { + margin-top: 5px; + } + + .title-container .title { + font-size: 1.0em; + font-weight: 600; + } + + .title-container .subtitle { + font-weight: normal; + font-size: .8em; + } + + +} + + + +/* .ptx-logobox */ +.logo-link { + grid-area: ptx-logobox; + color: #000; + padding: 15px 0px 0px 0px; + justify-self: stretch; +} + +/* Fix the width of logo to always be 50px */ +/* .ptx-logobox img */ +.ptx-masthead .logo-link img { + width: 50px; +} + +/* .ptx-title-byline-box */ +.title-container { + grid-area: ptx-title-byline-box; + color: #000; + padding: 0px 0px 0px 0px; + justify-self: stretch; +} + +/* ptx-searchbox */ +.searchbox { + grid-area: ptx-searchbox; +} diff --git a/_static/pretext/css/banner_default.css b/_static/pretext/css/banner_default.css new file mode 100644 index 0000000..5933675 --- /dev/null +++ b/_static/pretext/css/banner_default.css @@ -0,0 +1,141 @@ +/******************************************************************************* + * PreTeXt Masthead Stylesheet + *******************************************************************************/ + +.ptx-masthead .ptx-banner { + border-bottom: 1px solid #d4d4d4; + border-top: 1px solid transparent; + overflow: hidden; + padding-top: 0.625em; + padding-bottom: 1.125em; + border-bottom: none; +} + +.ptx-masthead { + max-width: 904px; + border-right: 1px solid #bababa; +} + +.ptx-masthead .title-container { + font-size: 1em; + padding-left: 9.68px; + overflow: hidden; +} +@media screen and (max-width: 480px) { + .ptx-masthead .title-container { + padding: 0; + text-align: center; + margin-top: 0.625em; + } +} +.ptx-masthead .title-container > .heading { + font-family: "PT Serif", "Times New Roman", Times, serif; + font-weight: 700; + margin: 0; + font-size: 2em; + line-height: 1.25em; + color: #932919; +} +@media screen and (max-width: 480px) { + .ptx-masthead .title-container > .heading { + font-size: 1.5em; + line-height: 1.25em; + margin: 0; + margin-bottom: 0.41667em; + } +} +.ptx-masthead .title-container > .heading a { + color: #932919; + background: none; + text-decoration: none; +} +.ptx-masthead .title-container > .heading .subtitle { + font-weight: normal; +} +@media screen and (max-width: 800px) { + .ptx-masthead .title-container > .heading .subtitle { + /* Force the subtitle onto a separate line */ + display: block; + font-size: 1.16667em; + line-height: 1.42857em; + /* De-emphasize relative to main title */ + color: #595959; + /* Remove colon */ + } + .ptx-masthead .title-container > .heading .subtitle:before { + content: normal; + } +} +.ptx-masthead .logo-link { + position: relative; + float: left; + font-size: 50px; + margin-top: 0.1em; + margin-left: 9.68px; + text-align: center; + line-height: 1; +} +.ptx-masthead .logo-link img { + width: auto; + height: auto; + /* Allow font-size to control height + * so that icon placeholder height matches */ + max-height: 1em; +} +.ptx-masthead .logo-link:empty:before { + font-family: "Open Sans"; + font-size: 1em; + content: "\2211"; + /* Center the icon in a square the size of the parent's font-size */ + line-height: 1; + width: 1em; + display: inline-block; + vertical-align: top; + text-align: center; + color: #ccc; +} +.ptx-masthead .logo-link:empty:hover:before { + color: #932919; +} +.ptx-masthead .logo-link:empty:active:before { + color: #3572a0; +} +.ptx-masthead .logo-link { + background: transparent; + border: none; + text-decoration: none; +} +@media screen and (max-width: 480px) { + .ptx-masthead .logo-link { + display: block; + float: none; + margin: 0; + font-size: 50px; + } +} +.ptx-masthead .byline { + color: #333333; + font-weight: normal; + margin: 0; + font-size: 1.3125em; + line-height: 1.42857em; + min-height: inherit; + font-family: "PT Serif", "Times New Roman", Times, serif; +} +@media screen and (max-width: 480px) { + .ptx-masthead .byline { + margin-top: 0; + font-size: 1em; + line-height: 1.25em; + } +} +.ptx-masthead .byline a { + color: #333333; +} +.ptx-masthead .byline a:hover, .ptx-masthead .byline a:focus { + color: #932919; +} +.ptx-masthead .byline a:active { + color: #3572a0; +} + diff --git a/_static/pretext/css/banner_wide.css b/_static/pretext/css/banner_wide.css new file mode 100644 index 0000000..45ce9ed --- /dev/null +++ b/_static/pretext/css/banner_wide.css @@ -0,0 +1,20 @@ +@import url("banner_default.css"); + +:root { + --banner-background-color: #ffffff; +} + +.pretext .ptx-masthead { + max-width: var(--page-width); + background-color: var(--banner-background-color); + margin: 0 auto; +} + +.pretext .ptx-masthead .ptx-banner { + margin: 0 auto; + display: flex; + align-items: center; + justify-content: center; + max-width: var(--page-width); + padding: 8px 0; +} \ No newline at end of file diff --git a/_static/pretext/css/catalog.css b/_static/pretext/css/catalog.css new file mode 100644 index 0000000..a618059 --- /dev/null +++ b/_static/pretext/css/catalog.css @@ -0,0 +1,94 @@ + +.projects a { + text-decoration: none; +} +.projects p { + margin: 0; +} +.projects p + p { + margin-top: 0.75em; +} + +.projects .category { + max-width: 700px; +} +.projects .fact-sheet-knowl { + display: none; +} +.projects .description-knowl { + display: none; +} +.projects .awards-knowl { + display: none; +} +.projects .book-summary { + margin-left: 2em; + padding-left: 0.5em; +} +.projects .book-summary + .book-summary { + padding-top: 0.5em; + padding-bottom: 0.5em; + margin-top: 1em; +} + +.projects .book-summary:nth-of-type(even) { + background: #efe; +} +.projects .badges { + margin-top: 0.25em; + padding-left: 0.5em; + min-height: 30px; +} +.projects .badges img { + max-height: 25px; +} +.projects .badges img + img { + margin-left: 5px; +} +.projects .badge.award + .badge:not(.award) { + margin-left: 2em; +} +.projects .badge.license { + margin-right: 0.5em; + float: right; +} + +.projects .biblio > .title { + font-style: italic; + font-size: 120%; +} +.projects .biblio > .authors { + margin-left: 0.25em; +} + +.projects .category > .title { + display: block; + margin-top: 1em; + margin-bottom: 0.4em; + margin-left: 1em; + background: #ccf; + font-size: 150%; + padding: 0.5em 0 0.25em 0.2em; +} + +.projects .blurb { + margin-top: 0.2em; + padding-left: 0.5em; +} +.projects .category .blurb .id-ref { /* why that name? */ + font-style: italic; + font-size: 90%; + margin-left: 0.5em; +} +.projects .category .description { + padding: 0.5em 2em 0.5em 2em; +} +[data-knowl]:hover, [data-knowl]:active, [data-knowl].active { + color: #8a1200; + background: #ffedeb; +/* + margin-bottom: 0; +*/ + border-bottom: none; +} + diff --git a/_static/pretext/css/colors_blue_green.css b/_static/pretext/css/colors_blue_green.css new file mode 100644 index 0000000..210e773 --- /dev/null +++ b/_static/pretext/css/colors_blue_green.css @@ -0,0 +1,118 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +:root { + --documenttitle: #2a5ea4; + --bodytitle: #2b5f82; + --bodysubtitle: #a62e1c; + --bodytitlehighlight: #e0e9ff; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #28803f; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #20477b; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #20477b; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); + + /* Colors for block envirornments: */ + /* + We specify 6 color families (hues), each with 5 hue/lightness options, to be used by style files if they wish. + + The hues should roughly corrspond to red, orange, yellow, green, blue, violet, but should be consistent with the colors specified for titles and toc defined above. + + Each color has *light, *dark variants (adjusting the lightness of hsl) and *rich, *dull variants (adjusting the saturation). *light and *dull should work for a main background. The standard and *riche should work for borders. For a bold title background, the *dark could be used. + + The *dark should always contrast correctly with white text (we could later specify a *dark-text to be the correct contrast with *dark). All other variants should contrast correctly with black text. + */ + --red: hsl(345, 60%, 60%); + --redlight: hsl(345, 60%, 80%); + --reddark: hsl(345, 60%, 15%); + --redrich: hsl(345, 100%, 60%); + --reddull: hsl(345, 20%, 60%); + + --orange: hsl(30, 70%, 60%); + --orangelight: hsl(30, 60%, 80%); + --orangedark: hsl(30, 60%, 15%); + --orangerich: hsl(30, 100%, 60%); + --orangedull: hsl(30, 30%, 60%); + + --yellow: hsl(58, 60%, 60%); + --yellowlight: hsl(58, 60%, 80%); + --yellowdark: hsl(58, 60%, 15%); + --yellowrich: hsl(58, 100%, 60%); + --yellowdull: hsl(58, 30%, 60%); + + --green: hsl(136, 52%, 33%); + --greenlight: hsl(136, 52%, 80%); + --greendark: hsl(136, 52%, 15%); + --greenrich: hsl(136, 100%, 60%); + --greendull: hsl(136, 20%, 60%); + + --blue: hsl(214, 59%, 60%); + --bluelight: hsl(214, 59%, 80%); + --bluedark: hsl(214, 59%, 15%); + --bluerich: hsl(214, 100%, 50%); + --bluedull: hsl(214, 20%, 50%); + + --violet: hsl(259, 60%, 60%); + --violetlight: hsl(259, 60%, 80%); + --violetdark: hsl(259, 60%, 15%); + --violetrich: hsl(259, 100%, 60%); + --violetdull: hsl(259, 20%, 60%); +} + diff --git a/_static/pretext/css/colors_blue_grey.css b/_static/pretext/css/colors_blue_grey.css new file mode 100644 index 0000000..30835d1 --- /dev/null +++ b/_static/pretext/css/colors_blue_grey.css @@ -0,0 +1,74 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +/* Colors formerly in mathbook-4.css */ + +:root { + --documenttitle: #2a5ea4; + --bodytitle: #2B5F82; + --bodysubtitle: #A62E1C; + --bodytitlehighlight: #e0e9ff; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #525252; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #20477b; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #20477b; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #5B2F82; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_blue_red.css b/_static/pretext/css/colors_blue_red.css new file mode 100644 index 0000000..19b6520 --- /dev/null +++ b/_static/pretext/css/colors_blue_red.css @@ -0,0 +1,72 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +:root { + --documenttitle: #2a5ea4; + --bodytitle: #2B5F82; + --bodysubtitle: #A62E1C; + --bodytitlehighlight: #e0e9ff; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #932c1c; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #20477b; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #20477b; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_blue_red_dark.css b/_static/pretext/css/colors_blue_red_dark.css new file mode 100644 index 0000000..6442cba --- /dev/null +++ b/_static/pretext/css/colors_blue_red_dark.css @@ -0,0 +1,130 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +:root { + --bodyfontcolor: #eee; + --documenttitle: #2a5ea4; + --documenttitledark: #20477b; + --documenttitlelight: #abf; + --bodytitle: #2B5F82; + --bodysubtitle: #A62E1C; + --bodytitlehighlight: #316; /* DARKER, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #932c1c; + --chaptertoctext: #dee; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: #666; + --sectiontoctext: #eed; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: var(--documenttitledark); + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + --assemblagebackground: #003; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + +body.pretext { + background: #222; +} +.pretext .ptx-page > .ptx-main { + background: #444; + color: var(--bodyfontcolor); +} +.ptx-content .summary-links a { + background: var(--documenttitledark); + background: var(--chaptertoc); +} +.ptx-navbar { + background: #333; +} +.ptx-navbar .button{ + background-color: #635; + color: #fff; +} +.ptx-navbar .button:hover { + background-color: #fafafa; + color: #000; +} +.ptx-navbar .calculator-toggle { + background-color: #336; +} +.ptx-navbar .calculator-toggle:hover { + background-color: #fce; +} + +.pretext .ptx-masthead { + background: #555; +} +.pretext .ptx-masthead .title-container > .pretext .heading, +.pretext .ptx-masthead .title-container > .heading a, +.pretext .ptx-masthead .logo-link:empty:hover::before, +.pretext .ptx-masthead .byline, +.pretext .ptx-masthead .byline a { + color: var(--documenttitlelight); +} +.pretext .ptx-content .code-inline { + color: var(--documenttitledark); +} +.ptx-content .goal-like > .heading { + background: var(--chaptertoc); +} +.pretext .ptx-content [data-knowl], +.pretext .ptx-content [data-knowl]:hover, +.pretext .ptx-content [data-knowl]:active, +.pretext .ptx-content [data-knowl].active { + color: var(--documenttitlelight); +} +.pretext .ptx-page .ptx-main .ptx-content .knowl-content > .solution-like { + background: #606; +} diff --git a/_static/pretext/css/colors_bluegreen_grey.css b/_static/pretext/css/colors_bluegreen_grey.css new file mode 100644 index 0000000..2546fe3 --- /dev/null +++ b/_static/pretext/css/colors_bluegreen_grey.css @@ -0,0 +1,119 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +:root { + --bluegreen: hsl(192, 98%, 23%); + --documenttitle: var(--bluegreen); + --bodytitle: var(--bluegreen); + --bodysubtitle: var(--bluegreen); + --bodytitlehighlight: #e0e9ff; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #ddd; /* #28803f; */ + --chaptertoctext: var(--bluegreen); /* white; */ + --chaptertocactive: hsl(192, 98%, 19%); + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: var(--bluegreen); /* #20477b; */ + --sectiontocactive: hsl(192, 98%, 19%); + --sectiontoctextactive: white; + --tocborder: var(--bluegreen); /* #152f53; */ + + --highlighttoc: var(--bluegreen); /* #20477b; */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); + + /* Colors for block envirornments: */ + /* + We specify 6 color families (hues), each with 5 hue/lightness options, to be used by style files if they wish. + + The hues should roughly corrspond to red, orange, yellow, green, blue, violet, but should be consistent with the colors specified for titles and toc defined above. + + Each color has *light, *dark variants (adjusting the lightness of hsl) and *rich, *dull variants (adjusting the saturation). *light and *dull should work for a main background. The standard and *riche should work for borders. For a bold title background, the *dark could be used. + + The *dark should always contrast correctly with white text (we could later specify a *dark-text to be the correct contrast with *dark). All other variants should contrast correctly with black text. + */ + --red: hsl(345, 60%, 60%); + --redlight: hsl(345, 60%, 80%); + --reddark: hsl(345, 60%, 15%); + --redrich: hsl(345, 100%, 60%); + --reddull: hsl(345, 20%, 60%); + + --orange: hsl(30, 70%, 60%); + --orangelight: hsl(30, 60%, 80%); + --orangedark: hsl(30, 60%, 15%); + --orangerich: hsl(30, 100%, 60%); + --orangedull: hsl(30, 30%, 60%); + + --yellow: hsl(58, 60%, 60%); + --yellowlight: hsl(58, 60%, 80%); + --yellowdark: hsl(58, 60%, 15%); + --yellowrich: hsl(58, 100%, 60%); + --yellowdull: hsl(58, 30%, 60%); + + --green: hsl(136, 52%, 33%); + --greenlight: hsl(136, 52%, 80%); + --greendark: hsl(136, 52%, 15%); + --greenrich: hsl(136, 100%, 60%); + --greendull: hsl(136, 20%, 60%); + + --blue: hsl(214, 59%, 60%); + --bluelight: hsl(214, 59%, 80%); + --bluedark: hsl(214, 59%, 15%); + --bluerich: hsl(214, 100%, 50%); + --bluedull: hsl(214, 20%, 50%); + + --violet: hsl(259, 60%, 60%); + --violetlight: hsl(259, 60%, 80%); + --violetdark: hsl(259, 60%, 15%); + --violetrich: hsl(259, 100%, 60%); + --violetdull: hsl(259, 20%, 60%); +} + diff --git a/_static/pretext/css/colors_brown_gold.css b/_static/pretext/css/colors_brown_gold.css new file mode 100644 index 0000000..9b446bd --- /dev/null +++ b/_static/pretext/css/colors_brown_gold.css @@ -0,0 +1,37 @@ + +/* Colors for Manitoba */ + +:root { + --documenttitle: #472200; + --bodytitle: #8e4a0c; + --bodysubtitle: #864E1C; + --bodytitlehighlight: #eeeff3; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #eaaf0f; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #6f080b; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #140a00 /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_darkmartiansands.css b/_static/pretext/css/colors_darkmartiansands.css new file mode 100644 index 0000000..d2d80da --- /dev/null +++ b/_static/pretext/css/colors_darkmartiansands.css @@ -0,0 +1,74 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +/* Martian sands color scheme by Alex Jordan */ + +:root { + --documenttitle: #880000; + --bodytitle: #932c10; + --bodysubtitle: #A62E1C; + --bodytitlehighlight: #dcd3f0; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #b58039; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #20477b; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #d1d1d1; + + --highlighttoc: #550000; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #5B2F82; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_default.css b/_static/pretext/css/colors_default.css new file mode 100644 index 0000000..f10eb36 --- /dev/null +++ b/_static/pretext/css/colors_default.css @@ -0,0 +1,82 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 4) A dark color for each chapter background + 5) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 4') A light color for each chapter background + 5') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 4) and 5) you need white letters to go on the dark + background, and with 4') and 5') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +:root { + --documenttitle: #932919; + --bodytitle: #A62E1C; /* often a darker version of documenttitle */ + --bodysubtitle: #2B5F82; /* can be the same as bodytitle */ + --bodytitlehighlight: #e0e9ff; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + /* Part colors are not used in non-focused TOC */ + --parttoc: #932c1c; + --parttoctext: white; + --parttocactive: var(--documenttitle); + --parttoctextactive: white; + + --chaptertoc: #3572a0; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #662211; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #185f65; + + --highlighttoc: #671d12; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblagebackground: #f5f8ff; + --assemblagebackground: #F0EAF6; + --assemblageborder: #5B2F82; + --assemblageborder: #B793D7; + --assemblageborder: #CAAEE0; + --assemblagedarkborder: #472664; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_focused_gray_aqua.css b/_static/pretext/css/colors_focused_gray_aqua.css new file mode 100644 index 0000000..af0f56b --- /dev/null +++ b/_static/pretext/css/colors_focused_gray_aqua.css @@ -0,0 +1,47 @@ +/* + Sample bolder focused TOC color scheme + See colors_default for general color tips +*/ + + +:root { + /* -------- general -------- */ + --documenttitle: #343b48; + --bodytitle: #2B5F82; + --bodysubtitle: #1d686e; + --bodytitlehighlight: #e0e9ff; + --bodysubtitlehighlight: #fce5e4; + + --videoplay: var(--bodytitle); + --assemblageborder: #343b48; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); + + /* -------- TOC -------- */ + --toc-text-dark: #343b48; + --toc-text-light: white; + --tocborder: var(--toc-text-dark); + --active-toc-item: #e5ca34; + + --parttoc: var(--toc-text-dark); + --parttoctext: var(--toc-text-light); + --parttocactive: var(--active-toc-item); + --parttoctextactive: var(--toc-text-dark); + + --chaptertoc: #1d686e; + --chaptertoctext: var(--toc-text-light); + --chaptertocactive: var(--active-toc-item); + --chaptertoctextactive: var(--toc-text-dark); + + --sectiontoc: #fffffd; + --sectiontoctext: var(--toc-text-dark); + --sectiontocactive: var(--active-toc-item); + --sectiontoctextactive: var(--toc-text-dark); + + + --highlighttoc: var(--active-toc-item); + --highlighttoctext: var(--toc-text-dark); + --highlighttocborder: var(--chaptertoc); +} \ No newline at end of file diff --git a/_static/pretext/css/colors_focused_light.css b/_static/pretext/css/colors_focused_light.css new file mode 100644 index 0000000..ddedb0a --- /dev/null +++ b/_static/pretext/css/colors_focused_light.css @@ -0,0 +1,44 @@ +/* + Sample light, non-distracting focused TOC color scheme + See colors_default for general color tips +*/ + +:root { + /* -------- general -------- */ + --documenttitle: #343b48; + --bodytitle: #2B5F82; + --bodysubtitle: #A62E1C; + --bodytitlehighlight: #e0e9ff; + --bodysubtitlehighlight: #fce5e4; + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); + + /* -------- TOC -------- */ + --toc-text-dark: #333; + --tocborder: var(--toc-text-dark); + --active-toc-item: #dbebf1; + + --parttoc: #e8e8e8; + --parttoctext: var(--toc-text-dark); + --parttocactive: var(--active-toc-item); + --parttoctextactive: var(--toc-text-dark); + + --chaptertoc: #f2f2f2; + --chaptertoctext: var(--toc-text-dark); + --chaptertocactive: var(--active-toc-item); + --chaptertoctextactive: var(--toc-text-dark); + + --sectiontoc: #fdfdfd; + --sectiontoctext: var(--toc-text-dark); + --sectiontocactive: var(--active-toc-item); + --sectiontoctextactive: var(--toc-text-dark); + + --highlighttoc: #c2e5f2; + --highlighttoctext: var(--toc-text-dark); + --highlighttocborder: var(--chaptertoc); +} \ No newline at end of file diff --git a/_static/pretext/css/colors_green_blue.css b/_static/pretext/css/colors_green_blue.css new file mode 100644 index 0000000..0b637e3 --- /dev/null +++ b/_static/pretext/css/colors_green_blue.css @@ -0,0 +1,72 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +:root { + --documenttitle: #248038; + --bodytitle: #20602f; + --bodysubtitle: #822060; + --bodytitlehighlight: #e0e9ff; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #2650a0; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #20602f; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #195827; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_green_plum.css b/_static/pretext/css/colors_green_plum.css new file mode 100644 index 0000000..20edb33 --- /dev/null +++ b/_static/pretext/css/colors_green_plum.css @@ -0,0 +1,72 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +:root { + --documenttitle: #28803f; + --bodytitle: #20602f; + --bodysubtitle: #822060; + --bodytitlehighlight: #e0e9ff; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #822060; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #20602f; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #20602f; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_maroon_grey.css b/_static/pretext/css/colors_maroon_grey.css new file mode 100644 index 0000000..8a8506c --- /dev/null +++ b/_static/pretext/css/colors_maroon_grey.css @@ -0,0 +1,37 @@ + +/* Colors for UPS */ + +:root { + --documenttitle: #660000; + --bodytitle: #8e0a0c; + --bodysubtitle: #A62E1C; + --bodytitlehighlight: #eeeff3; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #6d8899; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #6f080b; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #330000; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_martiansands.css b/_static/pretext/css/colors_martiansands.css new file mode 100644 index 0000000..d26e8ca --- /dev/null +++ b/_static/pretext/css/colors_martiansands.css @@ -0,0 +1,74 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +/* Martian sands color scheme by Alex Jordan */ + +:root { + --documenttitle: #944921; + --bodytitle: #932c10; + --bodysubtitle: #A62E1C; + --bodytitlehighlight: #dcd3f0; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #d19e69; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #20477b; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #d1d1d1; + + --highlighttoc: #6a3418; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #5B2F82; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_orange_navy.css b/_static/pretext/css/colors_orange_navy.css new file mode 100644 index 0000000..502f180 --- /dev/null +++ b/_static/pretext/css/colors_orange_navy.css @@ -0,0 +1,72 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +:root { + --documenttitle: #d64000; + --bodytitle: #00408a; + --bodysubtitle: #9e2f00; + --bodytitlehighlight: #ffcdbd; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #00326b; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #00326b; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #006deb; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_pastel_blue_orange.css b/_static/pretext/css/colors_pastel_blue_orange.css new file mode 100644 index 0000000..2ec26e8 --- /dev/null +++ b/_static/pretext/css/colors_pastel_blue_orange.css @@ -0,0 +1,32 @@ + +/* Pastel color scheme by Nathan Wintersgill */ + +:root { + --documenttitle: #2a5ea4; + --bodytitle: #A62E1C; + --bodysubtitle: #2B5F82; + --bodytitlehighlight: #e0e9ff; + --bodysubtitlehighlight: #FCE5E4; + + --chaptertoc: #dbf5ff; + --chaptertoctext: #444444; + --chaptertocactive: #fae5b6; + --chaptertoctextactive: #303030; + --sectiontoc: #ffffff; + --sectiontoctext: #404040; + --sectiontocactive: #fae5b6; + --sectiontoctextactive: #202020; + --tocborder: #afc2e5; + + --highlighttoc: #fac793; + --highlighttoctext: #321a0c; + --highlighttocborder: #ec704b; + + --assemblageborder: #1100aa; + --assemblagebackground: #f4f4fe; + + --knowlborder: #e0e9ff; + --knowlbackground: #f5f8ff; + +} + diff --git a/_static/pretext/css/colors_red_blue.css b/_static/pretext/css/colors_red_blue.css new file mode 100644 index 0000000..c4a833f --- /dev/null +++ b/_static/pretext/css/colors_red_blue.css @@ -0,0 +1,35 @@ + +:root { + --documenttitle: #932919; + --bodytitle: #A62E1C; /* often a darker version of documenttitle */ + --bodysubtitle: #2B5F82; /* can be the same as bodytitle */ + --bodytitlehighlight: #e0e9ff; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #3572a0; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #662211; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #185f65; + + --highlighttoc: #671d12; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #5B2F82; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_ruby_amethyst.css b/_static/pretext/css/colors_ruby_amethyst.css new file mode 100644 index 0000000..57264cf --- /dev/null +++ b/_static/pretext/css/colors_ruby_amethyst.css @@ -0,0 +1,72 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +:root { + --documenttitle: #9e0c0f; + --bodytitle: #8e0a0c; + --bodysubtitle: #A62E1C; + --bodytitlehighlight: #d0f9ff; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #6f080b; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #6f080b; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #008099; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_ruby_emerald.css b/_static/pretext/css/colors_ruby_emerald.css new file mode 100644 index 0000000..cb92c04 --- /dev/null +++ b/_static/pretext/css/colors_ruby_emerald.css @@ -0,0 +1,72 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +:root { + --documenttitle: #9e0c0f; + --bodytitle: #8e0a0c; + --bodysubtitle: #A62E1C; + --bodytitlehighlight: #d9ffe9; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #16a67d; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #6f080b; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #6f080b; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/colors_ruby_turquoise.css b/_static/pretext/css/colors_ruby_turquoise.css new file mode 100644 index 0000000..17c6b31 --- /dev/null +++ b/_static/pretext/css/colors_ruby_turquoise.css @@ -0,0 +1,72 @@ + +/* + There are five main choices that define a color scheme in the + HTML output of PreTeXt: + 1) A dark color for the title on each page + 2) A dark color for highlighted words in the body + 3) A dark color for other highlighted words in the body + + In the CSS those are called 'documenttitle', 'bodytitle', + and 'bodysubtitle'. + + The other two choices appear in the ToC. + + Either: + 3) A dark color for each chapter background + 4) A dark color for the current section background + (Often the ToC section background equals documenttitle. + + Or: + 3') A light color for each chapter background + 4') A light color for the current section background + + In the CSS those are called 'chaptertoc' and 'sectiontoc', + respectively. + + With 3) and 4) you need white letters to go on the dark + background, and with 3') and 4') you need dark letters + on the light background. Set the color of those letters + with 'chaptertoctext'. + + In addition to the above four choices, you need to + choose a contrasting shade of each color, to be used + for highlighting, borders, etc. + + In the future you will be able to choose colors for assemblages + and for knowl output +*/ + +:root { + --documenttitle: #9e0c0f; + --bodytitle: #8e0a0c; + --bodysubtitle: #A62E1C; + --bodytitlehighlight: #d0f9ff; /* light, and contrasting to bodytitle */ + --bodysubtitlehighlight: #fce5e4; /* light, and contrasting to bodysubtitle */ + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: #008099; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: white; /* can also write it as #ffffff */ + --sectiontoctext: #6f080b; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #6f080b; /* often a dark version of documenttitle */ + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} + diff --git a/_static/pretext/css/edit.css b/_static/pretext/css/edit.css new file mode 100644 index 0000000..236ced7 --- /dev/null +++ b/_static/pretext/css/edit.css @@ -0,0 +1,493 @@ +/* CAT */ + +.edit_menu_holder { + position: relative; + left: 15em; + bottom: 1.5em; + z-index: 1000; +} +.edit_menu_holder li { + font-style: normal; +} +p > .edit_menu_holder, +.creator > .edit_menu_holder { + display: inline; +} +p > .edit_menu_holder { + bottom: 4.2em; +} +#local_menu_holder { + position: relative; + left: 20em; + bottom: 1.5em; + z-index: 1000; +} +.edit_menu, +#enter_choice { + background: #fee; + position: absolute; + left: 0; + white-space: nowrap; + z-index: 1000; + font-size: 95%; + font-weight: normal; +} +.edit_menu.past { + background: #ffe; + color: #999; +} +.past > li { + background: #fff9f9; + color: #aaa; +} +#enter_choice { + padding: 0.25em 0.5em 0 0.5em; + background: yellow; + bottom: -1.2em; + border-radius: 0.5em 0.5em 0 0; + font-style: italic; +} +.may_enter #enter_choice { + background: #ccccee; +} +.may_enter { + margin-top: 1.25em; + background: #eeeeff !important; +} +.may_enter > [data-editable] { + background: #feeedf !important; +} +.may_enter > [data-editable="99"] { + background: #ffffdd !important; +} + +p > .edit_menu_holder > #enter_choice { + bottom: -2.7em; +} +blockquote > .edit_menu_holder > #enter_choice { + bottom: -1.2em; +} +blockquote.may_leave + .edit_menu_holder > #enter_choice { + bottom: -2.3em; +} +article.project-like > .edit_menu_holder > #enter_choice { + bottom: -0.5em; +} +article.theorem-like > .edit_menu_holder > #enter_choice, +article.definition-like > .edit_menu_holder > #enter_choice { + bottom: -0.2em; +} +/* +article.project-like > ol > .edit_menu_holder > #enter_choice { + bottom: -1.3em; +} +*/ +.ptx-content section article.project-like.may-enter > .heading, +.ptx-content section article.project-like.may-leave > .heading { + background-color: inherit; +} + +ol > .edit_menu_holder > #enter_choice { + bottom: -1.3em; +} +ol.may_leave + .edit_menu_holder > #enter_choice { + bottom: -3.3em; +} +li > .para > .edit_menu_holder > #enter_choice { + bottom: -4.1em; +} +#enter_choice[data-location="inline"] { + bottom: -0.2em; + left: -0.5em; +} + +.edit_menu_holder + .para { + margin-top: 0; +} +li > .edit_menu_holder { + display: block; +} +.may_leave + .edit_menu_holder #enter_choice { + position: absolute; + padding: 0em 0.5em 0.25em 0.25em; + background: #FFD6D9; + bottom: -1.9em; + border-radius: 0 0 0.5em 0.5em; + list-style-type: none; + font-style: italic; +} +section.may_leave + .edit_menu_holder #enter_choice { + bottom: -3.3em; +} +article.may_leave + .edit_menu_holder #enter_choice { + bottom: -2.3em; +} +.may_leave + .edit_menu_holder #enter_choice li { + padding: 0; + padding-left: 0.25em; + padding-right: 0.25em; +} + +.edit_menu li.chosen, +.edit_menu #choose_current { + background: #ddf; + color: #000; +} +.edit_menu.past > .choose { + background: #eef; + color: #000; +} +.edit_menu { + margin-top: 0; + margin-bottom: 0; + padding-left: 0; + list-style-type: none; +} +.edit_menu li { + margin-top: 0; + padding-right: 1.4em; + padding-left: 0.4em; + padding-bottom: 0.1em; +} +.edit_menu li:last-of-type { + padding-bottom: 0.3em; +} +.edit_menu_holder ol.past { + box-shadow: -0.25em 0.25em 0 #ccc; +} +.edit_menu_holder ol:not(.past) { + border: 0.1em solid #999; + box-shadow: 0.15em 0.15em 0.05em #ccc; +} +.edit_menu li#choose_current { + background: #ddf; +} +.edit_menu li.choosen { + background: #ddf; +} +.edit_menu li ol { + position: absolute; + left: 8em; +/* + bottom: -0.5em; +*/ + top: -3.5em; + margin-top: 0; + padding-left: 0; + list-style-type: none; + background: #fdd; +} +.edit_menu li ol li { + position: relative; +} +.edit_menu li ol ol { + position: absolute; + top: -1.5em; + z-index: 500; +} +.edit_menu li.choose { + background: #eef; +} +.edit_menu .wrap_to_submenu { + float: right; +} +.past > li > .wrap_to_submenu { + display: none; +} +.edit_menu .to_submenu { + position: absolute; + padding-left: 0.5em; +} +.text_source { + font-size: 95%; +} +.may_select > .para:first-of-type { + margin-top: 0; +} +.sbspanel.may_select { + margin-top: 0; +} +sbspanel:empty { /* can only happen when partially created */ + height: 10em; + background-color: rgb(221, 221, 255); +} +.ptx-content .sbspanel:empty + .sbspanel:empty { + background-color: #dfd; +} +.ptx-content .sbspanel:empty + .sbspanel:empty + .sbspanel:empty { + background-color: #eee; +} + +#actively_editing { + margin-top: 1em; +} +#actively_editing_id { + float: right; + width: 8em; + margin-bottom: 0; +} +#actively_editing[data-component="title"] { + display: inline-block; + min-width: 10em; + margin-top: 0; + margin-left: 0.75em; + background: #fff; + border: 1px dotted black; +} +.title > .edit_menu_holder { + display: inline; +} +.space + .title { + margin-left: 0.5em; +} + +.edit_menu .in_edit_tree { + border: none; +} +.edit_menu .in_edit_tree:before, +.edit_menu .in_edit_tree:before { + display: none; +} + +.in_edit_tree > .workspace { + min-height: 3em; + background: #efe; + border: 1px dotted #aaa; +} +.in_edit_tree > .workspace::before { + content: "optional workspace (in printed worksheet)"; + font-size: 90%; + font-style: italic; + padding-left: 0.25em; +} +/* why not collapse the next groups of 4? */ +.in_edit_tree > .placeholder.proof, +.in_edit_tree > .placeholder.hint, +.in_edit_tree > .placeholder.answer, +.in_edit_tree > .placeholder.solution { + min-height: 1em; + background: #fee; +} +.in_edit_tree > .placeholder.proof::before, +.in_edit_tree > .placeholder.hint::before, +.in_edit_tree > .placeholder.answer::before, +.in_edit_tree > .placeholder.solution::before { + font-size: 90%; + font-style: italic; + padding-left: 0.25em; +} +.in_edit_tree > .placeholder.proof::before { + content: "optional proof"; +} +.in_edit_tree > .placeholder.hint::before { + content: "optional hint"; +} +.in_edit_tree > .placeholder.answer::before { + content: "optional answer"; +} +.in_edit_tree > .placeholder.solution::before { + content: "optional solution"; +} + +.group_description { + font-size: 75%; + font-color: #caa; + font-style: italic; +} +[data-objecttype="theorem-like"] .para { + font-style: italic; +} +[data-objecttype="theorem-like"] .para ol { + font-style: normal; +} + +.paragraph_input { + width: 98%; + min-height: 3em; + border: 3px dashed #999; +} +.paragraph_input:focus { + border: 1px solid #000; + padding: 2px; +} +.displaymath_input { + width: 98%; + min-height: 3em; + border: 3px dotted #399; +} +.displaymath_input:focus { + border: 1px dashed #900; + padding: 2px; +} +.edit_inline_math { + font-family: "Inconsolata"; + margin-left: 0.5em; + margin-right: 0.5em; + background-color: #ddf; +} +#actively_editing em { + background-color: #fdf; +} +#actively_editing q { + background-color: #eef; +} +#actively_editing span { + background-color: #dfd; +} +#actively_editing code { + background-color: #ddd; +} +#actively_editing dfn { + background-color: #fee; +} +.ptx-content section.may_enter > .heading { + margin-top: 0; +} +.ptx-content #deleting { + transition: all 0.5s; + background: #666; + height: 5em; + margin-right: 20em; + margin-left: 15em; + font-size: 5%; + box-shadow: -2px -1px 1px #770000; +} + +.ptx-content .phantomobject.move { + margin-left: 5em; + margin-right: 2em; + padding: 1.5em; + box-shadow: 1em 0.7em rgba(180, 180, 180,0.96); + margin-top: -1.5em; + margin-bottom: -1.5em; + z-index: 100; + background: rgba(239, 223,256,0.9); + font-size: 110%; + font-style: italic; + position: relative; +} +.ptx-content .phantomobject.move + .para { + margin-top: 0; +} +.ptx-content .phantomobject.move .done { + margin-left: 1em; + margin-top: 0em; +} +.ptx-content .phantomobject.move .movearrow { + position: relative; + z-index: 101; + background: rgba(243, 225,256,1); +} +.ptx-content .phantomobject.move .movearrow .arrow { + font-size: 200%; + margin-right: 0.6em; + margin-top: -0.5em; +} +.ptx-content .phantomobject.move .movearrow .para { + margin-top: 0.4em; +} +.ptx-content .phantomobject.move .movearrow .para.up { + margin-top: 0; + margin-bottom: -1em; +} +.ptx-content .phantomobject.move .movearrow .para.down { + margin-top: 0.0em; +} +.ptx-content .phantomobject.move .movearrow > * { + display: inline-block; +} + +.ptx-content .ref.tmp { + background: #dfd; +} +.ptx-content .may_enter q { + background: #ddf; +} +.ptx-content .may_enter abbr { + background: #adf; +} + +/* new editing css */ +.ptx-content .para.may_select { + display: block !important; +} +.ptx-content .may_select { + background: #fef; + border: 2px solid #999; +} + +.ptx-content .onepage.in_edit_tree, +.ptx-content .in_edit_tree .onepage { + border: 6px double #600 !important; + padding: 0.5em; +} + + +.ptx-content .para.in_edit_tree, +.ptx-content section.in_edit_tree, +.ptx-content article.in_edit_tree { + border: 3px solid #666 !important; + padding: 0.5em; +} +.ptx-content .in_edit_tree .para, +.ptx-content .in_edit_tree .displaymath, +.ptx-content .in_edit_tree section, +.ptx-content .in_edit_tree article { + border: 3px solid blue !important; + padding: 0.5em; +} +.ptx-content .in_edit_tree .para { + border: 3px solid #4a9 !important; + background: #ffd; + padding: 0.5em; +} +.ptx-content .in_edit_tree figcaption, +.ptx-content .in_edit_tree blockquote { + border: 3px dotted #9a0 !important; + background: #efd; + padding: 0.5em; +} +.ptx-content .in_edit_tree img { + border: 3px dotted #09a !important; + background: #fbd; + padding: 0.5em; +} +.ptx-content .in_edit_tree .displaymath, +.ptx-content .in_edit_tree figure { + border: 3px solid #92a !important; + background: #efe; + padding: 0.5em; +} +/* over-rive overflow-x on small screens */ +.ptx-content.canedit .displaymath, +.ptx-content.canedit .figure, +.ptx-content.canedit figure.figure-like figcaption { + overflow: initial; +} +.ptx-content .in_edit_tree * section, +.ptx-content .in_edit_tree * article { + border: 3px solid green !important; + padding: 0.5em; +} +.ptx-content .in_edit_tree * * .para, +.ptx-content .in_edit_tree * * .displaymath, +.ptx-content .in_edit_tree * * section, +.ptx-content .in_edit_tree * * article { + border: 3px dashed grey !important; + padding: 0.5em; +} + +.ptx-content .in_edit_tree .para.mp, +.ptx-content .in_edit_tree .para.fp { + margin-top: 0; +} + +.ptx-content .in_edit_tree .heading + .para { + display: block; +} +.ptx-content .in_edit_tree::before, +.ptx-content .in_edit_tree::after, +.ptx-content .in_edit_tree *::before, +.ptx-content .in_edit_tree *::after { + all: reset; +} diff --git a/_static/pretext/css/epub.css b/_static/pretext/css/epub.css new file mode 100644 index 0000000..31807ff --- /dev/null +++ b/_static/pretext/css/epub.css @@ -0,0 +1,58 @@ + +.ptx-content.epub img { + display: block; +} +.ptx-content.epub .solutions { + margin-top: 1em; +} + +.ptx-content.epub .solutions .solution .type, +.ptx-content.epub .solutions .answer .type { + font-family: "PT Serif", "Times New Roman", Times, serif; + font-weight: bold; +} +.ptx-content.epub .solutions .solution .type + .period, +.ptx-content.epub .solutions .answer .type + .period { + margin-right: 0.75em; +} +.ptx-content.epub .solutions .solution .type + p, +.ptx-content.epub .solutions .answer .type + p { + display: inline; +} + +/* sage cell code goes in a pre. What else goes there? */ +.ptx-content pre { + font-size: 95%; + padding-top: 0.3em; + padding-bottom: 0.5em; + padding-left: 0.5em; + background: #f0f0f0; +} +.ptx-content pre.code.input { + background: #f0f0ff; +} +.ptx-content pre.code.output { + background: #f0fff0; +} + + +/* these "break-(before/after) might not actually do anything */ +.ptx-content section > .heading { + display: block; + margin-top: 0; + break-after: avoid !important; +} +.ptx-content section > .heading + p { + display: block; + break-before: avoid !important; +} +.ptx-content figcaption { + break-before: avoid !important; +} +.ptx-content figure .image-box, +.ptx-content figure .tabular-box { + break-after: avoid !important; +} +.ptx-content figure { + break-inside: avoid !important; +} diff --git a/_static/pretext/css/features.css b/_static/pretext/css/features.css new file mode 100644 index 0000000..7420b57 --- /dev/null +++ b/_static/pretext/css/features.css @@ -0,0 +1,324 @@ + +/* + * + * login + * + */ + + /* Bordered form */ +.login form { + border: 3px solid #f1f1f1; +} + +/* Full-width inputs */ +.login input[type=text], input[type=password] { + width: 100%; + padding: 12px 20px; + margin: 8px 0; + display: inline-block; + border: 1px solid #ccc; + box-sizing: border-box; +} + +/* Set a style for all buttons */ +.login button { + background-color: #4CAF50; + color: white; + padding: 14px 20px; + margin: 8px 0; + border: none; + cursor: pointer; + width: 100%; +} + +.login .instructions { + padding-left: 1em; +} + +/* Add a hover effect for buttons */ +.login button:hover { + opacity: 0.8; +} + +/* Add padding to containers */ +.login .container { + padding: 16px; + padding-bottom: 32px; +} + +/* The "Forgot password" text */ +.login span.psw { + float: right; +} + + /* The Modal (background) */ +.login.modal { + position: fixed; /* Stay in place */ + z-index: 1; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ + padding-top: 60px; +} + +.survey.modal { + position: fixed; /* Stay in place */ + z-index: 1; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ + padding-top: 60px; +} + +.survey .instructions { + width: 80%; + margin: 1em auto 1em auto; + background: #eef; + font-style: italic; + text-align: center; +} +.surveyresponse { + display: block; + width: 80%; + margin: 1em auto 1em auto; + background: #efe; + padding: 0.5em; +} +.surveyresponse + .surveyresponse { + background: #ffe; +} + +/* Modal Content/Box */ +.survey .modal-content, +.login .modal-content { + background-color: #fefefe; + margin: 5px auto; /* 15% from the top and centered */ + border: 1px solid #888; + width: 50%; /* Could be more or less, depending on screen size */ +} + +/* The Close Button */ +.login .close { + /* Position it in the top right corner outside of the modal */ + position: absolute; + right: 25px; + top: 0; + color: #000; + font-size: 35px; + font-weight: bold; +} + +/* Close button on hover */ +.login .close:hover, +.login .close:focus { + color: red; + cursor: pointer; +} + +/* Add Zoom Animation */ +.login .animate { + animation: animatezoom 0.6s +} + +.login-link { + position: absolute; + right: 10px; + top: 10px; + cursor: pointer; +} +.login-link > * { + visibility: hidden; +} +.login-link:hover > * { + visibility: visible; + background-color: #fcc; +} +.login-link .logout { + visibility: visible; + background-color: #fcc; +} + +.dontlogout { + float: right; + font-size: 80%; + cursor: pointer; +} + +.dontlogout:hover { + background-color: #fdd; +} + +/* + * + * reading questions + * + */ + +.rq_answer .given_answer { + background: #ffd; +} + +#rq_submit { + padding: 3px 5px; + border-radius: 0.5em; +} +#rq_submit.submitted { + background: #EFE; + color: #BBB; +} + +.addcontent, .action, .submit { + cursor: pointer; +} + +.addcontent:hover, .action:hover { + background: #eff; +} + +/* +.action + .action { + margin-left: 0.25em; + display: block; +} +.action + .amhelp { + margin-left: 0.25em; + display: block; +} +*/ + +.input_controls { + font-family: sans-serif; + font-weight: lighter; + font-size: 90%; + background: #fff; + padding-left: 0; + padding-bottom: 0; + margin-top: 0; +/* + margin-bottom: -1.6em; + display: inline; +*/ + position: absolute; +} +.rq_answer_text { + display: inline; +} +textarea { + border-width: 0.1em; + margin-bottom: 0.3em; +} +.input_controls .action { + border: 1px solid #aaa; + display: inline; + /* border-radius: 3px; +*/ + padding: 1px 2px; +} +.input_controls .action.amhelp { + margin-left: 21.9em; +} +.clear_item:hover { + background: #fdd; +} + +.save_item:hover, .edit_item:hover { + background: #dfd; +} + +.hidecontrols { + display: none; +} + +.readingquestion_make_answer.instructor { + margin-left:1em; + font-size:80%; + color:#a0a; +} +.readingquestion_make_answer.student { + display: block; + margin-left: 10%; + margin-right: 11%; + width: 75%; + height: 63px; + border: 1px solid #999; + color: #999; +} + +.given_answer { + font-family: monospace; + font-family: "Lucida Console", Monaco, monospace; + white-space: pre-wrap; + margin-top: 0.5em; + margin-bottom: -0.5em; + min-height: 2.72em; +} +textarea.rq_answer_text { + font-family: "Lucida Console", Monaco, monospace; + resize: vertical; + font-size: inherit; +} +.compiled_answers { + border: 0.7em solid #dfd; + border-top: 0.35em; + margin-top: 1em; +} +.s_id { + font-size: 80%; + padding-top: 0.4em; + padding-left: 0.5em; + display: inline; +} +.rq_sub_time { + font-size: 70%; + padding-top: 0.5em; + padding-right: 0.5em; + float: right; + display: inline; +} +.s_ans { + font-family: "Lucida Console", Monaco, monospace; + white-space: pre-wrap; + width: 480px; + margin-left: 3em; + padding-bottom: 0.5em; +} +.noanswer .s_ans { + font-style: italic; + font-size: 80%; + margin-left: 4em; +} +.one_answer:nth-of-type(odd) { + background: #dfd; +} + +/* + * + * highlights + * + */ + +#hlmenu { + z-index: 1000; +} +#hlmenu *:hover { + cursor: pointer; +} + +span.hl { background: yellow; } +#hlmenu { position: absolute; top: 300px; left: 200px;} +#hlmenu { padding: 8px; background: #FFF; } +#hlmenu { box-shadow: 8px 10px 5px #888; border: 1px solid #aaa;} +#hlmenu .hldelete { background: #fdd; } +#hlmenu .hldelete:hover { background: #fbb; } +#hlmenu .hlcopy { background: #ddf; } +#hlmenu .hlcopy:hover { background: #bbf; } +#hlmenu .dismiss:hover { background: #ff9; } +#hlmenu > div { padding: 4px; font-size: 90%} diff --git a/_static/pretext/css/kindle.css b/_static/pretext/css/kindle.css new file mode 100644 index 0000000..9c17864 --- /dev/null +++ b/_static/pretext/css/kindle.css @@ -0,0 +1,103 @@ + +.ptx-content.epub img { + display: block; +} +.ptx-content.epub .solutions { + margin-top: 1em; +} + +.ptx-content.epub .solutions .solution .type, +.ptx-content.epub .solutions .answer .type { + font-family: "PT Serif", "Times New Roman", Times, serif; + font-weight: bold; +} +.ptx-content.epub .solutions .solution .type + .period, +.ptx-content.epub .solutions .answer .type + .period { + margin-right: 0.75em; +} +.ptx-content.epub .solutions .solution .type + p, +.ptx-content.epub .solutions .answer .type + p { + display: inline; +} + +/* default behavior is excessive space below display math. */ +/* should the selector be .mjpage__block? */ +.ptx-content .mjpage + p { + margin-top: -0.5em !important; +} +.ptx-content .mjpage { + margin-bottom: 0 !important; +} +/* align inline math baseline */ +.ptx-content .mjpage { + vertical-align: -.68ex; +} + +.ptx-content .solution-like > .type { + font-weight: bold; +} +.ptx-content .solution-like .type + p { + display: inline; +} + +/* Greg's L was a line too long */ +.ptx-content article.theorem-like::after, +.ptx-content article.definition-like::after, +.ptx-content article.example-like::after, +.ptx-content article.project-like::after, +.ptx-content article.remark-like::after, +.ptx-content article.computation-like::after { + margin-top: -1em; +} + +.ptx-content .mjpage { + vertical-align: -.68ex; +} + +.ptx-content section { + padding-top: 0 !important; +} +.ptx-content .subsection { + margin-top: 1.5em !important; +} + +/* sage cell code goes in a pre. What else goes there? */ +.ptx-content pre { + font-size: 95%; + padding-top: 0.3em; + padding-bottom: 0.5em; + padding-left: 0.5em; + background: #f0f0f0; +} +.ptx-content pre.code.input { + background: #f0f0ff; +} +.ptx-content pre.code.output { + background: #f0fff0; +} + + +/* these "break-(before/after) might not actually do anything */ +.ptx-content section article > .heading, +.ptx-content section > .heading { + display: block; + margin-top: 0; + break-after: avoid !important; +} +.ptx-content section > .heading + p, +.ptx-content section article > .heading + p, +.ptx-content section article > .heading + .introduction { + display: block; + break-before: avoid !important; +} +.ptx-content figcaption { + break-before: avoid !important; +} +.ptx-content figure .image-box, +.ptx-content figure .tabular-box { + break-after: avoid !important; +} +.ptx-content figure { + break-inside: avoid !important; +} + diff --git a/_static/pretext/css/knowls_default.css b/_static/pretext/css/knowls_default.css new file mode 100644 index 0000000..dd7d528 --- /dev/null +++ b/_static/pretext/css/knowls_default.css @@ -0,0 +1,230 @@ +/* + main knowls style +*/ + +[data-knowl] { + display: inline; + position: relative; + cursor: pointer; + color: #9c2310; + padding: 0px 2px 0px 2px; + margin: 0; + text-decoration: none; + margin-bottom: 1px; +/* + margin-bottom: 0; +*/ + font-weight: 500; + white-space: nowrap; + border-bottom: none; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + transition-property: background-color; + transition-duration: 0ms; +} +table [data-knowl] { + white-space: pre-line; +} + +[data-knowl]:hover, [data-knowl]:active, [data-knowl].active { + color: #8a1200; + background: #ffedeb; +/* + margin-bottom: 0; +*/ + border-bottom: none; +} + +[data-knowl]::after, [data-knowl]:hover::after, [data-knowl].active::after { + content: ""; + position: absolute; + top: 0; + bottom: 1px; + right: 2.4px; + left: 2.4px; + border-bottom: 1px dotted #9c2310; + transition-property: left, right; + transition-duration: 0ms; + z-index: 0; +} +/* is the next only for a proof or other content that is only a knowl? */ +article > [data-knowl]::after, article > [data-knowl]:hover::after, article > [data-knowl].active::after, + section > details > summary > .heading, article + details > summary > .heading { + content: ""; + position: absolute; + top: 0; + bottom: 1px; + right: 8.4px; + right: 0.6em; + left: 2.4px; + border-bottom: 1px dotted #9c2310; + transition-property: left, right; + transition-duration: 0ms; + z-index: 0; +} + +[data-knowl].fn-knowl { + padding-left: 0; + padding-right: 0; + margin-right: 2px; +} +[data-knowl].fn-knowl::after { + bottom: 7px; +} + +.knowl-error { + color: red; + border-bottom: 0; +} +.knowl-output { + background: #f5f5ff; + border: 10px solid #ddf; + border-radius: 10px; + padding: 0; + margin-top: 10px; + scroll-margin-top: 60px; /* height of header */ +} + +.knowl-output.original { + background: #f8f8f8; + border: none; +/* border-left: 1px solid #666; +*/ + border-radius: 0; + padding: 0; + margin-top: 10px; +} +.knowl-output.original .knowl-content { + padding-top: 0; + padding-bottom: 0; + margin-bottom: 0; +} +/* +.knowl-output.original:after { + content: ''; + display: block; + padding-top: 0.35em; +} +*/ +.example-like .knowl-output.original { + background: inherit; +} + +.knowl-output--hide { + display: none; +} + +.knowl-output__error .para:first-child { + margin-top: 0; +} + +.knowl-output__error a { + text-decoration: underline; +} + +.knowl-output .knowl-output { + border-width: 6px; + background: #fffff5; + border-radius: 4px; + margin-bottom: -3px; + margin-left: -7px; + margin-right: -7px; +} +.knowl-output .knowl-output .knowl-output { + background: #fff5ff; +} +.knowl-output .knowl-output .knowl-output .knowl-output { + background: #fafffa; +} +.knowl-footer { + position: relative; + bottom: -9px; + font-size: x-small; + background: #ddf; + color: grey; + padding: 0 0 0 12px; + margin: -10px 0 0 0; +} +.knowl-footer a { + color: #006; +} +.knowl-footer a:hover { + background: none; + color: #88f; +} +/* .knowl-footer:after { + content: "\2002"; +} */ + +.knowl-output .knowl-output .knowl-footer { + bottom: -5px; + margin: -5px 0 0 0; +} + +.knowl-output + .knowl-output { + margin-top: 0; +} +.knowl-output + .knowl-output.original { + margin-top: 0.5em; +} +.knowl-content { + padding: 10px; + padding-bottom: 7px; +} +.knowl-content > *:first-child { + margin-top: 0; +} + +/* sort of a hack for proof knows in theorem knowls */ +.ptx-content div.knowl .posterior a[data-knowl]:first-child { + padding: 0; +} + +/* not sure where this was being used, but it made short knowls + * look bad, like the hint here: + * SAFurtherReading.html +*/ +.ptx-content .knowl-output .knowl-content > *:last-child:not(.incontext) { + margin-bottom: 0.5em; +} + +/* No Greg's L in knowls, to save space */ + +.ptx-content .knowl-content > article.theorem-like, +.ptx-content .knowl-content > article.definition-like, +.ptx-content .knowl-content > article.example-like, +.ptx-content .knowl-content > article.project-like, +.ptx-content .knowl-content > article.objectives, +.ptx-content .knowl-content > article.outcomes, +.ptx-content .knowl-content > article.remark-like { + padding-left: 0; + border-left: none; +} +.ptx-content .knowl-content > article.theorem-like::after, +.ptx-content .knowl-content > article.definition-like::after, +.ptx-content .knowl-content > article.example-like::after, +.ptx-content .knowl-content > article.project-like::after, +.ptx-content .knowl-content > article.objectives::after, +.ptx-content .knowl-content > article.outcomes::after, +.ptx-content .knowl-content > article.remark-like::after { + content: ''; + border-bottom: none; + margin: 0; + padding: 0; + width: 0; +} + +/* sup knowls are used for footnotes */ +/* the next 2 are obsolete, because (in PTX HTML) the structure is now a(sup), not sup(a) */ +sup [data-knowl] { + padding: 0px 0px 0px 3px; +} + +sup .active[data-knowl] { + padding: 0px 0px 0px 3px; +} + +sup [data-knowl]:hover { + padding: 0px 0px 0px 3px; +} + diff --git a/_static/pretext/css/navbar_crc.css b/_static/pretext/css/navbar_crc.css new file mode 100644 index 0000000..71618dd --- /dev/null +++ b/_static/pretext/css/navbar_crc.css @@ -0,0 +1,358 @@ + +/* Since CRC loads after default, we need to suppress some of the default styling */ + +.ptx-navbar .treebuttons .next-button, .ptx-navbar .treebuttons .up-button, +.ptx-navbar .treebuttons .previous-button { + float: unset; +} + +.ptx-navbar .previous-button, .ptx-navbar .up-button, .ptx-navbar .next-button, +.ptx-navbar .index-button, .ptx-navbar .calculator-toggle, .ptx-navbar .toc-toggle { + width: unset; +} + +.ptx-navbar .calculator-toggle { + margin-left: unset; + margin-right: unset; +} + +.ptx-navbar .index-button .name { + padding-top: unset; +} + + +/* Generic and large screen layout */ +.ptx-navbar .toc-toggle, .ptx-navbar .index-button, .ptx-navbar .searchbox +{ +} + +.ptx-navbar .nav-other-controls +{ + margin-left: 1em; +} + +.ptx-navbar .treebuttons { + display: flex; + justify-content: right; +} + +.ptx-navbar .button { + padding: 0 10px 0 10px; +} + +.ptx-navbar .treebuttons .button { + display: flex; + justify-content: center; + align-items: center; +} + +.ptx-navbar .treebuttons .previous-button { padding-left: 0px; } +.ptx-navbar .treebuttons .next-button { padding-right: 0px; } + +.ptx-navbar .nav-runestone-controls { + display: flex; +} + + +nav.ptx-navbar { + display: grid; + grid-column-gap: 0em; + + grid-template-columns: auto auto auto 1fr 1fr auto; + grid-template-areas: + "MH-toc-area MH-extras-area1 ptx-searchbox MH-extras-area2 MH-page-navigation-area MH-preferences-area"; + background-color: #fff; +/* + padding: 20px 0px 0px 0px; +*/ + align-items: start; + + border: 2px solid #ddd; + border-top: none; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + z-index: 20; + + position: sticky; + top: 0; + align-items: end; + min-height: unset; /* to thwart navbar.less */ + margin-bottom: 0; /* to thwart navbar.less */ +} +nav.ptx-navbar::before, +nav.ptx-navbar::after { + content: none; /* to thwart clearfix.less */ +} + + +/* TOC button may be sized differently */ +.toc-toggle { + display: inline-block; + height: 32px; + color: #333; + font-family: inherit; + text-align: center; + font-size: .8em; /*11px; */ + font-weight: 600; + line-height: 32px; + letter-spacing: .1rem; + text-transform: uppercase; + text-decoration: none; + white-space: nowrap; + background-color: #eee; + border-radius: 4px; + border: 1px solid #888; + cursor: pointer; + box-sizing: border-box; + margin-right: 2em; +} + +.toc-toggle:hover { + background-color: #fafafa; + color: black; + +} + + +/* .ptx-MH-toc-area */ +.toc-toggle { + grid-area: MH-toc-area; + justify-self: start; +/* + align-self: start; +*/ +} + +/* .ptx-MH-extras-area */ +.index-button { + grid-area: MH-extras-area1; + justify-self: right; +} +.calculator-toggle { + grid-area: MH-extras-area2; + justify-self: left; +} +.user-preferences-button { + justify-self: left; +} + +/* .ptx-page-navigation-area */ +.treebuttons { + grid-area: MH-page-navigation-area; + justify-self: end; + display: flex; + width: 100%; +/* + align-self: start; +*/ +} + +.nav-runestone-controls { + grid-area: MH-preferences-area; + justify-self: end; + display: flex; + padding-left: 4em; +} + +/* .ptx-navbar button, */ +.ptx-navbar .button { + display: inline-block; + height: 32px; + color: var(--bodytitle); + font-family: inherit; + text-align: center; + font-size: .8em; + font-weight: 600; + line-height: 32px; + letter-spacing: .1rem; + text-transform: uppercase; + text-decoration: none; + white-space: nowrap; + background-color: #eee; + border-radius: 4px; + border: 1px solid #888; + cursor: pointer; + box-sizing: border-box; +} + +.ptx-navbar .searchbutton { + display: flex; + align-items: center; + justify-content: center; +} + +.searchresultsplaceholder { + left: calc(50vw - 300px); +} + + +/* Small screen layout */ +@media only screen and (max-width: 800px) { + .pretext .ptx-navbar { + position: fixed; + top: auto; + bottom: 0; + left: 0; + right: 0; + padding: 0; + background: #ededed; + grid-template-columns: auto auto auto auto 1fr auto; +/* + box-shadow: rgba(0, 0, 0, 0.3) 0px -2px 5px; +*/ + /* height: 44.2px; */ + + align-items: end; + } + + /* .pretext .ptx-navbar .button { + width: 24.95%; + height: 36px; + line-height: 40px; + margin: 0; + } + .ptx-navbar .toc-toggle { + width: 25%; + margin: 0; + } */ + + .ptx-navbar .toc-toggle { + padding: 0 40px; + } + + .ptx-navbar .nav-runestone-controls { + padding-left: 0; + } + + .ptx-navbar .treebuttons { + justify-content: center; + } + + .ptx-navbar :is(.toc-toggle, .previous-button, .up-button, .next-button, .calculator-toggle, .index-button) .name { + display: none; + } + + .pretext .ptx-navbar :is(.calculator-toggle, .index-button) .icon { + display: inline-block; + } + + .searchresultsplaceholder { + left: 10vw; + } +} + +.ptx-navbar .button:hover { + background-color: #fafafa; + color: #888; +} + +.ptx-navbar .button:focus { + outline: thin dotted #333; + outline-offset: -2px; +} + +.ptx-navbar .button:active { + background-color: #e0e0e0; +} + + +.ptx-navbar .button.disabled { + opacity: .4; + color: #333333; + background: #ededed; + cursor: default; + box-shadow: none; +} +.ptx-navbar .toc-toggle .icon { + font-size: 1.5em; + position: relative; + bottom: -0.1em; + padding-left: 0; + padding-right: 0.4em; +} +.ptx-navbar .toc-toggle .name { + font-size: 1.0em; +} + +.ptx-navbar .index-button .name { + /* Nada */ +} +.ptx-navbar .index-button .icon { + display: none; +} + +.ptx-navbar .calculator-toggle .name { + /* Nada */ +} +.ptx-navbar .calculator-toggle .icon { + display: none; +} + +.ptx-navbar .runestone-profile .name { + display: none; +} + +.ptx-navbar .activecode-toggle .name { + display: none; +} + +.pretext .ptx-navbar .dropdown { + height: 32px; +} + +.ptx-navbar .up-button { + text-align: center; +} + +.ptx-navbar .name { + display: inline-block; +} +.ptx-navbar .searchbutton .name { + display: none; + position: relative; + bottom: 0; +} + +.ptx-navbar .icon { + display: inline-block; + font-size: 1.5em; +} +.ptx-navbar .previous-button .icon { + margin-left: 0.3em; + margin-right: 0.2em; +} +.ptx-navbar .up-button .icon { + margin-left: 0; + margin-right: 0.2em; +} +.ptx-navbar .next-button .icon { + margin-left: 0.2em; + margin-right: 0.3em; +} +.ptx-navbar .user-preferences-button { + padding: 0 0.8em 0 0.8em; + margin-left: 2em; + border: 1px solid #bababa; + width: 6em; +} + +@media screen and (max-width: 800px) { + .ptx-navbar .toc-toggle .name, + .ptx-navbar .previous-button .name, + .ptx-navbar .up-button .name, + .ptx-navbar .up-button .disabled .name, + .ptx-navbar .next-button .name { + display: none; + } + + .ptx-navbar .toc-toggle { + margin: 0; + } + + .ptx-navbar .calculator-toggle .icon { + padding-top: 5px; + } +} + diff --git a/_static/pretext/css/navbar_default.css b/_static/pretext/css/navbar_default.css new file mode 100644 index 0000000..6dd8c1e --- /dev/null +++ b/_static/pretext/css/navbar_default.css @@ -0,0 +1,194 @@ +/******************************************************************************* + * Navbar Stylesheet + ******************************************************************************* + * + * Authors: David Farmer, Rob Beezer + * + ******************************************************************************* + */ + +nav.ptx-navbar { + background: #ededed; + border: 0; + border-top: 1px solid #bababa; + border-bottom: 1px solid #bababa; + margin: 0; + z-index: 100; + font-family: "Open Sans"; + overflow: visible; + display: flex; +} + +.ptx-navbar .button { + font-size: 1.0em; + display: flex; + justify-content: center; + align-items: center; + padding: 0 10px; + gap: 10px; + min-height: 34px; + + color: #333333; + background-color: #ededed; + border: 0; + border-right: 1px solid #bababa; + + /* Disable accidental text-selection */ + user-select: none; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.ptx-navbar .button:focus { + outline: thin dotted #333; + outline-offset: -2px; +} + +.ptx-navbar .button:active { + box-shadow: rgba(0, 0, 0, 0.5) 0 2px 5px inset; +} + +.ptx-navbar .button:hover { + background-color: #fafafa; +} + +.ptx-navbar .button:active { + background-color: #e0e0e0; +} + +.ptx-navbar .button.disabled { + opacity: .4; + color: #333333; + background: #ededed; + box-shadow: none; +} + +.ptx-navbar .toc-toggle { + width: 240px; + gap: 0.4em; +} + +.ptx-navbar .button .icon { + font-size: 1.5em; +} + +.ptx-navbar :is(.treebuttons, .nav-runestone-controls) { + display: flex; +} + +.ptx-navbar .treebuttons { + flex: 1 1 210px; + justify-content: end; +} + +.ptx-navbar .nav-runestone-controls { + flex: 1 1 70px; + justify-content: end; +} + +.pretext .navbar .dropdown { + height: 34px; +} + + +.ptx-navbar :is(.treebuttons, .nav-runestone-controls) > *:first-child { + border-left: 1px solid #bababa; +} + + +.ptx-navbar .treebuttons > * { + display: flex; + align-items: center; + justify-content: center; + min-width: 75px; +} + +.ptx-navbar .treebuttons .icon { + margin: 0 -7px; /* chevrons have lots of horizontal padding */ +} + +.ptx-navbar :is(.index-button, .calculator-toggle) .icon { + display: none; +} +.ptx-navbar :is(.runestone-profile, .activecode-toggle, .searchbutton) .name { + display: none; +} + +.ptx-navbar .index-button { + width: 70px; +} + +.ptx-navbar .calculator-toggle { + width: 60px; + min-height: 32px; + text-align: center; + border-radius: 20px; + margin-left: 5px; + border: 2px solid #66f; + line-height: 25px; + margin-top: 1px; + background-color: #eef; +} + +.ptx-navbar .calculator-toggle.open { + background: #fee; + border: 2px solid #f66; +} + +@media screen and (max-width: 800px) { + .ptx-navbar { + position: fixed; + top: auto; + bottom: 0; + left: 0; + right: 0; + background: #ededed; + box-shadow: rgba(0, 0, 0, 0.3) 0px -2px 5px; + } + + .ptx-navbar .nav-runestone-controls { + flex: 0; + } + .ptx-navbar .toc-toggle { + flex: 2 1 100px; + } + .ptx-navbar .treebuttons { + flex: 3 1 150px; /* 3:2 ratio with toc-toggle */ + } + .ptx-navbar .treebuttons > * { + flex: 1 1; + min-width: 35px + } + .ptx-navbar .index-button { + display: none; + } + + .ptx-navbar :is(.treebuttons) > *:first-child { + border-left: 0; + } + + .ptx-navbar :is(.toc-toggle, .previous-button, .up-button, .next-button, .calculator-toggle, .index-button) .name { + display: none; + } + + .pretext .ptx-navbar :is(.calculator-toggle, .index-button) .icon { + display: inline-block; + } + + .ptx-navbar .nav-runestone-controls > *:first-child { + border-left: 0 + } + + .ptx-navbar .calculator-toggle { + width: auto; + height: 35px; + border-radius: 0; + margin-left: 0; + border: 0; + border-right: 1px solid #bababa; + line-height: inherit; + margin-top: 0; + background-color: inherit; + } +} \ No newline at end of file diff --git a/_static/pretext/css/navbar_wide.css b/_static/pretext/css/navbar_wide.css new file mode 100644 index 0000000..6229935 --- /dev/null +++ b/_static/pretext/css/navbar_wide.css @@ -0,0 +1,39 @@ +@import url("navbar_default.css"); + + +:root { + --nav-background-color: #ededed; +} + +.pretext .ptx-navbar { + max-width: 100%; + margin: 0 auto; + display: flex; + width: var(--page-width); + background: var(--nav-background-color); + border-top: 0; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); +} + +.pretext .ptx-navbar .toc-toggle { + border-left: 0; +} + +.ptx-navbar .calculator-toggle { + width: auto; + height: 35px; + text-align: center; + border-radius: 0; + margin-left: 0; + border: 0; + border-right: 1px solid #bababa; + line-height: inherit; + margin-top: 0; + background-color: #ededed; + padding: 0 15px; +} + + +.ptx-navbar > :last-child > :last-child { + border-right: none; +} \ No newline at end of file diff --git a/_static/pretext/css/pretext.css b/_static/pretext/css/pretext.css new file mode 100644 index 0000000..dc38010 --- /dev/null +++ b/_static/pretext/css/pretext.css @@ -0,0 +1,1151 @@ +/******************************************************************************* + * pretext.css handles structure which (should be) common to all styles + ******************************************************************************* + * + * Authors: David Farmer, Rob Beezer + * + ******************************************************************************* + */ + +@import url("https://fonts.googleapis.com/css?family=PT+Serif:400,700,400italic,700italic|Open+Sans:400italic,700italic,400,700"); + +* { + box-sizing: border-box; +} + +body.pretext { + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; +} +body.pretext[data-font="OS"] { + font-family: "Open Sans", sans-serif; +} +body.pretext[data-font="RS"] { + font-family: "Roboto Serif", serif; +} +body.pretext, +body.standalone { + margin: 0; + padding: 0; + font-size: 16px; +} + +body.pretext { background: #fff; } + +a { + color: inherit; + text-decoration: none; +} +a:hover, +a:focus { + text-decoration: none; +} + + +body.pretext > a.assistive { + padding:6px; + position: absolute; + top:-40px; + left:0px; + color:white; + border-right:1px solid white; + border-bottom:1px solid white; + border-bottom-right-radius:8px; + background:transparent; + z-index: 10000; +} + +body.pretext > a.assistive:focus { + top:0px; + background:#BF1722; + outline:0; + transition: top .1s ease-in, background .5s linear; +} + +/* over-write bootstrap (in Runestone, for example) */ +nav .ptx-navbar { + border-top: none; + border-right: none; + border-left: none; + min-height: unset; +} + +/* next for the Activecode popup */ +/* +.modal-backdrop.fade.in { + display: none; +} +*/ +.ptx-navbar .activecode-toggle { + padding: 3px 5px; +} + +/* Runestone nav for Runestone-wide features */ +.pretext #brand-navbar, +.pretext .brand-navbar { + left: 0; + position: fixed; + right: 0; + z-index: 1030; + height: 50px; + border-width: 0 0 1px; + top: 0; + margin-bottom: 0; +} +.pretext #brand-navbar > .container::before, +.pretext .brand-navbar > .container::before, +.pretext #brand-navbar > .container::after, +.pretext .brand-navbar > .container::after { + display: none; +} +.pretext #brand-navbar + .ptx-masthead, +.pretext .brand-navbar + .ptx-masthead { + margin-top: 50px; +} +.pretext #brand-navbar .navbar-collapse.collapse, +.pretext .brand-navbar .navbar-collapse.collapse { + overflow: hidden !important; +} +.pretext #brand-navbar ~ .ptx-navbar, +.pretext .brand-navbar ~ .ptx-navbar { + top: 50px; +} +@media screen and (max-width: 800px) { + .pretext #brand-navbar ~ .ptx-navbar, + .pretext .brand-navbar ~ .ptx-navbar { + top: auto; + } +} + +/* so that we can position things (like .autopermalink) absolutely wrt these items */ +.ptx-content section, +.ptx-content article, +.ptx-content figure, +.ptx-content figcaption, +.ptx-content .exercisegroup, +.ptx-content .discussion-like, +.ptx-content .para { + position: relative; +} + +/* we use .para as a wrapper around some "compound" p, so the + first p in .para is block-like because of the .pare */ +.ptx-content .para > p:first-child, +.ptx-content .para > .para:first-child { + display: inline; +} + +/* Oscar Levin figured out the cause of chrome showing a funny border focus */ +.ptx-content .knowl .para { + position: unset; +} + +/* CSS defult values: +https://www.w3schools.com/cssref/css_default_values.asp +*/ + +/* the default margin for pre is "1em 0", so we over-ride +so that we can set our own later */ +.ptx-content pre { + margin: 0; + padding: 0; + border: none; +} +/* these are to over-ride "pre" styling in code.less */ +.ptx-content pre { + border-radius: 0; +} + +.ptx-content textarea { + padding: 0; +} + +/* .para and other block-level elements should have space at the top, and not the bottom */ +.ptx-content h1, .ptx-content h2, .ptx-content h3, .ptx-content h4, .ptx-content h5, .ptx-content h6 { + margin: 0; + font-size: unset; +} +.pretext h1, .pretext h2, .pretext h3, .pretext h4, .pretext h5, .pretext h6 { + margin: 0; + font-size: unset; +} + +.ptx-content .heading { + line-height: 1.1; +} + +/* spacing around and after .para, and around and after article */ +.ptx-content .para { + margin-top: 1.25em; + margin-bottom: 0; + line-height: 1.35; +} +.ptx-content .para.continuation { + margin-top: 0; +} +.ptx-content pre + .para.continuation, +.ptx-content pre + form, +.ptx-content div + form { + margin-top: 1em; +} +.ptx-content ul + .para.continuation, +.ptx-content ol + .para.continuation, +.ptx-content dl + .para.continuation { + margin-top: 0.75em; +} + +.ptx-content .aside-like > .para:first-child, +.ptx-content td > .para:first-child, +.ptx-content .solution-like > .para:first-child { + margin-top: 0; +} +/* for assemblages without a title */ +.ptx-content .assemblage-like > .para:first-of-type { + margin-top: 0; +} +.ptx-content .assemblage-like > .heading + .para { + margin-top: 0.25em; +} +.ptx-content .assemblage-like + .para { + margin-top: 1.75em; +} + +.ptx-content .para.intertext { + margin-top: -0.25em; + text-indent: 0; +} + +.ptx-content .para + table { + margin-top: 1em; +} + +.ptx-content table tr td .para + .para { + margin-top: 1em; +} + +.ptx-content table + .para { + margin-top: 1.5em; +} + +.ptx-content .para + figure.figure-like > table { + margin-top: 1em; +} + +/* 1.25 = ol top + li top ? looked too big with 0.75 below */ +.ptx-content .exercise-like .para + ol { + margin-top: 0.5em; +} + +.ptx-content .para + pre.prettyprint, +.ptx-content .para + pre.plainprint { + margin-top: 1.25em; +} +.ptx-content .para + .code-box { + margin-top: 1.25em; +} +.ptx-content .code-box > .console { + margin-left: 1.5em; +} + +.ptx-content .exercisegroup { + padding-top: 1.25em; + margin-bottom: 1.0em; +} +.ptx-content section .exercisegroup > .heading { + font-size: 1.10em; + line-height: 1.05em; + margin-top: 0.75em; + display: inline; +} +.ptx-content section .exercisegroup > .heading + .introduction { + display: inline; +} +.ptx-content section .exercisegroup > .heading + .introduction > .para:first-child { + display: inline; +} + +.ptx-content .exercisegroup article.exercise-like .solution .para:first-child { + margin-top: -3px; /* because of the 10px (instread of 7) on the .knowl-content */ +} +.ptx-content .exercisegroup article.exercise-like li > .para:first-child { + margin-top: 0; +} + +.ptx-content .exercisegroup article.exercise-like .heading { + margin: 0; +} +.ptx-content article.exercise-like .task > .heading + .heading { + font-weight: 600; /* should be slightly less bold, but some browsers make it bold */ +} +.ptx-content article.exercise-like .task > .heading + .heading + .para, +.ptx-content article.exercise-like .task > .heading + .heading + div { + display: block; + margin-top: 0; +} +.ptx-content .exercisegroup .conclusion .heading { + margin-top: 0.5em; +} +.ptx-content .exercisegroup .hidden-knowl-wrapper { + margin: 0; +} +.ptx-content .exercisegroup article + article { + margin-top: 1em; +} + +/* http://spot.pcc.edu/math/APEXCalculus/sec_interp_deriv.html */ +.ptx-content .exercisegroup > article, +.ptx-content .exercisegroup-exercises > article { + margin-left: 2em; +} +.ptx-content .exercisegroup .cols2 > article { + margin-left: 1.25em; +} +.ptx-content .exercisegroup > .introduction, +.ptx-content .exercisegroup > .conclusion { + margin-left: 0; +} +.ptx-content .exercisegroup > .introduction { + margin-top: 1.25em; + margin-top: 0; +} +.ptx-content .exercisegroup > .introduction > .para:first-child::before { + content: '\25a0\2009'; + /* font-size: 70%; */ + color: #06a; + position: relative; + top: -1px; + right: 1px; +} +.ptx-content .exercisegroup > .heading + .introduction > .para:first-child::before { + content: '\2003'; +} + +.ptx-content .exercisegroup > .introduction > .para:first-child { + margin-top: 0; +} + +.ptx-content .exercisegroup article + .hidden-knowl-wrapper { + margin-left: 4em; +} + +/* make it look like a list, and have entra indenting when already more indented */ +.ptx-content .exercise-like .introduction + .hidden-knowl-wrapper, +.ptx-content .exercise-like .conclusion { + margin-left: 1.0em; +} +.ptx-content .exercisegroup .exercise-like .introduction + .hidden-knowl-wrapper, +.ptx-content .exercisegroup .exercise-like .conclusion { + margin-left: 1.5em; +} +.ptx-content section > .hidden-knowl-wrapper { + margin-top: 1em; +} +.ptx-content article + .hidden-knowl-wrapper { + margin-top: 1em; +} +.ptx-content .knowl-content > section:first-child > .heading:first-child { + margin-top: 0; +} + + + +/* 9/23/23 a knowled article is now in a "details", so we add style + to mimic the old style below */ + +.ptx-content section .born-hidden-knowl > summary { + cursor: pointer; +} + +.ptx-content section > .born-hidden-knowl > summary::marker, +.ptx-content article + .born-hidden-knowl > summary::marker { + content: ""; +} + +.ptx-content section > .born-hidden-knowl , .ptx-content .paragraphs > .born-hidden-knowl , +.ptx-content article + .born-hidden-knowl { + margin-top: 1.25em; +} +.ptx-content .born-hidden-knowl summary + article { + margin-top: 1em; +} +.ptx-content section .born-hidden-knowl + .born-hidden-knowl , +.ptx-content section .introduction + .born-hidden-knowl , +.ptx-content section .para + .born-hidden-knowl , +.ptx-content section .posterior + .born-hidden-knowl { + margin-top: 1.75em; +} + +.ptx-content .born-hidden-knowl > article { + padding-top: 0.25em; +} +.ptx-content .born-hidden-knowl > article:not(.theorem-like):not(.definition-like) { + padding: 0.25em; + padding-left: 0.5em; + padding-bottom: 0; +} +.ptx-content .born-hidden-knowl > article { + background-color: #f5f5ff; +} +.ptx-content .born-hidden-knowl > article .born-hidden-knowl > article, +.ptx-content .born-hidden-knowl > article .born-hidden-knowl > .answer { + margin: 0.5em; + padding: 0.25em; + padding-left: 0.5em; + background-color: #fffff5; +} +.ptx-content .born-hidden-knowl > article .born-hidden-knowl > article .born-hidden-knowl > article { + background-color: #fff5ff; +} +.ptx-content .born-hidden-knowl > article .born-hidden-knowl > article .born-hidden-knowl > article .born-hidden-knowl > article { + background-color: #fafffa; +} + +/* this > may be too restrictive. The purpose is to not put a + top margin on an article at the top of a knowl */ +.ptx-content section > article, .ptx-content section > section.paragraphs, .ptx-content .paragraphs > article { + margin-top: 1.25em; +} +.ptx-content section article + article, +.ptx-content section .introduction + article, +.ptx-content section .para + article, +.ptx-content section .posterior + article { + margin-top: 1.75em; +} +.ptx-content section article > .introduction + article { + margin-top: 1em; +} + +.ptx-content section article > .discussion-like { + margin-top: 1em; +} +.ptx-content section article > .discussion-like .para { + margin-top: 1em; +} + +.ptx-content article + .posterior { + margin-top: 0.5em; +} +.ptx-content section .para + .tabular-box { + margin-top: 0.75em; +} +.ptx-content section .tabular-box + .tabular-box { + margin-top: 1.0em; +} +.ptx-content section .proof { + margin-top: 0.75em; +} + +.ptx-content section > pre, .ptx-content .para + pre { + margin-top: 1.25em; +} + +.ptx-content ol .para + .para, .ptx-content ul .para + .para { + margin-top: 1em; +} + +/* see Ex 29 https://yoshiwarabooks.org/linear-functions.html +and ex 2.91 in +https://yoshiwarabooks.org/mfg/MathModels.html */ +.ptx-content .introduction + .sidebyside, +.ptx-content .para + .sidebyside, +.ptx-content ol + .sidebyside, +.ptx-content ul + .sidebyside { + margin-top: 1em; +} + +.ptx-content section .heading, +.ptx-content article .heading { + font-family: "PT Serif", "Times New Roman", Times, serif; + font-weight: 700; + color: inherit; +} +.ptx-content article .exercise-stage { + font-family: "PT Serif", "Times New Roman", Times, serif; + font-weight: 700; + color: inherit; + font-size: 100%; + margin-top: 0.4em; +} + +.ptx-content article > .heading + .para { + margin-top: 0; +} +.ptx-content section .heading + .para, +.ptx-content section .title + .para, /* list items have bare .title, not in a .heading */ +.ptx-content section .heading + .introduction > .para:first-child, +.ptx-content section .blob > .para:first-child { + margin-top: 0.25em; +} +.ptx-content section .heading + article { /* , .ptx-content section header + article { */ + margin-top: 1em; +} +.ptx-content section .heading + .sidebyside { + margin-top: 1em; +} + +.ptx-content a > .heading { display: inline;} + +.ptx-content section > .heading { + font-size: 1.75em; + line-height: 1.25em; + margin-top: 1em; + margin-bottom: 0.35em; +} +.ptx-content section section > .heading { + font-size: 1.5em; + line-height: 1.25em; + margin-bottom: 0; +} +.ptx-content .paragraphs > .heading { + font-size: 1.125em; + line-height: 1.125em; + display: inline; +} +/* +.ptx-content .paragraphs .heading { + display: inline; +} +*/ + +.ptx-content .paragraphs .heading + .para { + display: inline; +} +.ptx-content .para.logical > .para:first-child { + display: inline; +} + +/* next is for runestone multiple choice */ +.ptx-content .runestone label > .para { + display: inline; +} +/* the next are to avoid stlping a .para as inline, because + * inline styling messes up the meaning of line-height. + * */ + +.ptx-content .paragraphs .para .title { + font-family: "PT Serif", "Times New Roman", Times, serif; + font-size: 1.125em; + font-weight: 700; +} + +.ptx-content .paragraphs > .heading { + margin-top: 0; +} + +.ptx-content .paragraphs + .paragraphs { + margin-top: 3em; +} + +.ptx-content article .paragraphs > .heading { + font-size: 1.05em; +} +.ptx-content section section section > .heading { + font-size: 1.40em; + line-height: 1.15em; + margin-top: 0.75em; +} +@media screen and (max-width: 480px) { + .ptx-content section > .heading { + font-size: 1.5em; + line-height: 1.33em; + margin-top: 1em; + } + .ptx-content section section > .heading { + font-size: 1.3em; + line-height: 1.15em; + } + .ptx-content section section section > .heading { + font-size: 1.15em; + line-height: 1em; + } +} + +.ptx-content .abstract { + margin: 4em 2em; +} +.ptx-content .abstract > .title { + font-size: 1.125em; + font-weight: 600; + line-height: 1.125em; + display: inline; +} +.ptx-content .abstract > .title::after { + content: ".\2009\2009\2009"; +} +.ptx-content .abstract > .title + .para { + display: inline; +} + +/* born hidden articls are now in "details", so adding markup +to immitate what is below. */ + +.ptx-content .born-hidden-knowl summary, +.ptx-content .born-hidden-knowl summary > .heading { + position: relative; +} + +.ptx-content .born-hidden-knowl summary > .heading { + font-size: 1.125em; + line-height: 1.125em; + margin-top: 0; + display: inline; +} + + +/* ----- */ + + +.ptx-content article > .heading, +.ptx-content article > a .heading { + font-size: 1.125em; + line-height: 1.125em; + margin-top: 0; + display: inline; +} +.ptx-content .discussion-like > .heading { + font-size: 1.0em; + line-height: 1.125em; + margin-top: 0; + display: inline; +} +.ptx-content .discussion-like.discussion > .heading .codenumber, +.ptx-content .discussion-like.discussion > .heading .space, +.ptx-content .discussion-like.discussion > .heading .period { + display: none; +} +.ptx-content .discussion-like.discussion > .heading .type::after { + content: ". "; +} +.ptx-content .discussion-like.status > .heading { + display: none; +} +.ptx-content .discussion-like.status > .heading + .para, +.ptx-content .discussion-like.status > .para { + font-style: italic; + display: block; + padding-left: 1em; +} + + +.ptx-content article > .heading::after, +.ptx-content .discussion-like > .heading::after, +.ptx-content .paragraphs > .heading::after, +.ptx-content article > a > .heading::after { + content: "\2009"; +} +/* Currently only for Solution to example */ +.ptx-content .posterior .heading { + font-weight: normal; + font-size: 1.125em; + line-height: 1.125em; + margin-top: 0; +} + +/* + * Contents of articles + */ +.ptx-content article > .heading + .para, +.ptx-content .discussion-like > .heading + .para, +.ptx-content article > .heading + .introduction, +.ptx-content article > .heading + .introduction > .para:first-child { + display: inline; +} +/* when a list is the only thing in an environment with a border, + there is too much space to the left */ +.ptx-content article > .heading + ol, +.ptx-content article > .heading + ul { + padding-left: 1.5em; +} +.ptx-content article.theorem-like .para, +.ptx-content article.theorem-like li { + font-style: italic; +} +.ptx-content article.theorem-like .emphasis { + font-weight: 700; +} + +.ptx-content ol, .ptx-content ul { + margin-bottom: 0; +} +.ptx-content li { + margin-bottom: 0; +} +.ptx-content li .title { + font-size: 100%; + font-weight: normal; + font-style: italic; +} +.ptx-content article.theorem-like li .title { + font-weight: 600; + font-style: normal; + font-size: 96%; +} + +.ptx-content figure { + margin-bottom: 0; +} + +.ptx-content .heading { + margin-top: 0; + margin-bottom: 0; +} + +.ptx-content .conclusion { + margin-top: 1em; +} +.ptx-content .conclusion > .para:first-child { + margin-top: 0.5em; +} + +.ptx-content ol, .ptx-content ul { + margin-top: 0.75em; +} +.ptx-content .exercise-like > ol:first-child, +.ptx-content .exercise-like > ul:first-child { + margin-top: 0; +} +.ptx-content .heading + ol, .ptx-content .heading + ul { + margin-top: 0.45em; +} +.ptx-content li > .heading + ol, .ptx-content li > .heading + ul { + margin-top: 0.25em; +} +.ptx-content li > .heading + ol > li:nth-child(1), +.ptx-content li > .heading + ul > li:nth-child(1) { + margin-top: 0; +} +.ptx-content li > .heading + ol.cols2 > li:nth-child(2), +.ptx-content li > .heading + ul.cols2 > li:nth-child(2) { + margin-top: 0; +} + +.ptx-content li { + margin-top: 0.5em; +} +.ptx-content li > .para:first-child { + margin-top: 0; +} +.ptx-content article .para:first-child { + margin-top: 0; +} + +.ptx-content ol ol, .ptx-content ol ul, .ptx-content ul ol, .ptx-content ul ul { + margin-top: 0.5em; +} + +.ptx-content .frontmatter > .heading { + display: block; + text-align: center; +} +.ptx-content .frontmatter > .heading .title, .ptx-content .book > .heading .title { + font-size: 1.3em; +} +.ptx-content .frontmatter > .heading .subtitle, .ptx-content .book > .heading .subtitle { + display: block; + font-weight: normal; + color: #666666; + font-size: 0.875em; + line-height: 1.42857em; + margin-top: 0.35714em; +} + +.ptx-content .frontmatter .author:first-of-type { + margin-top: 4em; +} +.ptx-content .frontmatter > .para:first-of-type { + margin-top: 4em; +} +.ptx-content .frontmatter > .author, +.ptx-content .frontmatter > .credit { + margin-top: 2em; + text-align: center; +} +.ptx-content .frontmatter > .author .author-name { + font-size: 120%; +} +.ptx-content .frontmatter .date { + display: block; + margin-top: 2em; + text-align: center; +} +.ptx-content .frontmatter .credit .title { + font-size: 1em; +} +.ptx-content .frontmatter .credit .author { + font-size: 0.9em; + margin-top: 0.75em; +} +.ptx-content .frontmatter .author-info { + font-size: 90%; +} +.ptx-content a[href^="mailto:"] { + white-space: pre; +} + +button { + font: inherit; +} + +.print-button { + position: relative; + right: 2px; + top: 66px; + background-color: LightGreen; + z-index: 1; + margin-top: -4em; + float: right; +} + +@media print { + .pretext .ptx-masthead, + .pretext .ptx-navbar, + body.pretext > a.assistive, + .pretext .ptx-page > .ptx-sidebar, + .pretext .ptx-page-footer, + .pretext .ptx-main > div.ptx-content-footer { + display:none; + border:none; + } + .pretext .ptx-page main.ptx-main { + margin-left:0; + left:auto; + border:none; + box-shadow:none; + padding: 0; + } + .pretext .ptx-page .ptx-main .ptx-content { margin-top:0 } + .pretext .ptx-page .ptx-main .ptx-content.ptx-content section { margin-top:1em } + .pretext .ptx-page .ptx-main .ptx-content.ptx-content section .heading { margin-top:0 } + + /* over-ride print.less */ + .pretext a[href]::after { + content: ""; + } + + /* don't print the print-button */ + .print-button { + display: none; + } +} + +/* printing for one-page worksheets */ + +@media print { + body.standalone.worksheet .ptx-page > .ptx-main .ptx-content { + width: 820px; + max-width: 820px; + font-size: 12.5px; + } + body.standalone.worksheet { + margin: 0; + } + body.standalone .ptx-content section.worksheet { + border: none; + } + body.standalone.worksheet .ptx-masthead, + body.standalone.worksheet .ptx-page-footer { + display: none; + } + + body.standalone.worksheet.has-sidebar-left.mathbook-loaded .ptx-page .ptx-main { + margin: 0; + } + + body.standalone.worksheet .ptx-page > .ptx-main .ptx-content { + margin: 0; + } + body.standalone.worksheet .ptx-content section.onepage { + max-height: 100%; + max-width: 100%; + overflow: hidden; + page-break-after: always; +/* + height: 1243px; +*/ + border: none; + page-break-inside: avoid; + } + body.standalone.worksheet .ptx-content .onepage.lastpage { + margin-bottom: -2em; /* to avoid blank space overflow causing an extra blank page */ + page-break-after: auto; + } + body.standalone.worksheet.a4 .ptx-content .onepage { +/* + height: 1320px; +*/ + } + body.standalone.worksheet .ptx-content .onepage div.workspace, + body.standalone.worksheet .ptx-content .onepage div.workspace.squashed.tight { + border: none; + padding: 0; + background: none !important; + } + body.standalone.worksheet a { + color: black; + } + + body.standalone.worksheet .ptx-page .ptx-main { + padding: 0; + } + + body.standalone.worksheet.mathbook-loaded .ptx-page .ptx-main .ptx-content.ptx-content section.onepage { + padding-bottom: 20px; /* to help prevent flow onto the next page, particularly in Safari */ + /* the page is not full length, but what is missing was blank anyway */ +/* + margin: 0; +*/ + } + + @page { margin: 0 } +} + +.hidden { + display: none; +} + +.ptx-navbar .preferences_menu_holder .active > li { + color: #ddd; +} +.ptx-navbar .preferences_menu_holder > ol > li:focus { + background: #eef; + border: 2px solid #909; + padding: 2px 24px 2px 8px; +} +.ptx-navbar .preferences_menu_holder > ol > li > ol > li:focus { + background: #eef; + border: 2px solid #909; + padding: 4px 4px 2px 4px; +} + +.ptx-navbar .preferences_menu_holder .active .selected { + background: #eef; + color: #111; +} +.ptx-navbar .button.user-preferences-button { + overflow: visible; + display: none; +} +.preferences_menu_holder { + z-index: 30; + background: #fee; + color: #222; + position: absolute; + left: -11em; + top: 4em; +} +.preferences_menu_holder ol { + list-style-type: none; + padding: 0; + margin: 0; +} +.preferences_menu_holder > ol { + width: 12.5em; +} +.preferences_menu_holder > ol > li { + padding: 4px 26px 4px 10px; +} +.preferences_menu_holder ol li ol { + z-index: 40; + position: absolute; + left: 13em; + top: -2em; + background: #fee; +} +.preferences_menu_holder ol li ol li { + padding: 6px 6px 4px 6px; + display: flex; + align-items: center; +} +.preferences_menu_holder ol.fonts:not(.hidden) { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; +} +.preferences_menu_holder ol.fonts li:nth-child(8n+1), +.preferences_menu_holder ol.fonts li:nth-child(8n+2), +.preferences_menu_holder ol.fonts li:nth-child(8n+3), +.preferences_menu_holder ol.fonts li:nth-child(8n+4) { + background-color: #eff; +} +.preferences_menu_holder ol.fonts li:nth-child(4n+2) { + width: 4em; + justify-content: center; + text-align: center; + align-items: center; +} +.preferences_menu_holder ol.fonts li:nth-child(4n+1) { + padding-left: 14px; +} + +.preferences_menu_holder .wrap_to_submenu { + float: right; + line-height: 0.95em; + margin-right: -7px; +} +.preferences_menu_holder .to_submenu { + position: absolute; +} +.preferences_menu_holder .avatars li { + font-size: 200%; + text-align: center; +} +.preferences_menu_holder .fontfamily .name { + margin-right: 2em; +} +.preferences_menu_holder .fontfamily .sample { + margin-left: auto; +} +.preferences_menu_holder .fonts .byunits { + font-size: 80%; + margin-bottom: -0.3em; +} +#choose_topic { + background: #eef; +} +.ffcheck, +.atmospherecheck, +.avatarcheck, +.rulercheck, +.motioncheck { + width: 1em; + margin-left: 0.2em; + margin-right: 0.7em; + font-size: 11pt; +} + +.preferences_menu_holder .moveQ { + padding-top: 0.5em; + border-top: 0.3em solid #eef; +} +.preferences_menu_holder .moveQ, +.preferences_menu_holder .moveQ ~ li { + background: #efe; +} + +[data-ruler="greybar"] .onelineX:hover{ + padding-top: 2px; + margin-top: -2px; + padding-bottom: 2px; + margin-bottom: -2px; + background-color: #f3f3f3; +} +[data-atmosphere*="dark"][data-ruler="greybar"] .onelineX:hover{ + color: #333; +} +[data-ruler="lightbox"] .onelineX { + background-color: #e3e3e3; +} +[data-ruler="lightbox"] .onelineX:hover{ + padding-top: 2px; + margin-top: -2px; + padding-bottom: 2px; + margin-bottom: -2px; + background-color: inherit; +} +[data-ruler="sunrise"] .onelineX:hover ~ .onelineX { + background-color: #e3e3e3; +} +[data-ruler="sunrise"] .para:hover ~ * .onelineX { + background-color: #e3e3e3; +} +[data-ruler="sunrise"] section:hover ~ * .onelineX { + background-color: #e3e3e3; +} + +[data-ruler="sunriseunderline"] .onelineX:hover{ + background-color: inherit; + border-bottom: 2px solid black; + margin-bottom: -2px; + position: relative; + z-index: 10; +} +xxxxxx[data-ruler="sunriseunderline"] .onelineX:hover + .onelineX { + margin-top: -2px; +} +[data-ruler="sunriseunderline"] .onelineX:hover ~ .onelineX { + background-color: #e3e3e3; +} +[data-ruler="sunriseunderline"] .para:hover ~ * .onelineX { + background-color: #e3e3e3; +} +[data-ruler="sunriseunderline"] section:hover ~ * .onelineX { + background-color: #e3e3e3; +} + + +[data-ruler="underline"] .onelineX:hover{ + background-color: inherit; + border-bottom: 1px solid black; + margin-bottom: -1px; +} +[data-ruler="lunderline"] .onelineX:hover{ + background-color: inherit; + border-bottom: 1px solid black; + border-left: 1px solid black; + padding-left: 4px; + margin-left: -5px; + margin-bottom: -1px; +} +[data-atmosphere*="dark"][data-ruler*="underline"] .onelineX:hover{ + border-bottom: 1.5px solid #ddd; + margin-bottom: -1.5px; +} +[data-atmosphere*="dark"][data-ruler="lunderline"] .onelineX:hover{ + border-left: 1.5px solid #ddd; + padding-left: 3.5px; + margin-left: -5px; +} + + +.material-symbols-outlined { + font-variation-settings: + 'FILL' 0, + 'wght' 400, + 'GRAD' 0, + 'opsz' 24 +} + +.ptx-footnote { + display: inline; +} + +.ptx-footnote[open] { + display: contents; +} + +.ptx-footnote[open] .ptx-footnote__number { + visibility: hidden; +} +.ptx-footnote[open] .ptx-footnote__number::before { + font-size: 0.6rem; + content: "[x]"; + visibility: visible; + vertical-align: super; +} + +.ptx-footnote__number { + display: inline; + cursor: pointer; +} + +.ptx-footnote__number::marker { + content: ""; +} + +.ptx-footnote__contents { + display: block; + font-style: italic; + background: var(--knowlbackground); + border-radius: 6px; + padding: 0px 8px; + margin: 4px auto; + width: fit-content; + max-width: calc(100% - 60px); + border: 2px solid var(--knowlborder); +} + + +/******************************************************************************* + * + * Authors: David Farmer, Rob Beezer + * + ******************************************************************************* + */ diff --git a/_static/pretext/css/pretext_add_on.css b/_static/pretext/css/pretext_add_on.css new file mode 100644 index 0000000..9a08c89 --- /dev/null +++ b/_static/pretext/css/pretext_add_on.css @@ -0,0 +1,3178 @@ + +.ptx-content section .para.credit + .para.credit { + margin-top: 0.25em; +} +.ptx-content section .para.credit > .title { + font-weight: 700; + margin-right: 0.5em; +} +/* .ptx-content section .para.credit > .title::after { + content: ": "; +} */ + +.ptx-content section .para.copyright { + margin-top: 2.5em; +} +.ptx-content section .para.license { + margin-top: 2.5em; +} + +/* stacked headings in the solutions backmatter */ +.ptx-content section > .heading + .heading, +.ptx-content section section > .heading + .heading { + margin-top: 0.5em; +} +.ptx-content section.solutions > h3.heading, +.ptx-content section.solutions section > h3.heading { + font-size: 1.6em; +} +.ptx-content section.solutions > h4.heading, +.ptx-content section.solutions section > h4.heading { + font-size: 1.45em; +} +.ptx-content section.solutions > h5.heading, +.ptx-content section.solutions section > h5.heading { + font-size: 1.35em; +} +.ptx-content section.solutions > h6.heading, +.ptx-content section.solutions section > h6.heading { + font-size: 1.25em; +} + +.ptx-content .bibitem + .bibentry { + display: inline-block; + width: 90%; +} +.ptx-content .bibitem { + display: inline-block; + vertical-align: top; + width: 7%; + margin-right: 0; +} + +.ptx-content figcaption { + font-weight: normal; +} + +.ptx-content figcaption { + margin-top: 0.6em; + margin-left: auto; + margin-right: auto; +/* Commenting this out because the initial letter of some captions were cut off + text-indent: -30px; +*/ +} + +.ptx-content figure.table-like figcaption:first-child { + font-style: oblique; + margin-top: 0; +} +.ptx-content figure.table-like figcaption:first-child .type, +.ptx-content figure.table-like figcaption:first-child .codenumber { + font-style: normal; +} + +.ptx-content section figcaption .codenumber, +.ptx-content section figcaption .type { + font-weight: 700; + font-size: inherit; +} + +.ptx-content figcaption .codenumber:after { + content: "\2002"; +} +.ptx-content figcaption .type:last-of-type::after { + /* so, not followed by a span.codenumber */ + /* not sure where this is used */ + content: "\2002"; +} + +.ptx-content figcaption code.code-inline { + white-space: pre; +} + +.ptx-content figure > figcaption:first-child { + margin-top: 1.5em; +} + +.ptx-content figcaption + .named-list-content { + margin-top: 0.6em; +} +.ptx-content figcaption + .named-list-content > .introduction > .para:first-child { + margin-top: 0; +} +.ptx-content figcaption + table, +.ptx-content figcaption + .tabular-box { + margin-top: 0.5em; +} + +.ptx-content .definition-like .para > .emphasis { + font-weight: 700; +} +.ptx-content em.alert { + font-weight: bold; +} + +.unprocessed { + padding: 8px; + background-color: rgb(255,230,230) +} + +.unprocessed .unprocessed { + margin: 8px; + background-color: rgb(255,200,255) +} + +.unprocessed .unprocessed .unprocessed { + margin: 8px; + background-color: rgb(205,205,255) +} + +.ptx-content section.introduction + section { + margin-top: 2em; +} + +.ptx-content { + margin: 0; +} + +.ptx-content .runestone.parsons_section { + display: inline-block; + max-width: unset; +} + +.ptx-content .runestone.ac_section { + width: 60em; + max-width: unset; +} +.ptx-content .runestone.ac_section .ac_section { + max-width: unset; +} +.ptx-content .runestone.ac_section > div { + max-width: unset; +} + +.ptx-content .runestone > .parsons { + width: 60em; + max-width: unset; +} + +.ptx-content .runestone .parsons { + margin: 0; +} +.ptx-content .runestone.parsons_section > .parsons { + width: max-content; + padding-right: 1em; +} +.ptx-content .runestone .parsons .sortable-code-container { + text-align: unset; +} +.ptx-content .runestone .parsons .parsons-text, +.ptx-content .runestone .parsons .parsons-controls { + margin-left: 0; + margin-right: 0; +} +.ptx-content .runestone .parsons .sortable-code + .sortable-code { + margin-right: 0; +} + +.ptx-content .runestone .parsons .runestone_caption_text { + max-width: 660px; +} + +.runestonebustmenu { + position: absolute; + right: 0; + top: 0; +} +.runestonebustmenu .dropdown-content { + position: absolute; + right: 2em; + left: unset; + top: 1em; +} +@media screen and (max-width: 800px) { +/* + .runestonebustmenu { display: none } +*/ + nav .dropdown .dropdown-content { + top: unset; + bottom: 36px; + } + + .activecode-toggle { display: none } +} +/* above may be obsolete because we do not have the runestonebustmenu class in overhaul? +*/ +.pretext .navbar .dropdown { + height: 35px; +} + +.ptx-content section section + section { + margin-top: 3em; +} + + +.ptx-content .sidebyside > .para, .ptx-content .sidebyside > figure, .ptx-content .sidebyside > img, .ptx-content .sidebyside > table, .ptx-content .sidebyside > tabular, .ptx-content .sidebyside > section, .ptx-content .sidebyside > .paragraphs { + display: inline-block; + margin: 0; +} +.ptx-content .sidebyside .sbspanel > table { +/* see Sec 23.12 of sample article */ + overflow-x: auto; + margin-left: auto; + margin-right: auto; +} + +.ptx-content .sidebyside figcaption { + padding-left: 1em; + padding-right: 0; + padding-bottom: 0; + margin: 0.75em 0 0 0; +} + + +.ptx-content figcaption { + font-family: "PT Serif", "Times New Roman", Times, serif; +} + +.ptx-content .sidebyside > .para { /* what about sbspanel? */ + width: 32%; + vertical-align: top; +} + +.ptx-content .sidebyside > .para.left, .ptx-content .sidebyside > .para.middle, .ptx-content .sidebyside > .para.right { + vertical-align: middle; +} + +.ptx-content .sidebyside > .para + img { + vertical-align: middle; +} + +.ptx-content .sidebyside .sbsrow .sbsheader { + margin-top: 0; +} + +.ptx-content .sbsgroup { + width: 100%; +} + +.ptx-content .sidebyside { + width: 100%; +} + +.ptx-content .sbsrow { + display: flex; + justify-content: space-between; +} + +/* Components of three types of "sbsrow" */ + +/* titles, totally centered text */ +.ptx-content .sbsheader { + text-align: center; + justify-content: center; + font-size: 1em; +} + +.ptx-content .sbspanel:empty { /* can only happen when partially created */ + height: 10em; + background-color: rgb(221, 221, 255); +} +/* containers of desired width for actual content */ +.ptx-content .sbspanel { + display: flex; + flex-direction: column; + justify-content: flex-start; +} +.ptx-content .sbspanel.top { /* also the default */ + justify-content: flex-start; +} +.ptx-content .sbspanel.middle { + justify-content: center; /* should that be space-between? */ +} +.ptx-content .sbspanel.bottom { + justify-content: flex-end; +} + +.ptx-content .sbspanel > .para:first-child { + margin-top: 0; +} + +/* fixed-width items are centered horizontally in their panel */ +/* always used in conjunction with sbspanel */ +.ptx-content .fixed-width { + align-items: center; +} + +/* captions, centered until word-wrapped */ +.ptx-content .sbscaption { + justify-content: center; +} + + +/* good for table, bad for image +.ptx-content .sidebyside { + overflow-x: scroll; +} +*/ + +.ptx-content table { + border-spacing: 0; +} + +.ptx-content table { + border-collapse: collapse; +} + +.ptx-content .image-box + table, +.ptx-content .image-box + .sidebyside > .sbsrow:first-child > .sbspanel > table:first-child { + margin-top: 1.5em; +} + +.ptx-content table tr td, +.ptx-content table tr th { + padding-top: 2px; + padding-bottom: 2px; + padding-left: 5px; + padding-right: 5px; +} +.ptx-content table tr td { + font-size: 90%; +} + +.ptx-content table tr td.l { + text-align: left; +} +.ptx-content table tr td.c { + text-align: center; +} +.ptx-content table tr td.r { + text-align: right; +} +.ptx-content table tr td.j { + text-align: justify; +} +.ptx-content table tr td.lines { + white-space: nowrap; +} + + +.ptx-content table tr td.t { + vertical-align: top; +} +.ptx-content table tr td.b { + vertical-align: bottom; +} +.ptx-content table tr td.m { + vertical-align: middle; +} + +.ptx-content table tr td.vv { + border-left: 2px solid #000; + border-right: 2px solid #000; +} + +.ptx-content table tr td.vcv { + border-left: 2px solid #000; + border-right: 2px solid #000; + text-align: center; +} + +.ptx-content table tr td.vcvv { + border-left: 2px solid #000; + border-right: 4px solid #000; + text-align: center; +} + +.ptx-content table tr td.vlv { + border-left: 2px solid #000; + border-right: 2px solid #000; + text-align: left; +} + +.ptx-content table tr td.vrv { + border-left: 2px solid #000; + border-right: 2px solid #000; + text-align: right; +} + +.ptx-content table tr td.rv { + border-right: 2px solid #000; + text-align: right; +} + +.ptx-content table tr td.vr { + border-left: 2px solid #000; + text-align: right; +} + +.ptx-content table tr td.lv { + border-right: 2px solid #000; + text-align: left; +} + +.ptx-content table tr td.vl { + border-left: 2px solid #000; + text-align: left; +} +.ptx-content table tr td.cv { + border-right: 2px solid #000; + text-align: center; +} + +.ptx-content table tr td.Xv { + border-right: 2px solid #000; + text-align: left; +} + +.ptx-content table tr td.vc { + border-left: 2px solid #000; + text-align: center; +} + +.ptx-content table tr td.hline { + padding: 0; +} + +.ptx-content table tr td.hlinethick { + + padding-left: 0px; + padding-right: 0px; + +} + +.ptx-content table tr td.hline hr { + + margin-top:0; + margin-bottom:0; + margin-left: -1px; + margin-right: -1px; + border: 1px solid rgb(0,0,0); + +} + +.ptx-content table tr td.hlinethick hr { + + margin-top:0; + margin-bottom:0; + margin-left: -1px; + margin-right: -1px; + border: 2px solid rgb(0,0,0); + +} + +.center table { + text-align: center; + margin-left: auto; + margin-right: auto; +} + +.ptx-content table tr th.b1, +.ptx-content table tr td.b1 { + border-bottom: 1px solid #000; +} +.ptx-content table tr th.b2, +.ptx-content table tr td.b2 { + border-bottom: 2px solid #000; +} +.ptx-content table tr th.b3, +.ptx-content table tr td.b3 { + border-bottom: 3px solid #000; +} +.ptx-content table tr th.b0, +.ptx-content table tr td.b0 { + border-bottom: none; +} + +.ptx-content table tr th.t1, +.ptx-content table tr td.t1 { + border-top: 1px solid #000; +} +.ptx-content table tr th.t2, +.ptx-content table tr td.t2 { + border-top: 2px solid #000; +} +.ptx-content table tr th.t3, +.ptx-content table tr td.t3 { + border-top: 3px solid #000; +} +.ptx-content table tr th.t0, +.ptx-content table tr td.t0 { + border-top: none; +} + +.ptx-content table tr th.r1, +.ptx-content table tr td.r1 { + border-right: 1px solid #000; +} +.ptx-content table tr th.r2, +.ptx-content table tr td.r2 { + border-right: 2px solid #000; +} +.ptx-content table tr th.r3, +.ptx-content table tr td.r3 { + border-right: 3px solid #000; +} +.ptx-content table tr th.r0, +.ptx-content table tr td.r0 { + border-right: none; +} + +.ptx-content table tr th.l1, +.ptx-content table tr td.l1 { + border-left: 1px solid #000; +} +.ptx-content table tr th.l2, +.ptx-content table tr td.l2 { + border-left: 2px solid #000; +} +.ptx-content table tr th.l3, +.ptx-content table tr td.l3 { + border-left: 3px solid #000; +} +.ptx-content table tr th.l0, +.ptx-content table tr td.l0 { + border-left: none; +} + +.ptx-content table tr td img { + max-width: 200px; + margin-right: 30px; +} + +.ptx-content table.notation-list tr th { + text-align: left; +} +.ptx-content table.notation-list tr td { + text-align:left; + vertical-align:top; +} +.ptx-content table.notation-list tr th { + margin-left: 2em; +} +.ptx-content table.notation-list tr td { + margin-left: 1em; +} + +.ptx-content tr th.r0.l0, +.ptx-content tr td.r0.l0 { + padding-left: 0.8em; + padding-right: 0.8em; +} + +.ptx-content table tr td span.decimal { + float: left; + text-align: right; +} + +.ptx-content table tr.header-vertical th { + writing-mode: vertical-rl; + padding-left: 2em; +/* + transform: rotate(180deg); +*/ +} + +.ptx-content table + article { + margin-top: 1em; +} + +.ptx-content .hidden-knowl-wrapper .hiddenproof, +.ptx-content .blob > article.hiddenproof, +.ptx-content section > article.hiddenproof { + margin-top: 0.3em; +} + +.ptx-content .hidden-knowl-wrapper article { + display: inline; +} + +/* next disabled accidentally or on purpose? */ +.apretext-content figure.figure-like { + overflow: auto; +} +.ptx-content figure.figure-like { + margin-left: 0; + margin-right: 0; +} +.ptx-content figure.table-like { + margin-left: 30px; + margin-right: 30px; +} +.ptx-content figure.table-like.list { + margin-right: 0; +} + +/* why was this ever added ? +.ptx-content figure.figure-like figcaption { + overflow: hidden; +} +*/ + +.ptx-content a > tt { + font-size: 110%; +} + +.ptx-content section .videolink a:link { + background-size: 0; +} +.ptx-content .playvideo { + cursor: pointer; +} + +.ptx-content .videobig { + padding-right: 0.3em; + padding-left: 0.3em; + font-size: 85%; +/* background: #ffff66; +*/ + background-color: rgba(255,255,100,0.9); + display: inline-block; + position: relative; + top: 100px; + cursor: zoom-in; +} +.ptx-content .videobig.nofigure { + /* not actually used */ +} +.ptx-content .knowl .videobig { + display: none; +} + +.ptx-content .videosmall { + padding-right: 0.3em; + padding-left: 0.3em; + font-size: 80%; + background-color: rgba(255,255,100,0.9); + display: inline-block; + position: absolute; + left: -250px; + z-index: 1001; + cursor: zoom-out; +} + + +.ptx-content .exercise-like ol li table { + margin-bottom: 0.5em; +} + +.ptx-content .exercise-like > ol li + li { + margin-top: 0.5em; +} +.ptx-content .solution > ol li + li { + margin-top: 0.5em; +} + +/* should be the default +.ptx-content section.worksheet > .heading, +.ptx-content section section.worksheet > .heading, +.ptx-content section section section.worksheet > .heading { + display: block; +} +*/ +.ptx-content section.worksheet > .heading > .codenumber { + display: inline-block; + vertical-align: top; +} +.ptx-content section.worksheet > .heading > .title { + display: inline-block; + max-width: 70%; +} +.ptx-content .heading .print-links { + display: inline-block; + float: right; + vertical-align: top; + width: 19%; + text-align: right; +} +.standalone .ptx-content .heading .print-links { + display: none; +} +.standalone.worksheet .previous-button, +.standalone.worksheet .up-button, +.standalone.worksheet .next-button { + display: none; +} +.standalone.worksheet .ptx-navbar .toc-toggle { + display: none; +} +.standalone.worksheet .ptx-content [data-knowl]:hover, +.standalone.worksheet .ptx-content [data-knowl]:active, +.standalone.worksheet .ptx-content [data-knowl].active { + background: none; + color: black; +} +.standalone.worksheet .ptx-content [data-knowl]::after { + border: none; +} +.standalone.worksheet .ptx-content .knowl-content { + padding: 0; +} +.standalone.worksheet .ptx-content article > .knowl-output.original { + margin: 0; +} + +.ptx-content .appendix .heading > .type { + display: inline; +} +.ptx-content .heading.hide-type > .type { + display: none; +} + +.ptx-content .heading .print-links > a { + font-family: "Open Sans"; + font-size: 0.6em; + font-weight: bold; + padding: 0.1em 0.2em; + background: #ffa; + border: 2px solid green; +} +.ptx-content .heading .print-links > a.us { + background: #eef; + color: #9b1c2c; + border-color: #041E42; +} +.ptx-content .heading .print-links > a + a { + margin-left: 0.25em; +} + +.ptx-content .autopermalink { + position: absolute; + display: inline-block; + top: 3px; + left: -1.9em; + font-size: 85%; + color: #a00; + opacity: 0.05; + margin-top: 0.1em; +} + +.ptx-content li > .para > .autopermalink { + left: -3.4em; + top: 0; +} +.ptx-content .autopermalink a { + color: #a00; +} +.ptx-content .autopermalink > * { + padding-left: 0.2em; + padding-right: 0.2em; +} +/* when jumping to a permalink, push down so sticky navbar does not cover */ +:target { + /* scroll-snap-margin-top: 45px; for safari, except it doesn't work */ + scroll-margin-top: 45px; +} + +.ptx-content .para > .autopermalink { + margin-top: 0.2em; +} + +.ptx-content .exercises > .autopermalink, +.ptx-content .introduction > .autopermalink, +.ptx-content .glossary > .autopermalink { + margin-top: 0.3em; +/* + margin-top: 1em; +*/ +} +.ptx-content .appendix > .autopermalink, +.ptx-content .chapter > .autopermalink, +.ptx-content .index > .autopermalink, +.ptx-content .section > .autopermalink { + margin-top: 0.3em; +/* + margin-top: 2.7em; +*/ +} +.ptx-content .subsection > .autopermalink, +.ptx-content .references > .autopermalink, +.ptx-content .exercises > .autopermalink { + margin-top: 0.3em; +/* + margin-top: 2.0em; +*/ +} +.ptx-content .figure-like > .autopermalink { + margin-top: 1.4em; +} + +.ptx-content .subsubsection > .autopermalink { + margin-top: 0; +} +.ptx-content .exercisegroup > .autopermalink { +/* + margin-top: 0.3em; +*/ + margin-top: 1.4em; +} + +.ptx-content .autopermalink:hover { + opacity: 1; + background: #eeddff; +} +.ptx-content .permalink-alert { + position: absolute; + top: -3em; + left: 5em; + padding: 1.5em 2em; + background: #fff; + border: 3px solid blue; + z-index: 2001; +} + +.navbar .indexnav { + position: absolute; + top: 46px; + right: 0; +} +.mininav { + float: left; + padding-top: 0.7ex; + padding-left: 1ex; +} + +/* the index at the back of the book */ + +.indexjump { + margin-left: 1.5ex; + margin-top: 0.2ex; + padding-top: 0; + float: left; + line-height: 0.95; +} + +.indexjump a { + padding-left: 2.5px; + padding-right: 0.5px; + width: 2.5ex; +/* + * * omitted, because we put a space in the source + * padding-right: 3px; + * */ + margin-right: -1px; + color: inherit; + font-size: 80%; + text-align: center; +} +.indexjump a::after{ + content: ""; + display: inline-block; +} +.indexjump a:nth-of-type(14){ + padding-left: 1.8ex; +} +.indexjump a:last-child { + padding-right: 10px; +} + +.indexjump a:hover { + background: #eeaaff; +} + +.ptx-content .indexitem { + margin-top: 2px; +} + +.ptx-content .subindexitem { + margin-left: 2em; + font-size: 95%; + margin-top: -1px; +} + +.ptx-content .subsubindexitem { + margin-left: 3.5em; + font-size: 95%; + margin-top: -1px; +} + +.ptx-content .indexknowl { + margin-left: 0.11em; +} +.ptx-content em + .indexknowl { + margin-left: -0.25em; +} +.ptx-content .indexknowl a { + margin-left: 2em; +} + +.ptx-content .indexitem .see, +.ptx-content .subindexitem .see, +.ptx-content .subsubindexitem .see { + margin-left: 1em; + margin-right: 0; +} +.ptx-content .indexitem .seealso, +.ptx-content .subindexitem .seealso, +.ptx-content .subsubindexitem .seealso { + margin-left: 1em; + margin-right: 0; +} +.ptx-content .indexitem .see em, +.ptx-content .subindexitem .see em, +.ptx-content .subsubindexitem .see em, +.ptx-content .indexitem .seealso em, +.ptx-content .subindexitem .seealso em, +.ptx-content .subsubindexitem .seealso em { + margin-right: 0.25em; + font-style: italic; +} +/* note that multiple things after "see" are in separate spans */ +.ptx-content .indexitem .see + .see, +.ptx-content .subindexitem .see + .see, +.ptx-content .subsubindexitem .see + .see, +.ptx-content .indexitem .seealso + .seealso, +.ptx-content .subindexitem .seealso + .seealso, +.ptx-content .subsubindexitem .seealso + .seealso { + margin-left: 0; + margin-right: 0; +} + +.ptx-content .indexitem .indexknowl { + font-size: 90%; +} + +.ptx-content .indexitem [data-knowl], .ptx-content .subindexitem [data-knowl], .ptx-content .indexitem [data-knowl]:hover { + padding-right: 2px; + padding-left: 2px; +} +.ptx-content .indexknowl [data-knowl]:hover, .ptx-content .indexknowl .active[data-knowl] { + margin-left: 2em; +} + +.ptx-content .subindexitem .indexknowl { + font-size: 95%; +} +.ptx-content .subsubindexitem .indexknowl { + font-size: 95%; +} + +.ptx-content .indexletter { + margin-top: 1.5em; +} + +/* end index */ + +.ptx-content .hidden-knowl-wrapper .heading { + display: inline; +} +.ptx-content .heading + .hidden-knowl-wrapper { + display: inline; +} + +.ptx-content .cols2 .knowl-output, .ptx-content .cols3 .knowl-output, .ptx-content .cols4 .knowl-output, .ptx-content .cols5 .knowl-output, .ptx-content .cols5 .knowl-output { + width: 100%; +} + +.ptx-content .cols2 + *, .ptx-content .cols3 + *, .ptx-content .cols4 + *, .ptx-content .cols5 + *, .ptx-content .cols6 + * { + clear: both; +} +/* does the next line eliminate the need for the previous line? */ +.ptx-content .cols2::after, .ptx-content .cols3::after, .ptx-content .cols4::after, .ptx-content .cols5::after, .ptx-content .cols6::after { + content: ""; + display: block; + clear: both; +} + +.ptx-content section > ol:last-child, +.ptx-content section > ul:last-child { + margin-bottom: 1.5em; +} +/* because of */ +/* .ptx-content .colsN > li:last-child { + padding-bottom: 1em; +} +*/ +.ptx-content section > ol:last-child > li:last-child, +.ptx-content section > ul:last-child > li:last-child { + padding-bottom: 0em; +} + +/* does this do anything which is not accomplished by the colsN::after above? */ +/* seems not +.ptx-content .cols2:last-child::after, .ptx-content .cols3:last-child::after, .ptx-content .cols4:last-child::after, .ptx-content .cols5:last-child::after, .ptx-content .cols6:last-child::after { + content: ""; + display: block; + clear: both; +} +*/ + +.ptx-content .cols2 > li:nth-child(2n+1), +.ptx-content .cols3 > li:nth-child(3n+1), +.ptx-content .cols4 > li:nth-child(4n+1), +.ptx-content .cols5 > li:nth-child(5n+1), +.ptx-content .cols6 > li:nth-child(6n+1) { + clear: left; +} +/* need to repeat for .colsN */ +.ptx-content .exercise-like ol.cols2 li { + margin-top: 0.5em; +} + +.ptx-content .cols2 > li, +.ptx-content .cols3 > li, +.ptx-content .cols4 > li, +.ptx-content .cols5 > li, +.ptx-content .cols6 > li { + float: left; +} + +.ptx-content .incontext { + display: block; + font-size: 85%; + text-align: right; +} + +.ptx-content .terminology { + font-style: italic; + font-weight: bold; +} + +.ptx-content .emphasis { + font-style: italic; +} +.ptx-content .emphasis .emphasis { + font-weight: bold; +} + +/* the "pink flash" when navigating to a target +*/ +:target { + animation: target-fade 15s 1; +} +@-webkit-keyframes target-fade { + 0% { background-color: rgba(120,0,120,.3); } + 100% { background-color: inherit; + opacity: 1; } +} +@-moz-keyframes target-fade { + 0% { background-color: rgba(120,0,120,.3); } + 100% { background-color: inherit; + opacity: 1; } +} + + +.ptx-content .autoterm [knowl], .ptx-content .autoterm [knowl]:after { + font-weight: inherit; + color: inherit; + padding: 0; + margin-bottom: inherit; + border-bottom: inherit; + border-bottom-color: inherit; +} + +.ptx-content .autoterm [knowl]:hover { + background: #ffddff; + border-top: 2px dotted purple; + border-bottom: 1px dotted red; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.ptx-content ol li.custom-list-style-type { + list-style-type: none; +} + +.ptx-content ol li.custom-list-style-type:before { + content: attr(label) "\00A0\00A0 "; +} + +.ptx-content ol.no-marker, +.ptx-content ul.no-marker, +.ptx-content li.no-marker { + list-style-type: none; +} + +.ptx-content ol.decimal { + list-style-type: decimal; +} +.ptx-content ol.lower-alpha { + list-style-type: lower-alpha; +} +.ptx-content ol.upper-alpha { + list-style-type: upper-alpha; +} +.ptx-content ol.lower-roman { + list-style-type: lower-roman; +} +.ptx-content ol.upper-roman { + list-style-type: upper-roman; +} +.ptx-content ul.disc { + list-style-type: disc; +} +.ptx-content ul.square { + list-style-type: square; +} +.ptx-content ul.circle { + list-style-type: circle; +} +.ptx-content ol.no-marker, +.ptx-content ul.no-marker { + list-style-type: none; +} + +/* needed for dl, but probably won't cause harm elsewhere */ +.ptx-content section, +.ptx-content article, +.ptx-content figure { + clear: both; +} + +/* dl is used for glossaries and descriptions lists. + Glossaries are simple: bold word by itself on a line. + Definition indented on the next line. + Vertical space before the next term. + + Description lists are more complicated. The wider version + (refering to the horizontal indentation of the definition; + this is the default) + has the (wrapped) term inline with the definition. + + The narrow version is complicated because the term is inline + with its definition if it fits, otherwise it is on the line above. + That means the vertical space between entries can't be handled by + a top margin on the dt. Instead we have an ::after on the dd . + */ + +.ptx-content dl { + margin-top: 1em; + margin-left: 0; + margin-bottom: 0; + overflow: hidden; +} +.ptx-content dl dd { + margin-top: 0; +} +.ptx-content dl dd::after { + content: ""; + display: block; + clear: both; +} +.ptx-content dl.glossary dt { + margin-top: 1.25em; +} +.ptx-content dl.description-list dt, +.ptx-content dl.description-list dd { + margin-top: 1em; +} +.ptx-content dl.description-list.narrow dt { + margin-top: 0; +} +.ptx-content dl.glosary dt:first-of-type, +.ptx-content dl.description-list dt:first-of-type, +.ptx-content dl.glosary dd:first-of-type, +.ptx-content dl.description-list dd:first-of-type { + margin-top: 0; +} +.ptx-content dl dd .para { + margin-top: 1em; +} +.ptx-content dl dt > .para:first-child, .ptx-content dl dd > .para:first-child { + margin-top: 0; +} + + +.ptx-content dl > dt { + font-weight: bold; + max-width: 55ex; +} + +.ptx-content dl.description-list dt { + float: left; + clear: left; + text-align: right; + width: 18ex; +} +.ptx-content dl.description-list.narrow dt, +.ptx-content dl.glossary dt { + text-align: left; +} +.ptx-content dl.glossary dd { + margin-left: 5ex; +} +.ptx-content dl.description-list dd { + margin-left: 22ex; +} +.ptx-content dl.description-list.narrow dd { + margin-left: 12ex; +} +.ptx-content dl.description-list dt:first-of-type { + clear: none; +} +.ptx-content dl.description-list.narrow dd::after { + content: ""; + display: block; + height: 1em; + clear: left; +} +.ptx-content dl.description-list.narrow dd:last-child::after { + height: 0; +} + +.ptx-content dl.description-list dt { + float: left; + clear: both; + margin-right: 1ex; +} +.ptx-content dl.description-list.narrow dt { + width: unset; + max-width: 55ex; + text-align: left; +} +.ptx-content dl.description-list.narrow dd { + margin-left: 0; + margin-top: 0; + width: 31em; + max-width: calc(100% - 12ex); + float: right; + clear: right; +} + +.ptx-content dl.description-list + * { + clear: both; +} + +@media screen and (max-width: 480px) { + .ptx-content dl.description-list dt { + float: none; + margin-left: 0; + text-align: left; + } + .ptx-content dl.description-list dd, + .ptx-content dl.description-list.narrow dd { + margin-top: 0.5em; + margin-left: 3em; + max-width: calc(100% - 3em); + } +} +/* where do we have nested dl? */ +.ptx-content dl.description-list dl dt { + width: 8ex; +} +.ptx-content dl.description-list dd dd { + margin-left: 18ex; +} +.ptx-content dl.description-list dl dd { + margin-left: 12ex; +} +.ptx-content [data-knowl] > mjx-mrow .TEX-I { + font-family: MJXZERO !important; + font-style: normal !important; +} + +/* remove this when MathJax fixes the bug that was setting the width to 0 */ +/* as in $x=0$. becomes $x=0\text{.}$ */ +.ptx-content .knowl mjx-mtext > mjx-utext, +.ptx-content mjx-mtext > mjx-utext { + width: revert !important; +} +.ptx-content mjx-msup mjx-utext, +.ptx-content mjx-msub mjx-utext { + display: inline; +} + +/* to stop things being blue when rendering MathJax with SVG */ +a.mjx-svg-href { + fill: inherit; + stroke: inherit; +} + +.displaymath + .para { + margin-top: 0 +} + +/* for long math formulas and tables to scroll on small screens */ +@media screen and (max-width: 943px) { + .ptx-content .displaymath { + position: relative; + overflow-x: auto; + } +/* maybe the remainder of this case is subsumed by the above, + and also does not apply to MJ3 */ + .ptx-content .mjx-chtml.MJXc-display { + /*Allow users on smaller screens to scroll equations*/ + /*horizontally when they don't fit on the screen*/ + overflow-x: auto; + overflow-y: hidden; + } + .ptx-content .figure-like { + overflow-x: auto; + } + + .ptx-content #MathJax_ZoomFrame { + position: static; + background: white; + } + .ptx-content #MathJax_Zoom { + background-color: inherit; + border: 0; + padding: 0; + position: absolute; + overflow-x: auto; + overflow-y: visible; + left: 10% !important; + max-height: none !important; + } +} + +/* http://sites.wcsu.edu/mbxml/OER_Linear_Alg/glossary.html + to fix the extra margin on top of the next term when + the previous definition ends in display math + May need to make less specific +*/ +.ptx-content dd .displaymath:last-child .MJXc-display { + margin-bottom: 0; +} + +.floatnav { + margin-top: 8px; + margin-left: 50px; +} + +.floatnav a { + padding-left: 3px; +/* + * omitted, because we put a space in the source + padding-right: 3px; +*/ + margin-right: -1px; + color: inherit; +} + +/* Example 4.8 of sample article (compare main page of sample book (4^{th} edition)`*/ +.ptx-content a .heading .mjx-chtml { + z-index: 1; + background: #fff; +} +.ptx-content .hidden-knowl-wrapper [data-knowl]::after, .ptx-content .hidden-knowl-wrapper [data-knowl]:hover::after, .ptx-content .hidden-knowl-wrapper .active[data-knowl]::after { + right: 7px; +} + +.floatnav a:hover { + background: #eeaaff; +} + +.ptx-content .unselectable { /* from Alex Jordan */ + user-select: none; /* Non-prefixed version, currently + not supported by any browser */ +} + +/* Adapted from William Hammond (attributed to David Carlisle) */ +/* "mathjax-users" Google Group, 2015-12-27 */ + +.ptx-content .latex-logo {font-family: "PT Serif", "Times New Roman", Times, serif;} + +.ptx-content .latex-logo .A {font-size: 75%; text-transform: uppercase; vertical-align: .5ex; + margin-left: -.48em; margin-right: -.2em;} + +.ptx-content .latex-logo .E {vertical-align:-.5ex; text-transform: uppercase; + margin-left: -.18em; margin-right: -.12em; } + +.ptx-content .fillin { + display: inline-block; + border-bottom-style: solid; + border-width: 1px; + margin-right: 0.1em; + margin-bottom: -0.25em; +} +.ptx-content .fillin.underline { + display: inline-block; + border-bottom-style: solid; + border-width: 1px; + margin-right: 0.1em; + margin-bottom: -0.25em; +} +.ptx-content .fillin.box { + display: inline-block; + border: none; + margin-left: 0.1em; + margin-right: 0.1em; + margin-bottom: -0.25em; + outline: 1px solid black; + height: 1.3em; +} +.ptx-content .fillin.shade { + display: inline-block; + border: none; + margin-right: 0.1em; + margin-left: 0.1em; + margin-bottom: -0.25em; + background-color: #eee; + height: 1.3em; +} + + +/* + * .hiddenproof + */ + +/* knowlified proofs are in an article.hiddenproof */ +/* .ptx-content .hiddenproof .heading, ???? can't happen, because the a does the hiding? */ +.ptx-content .hiddenproof > a > .heading { + font-style: italic; + font-weight: normal; +} + +/* show wide equation overflow even when no scroll bars, +from Jiří Lebl */ +.ptx-content .MJXc-display, .ptx-content .knowl-output .knowl-output .knowl-output .knowl-output .MJXc-display , +.ptx-content pre.prettyprint, +.ptx-content pre.plainprint, +.ptx-content pre.console, +.ptx-content .code-box { + background-image: linear-gradient(to right, white, white), linear-gradient(to right, white, white), linear-gradient(to right, rgba(0,0,0,.25), rgba(255,255,255,0)), linear-gradient(to left, rgba(0,0,0,.25), rgba(255,255,255,0)); + background-position: left center, right center, left center, right center; + background-repeat: no-repeat; + background-color: inherit; + background-size: 20px 100%, 20px 100%, 10px 100%, 10px 100%; + background-attachment: local, local, scroll, scroll; +} +.ptx-content .runestone .code-box { + background-image: none; +} +.ptx-content .knowl-output .MJXc-display { + background-image: linear-gradient(to right, var(--knowlbackground), var(--knowlbackground)), linear-gradient(to right, var(--knowlbackground), var(--knowlbackground)), linear-gradient(to right, rgba(0,0,0,.25), var(--knowlbackground)), linear-gradient(to left, rgba(0,0,0,.25), var(--knowlbackground)); +} +/* this should have a variable name, maybe? */ +.ptx-content .knowl-output.original .MJXc-display { + background: inherit; +} + +.ptx-content .assemblage-like .MJXc-display { +/* + background-image: none; + background-image: linear-gradient(to right, #f4f4fe, #f4f4fe), linear-gradient(to right, #f4f4fe, #f4f4fe), linear-gradient(to right, rgba(0,0,0,.25), rgba(242,242,254,0)), linear-gradient(to left, rgba(0,0,0,.25), rgba(242,242,254,0)); +*/ + background-image: linear-gradient(to right, var(--assemblagebackground), var(--assemblagebackground)), linear-gradient(to right, var(--assemblagebackground), var(--assemblagebackground)), linear-gradient(to right, rgba(0,0,0,.25), var(--assemblagebackground)), linear-gradient(to left, rgba(0,0,0,.25), var(--assemblagebackground)); +} + + +.ptx-content .knowl-output .knowl-output .MJXc-display { + background-image: none; + background-image: linear-gradient(to right, #fffff5, #fffff5), linear-gradient(to right, #fffff5, #fffff5), linear-gradient(to right, rgba(0,0,0,.25), rgba(255,255,243,0)), linear-gradient(to left, rgba(0,0,0,.25), rgba(255,255,243,0)); +} +.ptx-content .knowl-output .knowl-output .knowl-output .MJXc-display { + background-image: none; + background-image: linear-gradient(to right, #fff5fe, #fff5fe), linear-gradient(to right, #fff5fe, #fff5fe), linear-gradient(to right, rgba(0,0,0,.25), rgba(255,243,254,0)), linear-gradient(to left, rgba(0,0,0,.25), rgba(255,243,254,0)); +} + + + +/* not sure where this was being used, but it made short knowls + * look bad, like the hint here: + * SAFurtherReading.html +*/ +.ptx-content .knowl-output .knowl-content > *:last-child:not(.incontext) { + margin-bottom: 0.5em; +} +.ptx-content .knowl-output .knowl .knowl-content > .solution-like, +.ptx-content .knowl-output .knowl .knowl-content > .solution-like:not(.incontext) { + margin-bottom: 0.15em; +} +.ptx-content .knowl-output .knowl .knowl-content > .solution-like.hint { + border-left: 1px solid #0f0; + padding-left: 0.35em; + background: #efe; +} +.ptx-content .knowl-output .knowl .knowl-content > .solution-like.answer { + border-left: 2px solid #00f; + padding-left: 0.35em; + background: #eef; +} +.ptx-content .knowl-output .knowl .knowl-content > .solution-like.solution { + border-left: 3px solid #c0c; + padding-left: 0.5em; + background: #fef; +} + +.ptx-content .knowl-content > article:first-child, +.ptx-content .knowl-content > .solution-like:first-child { +/* padding, not margin, to get colored background (and not be absorbed) */ + padding-top: 0.25em; +} +.ptx-content .knowl-footer { + display: none; +} + +.ptx-content .exercisegroup > .conclusion { + margin-left: 1.5em; +} + +.ptx-content .exercise-like .introduction { + display: inline; +} +.ptx-content .exercise-like .introduction .heading { + display: inline; +} +.ptx-content .exercise-like .introduction .para:first-child { + display: inline; +} +.ptx-content .exercise-like .introduction::after { + content: ""; + display: block; +} +.ptx-content .exercise-like .conclusion::before { + content: ""; + display: block; + margin-top: 0.25em; +} + + +/* if hints and solutions are in .posterior, then + * some of the above styling does not apply */ + +.ptx-content article.exercise-like + .posterior { + margin-top: -0.75em; +} + + +.ptx-content article.example-like .hint { + display: block; + margin-top: -0.75em; +} + + +.ptx-content .exercisegroup .exercisegroup-exercises.cols2, .ptx-content .exercisegroup .exercisegroup-exercises.cols3, .ptx-content .exercisegroup .exercisegroup-exercises.cols4, .ptx-content .exercisegroup .exercisegroup-exercises.cols5, .ptx-content .exercisegroup .exercisegroup-exercises.cols6 { + width: 100%; + display:inline-flex; + flex-direction:row; + flex-wrap:wrap; + justify-content:flex-start; + align-items:flex-start; + align-content:flex-start; +} + +.ptx-content .exercisegroup .exercisegroup-exercises.cols1 { + display:inline; +} + +.ptx-content .exercisegroup .exercisegroup-exercises.cols1 .knowl-output { + display: block; +} + +.ptx-content .exercisegroup .cols1 > article.exercise-like {flex-basis: calc(100% - 2em);} +.ptx-content .exercisegroup .cols2 > article.exercise-like {flex-basis: calc(50% - 2em);} +.ptx-content .exercisegroup .cols3 > article.exercise-like {flex-basis: calc(33.33% - 2em);} +.ptx-content .exercisegroup .cols4 > article.exercise-like {flex-basis: calc(25% - 2em);} +.ptx-content .exercisegroup .cols5 > article.exercise-like {flex-basis: calc(20% - 2em);} +.ptx-content .exercisegroup .cols6 > article.exercise-like {flex-basis: calc(16.66% - 2em);} + +/* math directly adajacent to words is wrapped to avoid bad line breaks */ +.ptx-content .mathword { + white-space: nowrap; +} + +.ptx-content .unit, +.ptx-content .quantity { + white-space: nowrap; + word-spacing: -0.25ex; + margin-right: 0.125em; +} +.ptx-content .unit sub, +.ptx-content .unit sup, +.ptx-content .quantity sub, +.ptx-content .quantity sup { + word-spacing: normal; +} + +.ptx-content .code-inline, +.ptx-content .code-block, +.ptx-content .console, +.ptx-content .program, +.ptx-content .program code { + font-family: "Inconsolata", monospace; +} +.ptx-content .code-block, +.ptx-content .console, +.ptx-content .program { + overflow-x: auto; +} + +.ptx-content .code-inline { + font-size: 1em; + white-space: pre; + color: inherit; + background: #eeeeee; + border: 1px solid #dddddd; + padding: 0.0625em 0.25em; + margin-left: 0.2em; + margin-right: 0.2em; + border-radius: 0.2em; +} +.ptx-content .code-inline:first-child { + margin-left: 0; +} +.ptx-content .title .code-inline { + padding-left: 0; + padding-right: 0; + margin-left: 0; + margin-right: 0; +} +.ptx-content a .code-inline { + background: #f6f6f6; +} + +.ptx-content .kbdkey { + background: #f1f1f1; + border: 1px solid #dddddd; + border-radius: 3px; + padding: 1px 2px 0 2px; + vertical-align: 0.1em; + font-size: 110%; + line-height: 1; + box-shadow: 2px 2px grey; + display: inline-block; + margin-right: 3px; +} +.ptx-content .kbdkey { + color: #333; +} + +.ptx-content .sagecell_sessionOutput pre { + font-family: 'Inconsolata', monospace; +} + +.ptx-content .sagecell { + white-space: normal; + margin-top: 1.25em; + margin-bottom: 1.25em; +} +.ptx-content .sage-interact.sagecell { + margin: 0; +} + +.ptx-content .sagecell_evalButton { + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 16px; + padding: 0 0.65em; +} +.ptx-content .sagecell_evalButton { + cursor: pointer; + display: inline-block; + vertical-align: middle; + /* Disable accidental text-selection */ + user-select: none; + /* Truncate overflowing text with ellipsis */ + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + border-width: 1px; + border-style: solid; + font-weight: bold; + border-radius: 3px; +} +.ptx-content .sagecell_evalButton { + color: #383838; + background-image: linear-gradient(#f7f7f7, #bbbbbb); + border-color: #c4c4c4; +} +.ptx-content .sagecell_evalButton:hover { + color: #181868; + background-image: linear-gradient(#bbbbbb, #f7f7f7); +} +.ptx-content .sagecell_evalButton:focus, +.ptx-content .sagecell_evalButton:active { + color: #20160b; + background-image: linear-gradient(#ff6852, #ffd7d1); + border-color: #ff2822; +} + +.ptx-content .sagecell .sagecell_editor { + margin-bottom: 8px; +} + +.ptx-content .booktitle { + font-style: oblique; +} + +.ptx-content .objectives > .heading, +.ptx-content .outcomes > .heading { + font-size: 1.25em; +} + +/* Born-hidden example with a very long title */ +/* http://physics.thomasmore.edu/ConnectedPhysics/sss-netforce.html */ +.ptx-content a .heading { + white-space: normal; +} + + +.ptx-content .solutions > a, .ptx-content .solutions > a:hover, .ptx-content .solutions > a.active, +.ptx-content .instructions > a, .ptx-content .instructions > a:hover, .ptx-content .instructions > a.active { + display: inline-block; + margin-right: 1.5em; +} + +/* When the knowl is a Hint, Answer, or Solution, put a little + triangle in front of it */ +.ptx-content .solutions > a::before, +.ptx-content .instructions > a::before { + content: '\25ba'; + font-size: 70%; + color: #06a; + position: relative; + top: -2px; + right: 3px; +} +.ptx-content .solutions > a.active::before, +.ptx-content .instructions > a.active::before { + content: '\25bc'; + animation-name: solutiontriangle; + animation-duration: 3s; + animation-iteration-count: 1; +} +.ptx-content .solutions > a[data-knowl]::after, +.ptx-content .instructions > a[data-knowl]::after { + left: 12px; +} +@keyframes solutiontriangle { + from {content: '\25ba';} + to {content: '\25bc';} +} + +.ptx-content section.solutions { + font-size: 90%; + padding-left: 1em; + border-left: 1em solid #eeeeee; +} + +.ptx-content.ptx-content > section.solutions:first-child { + padding-left: 0; + border-left: none; +} + +.ptx-content article.example-like > .solution-like, +.ptx-content article.exercise-like > .solution-like { + margin-top: 1.0em; + padding-left: 0.7em; +} +.ptx-content article.example-like > .solution-like > .heading, +.ptx-content article.exercise-like > .solution-like > .heading { + font-size: 100%; + font-weight: 700; + margin-right: 0.25em; + display: inline; +} +.ptx-content article.example-like > .solution-like > .heading + .para, +.ptx-content article.exercise-like > .solution-like > .heading + .para { + display: inline; +} + + + + +/* these were taken from the local add-on.css. + * need to check if the are needed. + */ + +.ptx-content article > figure:first-child { + margin-top: 0; +} + +.ptx-content figure + figure, +.ptx-content figure + .sidebyside, +.ptx-content .sidebyside + .sidebyside, +.ptx-content article + figure, +.ptx-content .sidebyside + figure { + padding-top: 1.0em; +} + + +.ptx-content img { + display: inline-block; + margin-left: auto; + margin-right: auto; +} + +/* is .cs for commutative diagrams? */ +.ptx-content img.cs { + display: block; + margin-top: 20px; + margin-bottom: 20px; + margin-left: auto; + margin-right: auto; +} + +.ptx-content img:not(.cs) { + max-width: 650px; +} + +.ptx-content .tabular-box.natural-width table { + margin-left: auto; + margin-right: auto; +} + +.ptx-content figure img { + display: block; + margin-left: auto; + margin-right: auto; +} + +.ptx-content figure img + img { + margin-top: 30px; +} + +.ptx-content div.center img { + display: block; + margin-left: auto; + margin-right: auto; +} + +.ptx-content div.center + div.center > img { + margin-top: 60px; +} + +.ptx-content div.center > img + img { + margin-top: 60px; +} + +.ptx-content figure table { + margin-left: auto; + margin-right: auto; +} + +.ptx-content .caption { + margin-top: 10px; + margin-left: auto; + margin-right: auto; + font-size: 100%; + text-align: center; +} + + +.ptx-content figure.wrap img { + width: 250px; +} +.ptx-content figure.wrap { + float: right; + margin-right: 0; + margin-left: 30px; +} +.ptx-content figure img.wrap { + float: right; + margin: 0; +} + +.ptx-content figure figcaption.wrap { + margin: 10px; + font-size: 100%; + text-align: center; +} + +.ptx-content figure, .ptx-content .image-box { + margin-top: 0.5em; +} +.ptx-content figure .image-box { + margin-top: 0; +} +.ptx-content .sidebyside figure { + margin-top: 0; +} +.ptx-content .image-box img, /* See sample article Graphics section */ +.ptx-content img.contained, /* See sample article Graphics section */ +.ptx-content .sbspanel img { + /* previously these were hard-coded in the HTML */ + width: 100%; + height: auto; +} + +/* these seem to be obsolete because an img has to be in a .image-box . + Check on that. +.ptx-content .sbspanel > img:not(.draw_on_me):not(.mag_popup), +.ptx-content figure > img:not(.draw_on_me):not(.mag_popup), +.ptx-content figure > div > img:not(.draw_on_me):not(.mag_popup), +*/ +.ptx-content .image-box > img:not(.draw_on_me):not(.mag_popup) { + cursor: zoom-in; +} +.ptx-content img.mag_popup { + border: 1px solid #666; + box-shadow: 4px 6px 4px #999; + cursor: zoom-out; + max-width: 600px; +} +.ptx-content .mag_popup_container { + width:100%; + position:absolute; + z-index:1001; + overflow-x: visible; +} + +.ptx-content .image-box, +.ptx-content .audio-box, +.ptx-content .video-box, +.ptx-content .asymptote-box { + position: relative; +} +.ptx-content .image-box .asymptote-box iframe.asymptote, +.ptx-content iframe.asymptote, +.ptx-content .video-box .video, +.ptx-content .video-box .video-poster { + position: absolute; top: 0; left: 0; width: 100%; height: 100%; +} +.ptx-content section > .audio-box, +.ptx-content section > .video-box, +.ptx-content section > .image-box { + margin-top: 0.75em; +} + +.ptx-content .audio { + width: 100%; +} + +.caption .heading { + font-weight: bold; +} + +.caption .counter { + font-weight: bold; +} + +.ptx-content div.quote { + padding-left: 40px; + padding-right: 10px; + margin-bottom: 1em; +} + +.minipage + .minipage { + display: inline-block; +} + +.ptx-content code.inline { + background: none; + border: none; +} + +/* These next are for Prism */ +.ptx-content pre.program, +.ptx-content pre.program code, +.ptx-content pre.code-block, +.ptx-content pre.code-block code { + line-height: 1.1; +} +.ptx-content section > .code-box, +.ptx-content .para + .code-box, +.ptx-content section > .code-block, +.ptx-content .para + .code-block { + margin-top: 1em; +} + +.ptx-content pre.program, +.ptx-content pre.code-block { + margin-top: 0; + padding-left: 15px; + border-left: 1px solid #aaa; + font-size: 93%; + overflow: auto; +} +.ptx-content pre.program:before, +.ptx-content pre.code-block:before { + content:' '; + font-size: 50%; + border-top: 1px solid #aaa; + display: block; + margin-right: auto; + margin-left: -15px; + width: 3.0em; +} + +.ptx-content pre[data-line].program, +.ptx-content pre[data-line].code-block +{ + padding-left: 2.5em; +} + +.ptx-content pre[data-line].program:before, +.ptx-content pre[data-line].code-block:before { + margin-left: -5em; +} + +.ptx-content pre.program.line-numbers, +.ptx-content pre.code-block.line-numbers +{ + padding-left: 3.5em; + overflow: visible; +} + +.ptx-content pre.program.line-numbers:before, +.ptx-content pre.code-block.line-numbers:before { + margin-left: -7em; +} + +/* fine tune next 3 based on line-height of surrounding pre */ +.ptx-content pre[data-line].line-numbers code { + padding-top: 0em; /* increase with line-height */ +} +.ptx-content pre[data-line].line-numbers .line-highlight { + margin-top: 0em; /* decreases as line-height increases */ +} +.ptx-content pre[data-line]:not(.line-numbers) .line-highlight { + margin-top: 0.6em; /* decreases as line-height increases */ +} + + +/* next is for the old code formatting js */ +.ptx-content pre.prettyprint, +.ptx-content pre.plainprint { + margin-top: 0; + padding-left: 15px; + border-left: 1px solid #aaa; + font-size: 93%; + overflow: auto; +/* preveiously turned off the border and padding from pretty.css */ +} + +.ptx-content pre.prettyprint:before, +.ptx-content pre.plainprint:before { + content:''; + font-size: 50%; + border-top: 1px solid #aaa; + display: block; + margin-right: auto; + margin-left: -15px; + width: 2.5em; +} + +.ptx-content .objectives { + margin-bottom: 1.25em; +} + + +.ptx-content ol > li { + padding-left: 0.25em; +} +.ptx-content ol.cols2 > li, .ptx-content ul.cols2 > li { width: calc(49% - 1.75em); min-width: 190px} +/* +.ptx-content ol.cols2 > li, .ptx-content ul.cols2 > li { width: 50%; min-width: 240px} +*/ +.ptx-content ol.cols3 > li, .ptx-content ul.cols3 > li { width: calc(33% - 1.25em); min-width: 160px} +/* +.ptx-content ol.cols3 > li, .ptx-content ul.cols3 > li { width: 31%; min-width: 160px} +*/ +.ptx-content ol.cols4 > li, .ptx-content ul.cols4 > li { width: calc(24.5% - 1.25em); min-width: 100px} +.ptx-content ol.cols5 > li, .ptx-content ul.cols5 > li { width: calc(19.5% - 0.75em); min-width: 90px} +.ptx-content ol.cols6 > li, .ptx-content ul.cols6 > li { width: calc(16.3% - 0.5em); min-width: 80px} +/* sample-article sec 5 */ +.ptx-content ul.cols2 > li:nth-child(odd), .ptx-content ol.cols2 > li:nth-child(odd) { + padding-right: 1.5em; + padding-right: 2em; +} + +/* +.ptx-content .cols2 > li:first-child, +.ptx-content .cols3 > li:first-child, +.ptx-content .cols4 > li:first-child, +.ptx-content .cols5 > li:first-child, +.ptx-content .cols6 > li:first-child { + margin-top: 0.5em; +} +*/ + +.ptx-content .cols2 ol, +.ptx-content .cols3 ol, +.ptx-content .cols4 ol, +.ptx-content .cols5 ol, +.ptx-content .cols6 ol { + padding-left: 0.7em; +} +.ptx-content .exercisegroup-exercises > article.exercise-like { + margin-top: 1em; +} + + +/* see http://bob.cs.sonoma.edu/IntroCompOrg-RPi/exercises-10.html + for examples of an odd number of items in a cols2, followed by + a hint */ +.ptx-content .cols2 > li:last-child:nth-child(odd) { + float: none !important; + padding-top: 0.5em; +} + + +/* http://spot.pcc.edu/math/APEXCalculus/sec_prod_quot_rules.html + * solution to Example 2.4.14 + */ +.ptx-content .solution ol li { + margin-top: 1em; + padding-left: 0.5em; +} + +/* solution to Example 4.2.12 in http://spot.pcc.edu/math/orcca-draft/orcca/section-radical-expressions-and-rational-exponents.html +*/ +.ptx-content .solution ol li > .para:first-child, .ptx-content .solution ol li > .displaymath:first-child { + vertical-align: top; + display: inline-block; + margin-top: 0; +} +.ptx-content .solution ol li > .displaymath:first-child .MJXc-display { + margin-top: 0; +} + + +.ptx-content .exercise-like ol li { + margin-top: 1em; + padding-left: 0.5em; +} + +.ptx-content .exercise-like > .cols2 > li { width: calc(49% - 2.5em)} +.ptx-content .exercise-like > .cols3 > li { width: calc(33% - 2.5em)} +.ptx-content .exercise-like > .cols4 > li { width: calc(24.5% - 2.5em)} +.ptx-content .exercise-like > .cols5 > li { width: calc(19.5% - 2.5em)} +.ptx-content .exercise-like > .cols6 > li { width: calc(16.3% - 2.5em)} + +/* A colsN in a knowl needs to be narrower because of the margin/padding of the knowl */ +.ptx-content .knowl .exercise-like > .cols2 > li { width: calc(49% - 2em)} +/* next 4 not actually checked: just copied from cols2 */ +.ptx-content .knowl .exercise-like > .cols3 > li { width: calc(33% - 2em)} +.ptx-content .knowl .exercise-like > .cols4 > li { width: calc(24.5% - 2em)} +.ptx-content .knowl .exercise-like > .cols5 > li { width: calc(19.5% - 2em)} +.ptx-content .knowl .exercise-like > .cols6 > li { width: calc(16.3% - 2em)} + + +.ptx-content .exercise-like ol li > .para:first-child { + vertical-align: top; + display: inline-block; + margin-top: 0; +} + +.ptx-content .contributor .contributor-name { + font-variant: small-caps; +} +.ptx-content .contributor .contributor-info { + font-size: 88%; + font-style: italic; + margin-left: 3ex; +} +.ptx-content .contributor { + margin-top: 3ex; +} +.ptx-content .contributor + .contributor { + margin-top: 1.5ex; +} + +.ptx-content .contributor + .para { + margin-top: 3ex; +} + +.ptx-content .frontmatter .contributors, .ptx-content .book .contributors { + text-align: center; + font-style: normal; +} + +.pretext .searchwrapper { + max-width: 900px; + position: absolute; + right: 0; + bottom: 0; + margin-bottom: 39px; +} + +.pretext .searchwrapper .cse .gsc-control-cse, .searchwrapper .gsc-control-cse { + padding: 0; + border: none; + width: 25ex; +} +.pretext .searchwrapper .cse .gsc-search-button input.gsc-search-button-v2, .searchwrapper input.gsc-search-button-v2 { + padding: 2px 2px; +} +.pretext .searchwrapper form.gsc-search-box { + margin: 0; +} +.pretext .searchwrapper table.gsc-search-box { + margin: 0; +} +.pretext .searchwrapper .gsc-search-box-tools .gsc-search-box .gsc-input { + padding: 0; +} +.pretext .searchwrapper .gsib_a { + padding: 0 0 0 5px; +} +.pretext .searchwrapper .gsc-input-box { + height: 3.0ex; +} +.pretext .searchwrapper form.gsc-search-box { + font-size: 12px; +} + +/* turn off the green parentheses Alex does not like */ +.ptx-content div.CodeMirror span.CodeMirror-matchingbracket {color: #090;} + +.ptx-content .image-archive { + margin-left: auto; + margin-right: auto; + margin-bottom: 0; /* was auto */ + margin-top: 0.75em; + padding-bottom: 0.25em; + text-align: center; +} +.ptx-content .image-archive > a { + display: inline-block; + padding-left: 0.5em; + padding-right: 0.5em; + font-family: monospace; +} + +.ptx-content iframe { + margin: 0; + border: none; + box-sizing: border-box; +} + +.ptx-content .times-sign { + font-size: larger; + vertical-align: -0.15ex; +} +/* temporary for Geogebra development: replace with a more + restrictive selector for articles */ +.ptx-content article.notranslate { + margin-top: 0; +} + +/* +nested tasks. see +https://pretextbook.org/examples/sample-article/html/interesting-corollary.html#aBc +*/ + +/* 9/27/23 added "article" because of details.exercise-like */ +.ptx-content article.exercise-like > .exercise-like { + margin-left: 40px; +} +.ptx-content article.exercise-like > .exercise-like.task { + margin-left: 20px; +} +.ptx-content article.exercise-like > .exercise-like > .para { + margin-top: 1.25em; +/* margin-bottom: 0.25em; */ +} +.ptx-content article.example-like > .heading + .introduction { + display: inline; +} +.ptx-content article.example-like > .heading + .introduction > .para:first-child { + display: inline; +} +.ptx-content article.example-like > .exercise-like > .para { + margin-top: 1.25em; +} + +/* end of nested tasks */ + +/* genus and species in italics */ +.ptx-content .taxon { + font-style: italic; +} + +/* Sage stuff */ +.ptx-content .sageanswer { + font-family: monospace; + white-space: pre; + margin-left: 3em; + margin-bottom: 2em; +} +.ptx-content .sageanswer .key { + display: inline-block; + vertical-align: top; + margin-right: 1em; +} +.ptx-content .sageanswer .output { + display: inline-block; + vertical-align: top; +} +.ptx-content .CodeMirror-code pre.CodeMirror-line { + padding-bottom: 5px; +/* the next item is the CodeMirror default, which was + previously over-ridden */ + padding-left: 6px; +} + +/* used when knowl content is hidden in the page */ +.ptx-content .hidden-content, .pretext .hidden-content { +/* things will be different after 2022 overhaul */ + display: none; +} + +.ptx-content hr.ptx-pagebreak { + width: 30em; + text-align: center; + margin-left: auto; + margin-right: auto; + margin-bottom: 2.0em; + margin-top: 0; + height: 4em; + border: 0; + border-bottom: 1px dashed #ccc; +} + +.ptx-content hr.ptx-pagebreak:after { + content: "page"; + display: inline-block; + position: relative; + top: 4.0em; + font-size: 80%; + padding: 0 0.25em; + background: white; +} + +/* + See 10.1.8c in http://faculty.valpo.edu/calculus3ibl/ch10_01_gradient.html +and condider having this replace line 3338 of the general code (which uses .heading + p) +*/ +.ptx-content .example-like > .exercise-like > .para:first-of-type { + display: inline; +} +.ptx-content .example-like > .exercise-like > .aside-like { + margin-top: -3em; +} +.ptx-content .example-like > .exercise-like > .aside-like.front { + margin-top: 0; +} + +.ptx-content meta { + display: none; +} + +.ptx-content .summary-links a { + color: #671d12; + background: #f0f0f0; + text-decoration: none; + cursor: pointer; +} +.ptx-content .summary-links a:hover, .ptx-content .summary-links a:focus { + color: white; + background: #671d12; +} +.ptx-content .summary-links a .codenumber { + color: #303030; + margin-right: 0.41667em; +} + +.ptx-content .summary-links a:hover .codenumber, .ptx-content .summary-links a:focus .codenumber { + color: #f0f0f0; +} + + + +.ptx-content .summary-links { + margin-top: 4em; +} +.ptx-content section + .summary-links { + margin-top: 2em; +} +.ptx-content .summary-links ul { + list-style-type:none; +} +.ptx-content .summary-links li { + margin-top: 0; +} +.ptx-content section .summary-links li .title { + font-style: normal; +} +.ptx-content .summary-links a { + position: relative; + display: block; + font-size: 1.5em; + line-height: 1.25em; + padding: 0.41667em 0.83333em; + margin-top: 0.20833em; + border-radius: 3px; + padding-right: 2.06667em; +} +.ptx-content .summary-links a:after { + right: 0.83333em; +} +.ptx-content .summary-links a:after { + content: ""; + position: absolute; + /* center vertically */ + top: 50%; + margin-top: -0.4em; + width: 0; + height: 0; + border-top: 0.4em solid transparent; + border-bottom: 0.4em solid transparent; + border-left: 0.4em solid #c9c9c9; +} +.ptx-content .summary-links a, .ptx-content .summary-links a:link, .ptx-content .summary-links a:visited { + cursor: pointer; +} +.ptx-content .summary-links a:hover:after { + width: 0; + height: 0; + border-top: 0.4em solid transparent; + border-bottom: 0.4em solid transparent; + border-left: 0.4em solid white; +} +.ptx-content .summary-links a { + font-family: "PT Serif", "Times New Roman", Times, serif; +} +@media screen and (max-width: 480px) { + .ptx-content .summary-links a { + font-size: 1em; + line-height: 1.25em; + } +} +.ptx-content .summary-links a .codenumber { + margin-right: 0.41667em; +} + +.ptx-content .summary-links a:active { + position: relative; + color: white; + background: #932919; + text-decoration: none; + box-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px 5px inset; +} +.ptx-content .summary-links a:active:after { + width: 0; + height: 0; + border-top: 0.4em solid transparent; + border-bottom: 0.4em solid transparent; + border-left: 0.4em solid white; +} +.ptx-content .summary-links a:focus { + outline: thin dotted #333; + outline-offset: -2px; + /** + * Remove stupid inner dotted border applied by Firefox on focus + * See http://stackoverflow.com/a/199319/1599617 + */ +} + + +/* also see section > heading for worksheets, maybe around line 1200 */ +/* one-page documents in the browser */ + +body.standalone.worksheet .ptx-content .onepage > .heading { + margin-top: 0; + font-size: 1.3em; +} +body.standalone.worksheet .ptx-content .onepage > .introduction { + margin-top: 0.4em; +} +body.standalone.worksheet .ptx-content .onepage > .introduction > .heading { + font-size: 1.1em; +} +body.standalone.worksheet .ptx-content .onepage .solutions, +body.standalone.worksheet .ptx-content .onepage .instructions { + display: none; +} +body.standalone .ptx-content .worksheet { +/* + padding: 40px 45px 45px 55px; +*/ + padding: 40px 0 45px 0; + border: 2px solid grey; + margin: 0; +/* height: 1243px; */ +} + +body.standalone .ptx-content .onepage { +/* padding: 40px 45px 45px 55px; + padding: 0 0 45px 0; +*/ + padding: 40px 45px 45px 55px; + border-bottom: 2px solid grey; + margin: 0; +/* height: 1243px; */ +} +body.standalone .ptx-content .onepage + .onepage { +/* + padding-top: 40px; +*/ + border-top: 2px solid grey; +} +/* there may be worksheet content before the first page + or after the last page +*/ +body.standalone .ptx-content .onepage.firstpage { + padding-top: 0 +} +body.standalone .ptx-content .onepage.lastpage { + padding-bottom: 0; + border-bottom: none; +} + +body.standalone .ptx-content .worksheet > *:last-child { + padding-bottom: 0 !important +} +.ptx-content .onepage + .onepage { + margin-top: 2.5em; + padding-top: 1.5em; + border-top: 1px dashed #aaa; +} +.ptx-content .onepage + .onepage::before { + content: "pagebreak"; + text-align: center; + margin-left: 40%; + padding-left: 1em; + padding-right: 1em; + position: absolute; + top: -0.8em; + font-size: 80%; + font-style: italic; + background: white; +} + +body.standalone .ptx-content .onepage + .onepage { + margin-top: 10px; +} +body.standalone .ptx-content .onepage + .onepage::before { + content: none; +} + +body.standalone .ptx-content .onepage article { + padding-left: 0; + border: none; +} +body.standalone .ptx-content .onepage article::after { + all: unset; +} +.ptx-content .onepage > .para:first-child, +.ptx-content .onepage > article:first-child { + margin-top: 0; +} +.ptx-content section + .onepage.firstpage, +.ptx-content article + .onepage.firstpage, +.ptx-content .para + .onepage.firstpage { + margin-top: 1.25em; +} + +/* not good, because of image next to image +.ptx-content .onepage .sbspanel + .sbspanel { + padding-left: 1.25em; + border-left: 1px solid grey; + margin-left: -1.25em; +} +*/ +body.worksheet .ptx-content .onepage .sbspanel + .sbspanel > .exercise::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + right: 0; + left: 0; + padding-left: 1.25em; + border-left: 1px solid grey; + margin-left: -1.25em; + z-index: -100; /* to not block editable content */ +} + +body.standalone.worksheet .ptx-content section article.task { + margin-left: 0; +} +body.standalone.worksheet .ptx-content section article.task > .heading { + font-weight: normal; +} + +body.standalone .autopermalink { + display: none; +} + +body.standalone.worksheet .ptx-content .onepage .workspace { + border: 2px dotted grey; + background: #f3fff3; +/* Sally suggests light and dark blue + background: linear-gradient( + #eef 0px, #eef 200px, + #eef 200px, #99f 205px, + #99f 205px, #99f 100%) +*/ +} +body.standalone.worksheet .ptx-content .onepage .workspace.squashed { + border: 2px dotted grey; + background: #ffe; +} + +body.standalone.worksheet .ptx-content .onepage .workspace.squashed.tight { + border: 15px solid; + border-image: repeating-linear-gradient( + -35deg, + #f33, + #f33 10px, + #000 10px, + #000 20px + ) 20; +/* + background: linear-gradient( + #ff0 0%, #ff0 8%, + #000 8%, #000 9%, + #ff6 9%, #ff6 17%, + #555 17%, #555 19%, + #ff8 19%, #ff8 26%, + #777 26%, #777 29%, + #ffa 29%, #ffa 37%, + #aaa 37%, #aaa 41%, + #ffd 41%, #ffd 48%, + #ccc 48%, #ccc 52%, + #ffd 52%, #ffd 59%, + #aaa 59%, #aaa 63%, + #ffa 63%, #ffa 71%, + #777 71%, #777 74%, + #ff8 74%, #ff8 81%, + #555 81%, #555 83%, + #ff6 83%, #ff6 91%, + #000 91%, #000 92%, + #ff0 92%, #ff0 100% + ); +*/ + background: yellow; +} + +body.has-sidebar-left.mathbook-loaded.standalone.worksheet .ptx-page .ptx-main { + margin-left: 0; +} +body.standalone.worksheet .ptx-page > .ptx-main .ptx-content { + max-width: 1030px; + width: 1030px; + margin-right: 0; +} +body.standalone.worksheet.a4 .ptx-page > .ptx-main .ptx-content { + max-width: 1001px; + width: 1001px; +} + +body.standalone.worksheet .ptx-content .goal-like { + border: none; + padding: 0; +} +body.standalone.worksheet .ptx-content .goal-like > .heading { + margin-top: -0.5em; + padding: 0; + margin: 0; + font-size: 1.1em; +} +body.standalone.worksheet .ptx-content section.worksheet > .heading { + display: inline; + font-size: 1.1em; +} +/* becaues the worksheet has no side margins but the .onepage does */ +body.standalone.worksheet .ptx-content section.worksheet > .heading, +body.standalone.worksheet .ptx-content section.worksheet > .objectives, +body.standalone.worksheet .ptx-content section.worksheet > .introduction, +body.standalone.worksheet .ptx-content section.worksheet > .conclusion { + margin-left: 55px; + margin-right: 40px; +} +body.standalone.worksheet .ptx-content section.worksheet > .heading + .para { + display: inline; +} + +/* printing for one-page worksheets */ + +.ui-dialog.ui-widget.ui-widget-content.ui-corner-all.ui-draggable.ui-resizable { + left: 0 !important; + top: 0 !important; +} + +/* move to the color file(s) and figure out next comment */ +/* +.ptx-content a.internal { + color: #900; +} +.ptx-content a.internal:hover { + background-color: #ddf; +} +*/ +/* check whether class="url" under Endnotes in pretext-epub.xsl can be + changed to class = "external"*/ +.ptx-content a.url, +.ptx-content a.external { + color: #22a; +} +.ptx-content a.url:hover, +.ptx-content a.external:hover { + background: #ffd; +} + +/* +.ptx-content a.internal:hover, +.ptx-content a.external:hover, +.ptx-content a.internal:focus, +.ptx-content a.external:focus { + text-decoration: underline; +} +*/ + +/* style for poems */ + +.ptx-content .poem { + margin-top: 1.5em; +} +.ptx-content .poem { + display: table; + margin-top: 1.5em; + margin-left: auto; + margin-right: auto; + margin-bottom: 0; + width: auto; + max-width: 90%; +} + +.ptx-content .poem > .heading { + display: block; + text-align: center; +} +.ptx-content section article.poem > .heading::after { + content: ""; +} +.ptx-content .poem > .heading > .title { + font-weight: bold; + font-size: 1.2em; + line-height: 1.2em; +} + +.ptx-content .poem .author { + font-style: italic; + margin-top: 0.75em; +} +.ptx-content .poem .author.left { + text-align: left; +} +.ptx-content .poem .author.center { + text-align: center; +} +.ptx-content .poem .author.right { + text-align: right; +} + +.ptx-content .poem .stanza > .heading { + text-align: center; + font-weight: bold; + font-size: 1em; + line-height: 1em; +} +.ptx-content .poem .stanza + .stanza { + margin-top: 1em; +} +.ptx-content .poem .heading + .stanza { + margin-top: 0.2em; +} +.ptx-content .poem .heading + .line { + margin-top: 0.2em; +} + +.ptx-content .poem .line.left { + text-align: left; + margin-left: 4em; + text-indent: -4em; +} +.ptx-content .poem .line.center { + text-align: center; +} +.ptx-content .poem .line.right { + text-align: right; +} +.ptx-content .poem .tab { + margin-left: 2em; +} + +/* GeoGebra calculator */ + +.calculator-container { + position: fixed; + z-index: 100; + bottom: 5px; + right: 5px; +/* + width: 320px; +*/ + width: 253px; +/* + height: 600px; +*/ + height: 460px; +} +@media screen and (max-width: 800px) { + .calculator-container { + bottom: 50px !important; + } +} + +.toolBPanel { + overflow: hidden !important; +} +.toolBPanel:hover { + overflow: auto !important; +} + +/* Preview of annual edition */ + +.pretext main .para.newstuff { + border-right: 6px solid #6f6; + background: #dfd; +} +.pretext main li.newstuff { + border-right: 6px solid #66f; + background: #eef; +} +.pretext main li.newstuff .para.newstuff { + border-right: none; + background: inherit; +} +.pretext main article.newstuff { + border-right: 6px solid #ff6; + background: #ffd; +} +.pretext main section.newstuff { + border-right: 10px solid #f6f; +} +.pretext main a[data-knowl].newstuff { + border: 1px solid #f33; + background: #fdd; +} + +#aboelkins-ACS .ptx-main .ptx-content > section:first-of-type > section:first-of-type > .project-like:first-of-type li { + font-size: 300% +} +/* WW problems */ + +.ptx-content .wwprob table.attemptResults { + margin-left: 2em; + background: #efefef; + padding: 0.2em; +} +.ptx-content .wwprob table.attemptResults + .attemptResultsSummary { + margin-top: 1em; +} + +.ptx-content .wwprob .problem-main-form { + margin-top: 1em; + background: #eeeeff; + padding: 0.5em; +} +.ptx-content .wwprob td.ResultsWithoutError { + background: #9f9; +} +.ptx-content .wwprob td.ResultsWithError { + background: #f99; +} + +.ptx-content .wwprob tr th { + text-align: center; + padding: 0.2em 1em 0.2em 1em; +} +.ptx-content .wwprob tr td { + text-align: center; +} +.ptx-content .wwprob tr td:empty { + background: #fff; +} + +.ptx-content .wwprob ol, .ptx-content .wwprob ul { + margin-top: 0.75em !important; +} + +.ptx-content .wwprob .problem { + background: #fdfdfd; +} + +.ptx-content .wwprob .problem a { + text-decoration: none; +} + +.ptx-content .wwprob #footer { + font-size: 70%; + text-align: right; +} + +.ptx-content .marginresource { + position: relative; + height: 0; + left: 40em; + top: 1em; +} +.ptx-content .marginresource a { + color: blue; +} +.ptx-content .marginresource a[knowl] { + border-bottom: 1px dotted blue; +} +.ptx-content .marginresource .icon { + font-size: 200%; + margin-right: 1em; + display: inline-block; +} +.ptx-content .marginresource .resource_description { + display: inline-block; +} +.ptx-content .marginresource .resource_links { + display: block; + margin-left: 2em; +} + +.collectedworks .knowl-output { + border: 12px + solid #D6E3FF; + background: none repeat scroll 0% 0% #FAFCFF; + border-radius: 4px; + margin-bottom: 1.25em; +} + +.collectedworks .subjectwork { + max-width: 750px; +} + +.collectedworks .bib { + margin-bottom: 1em; +} + +.collectedworks .bibitem + .bibentry { + display: inline; +} + +.collectedworks .bibitem { + display: inline; + font-weight: bold; + margin-right: 1em; +} +.collectedworks .work .title a { + text-decoration: none; + color: #009; +} +.collectedworks .work .title { +} + + +.iconlegend { + position: absolute; + margin-top: 0.5em; + top: 0; + left: 920px; + line-height: 1; +} + +.iconlegend .icon_name { + font-size: 90%; + margin-right: 1em; +} +.icongroup + .icongroup { + margin-left: 1em; +} + +/* interactive WeBWorK */ + +label.webwork { +display:inline-flex; +flex-direction:column; +} + +label.correct .status { +background-color: #a0f0a0; +} + +label.partly-correct .status { + color: #ffcc66; +} + +label.incorrect .status { + color: #b00; +} +label.incorrect .status::before { + content: " "; +} + +.feedback { + word-wrap:break-word; +} + +label.correct .feedback { + background-color: #00ffcc; +} + +label.partly-correct .feedback { + color: #ffcc66; +} + +label.incorrect .feedback { + color: #e07070; +} + + +.ptx-content .webwork-button { + border-radius: 3px; + padding: 0px 3px 0px 3px; + border: 1px solid #999; + background-color: #ffffff; +} + +.ptx-content .webwork-button:hover { + cursor: pointer; + background-color: #e0e0ff; + border: 1px solid #000; +} +.ptx-content .webwork-button:active { + cursor: pointer; + background-color: #a0a0a0; + border: 1px solid #999; +} + +.webwork img, .webwork + .knowl-output img {max-width:100%;} + +.ptx-content .exercise-wrapper form button { + border-radius: 3px; + padding: 0px 3px 0px 3px; + border: 1px solid #999; + color: black; + background-color: #ffffff; +} +.ptx-content .webwork-button.activate { + width: 22px; + height: 22px; + background-image: url('https://raw.githubusercontent.com/openwebwork/webwork2/main/htdocs/images/favicon.ico'); + background-size: contain; + position: absolute; + right: -35px; +} + +article.project-like > .heading + div.ptx-runestone-container > div.runestone, +article.exercise-like > .heading + div.ptx-runestone-container > div.runestone { + margin-top: 0.5em; +} + +/* hack for runestone */ +/* +.ptx-content .exercise-wrapper form button.btn-success { + background-color: #5cb85c; +} +*/ +/* to undo Runestone's presentermode.css */ +.ptx-content .bottom { + position: unset; +} + +/* to undo Runestone's draganddrop.css */ +.ptx-content .rsdraggable { + font-size: 100%; +} + +.ptx-content .exercise-wrapper form button:hover { + cursor: pointer; + background-color: #e0e0ff; + border: 1px solid #000; +} +.ptx-content .exercise-wrapper form button:active { + background-color: #f0f0f0; +} +.ptx-content .exercise-wrapper form button + button { + margin-left: 0.8em; +} + +.ptx-content .exercise-wrapper, +.ptx-content .exercise-wrapper form, +.ptx-content .exercise-wrapper form > div:first-child { + display: inline-block; + vertical-align: top; + width: 100%; /* for live ww to open at 100% wide */ +} +.ptx-content .knowl .exercise-wrapper, +.ptx-content .knowl .exercise-wrapper form, +.ptx-content .knowl .exercise-wrapper form > div:first-child { + width: 100%; +} +/* +.ptx-content .exercise-wrapper form { + max-width: 95%; +} +*/ +.ptx-content .exercise-wrapper > .para:first-child, +.ptx-content .exercisegroup .exercise-wrapper > .para:first-child { + margin-top: 0; + display: inline; +} +/* next is realted to having exercises start in-line with their exercise number, + including when a static WW problem is made interactive */ +/* not sure this was the right way to do it */ +/* see https://opentext.uleth.ca/apex-calculus/sec_antider.html#exercise-722 */ +.ptx-content .heading + .exercise-wrapper { + display: inline-block; + max-width: 95%; + width: 100%; +} +/* +.ptx-content .exercisegroup .heading + .exercise-wrapper { + width: auto; +} +*/ +.ptx-content .cols2 .heading + .exercise-wrapper { + width: auto; +} + +/* next two need to be separate due to limitations in Chrome and Safari */ +@media screen and (max-width: 600px) { + .ptx-content .exercisegroup .cols2 > article.exercise-like {flex-basis: calc(100% - 2em);} + .ptx-content .exercisegroup .cols3 > article.exercise-like {flex-basis: calc(100% - 2em);} + .ptx-content .exercisegroup .cols4 > article.exercise-like {flex-basis: calc(50% - 2em);} + .ptx-content .exercisegroup .cols5 > article.exercise-like {flex-basis: calc(50% - 2em);} + .ptx-content .exercisegroup .cols6 > article.exercise-like {flex-basis: calc(33.3% - 2em);} + .ptx-content .exercisegroup .cols2 .heading + .exercise-wrapper { max-width: 100%; } +} +@media screen and (max-width: 850px) and (min-width: 786px) { + .ptx-content .exercisegroup .cols2 > article.exercise-like {flex-basis: calc(100% - 2em);} + .ptx-content .exercisegroup .cols3 > article.exercise-like {flex-basis: calc(100% - 2em);} + .ptx-content .exercisegroup .cols4 > article.exercise-like {flex-basis: calc(50% - 2em);} + .ptx-content .exercisegroup .cols5 > article.exercise-like {flex-basis: calc(50% - 2em);} + .ptx-content .exercisegroup .cols6 > article.exercise-like {flex-basis: calc(33.3% - 2em);} + .ptx-content .exercisegroup .cols2 .heading + .exercise-wrapper { max-width: 100%; } +} + +.APEXlogo { + white-space: nowrap; +} +.APEXlogo .A { + margin-right: -0.07em; +} +.APEXlogo .P { + margin-right: -0.33em; + position: relative; + top: -0.30em; +} +.APEXlogo .E { + position: relative; + top: 0.33em; +} + +/* testing */ + + +.runestone-profile .dropdown-content { + position: absolute; + display: none; + right: 0; + top: 35px; + text-align: left; + border: 1px solid; + border-color: #600; + border-color: var(--tocborder); +} +.runestone-profile.dropdown:hover { + background-color: #ddd; + overflow: visible; +} +.runestone-profile.dropdown:hover .dropdown-content { + display: block; +} +.runestone-profile .dropdown-content { + background-color: white; + z-index: 1800; + min-width: 100px; + padding: 5px; +} +.runestone-profile .dropdown-content a { + display: block; + text-decoration: none; + color: #662211; + padding: 2px 8px; +} +.runestone-profile.dropdown .dropdown-content a:hover { + background-color: #671d12; + color: #ffffff; + text-decoration: none; + background-color: var(--chaptertoc); +} +.runestone-profile.dropdown .dropdown-content hr { + margin-bottom: 4px; + margin-top: 4px; + border-color: #600; + border-color: var(--sectiontoctext); +} diff --git a/_static/pretext/css/pretext_search.css b/_static/pretext/css/pretext_search.css new file mode 100644 index 0000000..f49f956 --- /dev/null +++ b/_static/pretext/css/pretext_search.css @@ -0,0 +1,173 @@ +.searchresultsplaceholder article { + width: 60%; + margin-left: auto; + margin-right: auto; + font-family: sans-serif; +} + +.searchbox { +/* + height: 60px; + border: solid; + border-radius: 5px; + background-color: #eeee; +*/ + /* position: absolute; + top: 37px; + right: 0; */ +} + +.ptxsearch { + height: 35px; + flex: 1 1; +} + +.searchbutton .name { + display: none; +} + +.searchwidget { +/* + padding-top: 15px; + padding-left: 20px; + font-size: larger; +*/ + text-align: right; +} + +.searchwidget input { +/* + font-size: larger; +*/ +} + +.helpbox { + display: none; +} + +.detailed_result { + margin-bottom: 10px; +} + +.all_results a:link { + text-decoration: none; + font-size: large; +} + +.all_results a:hover { + background-color: lightgray; +} +.searchresults a:hover { + background-color: #eee; +} + +.searchresults a { + text-decoration: none; + color: #222; +} +.searchresults a:hover { + text-decoration: underline; + color: #33f; +} +.searchresults ul li { + list-style-type: none; +} +ol.searchresults { + padding-left: 10px; + margin-top: 0; + overflow-y: auto; + flex: 1 1; +} +ol.searchresults > li { + list-style-type: none; +} +.search-result-score { + display: none; +} +.high_result { + font-weight: 700; +} + +.medium_result { + font-weight: 500; +} + + +.low_result { + font-weight: 200; +} +.no_result { + font-weight: 200; + color: #444; +} +.detailed_result .no_result { + font-size: 90%; +} + +.searchresultsplaceholder { + position: fixed; + top: 5vh; + bottom: 5vh; + left: 152px; + width: 600px; + padding: 1em; + border: 0.2em solid #009; + background: aliceblue; + z-index: 5000; + display: flex; + flex-direction: column; +} + +.search-results-heading { + border-bottom: 1px solid rgba(0,0,125,0.5); +} + +.search-results-controls { + display:flex; + justify-content: space-between; + align-items: stretch; + gap: 10px; + margin-bottom: 1em; +} + +.closesearchresults { + display: flex; + justify-content: space-between; + align-items: center; + border: 1px solid black; +} +.closesearchresults:hover { + color: #c00; + background-color: #fee; + border-color: #f00; +} +.closesearchresults + h2 { + margin-top: -1em; +} +.searchempty { + display: none; + padding-left: 10px; + padding-top: 5px; +} +.search-result-bullet { + margin-top: 0.3em; +} +.search-result-clip { + font-size: 80%; + font-style: italic; + color: #444; + padding-left: 15px; +} +.search-results-unshown-count { + margin-top: 0.6em; +} +.search-result-clip-highlight { + background: rgba(255,255,0,0.5); +} +@media screen and (max-width: 800px) { + .searchresultsplaceholder { + width: 80vw; + left: 10vw; + bottom: 10vh; + } +} diff --git a/_static/pretext/css/reveal.css b/_static/pretext/css/reveal.css new file mode 100644 index 0000000..ce3bb71 --- /dev/null +++ b/_static/pretext/css/reveal.css @@ -0,0 +1,75 @@ + +ul { + display: block !important; +} +.reveal img { + border: 0.5px !important; + border-radius: 2px 10px 2px; + padding: 4px; +} +.definition,.theorem,.activity { + border-width: 0.5px; + border-style: solid; + border-radius: 2px 10px 2px; + padding: 1%; + margin-bottom: 2em; +} +.definition { + background: #00608010; +} +.theorem { + background: #ff000010; +} +.proof { + background: #ffffff90; +} +.activity { + background: #60800010; +} +dfn { + font-weight: bold; +} +.ptx-content ol.no-marker, +.ptx-content ul.no-marker, +.ptx-content li.no-marker { + list-style-type: none; +} + +.ptx-content ol.decimal { + list-style-type: decimal; +} +.ptx-content ol.lower-alpha { + list-style-type: lower-alpha; +} +.ptx-content ol.upper-alpha { + list-style-type: upper-alpha; +} +.ptx-content ol.lower-roman { + list-style-type: lower-roman; +} +.ptx-content ol.upper-roman { + list-style-type: upper-roman; +} +.ptx-content ul.disc { + list-style-type: disc; +} +.ptx-content ul.square { + list-style-type: square; +} +.ptx-content ul.circle { + list-style-type: circle; +} +.ptx-content ol.no-marker, +.ptx-content ul.no-marker { + list-style-type: none; +} +.ptx-content .cols1 li, +.ptx-content .cols2 li, +.ptx-content .cols3 li, +.ptx-content .cols4 li, +.ptx-content .cols5 li, +.ptx-content .cols6 li { + float: left; + padding-right:2em; +} + diff --git a/_static/pretext/css/setcolors.css b/_static/pretext/css/setcolors.css new file mode 100644 index 0000000..1e54aae --- /dev/null +++ b/_static/pretext/css/setcolors.css @@ -0,0 +1,452 @@ + +/* This file assigns the main colors, using variables that + have been set previously. */ + +body.pretext { + color: var(--bodyfontcolor); +} + +.ptx-masthead .title-container > .heading, .ptx-masthead .title-container > .heading a, .ptx-masthead .logo-link:empty:hover:before, .ptx-masthead .byline a { + color: var(--documenttitle, #2a5ea4); +} + +.ptx-masthead .title-container > .heading a:active, .ptx-masthead .logo-link:empty:active:before, .ptx-masthead .byline a:active { + color: var(--bodytitle, #932c1c); +} + + +/* Start by assuming any TOC item is a section, change others as appropriate */ +.ptx-toc .toc-item { + color: var(--sectiontoctext, #404040); + background-color: var(--sectiontoc); + border-color: var(--tocborder, #afc2e5); +} +.ptx-toc .toc-item.active { + color: var(--sectiontoctextactive); + background-color: var(--sectiontocactive); + border-color: var(--highlighttocborder); +} + +/* this looks weird but it matches previous ways the colors were applied */ +.ptx-toc:not(.depth2) .toc-chapter { + background-color: var(--chaptertocactive); + color: var(--chaptertoctextactive); +} +/* override for focused view */ +.ptx-toc.focused:not(.depth2) .toc-chapter { + background-color: var(--chaptertoc); + color: var(--chaptertoctext); +} + + +/* All top level items styled like chapters to match old styling */ +.ptx-toc > .toc-item-list > .toc-item { + color: var(--chaptertoctext); + background-color: var(--chaptertoc); +} +.ptx-toc > .toc-item-list > .toc-item.active { + color: var(--chaptertoctextactive); + background-color: var(--chaptertocactive); + border-color: var(--highlighttocborder); +} + + +.ptx-toc .toc-item > .toc-title-box > a:is(:hover, :focus) { + color: var(--highlighttoctext, #321a0c); + background-color: var(--highlighttoc); + border-color: var(--highlighttocborder, #ec704b); +} + +/* top level parts/front/backmatter styled as parts*/ +.ptx-toc.focused > .toc-item-list > :is(.toc-frontmatter, .toc-part, .toc-backmatter) { + background-color: var(--parttoc); + color: var(--parttoctext); +} +.ptx-toc.focused > .toc-item-list > :is(.toc-frontmatter, .toc-part, .toc-backmatter).active { + background-color: var(--parttocactive); + color: var(--parttoctextactive); +} + +.ptx-toc.focused .toc-chapter { + background-color: var(--chaptertoc); + color: var(--chaptertoctext); +} +.ptx-toc.focused .toc-chapter.active { + background-color: var(--chaptertocactive); + color: var(--chaptertoctextactive); +} + +/* Anything under a chapter, front matter, back matter styled as section */ +.ptx-toc.focused :is(.toc-chapter, .toc-frontmatter, .toc-backmatter) > ul > .toc-item { + background-color: var(--sectiontoc); + color: var(--sectiontoctext); +} +.ptx-toc.focused :is(.toc-chapter, .toc-frontmatter, .toc-backmatter) > ul > .toc-item.active { + background-color: var(--sectiontocactive); + color: var(--sectiontoctextactive); +} + + +.ptx-content .summary-links a { + color: var(--sectiontoctext); +} +.ptx-content .summary-links a:hover, .ptx-content .summary-links a:focus { + color: var(--highlighttoctext); + background: var(--highlighttoc); +} + +.ptx-content [data-knowl], .ptx-content [data-knowl]:hover, .ptx-content [data-knowl]:active, .ptx-content [data-knowl].active, .ptx-content summary { + color: var(--bodytitle); +} +.ptx-content [data-knowl]:hover, .ptx-content [data-knowl]:active, .ptx-content [data-knowl].active { + color: var(--bodyfontcolorhighlight); + background-color: var(--bodytitlehighlight); +} + +/* next two groups concern accessibility, so check when making changes */ +.ptx-content .para > a.internal { + color: var(--bodytitle); +} +.ptx-content .para > a.external { + color: var(--bodysubtitle); +} +.ptx-content .para > a.internal:hover, .ptx-content .para > a.internal:hover *, +.ptx-content .para > a.internal:focus, .ptx-content .para > a.internal:focus * { + color: var(--bodyfontcolorhighlight); + background-color: var(--bodytitlehighlight); +} +.ptx-content .para > a.external:hover, .ptx-content .para > a.external:hover *, +.ptx-content .para > a.external:focus, .ptx-content .para > a.external:focus * { + color: var(--bodyfontcolorhighlight); + background-color: var(--bodysubtitlehighlight); +} + +.ptx-content .playvideo { + background-color: var(--videoplay); +} + +.ptx-content .goal-like { + border-color: var(--chaptertoc); +} + +.ptx-content .assemblage-like { + border-color: var(--assemblageborder); + background-color: var(--assemblagebackground); +} + +.ptx-content .knowl-output { + border-color: var(--knowlborder); + background-color: var(--knowlbackground); +} +.ptx-content .knowl-footer { + background-color: var(--knowlborder); +} + +/* + pastel +*/ +.pretext[data-atmosphere="pastel"], +.pretext[data-atmosphere="pastel"] .ptx-main { + background: #dbf5ff; + background: #efe; +} +.pretext[data-atmosphere="pastel"] { + --documenttitle: #2a5ea4; + --bodytitle: #A62E1C; + --bodysubtitle: #2B5F82; + --bodytitlehighlight: #e0e9ff; + --bodyfonttitlehighlight: #306; + --bodysubtitlehighlight: #FCE5E4; + + --chaptertoc: #dbf5ff; + --chaptertoc: #dcdcf9; + --chaptertoctext: #444444; + --chaptertocactive: #fae5b6; + --chaptertoctextactive: #303030; + --sectiontoc: #ffeeee; + --sectiontoctext: #404040; + --sectiontocactive: #fae5b6; + --sectiontoctextactive: #202020; + --tocborder: #afc2e5; + + --highlighttoc: #fac793; + --highlighttoc: #fadfa3; + --highlighttoctext: #321a0c; + --highlighttocborder: #ec704b; + + --assemblageborder: #1100aa; + --assemblagebackground: #f4f4fe; + + --knowlborder: #e0e9ff; + --knowlbackground: #f5f8ff; +} + +.pretext[data-atmosphere="pastel"] .ptx-toc { + scrollbar-color: var(--documenttitlelight) #efe; +} +.pretext[data-atmosphere="pastel"] .ptx-navbar { + background: #efe; + background: #dbf5ff; +} +.pretext[data-atmosphere="pastel"] .ptx-masthead { + background: #efe; + background: #dbf5ff; +} +.pretext[data-atmosphere="pastel"] .ptx-sidebar { + background: #ffd; +} + +/* twilight */ + +.pretext[data-atmosphere="darktwilight"] { + --bodyfontcolor: #ddd; + --bodyfontcolorhighlight: #222; + --documenttitle: #2a5ea4; + --documenttitledark: #20477b; + --documenttitlelight: #abd; + --bodytitle: #abd; + --bodysubtitle: #dcb; + --bodytitlehighlight: #ad6; + --bodyfonttitlehighlight: #306; + --bodysubtitlehighlight: #363; + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: hsl(9, 72%, 30%); /* #832615; */ + --chaptertoctext: #dee; + --chaptertocactive: var(--documenttitle); + --chaptertoctextactive: white; + --sectiontoc: hsl(0, 0%, 40%); + --sectiontoctext: #eed; + --sectiontocactive: var(--documenttitle); + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: var(--documenttitledark); + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + --assemblagebackground: #003; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); + + --bannerbackground: hsl(0, 0%, 33%); + --navbarbackground: hsl(0, 0%, 33%); + --footerbackground: hsl(0, 0%, 30%); + --mainbackground: hsl(0, 0%, 27%); + --buttonbackground: hsl(225, 80%, 25%); + --codebackground: hsl(120, 100%, 17%); + --linkbackground: hsl(120, 90%, 23%); + --linkbackgroundhighlight: hsl(0, 0%, 70%); + --keybackground: hsl(0, 100%, 20%); + +} + +/* dark */ + +.pretext[data-atmosphere="dark"] { + --bodyfontcolor: #ddd; + --bodyfontcolorhighlight: #222; + --documenttitle: #2a5ea4; + --documenttitledark: #20477b; + --documenttitlelight: #8ab; + --bodytitle: #abd; + --bodysubtitle: #dcb; + --bodytitlehighlight: #ad6; + --bodyfonttitlehighlight: #306; + --bodysubtitlehighlight: #363; + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: hsl(5, 86%, 24%); + --chaptertoctext: #dee; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: hsl(0, 0%, 27%); + --sectiontoctext: #eed; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: var(--documenttitledark); + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + --assemblagebackground: #003; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); + + --bannerbackground: hsl(0, 0%, 20%); + --navbarbackground: hsl(0, 0%, 20%); + --footerbackground: hsl(0, 0%, 22%); + --mainbackground: hsl(0, 0%, 17%); + --buttonbackground: hsl(232, 90%, 19%); + --codebackground: hsl(120, 100%, 15%); + --linkbackground: hsl(120, 90%, 20%); + --linkbackgroundhighlight: hsl(0, 0%, 70%); + --keybackground: hsl(0, 100%, 19%); + +} + + +/* midnight */ + +.pretext[data-atmosphere="darkmidnight"] { + --bodyfontcolor: #ddd; + --bodyfontcolorhighlight: #222; + --documenttitle: #2a5ea4; + --documenttitledark: #20477b; + --documenttitlelight: #8ab; + --bodytitle: #abd; + --bodysubtitle: #dcb; + --bodytitlehighlight: #ad9; + --bodyfonttitlehighlight: #306; + --bodysubtitlehighlight: #363; + /* + The bodytitle and bodysubtitle colors must have at least a 3:1 contrast + ratio with black, and at least 5:1 ratio with with the corresponding highlight. + (The second condition will guarantee an adequate contrast with white.) + */ + + --chaptertoc: hsl(0, 100%, 17%); + --chaptertoctext: #dee; + --chaptertocactive: var(--documenttitle); /* often the same as documenttitle */ + --chaptertoctextactive: white; + --sectiontoc: hsl(0, 0%, 13%); + --sectiontoctext: #eed; + --sectiontocactive: var(--documenttitle); /* often the same as documenttitle */ + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: var(--documenttitledark); + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + --assemblagebackground: #003; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); + + --bannerbackground: hsl(0, 0%, 16%); + --navbarbackground: hsl(0, 0%, 16%); + --footerbackground: hsl(0, 0%, 13%); + --mainbackground: hsl(0, 0%, 7%); + --buttonbackground: hsl(240, 100%, 13%); + --codebackground: hsl(120, 100%, 17%); + --linkbackground: hsl(120, 90%, 20%); + --linkbackgroundhighlight: hsl(0, 0%, 70%); + --keybackground: hsl(0, 100%, 17%); +} + +.pretext[data-atmosphere*="dark"] { + background: var(--mainbackground); +} +.pretext[data-atmosphere*="dark"] .ptx-page > .ptx-main { + background: var(--mainbackground); + color: var(--bodyfontcolor); +} +.pretext[data-atmosphere*="dark"] .ptx-content .summary-links a { + background: var(--documenttitledark); + background: var(--chaptertoc); +} +.pretext[data-atmosphere*="dark"] .ptx-navbar { + background: var(--navbarbackground); +} +.pretext[data-atmosphere*="dark"] .ptx-page-footer .feedback-link, +.pretext[data-atmosphere*="dark"] .ptx-content-footer .button, +.pretext[data-atmosphere*="dark"] .ptx-navbar .button { + background-color: var(--buttonbackground); + color: var(--bodyfontcolor); +} +.pretext[data-atmosphere*="dark"] .ptx-page-footer .feedback-link:hover, +.pretext[data-atmosphere*="dark"] .ptx-content-footer .button:hover, +.pretext[data-atmosphere*="dark"] .ptx-navbar .button:hover, +.pretext[data-atmosphere*="dark"] .ptx-content-footer .button:hover { + background-color: var(--linkbackgroundhighlight); + color: var(--bodyfontcolorhighlight); +} +.pretext[data-atmosphere*="dark"] .ptx-navbar .calculator-toggle { + background-color: var(--buttonbackground); +} +.pretext[data-atmosphere*="dark"] .ptx-navbar .calculator-toggle:hover { + background-color: var(--linkbackgroundhighlight); + color: var(--bodyfontcolorhighlight); +} + +.pretext[data-atmosphere*="dark"] .ptx-masthead { + background: var(--bannerbackground); +} + +.pretext[data-atmosphere*="dark"] .ptx-page-footer { + background: var(--footerbackground); + border-top-color: #447; + border-bottom-color: #447; +} +.pretext[data-atmosphere*="dark"] .ptx-page-footer .logo { + background: #779; + border-radius: 0.4em; +} +.pretext[data-atmosphere*="dark"] .ptx-masthead .title-container > .pretext .heading, +.pretext[data-atmosphere*="dark"] .ptx-masthead .title-container > .heading a, +.pretext[data-atmosphere*="dark"] .ptx-masthead .logo-link:empty:hover::before, +.pretext[data-atmosphere*="dark"] .ptx-masthead .byline, +.pretext[data-atmosphere*="dark"] .ptx-masthead .byline a { + color: var(--documenttitlelight); +} +.pretext[data-atmosphere*="dark"] .ptx-toc { + scrollbar-color: var(--documenttitlelight) var(--footerbackground); +} +.pretext[data-atmosphere*="dark"] .ptx-content .code-inline { +/* + color: var(--documenttitledark); +*/ + background: var(--codebackground); +} +.pretext[data-atmosphere*="dark"] .ptx-content .kbdkey { +/* + color: var(--documenttitledark); +*/ + background: var(--keybackground); +} +.pretext[data-atmosphere*="dark"] .ptx-content .goal-like > .heading { + background: var(--chaptertoc); +} +.pretext[data-atmosphere*="dark"] .ptx-content a.url, +.pretext[data-atmosphere*="dark"] .ptx-content a.internal, +.pretext[data-atmosphere*="dark"] .ptx-content a.external { + color: #ddc; + background-color: var(--linkbackground); + color: var(--bodyfontcolor); +} + +.pretext[data-atmosphere*="dark"] .ptx-content [data-knowl] { + background-color: var(--linkbackground); + color: var(--bodyfontcolor); +} +.pretext[data-atmosphere*="dark"] .ptx-content [data-knowl]:hover, +.pretext[data-atmosphere*="dark"] .ptx-content [data-knowl]:active, +.pretext[data-atmosphere*="dark"] .ptx-content [data-knowl].active { + background-color: var(--linkbackgroundhighlight); + color: var(--bodyfontcolorhighlight); +} +.pretext[data-atmosphere*="dark"] .ptx-page .ptx-main .ptx-content .knowl-content > .solution-like { + background: #606; +} + diff --git a/_static/pretext/css/shell_crc.css b/_static/pretext/css/shell_crc.css new file mode 100644 index 0000000..700d042 --- /dev/null +++ b/_static/pretext/css/shell_crc.css @@ -0,0 +1,408 @@ +/******************************************************************************* + * shell_X.css controls the overall arrangement of the blocks on the page. + ******************************************************************************* + * + * Author: Thomas Shemanske + * + ******************************************************************************* + */ + +/* The overall structure is + html + head + body.pretext + header.ptx-masthead + nav.ptx-navbar + div.ptx-page + div.sidebar + nav.ptx-toc + main.ptx-main + div.ptx-content + div.ptx-content-footer + div.ptx-page-footer +*/ + +/* Supplied by colors_bluegreen_grey.css */ +/* +:root{ + --bluegreen: hsl(192, 98%, 23%); + --bodytitle: var(--bluegreen); + --bodysubtitle: var(--bluegreen); +} +*/ + +/* over-ride some of the default style */ + +.pretext .ptx-page > .ptx-main { + margin-left: unset; +} +.ptx-masthead .logo-link img { + width: unset; + height: unset; + max-height: unset; +} +.ptx-masthead .logo-link { + font-size: unset; + text-align: unset; + line-height: unset; +} +.pretext .ptx-masthead { + position: unset; + background: unset; + min-height: unset; + border: unset; + position: unset; + z-index: unset; +} + +.ptx-content-footer .previous-button .name { + margin-left: unset; + padding-right: unset; +} +.pretext .ptx-content-footer .name { + position: relative; + bottom: 0; +} +.pretext .ptx-content-footer .button.previous-button, .pretext .ptx-content-footer .button.next-button { + font-size: 0.8em; + margin-top: 1.5em; + padding: 0.4em; +} +.pretext .ptx-content-footer .top-button .icon, .pretext .ptx-content-footer .top-button .name { + display: unset; +} +.pretext .ptx-content-footer .previous-button .icon { + margin-left: unset; + margin-right: unset; +} +.pretext .ptx-content-footer .button { + text-align: unset; +/* + color: unset; + background-color: unset; +*/ + padding: 0; + display: flex; + align-items: center; + justify-content: center; + height: 35px; + min-width: 85px; +} + +/* Elements introduced in order of appearance */ + +/* .ptx-container */ +body.pretext { +/* + position: relative; +*/ + max-width: 904px; /* To match PreTeXt */ + margin: 0 auto 0 auto; /* centered content */ + padding: 0; + box-sizing: border-box; +} + +/* .ptx-masthead-wrapper */ +.pretext .ptx-masthead { + border: 2px solid #ddd; + border-bottom: none; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + /* overflow: hidden;*/ /* otherwise the rounded corners are not visible */ +} +.pretext .ptx-masthead { + position: relative; + background: #fafafa; + min-height: inherit; + box-shadow: none; +} +.pretext .ptx-masthead { + max-width: 904px; + border-right: 1px solid #bababa; +} +@media only screen and (min-width: 600px) { + /* .ptx-masthead-wrapper {*/ + .ptx-masthead { + z-index: 100; + } +} +.ptx-masthead .searchbox { + bottom: 2px; + margin-right: -19px; +} + +/* .ptx-main-wrapper */ +.ptx-page { + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 1.0em; + min-height: 100vh; + + display: grid; + grid-template-columns: auto 1fr auto; + grid-template-rows: auto; + grid-template-areas: + "toc main-content" + "toc content-footer"; +} +.ptx-content { + min-height: 50vh; +} + +/* MH-toc dropdown Content (Hidden by Default) */ +.ptx-sidebar { + position: sticky; + top: 34px; + background-color: #f1f1f1; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + width: 240px; + max-height: 100vh; + height: 100vh; + grid-area: toc; + grid-column-start: 1; + grid-column-end: 2; + grid-row-start: 1; + grid-row-end: 3; + +/* + overflow-y: auto; + overflow-x: hidden; +*/ + border: 2px solid var(--bluegreen); + border-radius:5px; + z-index: 1; +} + +/* .ptx-main-content */ +.ptx-page > .ptx-main { + grid-area: main-content; + grid-column-start: 2; + grid-column-end: 3; + grid-row-start: 1; + grid-row-end: 2; + + justify-self: start; + max-width: 664px; + width: 97vw; + transition: 0s; + padding: 0; + margin: 0; + z-index: 0; /* Added so horizontal scrollbars in content don't bleed into TOC dropdown */ + // overflow-y: auto; + // border: 2px solid green; +} + +@media only screen and (min-width: 500px) { + .ptx-page > .ptx-main { + margin: 0; + max-width: 664px; + width: min(100vw,664px); + justify-self: center; + /* width: 570px; @ 810px */ + } + +} +.ptx-page > .ptx-main > .ptx-content { + margin-left: 2em; +} + +/* Content footer wrapper playground */ + +.pretext .ptx-page .ptx-content-footer { + display: grid; + max-width: 100%; + grid-template-columns: 1fr 1fr 1fr; + grid-template-areas: + "content-footer-prev content-footer-top content-footer-next"; + margin-left: 32px; + margin-top: 30px; +} + +.ptx-content-footer .previous-button { + grid-area: content-footer-prev; + + justify-self: start; + align-self: center; + margin: 20px; + padding: 5px; + + display: inline-block; + height: 32px; + color: var(--bodytitle); + font-family: inherit; + text-align: center; + font-size: .8em; + font-weight: 700; + letter-spacing: .1rem; + text-transform: uppercase; + text-decoration: none; + white-space: nowrap; + background-color: #eee; + border-radius: 4px; + border: 1px solid #888; + cursor: pointer; + box-sizing: border-box; + +} + +.ptx-content-footer .previous-button:hover{ + background-color: #fafafa; + color: #888; +} + + +.ptx-content-footer .previous-button .name{ + margin-left: 2px; + padding-right: 5px; +} + +.ptx-content-footer .previous-button .icon{ + padding-left: 5px; +} + +.ptx-content-footer .top-button{ + grid-area: content-footer-top; + justify-self: center; + align-self: center; + margin: 20px; + padding: 5px; + + display: inline-block; + height: 32px; + color: var(--bodytitle); + font-family: inherit; + text-align: center; + font-size: .8em; + font-weight: 700; + letter-spacing: .1rem; + text-transform: uppercase; + text-decoration: none; + white-space: nowrap; + background-color: #eee; + border-radius: 4px; + border: 1px solid #888; + cursor: pointer; + box-sizing: border-box; +} + +.ptx-content-footer .top-button:hover{ + background-color: #fafafa; + color: #888; +} + + color: #888; +} + +.ptx-content-footer .top-button .name{ + margin-left: 2px; + padding-right: 5px; + +} + +.ptx-content-footer .top-button .icon{ + padding-left: 5px; +} + +.ptx-content-footer .next-button { + grid-area: content-footer-next; + justify-self: end; + align-self: center; + margin: 20px; + padding: 5px; + + display: inline-block; + height: 32px; + color: var(--bodytitle); + font-family: inherit; + text-align: center; + font-size: .8em; + font-weight: 700; + letter-spacing: .1rem; + text-transform: uppercase; + text-decoration: none; + white-space: nowrap; + background-color: #eee; + border-radius: 4px; + border: 1px solid #888; + cursor: pointer; + box-sizing: border-box; + + +} + +.ptx-content-footer .next-button:hover{ + background-color: #fafafa; + color: #888; +} + +.ptx-content-footer .next-button .name{ + margin-right: 2px; + padding-left: 5px + +} + +.ptx-content-footer .next-button .icon{ + padding-right:5px; +} + +.pretext .ptx-sidebar.visible { + display: block; +} + +@media only screen and (max-width: 800px) { + + .pretext .ptx-sidebar { + display: none; + } +/* copied from shell_default.css Wher is ptx-navbar set in the CRC style */ +.pretext .ptx-navbar { + position: fixed; + top: auto; + bottom: 0; + z-index: 1100; + } + .pretext .ptx-sidebar { + display: none; + position: fixed; + top: 10px; + z-index: 1000; + background: white; + } +} + +.pretext .ptx-page-footer .feedback-link { + cursor: pointer; + text-align: center; + color: #333333; + background-color: #ededed; + border: 1px solid #bababa; + margin: 1.5em 0 0 0; + padding: 0 1em 0 1em; + height: 2em; + display: flex; + align-items: center; +} +.pretext .ptx-page-footer { + background: #f4f4f4; + margin-top: 2em; + padding-top: 0; + max-width: 900px; + border-top: 2px solid var(--sectiontoctext); + border-bottom: 2px solid var(--sectiontoctext); + display: flex; + flex-direction: row; + justify-content: space-around; + position: relative; +/* + z-index: 100; +*/ +} + +.pretext .ptx-page-footer > a { + margin: 1em 0; +} +.pretext .ptx-page-footer > a > .logo:first-child { + height: 3em; + width: unset; + margin: 0; +} + diff --git a/_static/pretext/css/shell_default.css b/_static/pretext/css/shell_default.css new file mode 100644 index 0000000..823c911 --- /dev/null +++ b/_static/pretext/css/shell_default.css @@ -0,0 +1,260 @@ +/******************************************************************************* + * shell_X.css controls the overall arrangement of the blocks on the page. + ******************************************************************************* + * + * Authors: David Farmer, Rob Beezer + * + ******************************************************************************* + */ + +/* The overall structure is + html + head + body.pretext + header.ptx-masthead + nav.ptx-navbar + div.ptx-page + div.sidebar + nav.ptx-toc + main.ptx-main + div.ptx-content + div.ptx-content-footer + div.ptx-page-footer +*/ + +.pretext .ptx-masthead { + position: relative; + background: #fafafa; + min-height: inherit; + border: none; + position: relative; +} + +.pretext .ptx-navbar { + position: sticky; + top: 0; + max-width: 904px; + height: 36px; +} + +.pretext .ptx-page { + position: relative; + min-height: 100vh; +} +.ptx-content { + min-height: 60vh; +} + +.pretext .ptx-sidebar { + position: sticky; + top: 36px; + left: 0; + float: left; + width: 240px; +} + +.pretext .ptx-toc { + position: sticky; + top: 50px; + box-sizing: border-box; + overflow-y: scroll; + height: calc(100vh - 60px); +} + +.pretext .ptx-page > .ptx-main { + display: block; + position: relative; + overflow-y: hidden; + margin: 0 0 0 240px; + padding: 1px 0 0 0; + background: white; + border-left: 1px solid #ccc; +} +.pretext .ptx-page .ptx-sidebar.hidden + .ptx-main { + margin-left: 0; +} +.pretext .ptx-page > .ptx-main.notoc { + margin-left: 0; + transition-property: margin-left; + transition-duration: 0.3s; +} +@media screen and (max-width: 800px) { + .pretext .ptx-page > .ptx-main { + margin-left: 0; + left: auto; + } + .pretext .ptx-page-footer { + /* Make space for navbar fixed to bottom of screen */ + margin-bottom: 38px; + } +} + +.pretext .ptx-page > .ptx-main .ptx-content { + max-width: 600px; + margin: 32px; +} +@media screen and (max-width: 663px) { + .pretext .ptx-page > .ptx-main .ptx-content { + /* Decrease the margins */ + margin: 28px; + } +} + +/* +.ptx-content.serif .para { + font-family: "PT Serif", "Times New Roman", serif; + font-size: 105%; +} +.ptx-content.serif #text-in-paragraphs .para, +.ptx-content.serif #Bcd .para, +.ptx-content.serif #interesting-corollary .para { + font-family: "Roboto Serif", serif; + font-size: 12pt; + line-height: 1.20; + font-variation-settings: 'wdth' 100; + +} +.ptx-content.serif #table-calisthenics .para, +.ptx-content.serif #section-7 .para, +.ptx-content.serif #section-11 .para { + font-family: "Tinos", serif; + font-size: 115%; + line-height: 1.30; +} + +.ptx-content.serif #section-6 .para, +.ptx-content.serif #section-6 .para { + font-family: "Noto", serif; + font-size: 115%; + line-height: 1.30; +} +*/ + +/* text in lists was big */ +.ptx-content.serif .para .para, +.ptx-content[data-font="RS"] .para .para { + font-size: 100%; +} + +.ptx-content[data-font="RS"] .code-inline { + background: #f6f6f6; + border: 1px solid #eee; + padding: 0.01em 0.15em 0.03em 0.15em; + margin-left: 0.15em; + margin-right: 0.15em; + border-radius: 0; +} + +.pretext .ptx-content-footer { + margin-top: 2em; + display: flex; + justify-content: space-around; + max-width: 600px; + margin-left: 32px; +} + +.pretext .ptx-content-footer .button { + min-width: 80px; + height: 35px; + color: #333333; + background-color: #ededed; + border: 1px solid #bababa; + padding: 0 10px; + display: flex; + gap: 10px; + align-items: center; + justify-content: center; + /* Disable accidental text-selection */ + user-select: none; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.pretext .ptx-content-footer .button .icon { + margin: 0 -7px; /* icons have lots of whitespace */ +} + +.pretext .ptx-content-footer .button:hover, +.pretext .ptx-content-footer .button:active, +.pretext .ptx-content-footer .button:focus { + background-color: #fafafa; +} + + +.pretext .ptx-sidebar.visible { + display: block; +} + + +.pretext .ptx-page-footer .feedback-link { + cursor: pointer; + text-align: center; + color: #333333; + background-color: #ededed; + border: 1px solid #bababa; + margin: 1.5em 0 0 0; + padding: 0 1em 0 1em; + height: 2em; + display: flex; + align-items: center; +} +.pretext .ptx-page-footer { + background: #f4f4f4; + margin-top: 2em; + padding-top: 0; + max-width: 900px; + border-top: 2px solid var(--sectiontoctext); + border-bottom: 2px solid var(--sectiontoctext); + display: flex; + flex-direction: row; + justify-content: space-around; + position: relative; +/* + z-index: 100; +*/ +} + +.pretext .ptx-page-footer > a { + margin: 1em 0; +} +.pretext .ptx-page-footer > a > .logo:first-child { + height: 3em; + width: unset; + margin: 0; +} + + + +@media screen and (max-width: 800px) { + .pretext .ptx-navbar { + position: fixed; + top: auto; + bottom: 0; + z-index: 1100; + } + .pretext .ptx-sidebar { + display: none; + position: fixed; + top: 10px; + z-index: 1000; + background: white; + } + .pretext .ptx-content-footer { + display: none; + } +/* + .pretext .ptx-content-footer { + margin-bottom: 60px; + } +*/ + .pretext .ptx-toc { + height: calc(100vh - 50px); + } +} + +/******************************************************************************* + * + * Authors: David Farmer, Rob Beezer + * + ******************************************************************************* + */ diff --git a/_static/pretext/css/shell_min.css b/_static/pretext/css/shell_min.css new file mode 100644 index 0000000..1c1ead3 --- /dev/null +++ b/_static/pretext/css/shell_min.css @@ -0,0 +1,273 @@ +/******************************************************************************* + * shell_X.css controls the overall arrangement of the blocks on the page. + ******************************************************************************* + * + * Authors: David Farmer, Rob Beezer + * + ******************************************************************************* + */ + +/* The overall structure is + html + head + body.pretext + header.ptx-masthead + nav.ptx-navbar + div.ptx-page + div.sidebar + nav.ptx-toc + main.ptx-main + div.ptx-content + div.ptx-content-footer + div.ptx-page-footer +*/ + +.pretext .ptx-masthead { + position: relative; + background: #fafafa; + min-height: inherit; + border: none; +} + +.pretext .ptx-navbar { + position: sticky; + top: 0; + max-width: 904px; +} + +.pretext .ptx-page { + position: relative; +} + +.pretext .ptx-sidebar { + position: sticky; + top: 41px; + float: left; + width: 240px; +} + +.pretext .ptx-toc { + position: sticky; + top: 50px; + box-sizing: border-box; + overflow-y: scroll; + height: calc(100vh - 60px); +} + +.pretext .ptx-page > .ptx-main { + display: block; + position: relative; + overflow-y: hidden; + margin: 0 0 0 240px; + padding: 1px 0 0 0; + background: white; + border-left: 1px solid #ccc; +} +@media screen and (max-width: 800px) { + .pretext .ptx-page > .ptx-main { + margin-left: 0; + left: auto; + } +} + +.pretext .ptx-page > .ptx-main .ptx-content { + max-width: 600px; + margin: 32px; +} +@media screen and (max-width: 663px) { + .pretext .ptx-page > .ptx-main .ptx-content { + /* Decrease the margins */ + margin: 28px; + } +} + +/* +.ptx-content.serif .para { + font-family: "PT Serif", "Times New Roman", serif; + font-size: 105%; +} +.ptx-content.serif #text-in-paragraphs .para, +.ptx-content.serif #Bcd .para, +.ptx-content.serif #interesting-corollary .para { + font-family: "Roboto Serif", serif; + font-size: 12pt; + line-height: 1.20; + font-variation-settings: 'wdth' 100; + +} +.ptx-content.serif #table-calisthenics .para, +.ptx-content.serif #section-7 .para, +.ptx-content.serif #section-11 .para { + font-family: "Tinos", serif; + font-size: 115%; + line-height: 1.30; +} + +.ptx-content.serif #section-6 .para, +.ptx-content.serif #section-6 .para { + font-family: "Noto", serif; + font-size: 115%; + line-height: 1.30; +} +*/ + +/* text in lists was big */ +.ptx-content.serif .para .para, +.ptx-content[data-font="RS"] .para .para { + font-size: 100%; +} + +.ptx-content[data-font="RS"] .code-inline { + background: #f6f6f6; + border: 1px solid #eee; + padding: 0.01em 0.15em 0.03em 0.15em; + margin-left: 0.15em; + margin-right: 0.15em; + border-radius: 0; +} + +.pretext .ptx-content-footer { + margin-top: 2em; + display: flex; + flex-direction: row; + justify-content: space-around; + max-width: 650px; +} +.pretext .ptx-content-footer .button { + cursor: pointer; + text-align: center; + color: #333333; + background-color: #ededed; + border: 1px solid #bababa; + padding: 0; + display: flex; + align-items: center; +} +.pretext .ptx-content-footer .button:hover, +.pretext .ptx-content-footer .button:active, +.pretext .ptx-content-footer .button:focus { + background-color: #fafafa; +} + +.pretext .ptx-content-footer .button.top-button { + text-align: center; + width: 40px; + height: 50px; +} +.pretext .ptx-content-footer .button.previous-button, +.pretext .ptx-content-footer .button.next-button { + font-size: 1.0em; + cursor: pointer; + display: inline-block; + vertical-align: middle; + height: 35px; + width: 65px; + /* Disable accidental text-selection */ + user-select: none; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + float: left; + position: relative; + margin-top: 0.5em; +} +.pretext .ptx-content-footer .previous-button { + text-align: left; +} +.pretext .ptx-content-footer .next-button { + text-align: right; +} + +.pretext .ptx-content-footer .name { + position: relative; + bottom: 0; +} +.pretext .ptx-content-footer .icon { + font-size: 1.3em; + Position: relative; + bottom: -0.1em; +} +.pretext .ptx-content-footer .previous-button .icon { + margin-left: 0.3em; + margin-right: 0.2em; +} +.pretext .ptx-content-footer .next-button .icon { + margin-left: 0.2em; + margin-right: 0.3em; +} +.pretext .ptx-content-footer .next-button { + text-align: right; +} +.pretext .ptx-content-footer .previous-button { + width: 70px; + float: right; + border-left: 1px solid #bababa; + border-right: 1px solid #bababa; +} +.pretext .ptx-content-footer .next-button { + width: 70px; + float: right; + border-right: 1px solid #bababa; +} + + + +.pretext .ptx-content-footer .top-button { + display: block; +} + +.pretext .ptx-content-footer .top-button .icon, +.pretext .ptx-content-footer .top-button .name { + display: block; +} +.pretext .ptx-content-footer .top-button .icon { + bottom: 0; +} +.pretext .ptx-content-footer .top-button .name { + position: relative; + bottom: 0.4em; +} + +@media screen and (max-width: 800px) { + .pretext .ptx-navbar { + position: fixed; + top: auto; + bottom: 0; + } + .pretext .ptx-sidebar { + display: none; + } + .pretext .ptx-content-footer { + display: none; + } +/* + .pretext .ptx-content-footer { + margin-bottom: 60px; + } +*/ + .pretext .ptx-toc { + height: calc(100vh - 50px); + } + .pretext .ptx-navbar .calculator-toggle, + .pretext .ptx-navbar .index-button { + display: none; + } + .pretext .ptx-navbar .toc-toggle { + width: 25%; + } + .pretext .ptx-navbar .treebuttons { + width: 75%; + } + .pretext .ptx-navbar .previous-button, + .pretext .ptx-navbar .up-button, + .pretext .ptx-navbar .next-button { + width: 33.3%; + } +} + +/******************************************************************************* + * + * Authors: David Farmer, Rob Beezer + * + ******************************************************************************* + */ diff --git a/_static/pretext/css/shell_wide.css b/_static/pretext/css/shell_wide.css new file mode 100644 index 0000000..93418b6 --- /dev/null +++ b/_static/pretext/css/shell_wide.css @@ -0,0 +1,350 @@ +@import url("shell_default.css"); + +:root { + --content-margin: 32px; + --content-width: 750px; + --content-width-wide: 1050px; + --page-width: 1100px; + --xl-margin: calc( + (var(--content-width) - var(--content-width-wide)) / 2 - + var(--content-margin) + ); + + --content-font-size: 1.2rem; +} + +html { + font-size: 16px !important; /* temp override runestone injection */ +} + +:root { + --questionBgColor: var(--componentBgColor) !important; +} + +:root { + --component-border-color: #bababa; + --page-gutter-color: #c5c4c4; + --page-border-color: #444; + --page-color: white; +} + +.pretext .ptx-masthead { + border-bottom: 1px solid var(--component-border-color); +} + +body.pretext { + background-color: var(--page-gutter-color); +} + +.pretext .ptx-page { + position: relative; + min-height: 100vh; + max-width: var(--page-width); + margin: 0 auto; + background: var(--page-color); + + box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); +} + +.searchresultsplaceholder { + left: calc(50vw - 300px); +} + +.pretext .ptx-page .ptx-main { + max-width: var(--content-width); + margin: 0 auto; + padding-bottom: 2em; + border: 0; + overflow: visible; +} + +.pretext .ptx-page .ptx-sidebar.hidden + .ptx-main { + margin: 0 auto; +} + +.pretext .ptx-page > .ptx-main .ptx-content { + max-width: var(--content-width); + font-size: var(--content-font-size); +} + +.pretext .ptx-page-footer { + max-width: var(--page-width); + justify-content: center; + margin: 0 auto; + gap: 90px; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); + border-bottom: 0; +} + +.pretext .ptx-content-footer { + max-width: 100%; + margin: 2em auto 0; + padding-bottom: 2em; + justify-content: space-evenly; +} + +.pretext .ptx-page-footer a { + --margin: 15px 45px; +} + +/* components that should be wide */ +.ptx-content + .runestone:is(.ac_section, .codelens, .parsons_section, .hparsons_section), +/* .ptx-content pre.program, */ +.ptx-content .runestone.datafile, +.ptx-content .contains-wide { + width: var(--content-width-wide); + max-width: unset; + margin-left: var(--xl-margin); + max-width: unset; + border-width: 1px; + border-radius: 3px; +} + +/* unless nested in other runestone's */ +.ptx-content + .runestone + .runestone:is(.ac_section, .codelens, .parsons_section, .hparsons_section), +/* .ptx-content .runestone pre.program, */ +.ptx-content .runestone .runestone.datafile { + width: 100%; + margin-left: auto; +} + +.ptx-content .runestone { + border-width: 1px; + border-radius: 3px; +} + +.pretext .ptx-page > .ptx-main .ptx-content pre, +.pretext + .ptx-page + > .ptx-main + .ptx-content + .ptx-runestone-container + :is(.ac_code_div), +.ptx-runestone-container .parsons .sortable-code-container, +.ptx-runestone-container .hparsons_section .hparsons-input { + font-size: 1rem; +} + +/* limit width of content inside ac except for actual activecode */ +.ptx-content + .runestone.ac_section + > div + > div + > *:not(.ac_code_div):not(.ac_output):not(.codelens):not(.ac_actions) { + max-width: calc(var(--content-width) - 2 * var(--content-margin)); + margin-left: auto; + margin-right: auto; +} + + +/* limit width of content inside contains-wide */ +.ptx-content .runestone.contains-wide .tab-content { + max-width: var(--content-width); + margin-left: auto; + margin-right: auto; +} + +/* but widen item that needs it */ +.ptx-content .runestone.contains-wide .tab-content + .runestone:is(.ac_section, .codelens, .parsons_section, .hparsons_section) { + width: calc(var(--content-width-wide) - 20px); + margin-left: calc(var(--xl-margin) + 8px); + } + + +/* limit width of content inside parsons except for actual parsons */ +.ptx-content .runestone.parsons_section > .parsons { + width: 100%; + padding-right: 0; +} + +.ptx-content + .runestone.parsons_section + > .parsons + > div + > *:not(.sortable-code-container) { + max-width: calc(var(--content-width) - 2 * var(--content-margin)); + margin-left: auto; + margin-right: auto; +} + +.ptx-content .runestone .parsons .sortable-code-container { + display: flex; + flex-flow: wrap; + justify-content: center; + gap: 15px; + margin: 10px auto; +} + +.ptx-content .ptx-runestone-container .parsons .sortable-code { + margin: 0; +} + +.ptx-content .runestone .parsons .runestone_caption_text { + max-width: unset; +} + +.ptx-content .runestone .parsons .lines code { + white-space: nowrap; +} + +.ptx-content .runestone .parsons .lines code .token { + background: none; /*fix prism overlap */ +} + +.ptx-runestone-container .runestone.parsons_section { + padding-top: 15px; +} + +/* whole bunch of rules to relatively gracefully handle lots of different sizes without js */ +@media screen and (max-width: 1100px) { + /* tune to match --page-width */ + :root { + --page-width: 100%; + } +} + +@media screen and (max-width: 1100px) { + :root { + --content-width-wide: 1000px; + } +} + +@media screen and (max-width: 1050px) { + :root { + --content-width-wide: 950px; + } +} + +@media screen and (max-width: 1000px) { + :root { + --content-width-wide: 900px; + } +} + +@media screen and (max-width: 950px) { + :root { + --content-width-wide: 850px; + } +} + +@media screen and (max-width: 900px) { + :root { + --content-width-wide: 800px; + } +} + +@media screen and (max-width: 943px) { + /* Override rule that adds scrollbars to program listings when not needed */ + .ptx-content .figure-like { + overflow-x: inherit; + } +} + +@media screen and (max-width: 850px) { + /* match to --content-width - should be that + 100 */ + :root { + --content-width: 100%; + --content-width-wide: calc(100% + 2 * var(--content-margin)); + --xl-margin: calc(-1 * var(--content-margin)); + } + + /* nested sizing */ + .ptx-content + article:is( + .theorem-like, + .definition-like, + .example-like, + .project-like, + .remark-like, + .openproblem-like, + .openproblems-like, + .computation-like + ) + > .ptx-runestone-container + > .runestone:is( + .ac_section, + .codelens, + .parsons_section, + .hparsons_section + ), + /* .ptx-content + article:is( + .theorem-like, + .definition-like, + .example-like, + .project-like, + .remark-like, + .openproblem-like, + .openproblems-like, + .computation-like + ) + > .ptx-runestone-container + > pre.program, */ + .ptx-content + article:is( + .theorem-like, + .definition-like, + .example-like, + .project-like, + .remark-like, + .openproblem-like, + .openproblems-like, + .computation-like + ) + > .ptx-runestone-container + > .runestone.datafile, + .ptx-content + article:is( + .theorem-like, + .definition-like, + .example-like, + .project-like, + .remark-like, + .openproblem-like, + .openproblems-like, + .computation-like + ) + > .ptx-runestone-container + > .runestone.contains-wide { + width: calc(var(--content-width-wide) + 10px); + } + + .ptx-content + .runestone:is(.ac_section, .codelens, .parsons_section, .hparsons_section, .contains-wide) { + border-left: 0; + border-right: 0; + border-top: 1px solid #aaa; + border-bottom: 1px solid #aaa; + border-radius: 0; + } + + .ptx-content .code-inline { + white-space: pre-wrap; + } + + .ptx-runestone-container .cd_section, + .ptx-content .ptx-runestone-container .parsons .sortable-code { + overflow-x: auto; + } + + .ptx-content .ptx-runestone-container .parsons .sortable-code:first-of-type { + padding: 0 25px; + } + + .searchresultsplaceholder { + width: 80vw; + left: 10vw; + bottom: 10vh; + } + +} + +@media screen and (max-width: 663px) { + :root { + --content-margin: 28px; /* based on shell_default */ + } +} diff --git a/_static/pretext/css/style_default.css b/_static/pretext/css/style_default.css new file mode 100644 index 0000000..0fb58fd --- /dev/null +++ b/_static/pretext/css/style_default.css @@ -0,0 +1,332 @@ + +/* The Greg's L for theorems, proofs, etc */ + +.ptx-content .proof { + border-right: 1px solid #666; + padding-right: 0.625em; + margin-right: -0.725em; +} +.ptx-content .proof:after { + content: ''; + border-bottom: 1px solid #666; + display: block; + margin-left: auto; + margin-right: -0.625em; + /* so the corner of the L meets */ + width: 1.5em; + padding-bottom: 0.25em; +} + +.ptx-content.epub .proof { + margin-right: 1px; +} + +.ptx-content .proof .proof { + margin-right: -0.2em; + border-right: 1.5px solid #ddd; +} +.ptx-content .proof .proof:after { + border-bottom: 1.5px solid #ddd; + width: 1em; +} + +.ptx-content article.theorem-like, +.ptx-content article.definition-like, +.ptx-content article.example-like, +.ptx-content article.project-like, +.ptx-content article.remark-like, +.ptx-content article.openproblem-like, +.ptx-content article.openproblems-like, /* delete once markup is fixed */ +.ptx-content article.computation-like { + padding-left: 0.4em; + border-left: 1px solid #569; +} + +.ptx-content.epub article.theorem-like, +.ptx-content.epub article.definition-like, +.ptx-content.epub article.example-like, +.ptx-content.epub article.project-like, +.ptx-content.epub article.remark-like, +.ptx-content article.openproblem-like, +.ptx-content article.openproblems-like, /* delete once markup is fixed */ +.ptx-content.epub article.computation-like { + margin-left: 1px; +} + + +.ptx-content article.theorem-like::after, +.ptx-content article.definition-like::after, +.ptx-content article.example-like::after, +.ptx-content article.project-like::after, +.ptx-content article.remark-like::after, +.ptx-content article.openproblem-like::after, +.ptx-content article.openproblems-like::after, /* delete once markup is fixed */ +.ptx-content article.computation-like::after { + content:''; + border-bottom: 1px solid #569; + display: block; + margin-right: auto; + margin-left: -0.5em; + padding-top: 0.25em; + width: 1.5em; +} +/* projects get a dotted L */ +.ptx-content article.project-like { + border-left: 1px dotted #569; +} +.ptx-content article.project-like::after { + border-bottom: 1px dotted #569; +} + +/* commentary gets a thicker red L */ + +.ptx-content article.commentary { + padding-left: 0.6em; + border-left: 3px solid #c33; +} +.ptx-content article.commentary::after { + content:''; + border-bottom: 3px solid #c33; + display: block; + margin-right: auto; + margin-left: -0.6em; + padding-top: 0.25em; + width: 1.5em; +} + +.ptx-content .assemblage-like { + border: solid 2px #1100AA; + border-radius: 12px; + padding: 10px; + background-color: #f4f4fe; +} + +.ptx-content .assemblage-like .heading { + margin-top: 0; +} + +.ptx-content .assemblage-like + .sidebyside { + margin-top: 1.25em; +} +.ptx-content section article.assemblage-like .heading + .para { + display: block; +} + +.ptx-content .goal-like { + border: solid 3px #999999; + padding: 0.7em; + margin-bottom: 1em; +} + +.ptx-content .goal-like > .heading { + margin-top: -1.5em; + background-color: white; + display: table; + padding: 5px 1em; + margin-left: 5px; + font-style: italic; + font-size: 120%; +} + +.ptx-content .goal-like > .heading .codenumber { + display:none; +} + +.ptx-content .goal-like > .heading::after { + display:none; +} + + +.ptx-content .aside-like { + position: absolute; + margin-left: 45%; + overflow-x: hidden; + max-width: 495px; + max-height: 7em; + overflow-y: hidden; + border: none; + padding: 4px 10px 0 10px; + color: #888; + z-index: 100; +} +.ptx-content .example-like .aside-like { + margin-top: 0; + position: absolute; +} +.ptx-content .aside-like { + font-size: 90%; +} +.ptx-content .aside-like { + margin-bottom: 5px; + background-color: #f5faff; + box-shadow: 0 0 1.0em 0.2em #fff inset; +} +.ptx-content .aside-like .para { + overflow-x: auto; +} +.ptx-content .aside-like:first-child { + margin-top: -2.25em; +} +.ptx-content .aside-like:after { + content : ""; + position : absolute; + z-index : 1; + top : 0em; + bottom : 0; + left : 0; + pointer-events : none; + background-image : linear-gradient(to bottom, + rgba(255,255,255, 0.4), + rgba(255,255,255, 1) 90%); + width : 550px; + height : 8em; +} +/* example of where the following is needed? */ +/* +.ptx-content .aside-like * { + background-color: #f5faff !important; +} +*/ +.ptx-content .aside-like.front, .ptx-content .example-like .aside-like.front { + position: relative; + z-index: 0; + padding: 8px 15px 10px 15px; + padding: 2px 10px; + margin: 5px 0px 5px 10px; + border: 2px solid #dcebfa; + max-height: none; + max-width: 550px; + color: inherit; + font-size: 100%; + box-shadow: none; +} +.ptx-content .aside-like.front:after, .ptx-content .example-like .aside-like.front:after { + background-image: none; +} +.ptx-content .example-like .aside-like.front { + margin-top: 1.25em; +} + +.ptx-content .aside-like.front + p{ + margin-top: 1.25em !important; + padding-top: 0; +} + + + +.ptx-content .aside-like .aside-like { + background-color: #fafff5; + border: 1px dotted #aaa; +} + +.ptx-content article.aside-like > p:first-child { + margin-top: 0; +} + +.ptx-content .aside-like > .heading { + font-size: 95%; +} + +.ptx-content .aside-like + *{ + margin-top: 3em; /* !important; */ + margin-right: 3em; +} + +/* on sufficiently large screens, there is enough of a margin to see part of the aside */ + +@media screen and (min-width: 943px) { + .ptx-content .aside-like + * { + margin-right: 0; + } +} + +/* on a wide screen, asides should appear in the right margin */ +@media screen and (min-width: 1100px) { + .ptx-content .aside-like, .ptx-content .aside-like.front, .ptx-content .example-like .aside-like, .ptx-content .example-like .aside-like.front { + position: absolute; + margin-top: -2em; + margin-left: 660px; + max-width: 200px; /* for some reason the width was too small, so I had to put width (next line) */ + width: 200px; + color: inherit; + } + .ptx-content .aside-like.front, .ptx-content .example-like .aside-like.front { + max-height: none; + max-width: 223px; + border: 2px solid #dcebfa; +} + .ptx-content .example-like .aside-like, .ptx-content .example-like .aside-like.front { + margin-left: 654px; /* because .example-like has 6px of padding */ + } + + .ptx-content .aside-like + * { + margin-top: 1.25em; + /* background: none; */ + margin-right: 0; + } + /* previous and next point to the need to rethink asides: structurally they are + in the midts of the other elements, so they affect neighbor selectors. + but visually they often are off to the side */ + .ptx-content .aside-like + .solutions, + .ptx-content .aside-like + .instructions { + margin-top: 0; + } + + .ptx-content .aside-like.front:after, .ptx-content .example-like .aside-like.front:after { + background-image: none; + } + + .ptx-content .aside-like:nth-of-type(3n+1) { + margin-left: 660px; +} + .ptx-content .aside-like:nth-of-type(3n) { + margin-left: 680px; +} + .ptx-content .aside-like:nth-of-type(3n+2) { + margin-left: 640px; +} +} + +.ptx-content .aside-like:hover:after, .ptx-content .aside-like:focus:after { + top: 3em; + height: auto; + background-image : none; +} + +.ptx-content .aside-like:hover, .ptx-content .aside-like:focus { + color: inherit; + padding: 2px 8px 0 8px; + border: 2px solid #dcebfa; + height: auto; + max-height: none; +} +.ptx-content .aside-like.front:hover, .ptx-content .aside-like.front:focus { + padding: 4px 10px; +} + +/* find a better way to handle asides in content that has a wide left margin */ +/* see http://pretext.jahrme.com/aside-in-knowl/section-1.html */ +.ptx-content section dl dd .aside-like { + margin-top: 0 !important; + margin-left: 100px !important; +} +.ptx-content section dl dd .aside-like.front { + margin-left: -300px !important; +} + +@media screen and (max-width: 1099px) { + .ptx-content .aside-like { + position: relative; + float: right; + z-index: 0; + overflow-x: hidden; + margin-left: 1em; + margin-top: 1em; + max-width: 195px; + max-height: 4em; + margin-right: -8em; +} + .ptx-content li > .aside-like:last-child { + position: absolute; +} +} diff --git a/_static/pretext/css/style_oscarlevin.css b/_static/pretext/css/style_oscarlevin.css new file mode 100644 index 0000000..2e1296c --- /dev/null +++ b/_static/pretext/css/style_oscarlevin.css @@ -0,0 +1,471 @@ +/* Since the detault style is loaded before the oscarlevin style, */ +/* some of the default style has to be undone */ + +.ptx-content article.theorem-like::after, .ptx-content article.definition-like::after, .ptx-content article.example-like::after, .ptx-content article.project-like::after, .ptx-content article.remark-like::after, .ptx-content article.openproblem-like::after, .ptx-content article.openproblems-like::after, .ptx-content article.computation-like::after { + content: unset; +} + +.ptx-content article.theorem-like, .ptx-content article.definition-like, .ptx-content article.example-like, .ptx-content article.project-like, .ptx-content article.remark-like, .ptx-content article.openproblem-like, .ptx-content article.openproblems-like, .ptx-content article.computation-like { + padding: unset; + border: unset; +} + + +:root { +/* Set colors for environments */ + + --assembbody: var(--bluelight, hsl(210, 90%, 80%)); + --assembborder: var(--blue, hsl(210, 40%, 60%)); + --assembhead: var(--blue, hsl(210, 40%, 75%)); + --definitionbody: var(--greenlight, hsl(180, 40%, 80%)); + --definitionborder: var(--green, hsl(180, 40%, 50%)); + --definitionhead: var(--green, hsl(180, 40%, 50%)); + --theorembody: var(--violetlight, hsl(270, 40%, 94%)); + --theoremborder: var(--violet, hsl(270, 40%, 75%)); + --theoremhead: var(--violetdark, hsl(270, 40%, 25%)); + --examplebody: var(--bluedull, hsl(240, 40%, 90%)); + --exampleborder: var(--bluedark, hsl(240, 40%, 25%)); + --examplehead: var(--exampleborder); + --examplelikebody: var(--examplebody); + --examplelikeborder: var(--bluedull, hsl(240, 40%, 75%)); + --examplelikehead: var(--examplelikeborder); + --projectbody: var(--greenlight, hsl(180, 40%, 94%)); + --projectborder: var(--green, hsl(180, 40%, 75%)); + --projecthead: var(--green, hsl(180, 40%, 75%)); + --investigateborder: var(--bluerich, hsl(180, 40%, 25%)); + --goalborder: var(--violetrich, hsl(270, 90%, 25%)); + --remarklikebody: var(--yellowlight, hsl(59, 55%, 85%)); + --remarklikeborder: var(--yellow, hsl(59, 55%, 50%)); + --remarklikehead: var(--yellow, hsl(59, 55%, 50%)); + --computationborder: var(--orangedull, hsl(180, 40%, 75%)); + + /* temporary workaround for setcolors.css use of assemblage */ + --asemblagebackground: var(--assembbody) !important; + --assemblageborder: var(--assembborder) !important; +} + +/* We can style all the *-like environments: + definition-like, + theorem-like, + example-like, + project-like, + remark-like, + computation-like, + goal-like, and + assemblage-like. + We also could do something for proofs, and commentary. + + (should we style aside-like? Or just copy from style_default?) + + We define the style of environments in three steps: first the shape, then the color, and finally the shape and color of the heading/title. The only reason to group these as such is that we can then have a common shape for differet *-like elements, but still allow for different colors to distinguish them. + + Start with the important custom environments (theorem might be different from the other theorem-like, etc.), then clean up any standard *-like. + +*/ + +/* definitions, theorems, assemblages, with theorem-like.theorem distinguished */ +.ptx-content article.assemblage-like, +.ptx-content article.definition-like, +.ptx-content article.theorem-like.theorem { + margin-top: 1.75em; + padding: 1em; + border-radius: 2px; + margin-bottom: 1em; +} + +.ptx-content article.theorem-like { + margin-top: 1.25em; + padding: 1em; + border-radius: 2px; + margin-bottom: 1em; +} + +.ptx-content article.assemblage-like{ + background-color: var(--assembbody); + border: 2px solid var(--assembborder); +} + +.ptx-content article.definition-like { + background-color: var(--definitionbody); + border: 2px solid var(--definitionborder); +} + +.ptx-content article.theorem-like.theorem, +.ptx-content article.theorem-like { + background-color: var(--theorembody); + border: 2px solid var(--theoremborder); +} + +.ptx-content article.assemblage-like .heading, +.ptx-content article.definition-like .heading, +.ptx-content article.theorem-like.theorem .heading { + margin-top: -1.75em; + margin-left: -0.25em; + display: table; + padding: 0.25em 0.4em; +} + +.ptx-content .assemblage-like .heading { + background-color: var(--assembhead); + color: #000; +} + +.ptx-content .definition-like .heading { + background-color: var(--definitionborder); + color: #000; +} + +.ptx-content .theorem-like.theorem .heading { + background-color: var(--theoremborder); + color: #000; +} + +.ptx-content .example-like > .heading + .introduction, +.ptx-content .computation-like > .heading + .introduction, +.ptx-content .assemblage-like .heading + .para, +.ptx-content .computation-like > .heading + .para, +.ptx-content .example-like .heading + .para, +.ptx-content .theorem-like.theorem .heading + .para, +.ptx-content .definition-like .heading + .para { + display: block; + margin-top: 0.25em; +} + +/* Examples and example-like; computation-like styled same as example-like with different colors */ +.ptx-content article.example-like, +.ptx-content article.computation-like { + padding-left: 0.8em; + padding-bottom: 0.5em; +} + +.ptx-content article.example-like.example { + border-left: 0.1em solid var(--examplehead); + border-bottom: 0.1em solid var(--examplehead); +} + +.ptx-content article.example-like { + border-left: 0.1em solid var(--examplelikeborder); + border-bottom: 0.1em solid var(--examplelikeborder); +} + +.ptx-content article.computation-like { + border-left: 0.1em solid var(--computationborder); + border-bottom: 0.1em solid var(--computationborder); +} + +.ptx-content .example-like > .heading, +.ptx-content .computation-like > .heading { + display: inline-block; + padding: 0.3em 0.5em; + margin-left: -0.8em; +} + + +.ptx-content .example-like.example > .heading { + border: 0.1em solid var(--examplehead); /* maybe no border-left? */ + background: var(--examplehead); + color: white; +} + +.ptx-content .example-like > .heading { + background: var(--examplelikeborder); + color: black; +} + +.ptx-content .computation-like > .heading { + background: var(--computationborder); + color: black; +} + +/* Project-like */ +.ptx-content article.project-like { + background-color: white; + border: solid 3px var(--projectborder); + border-radius: 10px; + padding: 10px; + margin-bottom: 1em; +} + +.ptx-content article.project-like.investigation { + border-color: var(--investigateborder); +} + +.ptx-content article.project-like > .heading { + margin-top: -1.5em; + background-color: white; + display: table !important; + padding: 5px 1em; + margin-left: 10px; + font-style: italic; + font-size: 120% !important; +} + + +/* Goal-like */ + +.ptx-content .goal-like { + background-color: white; + border-radius: 0em; + padding: 0.7em; + margin-bottom: 1em; +} +.ptx-content .goal-like.objectives { + border-top: solid 3px var(--goalborder); + border-bottom: solid 3px var(--goalborder); + border-left: none; + border-right: none; +} +.ptx-content .goal-like.outcomes { + border-top: solid 3px var(--goalborder); + border-bottom: solid 3px var(--goalborder); + border-left: none; + border-right: none; +} + +.ptx-content .goal-like .heading { + margin-top: -1.5em; + background-color: white; + display: table; + padding: 5px 1em; + margin-left: 10px; + font-style: italic; + font-size: 120%; +} + +/* remark-like */ + +.ptx-content article.remark-like { + margin-top: 1.25em; + padding: 1em; + padding-top: 0.7em; + margin-bottom: 1em; + border-radius: 0px; + border-left: 5px solid var(--remarklikeborder); + background-color: var(--remarklikebody); +} + + +/* proofs */ + +.ptx-content section > .proof { + margin-bottom: 1em; +} + + +/* Common fixes? */ +.ptx-content article.assemblage-like .heading::after, +.ptx-content article.theorem-like.theorem .heading::after, +.ptx-content article.theorem-like .heading::after, +.ptx-content article.example-like > .heading::after, +.ptx-content article.project-like > .heading::after { + content: ""; +} + +/* Fixes for mathjax: */ +/* These gradients need to be adjusted to match background colors */ +.ptx-content .assemblage-like .MJXc-display, +.ptx-content .definition-like .MJXc-display, +.ptx-content .theorem-like.theorem .MJXc-display { + background-image: linear-gradient(to right, #e9eff5, #e9eff5), linear-gradient(to right, #e9eff5, #e9eff5), linear-gradient(to right, rgba(0,0,0,.25), rgba(242,242,254,0)), linear-gradient(to left, rgba(0,0,0,.25), rgba(242,242,254,0)); +} +.ptx-content .theorem-like.corollary .MJXc-display { + background-image: linear-gradient(to right, var(--bodytitlehighlight), var(--bodytitlehighlight)), linear-gradient(to right, var(--bodytitlehighlight), var(--bodytitlehighlight)), linear-gradient(to right, rgba(0,0,0,.25), rgba(242,242,254,0)), linear-gradient(to left, rgba(0,0,0,.25), rgba(242,242,254,0)); +} + +/* +END OF STYLE_OSCARLEVIN +(below is only stuff copied from style_default) +*/ + + + +/* Assides, copied directly from style_default.css */ +/* next selector first part of the following is due to the mistake of + putting paragraph spacing in the margin-bottom + Redo when we fix that error */ +.ptx-content .aside-like { + /* margin-top: -1.25em; +*/ + position: absolute; + margin-left: 45%; + overflow-x: hidden; + max-width: 495px; + max-height: 7em; + overflow-y: hidden; + border: none; + padding: 4px 10px 0 10px; + color: #888; +} +.ptx-content .example-like .aside-like { + margin-top: 0; + position: absolute; +} +.ptx-content .aside-like { + font-size: 90%; +} +.ptx-content .aside-like { + margin-bottom: 5px; + background-color: #f5faff; + box-shadow: 0 0 1.0em 0.2em #fff inset; +} +.ptx-content .aside-like:first-child { + margin-top: -2.25em; +} +.ptx-content .aside-like:after { + content : ""; + position : absolute; + z-index : 1; + top : 0em; + bottom : 0; + left : 0; + pointer-events : none; + background-image : linear-gradient(to bottom, + rgba(255,255,255, 0.4), + rgba(255,255,255, 1) 90%); + width : 550px; + height : 8em; +} +/* example of where the following is needed? */ +/* +.ptx-content .aside-like * { + background-color: #f5faff !important; +} +*/ +.ptx-content .aside-like.front, .ptx-content .example-like .aside-like.front { + position: relative; + z-index: 0; + padding: 8px 15px 10px 15px; + padding: 2px 10px; + margin: 5px 0px 5px 10px; + border: 2px solid #dcebfa; + max-height: none; + max-width: 550px; + color: inherit; + font-size: 100%; + box-shadow: none; +} +.ptx-content .aside-like.front:after, .ptx-content .example-like .aside-like.front:after { + background-image: none; +} +.ptx-content .example-like .aside-like.front { + margin-top: 1.25em; +} + +.ptx-content .aside-like.front + .para{ + margin-top: 1.25em !important; + padding-top: 0; +} + + + +.ptx-content .aside-like .aside-like { + background-color: #fafff5; + border: 1px dotted #aaa; +} + +.ptx-content article.aside-like > .para:first-child { + margin-top: 0; +} + +.ptx-content .aside-like > .heading { + font-size: 95%; +} + +.ptx-content .aside-like + *{ + margin-top: 3em !important; + margin-right: 3em; +} + +/* on sufficiently large screens, there is enough of a margin to see part of the aside */ + +@media screen and (min-width: 943px) { + .ptx-content .aside-like + * { + margin-right: 0; + } +} + +/* on a wide screen, asides should appear in the right margin */ +@media screen and (min-width: 1100px) { + .ptx-content .aside-like, .ptx-content .aside-like.front, .ptx-content .example-like .aside-like, .ptx-content .example-like .aside-like.front { + position: absolute; + margin-top: -2em; + margin-left: 660px; + max-width: 200px; /* for some reason the width was too small, so I had to put width (next line) */ + width: 200px; + color: inherit; + } + .ptx-content .aside-like.front, .ptx-content .example-like .aside-like.front { + max-height: none; + max-width: 223px; + border: 2px solid #dcebfa; +} + .ptx-content .example-like .aside-like, .ptx-content .example-like .aside-like.front { + margin-left: 654px; /* because .example-like has 6px of padding */ + } + + .ptx-content .aside-like + * { + margin-top: 1.25em !important; + /* background: none; */ + margin-right: 0; + } + + .ptx-content .aside-like.front:after, .ptx-content .example-like .aside-like.front:after { + background-image: none; + } + + .ptx-content .aside-like:nth-of-type(3n+1) { + margin-left: 660px; +} + .ptx-content .aside-like:nth-of-type(3n) { + margin-left: 680px; +} + .ptx-content .aside-like:nth-of-type(3n+2) { + margin-left: 640px; +} +} + +.ptx-content .aside-like:hover:after, .ptx-content .aside-like:focus:after { + top: 3em; + height: auto; + background-image : none; +} + +.ptx-content .aside-like:hover, .ptx-content .aside-like:focus { + color: inherit; + padding: 2px 8px 0 8px; + border: 2px solid #dcebfa; + height: auto; + max-height: none; +} +.ptx-content .aside-like.front:hover, .ptx-content .aside-like.front:focus { + padding: 4px 10px; +} + +/* find a better way to handle asides in content that has a wide left margin */ +/* see http://pretext.jahrme.com/aside-in-knowl/section-1.html */ +.ptx-content section dl dd .aside-like { + margin-top: 0 !important; + margin-left: 100px !important; +} +.ptx-content section dl dd .aside-like.front { + margin-left: -300px !important; +} + +@media screen and (max-width: 1099px) { + .ptx-content .aside-like { + position: relative; + float: right; + z-index: 0; + overflow-x: hidden; + margin-left: 1em; + margin-top: 1em; + max-width: 195px; + max-height: 4em; + margin-right: -8em; +} + .ptx-content li > .aside-like:last-child { + position: absolute; +} +} + + diff --git a/_static/pretext/css/style_soundwriting.css b/_static/pretext/css/style_soundwriting.css new file mode 100644 index 0000000..4dcc5ca --- /dev/null +++ b/_static/pretext/css/style_soundwriting.css @@ -0,0 +1,156 @@ + +/* +:root { + --documenttitle: #660000; + --bodytitle: #8e0a0c; + --bodysubtitle: #A62E1C; + --bodytitlehighlight: #eeeff3; + --bodysubtitlehighlight: #fce5e4; + + --chaptertoc: #6d8899; + --chaptertoctext: white; + --chaptertocactive: var(--documenttitle); + --chaptertoctextactive: white; + --sectiontoc: white; + --sectiontoctext: #6f080b; + --sectiontocactive: var(--documenttitle); + --sectiontoctextactive: white; + --tocborder: #152f53; + + --highlighttoc: #330000; + --highlighttoctext: white; + --highlighttocborder: var(--chaptertoc); + + --videoplay: var(--bodytitle); + --assemblageborder: #1100aa; + --assemblagebackground: #f5f8ff; + + --knowlborder: var(--bodytitlehighlight); + --knowlbackground: var(--assemblagebackground); +} +*/ + + +:root { +/* Colors for titles */ +--chaptertitle: var(--documenttitle); +--sectiontitle: var(--documenttitle); +--subsectiontitle: var(--documenttitle); + +/* Set colors for blocks */ + + --bordercolor: var(--documenttitle); + --listbackground: #d0ccbd; /*neutral1*/ + --insightbackground: #d0c681; /*muted2*/ + --conventionbackground: #b1a77d; /*muted3*/ + --notebackground: #93a396; /*muted4*/ + --examplebackground: #a2bac2; /*muted5*/ + --warningbackground: #b4bd00; /*bright4*/ + --observationbackground: #48848d; /*bright6*/ +} + + +/* Headings: */ + +.ptx-content section.chapter h2.heading { + color: var(--chaptertitle); +} + +.ptx-content section.chapter h2.heading .title { + display:block; + font-size:larger; + margin-top: 5pt; +} + +.ptx-content section.section h2.heading { + color: var(--sectiontitle); + border-top: 1pt solid; + border-bottom: 1pt solid; + margin-bottom: 20pt; + width: 100%; +} +.ptx-content section.subsection h2.heading { + color: var(--subsectiontitle); + border-bottom: 1pt solid; + margin-bottom: 20pt; + width: 90%; +} + +/* frontmatter headings: */ +.ptx-content section.frontmatter h2.heading { + color: var(--chaptertitle); + font-size:2em; +} + +.ptx-content section.preface h2.heading, +.ptx-content section.acknowledgement h2.heading, +.ptx-content section.colophon h2.heading { + color: var(--chaptertitle); + margin-bottom: 15pt; + font-size: 1.75em; +} + +.ptx-content section.preface h2.heading .title { + display:block; + font-size:larger; +} + +/* Blocks: */ + +/* set background colors */ +.ptx-content .list { + background-color: var(--listbackground); +} +.ptx-content .insight { + background-color: var(--insightbackground); +} +.ptx-content .convention { + background-color: var(--conventionbackground); +} +.ptx-content .note { + background-color: var(--notebackground); +} +.ptx-content .example { + background-color: var(--examplebackground); +} +.ptx-content .warning { + background-color: var(--warningbackground); +} +.ptx-content .observation { + background-color: var(--observationbackground); +} + +/* set titles and borders */ +.ptx-content .remark-like, +.ptx-content .example-like, +.ptx-content .list { + padding: 1em; + border-radius: 10px; + margin-bottom: 1em; + border: 2px solid var(--bordercolor); +} + +.ptx-content .example-like .example-like { + padding: 0; + margin: 0; + border: none; + background: inherit; +} + + +/* override list margins */ +.ptx-content .list { + margin-left: 0 !important; + margin-right: 0 !important; +} + +.ptx-content .remark-like .heading, +/* .ptx-content .example-like .heading, */ +.ptx-content .list figcaption { + display: block; + margin-top: -0.5em !important; + padding-bottom: 1em; + font-size: large; /*sets font caption size to match h6*/ +} + + diff --git a/_static/pretext/css/style_wide.css b/_static/pretext/css/style_wide.css new file mode 100644 index 0000000..9a02ebc --- /dev/null +++ b/_static/pretext/css/style_wide.css @@ -0,0 +1,225 @@ +@import url("style_default.css"); + +/* handle margin of articles that items might be nested inside */ +/* first change nesting unit to px to avoid font-size issues */ +.ptx-content + article:is( + .theorem-like, + .definition-like, + .example-like, + .project-like, + .remark-like, + .openproblem-like, + .openproblems-like, + .computation-like + ) { + padding-left: 10px; +} +/* now overcome the indentation */ +.ptx-content + article:is( + .theorem-like, + .definition-like, + .example-like, + .project-like, + .remark-like, + .openproblem-like, + .openproblems-like, + .computation-like + ) + > .ptx-runestone-container + > .runestone:is(.ac_section, .codelens, .parsons_section, .hparsons_section), +/* .ptx-content + article:is( + .theorem-like, + .definition-like, + .example-like, + .project-like, + .remark-like, + .openproblem-like, + .openproblems-like, + .computation-like + ) + > pre.program, */ +.ptx-content + article:is( + .theorem-like, + .definition-like, + .example-like, + .project-like, + .remark-like, + .openproblem-like, + .openproblems-like, + .computation-like + ) + > .ptx-runestone-container + > .runestone.datafile, +.ptx-content + article:is( + .theorem-like, + .definition-like, + .example-like, + .project-like, + .remark-like, + .openproblem-like, + .openproblems-like, + .computation-like +) .contains-wide { + margin-left: calc(var(--xl-margin) - 10px); +} + + + +.ptx-content .datafile pre { + border: 1px solid #616160; + border-radius: 3px; + padding: 10px; +} + +.ptx-content .runestone.datafile { + margin-top: 10px; + margin-bottom: 10px; + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; +} + +.ptx-content .datafile_caption { + background: transparent; + border: 0; + margin: 0; + padding: 0; +} + +.ac_actions { + font-size: 1rem; + margin-bottom: 5px; +} + +.ptx-content .ptx-runestone-container .ac_output { + margin-bottom: 10px; +} + +.ptx-content .ptx-runestone-container .codelens { + margin-bottom: 10px; +} + +.ptx-content .ptx-runestone-container .ac_output pre { + width: 100%; + max-width: var(--content-width); + margin: 10px auto; +} +.ptx-runestone-container .ac-canvas { + margin-left: calc(50% - 202px); +} +.ptx-runestone-container .ac-canvas:empty { + display: none; +} + +.runestone_caption { + font-size: 1rem; +} + +.ptx-runestone-container .unittest-results table { + background: white; +} + +.ptx-content .ptx-runestone-container div.ExecutionVisualizer table.visualizer { + width: 100%; +} + +.ptx-content table tr td { + font-size: 1rem; +} + +.pretext .ptx-content-footer { + align-items: stretch; +} + + +/*change margin to px to avoid font size issues */ +.ptx-content + article:is( + .theorem-like, + .definition-like, + .example-like, + .project-like, + .remark-like, + .openproblem-like, + .openproblems-like, + .computation-like + )::after { + margin-left: -10px; +} + +.video-box { + margin: 0.75em auto !important; +} + +.ac_code_div { + margin-top: 10px; +} + +.pretext .ptx-runestone-container .ac_actions { + max-width: var(--content-width); + margin: 0 auto; + flex-wrap: nowrap; + align-items: center; + gap: 10px; + padding-left: 10px; + padding-right: 10px; +} + +.pretext .ptx-runestone-container .ac_actions > * { + flex: 0 1; + margin: 0 !important; +} + + +.pretext .ptx-runestone-container .ac_actions > div:first-of-type { + display: flex !important; + flex-direction: column; + align-items: stretch; + text-align: center; + flex-grow: 1; +} + +.ptx-runestone-container .unittest-results { + display: flex; + flex-direction: column; + align-items: center; +} + + +.ptx-content pre.program.line-numbers, +.ptx-content pre.code-block.line-numbers { + overflow-x: auto; +} + +.hparsons_section { + max-width: unset !important; +} + +.hparsons_section > :not(.hparsons_section, .hp_question) { + max-width: unset !important; +} + +.ptx-runestone-container .hparsons_section .hp_question { + max-width: var(--content-width); +} + +.matching_section > div > div { + font-size: 1rem; + clear: both; +} +.matching_section > div > div:first-of-type { + font-size: var(--content-font-size); +} + +@media screen and (max-width: 600px) { + .pretext .ptx-runestone-container .ac_actions > * { + white-space: break-spaces; + flex-grow: 1; + } +} diff --git a/_static/pretext/css/toc_crc.css b/_static/pretext/css/toc_crc.css new file mode 100644 index 0000000..b31c875 --- /dev/null +++ b/_static/pretext/css/toc_crc.css @@ -0,0 +1,276 @@ + +/* over-ride default css */ +.ptx-toc > ul.structural > li:not(:first-child) { + margin-top: 0; +} +.ptx-toc ul.structural li a { + border-bottom: 0; +} + +.ptx-toc ul.structural li li a { + border-bottom: none; /*solid #999 1px; */ +} +.ptx-toc ul.structural .toc-title-box { + border-top: solid #999 1px; +} +.ptx-toc ul.structural li ul.structural li:last-child { + margin-bottom: 0; +} + +.ptx-toc { + width: 240px; + margin: 0; + font-size: 14.72px; + overflow-y: auto; + overflow-x: hidden; + background: #fff; +} + +/* Aligns toc to the top and side of the allotted space, respectively */ +.ptx-toc ul { + margin: 0px; + padding: 0px; +} + +.ptx-toc ul a, +.ptx-toc ul .part a, +.ptx-toc ul .frontmatter a { + font-weight: 700; + font-size: .9em; +} +.ptx-toc ul ul li a { + font-weight: 400; + grid-template-columns: 1.5em 1fr; +} + +.ptx-toc .toc-chapter .toc-item-list .toc-item .codenumber { + font-size: 80%; + padding-top: 0.16em; +} +/* no codenumbers on subsections (anything under section) */ +.ptx-toc .toc-section .toc-item-list .toc-item a > .codenumber { + display: none; +} +.ptx-toc .toc-section .toc-item-list .toc-item a:hover > .codenumber { + display: inline-block; +} + +.ptx-toc ul ul a > .title { + margin-left: 0; +} +.ptx-toc ul ul a > .title:empty::after { + content: "empty heading!"; + font-weight: bold; +} +.ptx-toc ul ul ul a > .title { + margin-left: 0.5em; + font-size: 90%; +} +.ptx-toc ul ul ul ul a > .title { + margin-left: 2em; + font-size: 90%; + font-style: italic; +} + +.ptx-toc ul li a { + text-decoration: none; +} + +.ptx-toc > ul > li a { + font-weight: bold; + font-family: "PT Serif", "Times New Roman", Times, serif; + padding-left: 0.2em; +} +/* +.ptx-toc ul li ul a:hover { + padding-top: -10px; +} +*/ + +.ptx-toc ul li a:active { + box-shadow: rgba(0, 0, 0, 0.5) 0 2px 5px inset; +} + + +/* ************************************************** */ +/* Above code may be old. New code below */ +/* ************************************************** */ + + +/* TOC is initially closed in the CRC style */ +/* The onload js will close it, but you get an odd fluttering effect */ + +/* comment out because we need to fix the fluttering effect. + if this is hidden by default, the page is not usable without JavaScript +.ptx-sidebar { + display: none; +} +*/ + + + +/* Links inside the dropdown */ +.ptx-toc a { + padding: .25em .5em .25em .5em; + text-decoration: none; + font-weight: 500; + font-size: .9em; + margin: 0px; +} + +.ptx-toc ul, +.ptx-toc ul li { + list-style-type: none; + margin: 0px; +/* width: 255px; */ /* This one is key to making items menu uniform width */ + padding-inline-start: 0px; +} + +/* The anchor carries the grid content */ +/* undo what is in toc_default.css */ +.ptx-toc ul li a { + display: grid; +/* made titles too wide */ +/* + width: 240px; +*/ + grid-gap: 3px; + grid-template-columns: 1.25em 10fr; + grid-template-areas: + "toc-codenumber toc-content"; +} +.ptx-toc { + position: sticky; + top: 0; + width: unset; + height: 100vh; +} + +/* +.ptx-toc::after { + content: ""; + display: block; + height: 13em; + background: #fff; +} +*/ + +.ptx-toc::after { + content: url("data:image/svg+xml; utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='338 3000 8772 6866'%3E%3Cg style='stroke-width:.025in; stroke:black; fill:none'%3E%3Cpolyline points='472,3590 472,9732 ' style='stroke:%23000000;stroke-width:174; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpath style='stroke:%23000000;stroke-width:126;stroke-linecap:butt;' d='M 4724,9448 A 4660 4660 0 0 1 8598 9259 '%3E%3C/path%3E%3Cpath style='stroke:%23000000;stroke-width:174;stroke-linecap:butt;' d='M 4488,9685 A 4228 4228 0 0 0 472 9732 '%3E%3C/path%3E%3Cpath style='stroke:%23000000;stroke-width:126;stroke-linecap:butt;' d='M 4724,3590 A 4241 4241 0 0 1 8598 3496 '%3E%3C/path%3E%3Cpath style='stroke:%23000000;stroke-width:126;stroke-linecap:round;' d='M 850,3496 A 4241 4241 0 0 1 4724 3590 '%3E%3C/path%3E%3Cpath style='stroke:%23000000;stroke-width:126;stroke-linecap:round;' d='M 850,9259 A 4507 4507 0 0 1 4724 9448 '%3E%3C/path%3E%3Cpolyline points='5385,4299 4062,8125 ' style='stroke:%23000000;stroke-width:300; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='8598,3496 8598,9259 ' style='stroke:%23000000;stroke-width:126; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='850,3496 850,9259 ' style='stroke:%23000000;stroke-width:126; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='4960,9685 4488,9685 ' style='stroke:%23000000;stroke-width:174; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='3070,4582 1889,6141 3070,7700 ' style='stroke:%23000000;stroke-width:300; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='6418,4582 7600,6141 6418,7700 ' style='stroke:%23000000;stroke-width:300; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='8976,3590 8976,9732 ' style='stroke:%23000000;stroke-width:174; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpath style='stroke:%23000000;stroke-width:174;stroke-linecap:butt;' d='M 4960,9685 A 4228 4228 0 0 1 8976 9732 '%3E%3C/path%3E%3C/g%3E%3C/svg%3E"); + display: block; + height: 13em; + padding: 2em 1em; + background: #fff; +} + +.ptx-toc > ul:first-child > li:last-child { + border-bottom: 4px solid #669; +} + + + +/**** Use serif font for Roman numerals ****/ +/* .ptx-TOC-codenumber */ +.ptx-toc a > .codenumber { + font-family: "PT Serif", "Times New Roman", Times, serif; + grid-area: toc-codenumber; +} + +/* .ptx-TOC-contents */ +.ptx-toc a > .title { + grid-area: toc-content; +} + +.ptx-toc.depth0 ul.structural { + display: none; +} +.ptx-toc.depth1 ul.structural ul.structural { + display: none; +} +.ptx-toc.depth2 ul.structural ul.structural ul.structural { + display: none; +} +.ptx-toc.depth3 ul.structural ul.structural ul.structural ul.structural { + display: none; +} +.ptx-toc.depth4 ul.structural ul.structural ul.structural ul.structural ul.structural { + display: none; +} + + +/* Hide all but active area of book */ +.ptx-toc.focused ul.structural:not(.contains-active) > li { + display: none; +} +.ptx-toc.focused ul.structural li.active > ul > li { + display: block; +} + +/* Hooks for js based switching */ +.ptx-toc.focused ul.structural:not(.contains-active) > li.visible { + display: block; +} +.ptx-toc.focused ul.structural li.active > ul > li.hidden { + display: none ; +} + + +.ptx-toc.focused > ul.structural > li:not(:first-child) { + margin-top: 0em; +} +.ptx-toc.focused ul.structural li ul.structural a:hover { + border: 0; +} + + +.toc-title-box { + display: flex; +} + +.ptx-toc ul.structural li .toc-title-box a { + flex: 1 1; +} + +.ptx-toc.focused .toc-expander { + border: 0; + padding: 2px 5px; + background: inherit; + color: inherit; + display: flex; + align-items: center; +} + +.ptx-toc.focused .toc-expander .icon { + font-size: 30px; + line-height: 18px; + font-variation-settings: 'wght' 200; +} + +.ptx-toc.focused .toc-expander:is(:hover) { + background-color: var(--highlighttoc); + color: var(--highlighttoctext); +} + +.ptx-toc.focused .toc-expander:is(:hover) .icon { + fill: var(--highlighttoctext); +} + +.ptx-toc.focused .toc-item.expanded > .toc-title-box > .toc-expander > .icon { + transform: rotate(-90deg); +} + +/* Part colors fall back to same as chapter if not defined + Defined here and not in setcolors so that colors_ file can override as include + order is toc/colors/setcolors */ +:root { + --parttoc: var(--chaptertoc); + --parttoctext: var(--chaptertoctext); + --parttocactive: var(--documenttitle); + --parttoctextactive: var(--chaptertoctextactive); +} +/* But if browser supports, make parts very slightly darker than chapters */ +@supports (background: color-mix(in srgb, red 50%, blue)) { + :root { + --parttoc: color-mix(in srgb, var(--chaptertoc), black 15%); + } +} \ No newline at end of file diff --git a/_static/pretext/css/toc_default.css b/_static/pretext/css/toc_default.css new file mode 100644 index 0000000..a6f4314 --- /dev/null +++ b/_static/pretext/css/toc_default.css @@ -0,0 +1,274 @@ +/* -------------------toc-------------------- */ +.ptx-toc { + /* IMPORTANT height must be calculated by javascript. */ + width: 240px; + margin: 0; + font-size: 14.72px; + overflow-y: auto; + overflow-x: hidden; +} +.ptx-toc::after { + content: url("data:image/svg+xml; utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='338 3000 8772 6866'%3E%3Cg style='stroke-width:.025in; stroke:black; fill:none'%3E%3Cpolyline points='472,3590 472,9732 ' style='stroke:%23000000;stroke-width:174; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpath style='stroke:%23000000;stroke-width:126;stroke-linecap:butt;' d='M 4724,9448 A 4660 4660 0 0 1 8598 9259 '%3E%3C/path%3E%3Cpath style='stroke:%23000000;stroke-width:174;stroke-linecap:butt;' d='M 4488,9685 A 4228 4228 0 0 0 472 9732 '%3E%3C/path%3E%3Cpath style='stroke:%23000000;stroke-width:126;stroke-linecap:butt;' d='M 4724,3590 A 4241 4241 0 0 1 8598 3496 '%3E%3C/path%3E%3Cpath style='stroke:%23000000;stroke-width:126;stroke-linecap:round;' d='M 850,3496 A 4241 4241 0 0 1 4724 3590 '%3E%3C/path%3E%3Cpath style='stroke:%23000000;stroke-width:126;stroke-linecap:round;' d='M 850,9259 A 4507 4507 0 0 1 4724 9448 '%3E%3C/path%3E%3Cpolyline points='5385,4299 4062,8125 ' style='stroke:%23000000;stroke-width:300; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='8598,3496 8598,9259 ' style='stroke:%23000000;stroke-width:126; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='850,3496 850,9259 ' style='stroke:%23000000;stroke-width:126; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='4960,9685 4488,9685 ' style='stroke:%23000000;stroke-width:174; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='3070,4582 1889,6141 3070,7700 ' style='stroke:%23000000;stroke-width:300; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='6418,4582 7600,6141 6418,7700 ' style='stroke:%23000000;stroke-width:300; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpolyline points='8976,3590 8976,9732 ' style='stroke:%23000000;stroke-width:174; stroke-linejoin:miter; stroke-linecap:round; '%3E%3C/polyline%3E%3Cpath style='stroke:%23000000;stroke-width:174;stroke-linecap:butt;' d='M 4960,9685 A 4228 4228 0 0 1 8976 9732 '%3E%3C/path%3E%3C/g%3E%3C/svg%3E"); + display: block; + height: 13em; + padding: 2em 1em; + background: #fff; +} + +.ptx-toc > .toc-item-list:first-child > .toc-item:last-child { + border-bottom: 8px solid #999; +} + +/* -------------------toc-items-------------------- */ + +.ptx-toc { + --codenumber-pad-left: 0.3rem; + --codenumber-pad-right: 0.5rem; + + --toc-indent-first: calc(1.0rem + var(--codenumber-pad-left) + var(--codenumber-pad-right)); + --toc-indent-second: calc(1.7rem + var(--codenumber-pad-left) + var(--codenumber-pad-right)); + --toc-indent-third: calc(2.2rem + var(--codenumber-pad-left) + var(--codenumber-pad-right)); +} + +/* will be less indentation */ +.ptx-toc:is(.depth1, .parts.depth2) { + --codenumber-pad-right: 0.5rem; +} + +.ptx-toc .toc-item-list { + margin: 0px; + padding: 0px; + list-style-type: none; +} + +.ptx-toc .toc-item { + border-top: 1px solid var(--tocborder, #d1d1d1); +} + +/* -------------------title-box------------------- */ + +.ptx-toc .toc-title-box { + display: flex; +} + +.ptx-toc .toc-title-box > .internal { + position: relative; + display: flex; + flex-grow: 1; + padding: 0.2em; + font-family: "PT Serif", "Times New Roman", Times, serif; + font-weight: bold; +} + +/* at second level, switch fonts */ +.ptx-toc .toc-item-list .toc-item-list .toc-title-box > .internal { + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: normal; +} + +/* Extra border above top level items */ +.ptx-toc > .toc-item-list > .toc-item { + border-top: 2px solid var(--tocborder, #d1d1d1); +} + +.ptx-toc .toc-item.active { + box-shadow: rgba(0, 0, 0, 0.5) 0 2px 5px inset; +} + + +/* -------------------codenumbers-------------------- */ +.ptx-toc .codenumber { + min-width: var(--toc-indent-first); + padding-left: var(--codenumber-pad-left); + padding-right: var(--codenumber-pad-right); + display: inline-block; + text-align: left; + flex-grow: 0; +} + +/* second level of numbering */ +/* anything 1+ levels deeper than a chapter in a book */ +.book .ptx-toc .toc-chapter .toc-item-list .codenumber, +/* anything 1+ levels deeper than a section in an article */ +.article .ptx-toc .toc-section .toc-item-list .codenumber, +/* anything 1+ levels deeper than backmatter */ +.ptx-toc .toc-backmatter .toc-item-list .codenumber +{ + font-size: 80%; + padding-top: 0.16em; + min-width: var(--toc-indent-second); +} + +/* third level of numbering */ +/* anything 2+ levels deeper than a chapter in a book */ +.book .ptx-toc .toc-chapter .toc-item-list .toc-item-list .codenumber, +/* anything 2+ levels deeper than a section in an article */ +.article .ptx-toc .toc-section .toc-item-list .toc-item-list .codenumber, +/* anything 2+ levels deeper than backmatter */ +.ptx-toc .toc-backmatter .toc-item-list .toc-item-list .codenumber +{ + min-width: var(--toc-indent-third); + visibility: hidden; +} + +/* reveal on interaction */ +.ptx-toc .toc-item-list .toc-item-list .toc-item-list a:is(:hover, :focus) > .codenumber { + visibility: visible; +} + +/* -------------------titles-------------------- */ +.ptx-toc .toc-title-box .title { + flex-grow: 1; +} + +/* Any toc item without a codenumber needs indentation + Can't select absence of a preceeding, so indent all titles + and then clear indent if there is a codenumber */ +.ptx-toc .toc-item .toc-title-box .title { + margin-left: var(--toc-indent-first); +} + +/* second level as defined by codenumber selectors */ +.book .ptx-toc .toc-chapter .toc-item-list .title, +.article .ptx-toc .toc-section .toc-item-list .title, +.ptx-toc .toc-backmatter .toc-item-list .title +{ + margin-left: var(--toc-indent-second); +} + +/* third level as defined by codenumber selectors */ +.book .ptx-toc .toc-chapter .toc-item-list .toc-item-list .title, +.article .ptx-toc .toc-section .toc-item-list .toc-item-list .title, +.ptx-toc .toc-backmatter .toc-item-list .toc-item-list .title +{ + margin-left: var(--toc-indent-third); +} + +/* unless there is a codenumber */ +.ptx-toc .toc-item > .toc-title-box .codenumber + .title { + margin-left: 0 !important; +} + +.ptx-toc ul.structural ul.structural .title:empty::after { + content: "empty heading!"; + font-weight: bold; +} + + +.ptx-toc .toc-chapter .toc-item-list .title, +.ptx-toc .toc-section .toc-item-list .title, +/* 2 levels deep in back matter */ +.ptx-toc .toc-backmatter .toc-item-list .toc-item-list .title +{ + font-size: 90%; +} + +.ptx-toc .toc-chapter .toc-item-list .toc-item-list .title, +.ptx-toc .toc-section .toc-item-list .toc-item-list .title, +/* 3 levels deep in back matter */ +.ptx-toc .toc-backmatter .toc-item-list .toc-item-list .toc-item-list .title +{ + font-style: italic; +} + +/* ??? */ +.ptx-toc ul.structural li a.has-chevron { + padding-right: 2em; +} + +/* -------------------depth controls-------------------- */ +.ptx-toc.depth0 ul.structural { + display: none; +} +.ptx-toc.depth1 ul.structural ul.structural { + display: none; +} +.ptx-toc.depth2 ul.structural ul.structural ul.structural { + display: none; +} +.ptx-toc.depth3 ul.structural ul.structural ul.structural ul.structural { + display: none; +} +.ptx-toc.depth4 ul.structural ul.structural ul.structural ul.structural ul.structural { + display: none; +} + +/* if depth is shallow, identify best available toc item */ +.ptx-toc.depth1 ul.structural .toc-item.contains-active { + background-color: var(--chaptertocactive); + color: var(--chaptertoctextactive); +} +.ptx-toc.depth2 ul.structural ul.structural .toc-item.contains-active { + background-color: var(--parttocactive); + color: var(--parttoctextactive); +} + + +/* -------------------focused toc-------------------- */ +/* Hide all but active area of book */ +.ptx-toc.focused ul.structural:not(.contains-active) > li { + display: none; +} +.ptx-toc.focused ul.structural li.active > ul > li { + display: block; +} + +/* Hooks for js based switching */ +.ptx-toc.focused ul.structural:not(.contains-active) > li.visible { + display: block; +} +.ptx-toc.focused ul.structural li.active > ul > li.hidden { + display: none ; +} + + +.ptx-toc.focused > ul.structural > li:not(:first-child) { + margin-top: 0em; +} +.ptx-toc.focused ul.structural li ul.structural a:hover { + border: 0; +} + +.ptx-toc.focused .toc-expander { + border: 0; + padding: 2px 5px; + background: inherit; + color: inherit; + display: flex; + align-items: center; +} + +.ptx-toc.focused .toc-expander .icon { + font-size: 30px; + line-height: 18px; + font-variation-settings: 'wght' 200; +} + +.ptx-toc.focused .toc-expander:is(:hover) { + background-color: var(--highlighttoc); + color: var(--highlighttoctext); +} + +.ptx-toc.focused .toc-expander:is(:hover) .icon { + fill: var(--highlighttoctext); +} + +.ptx-toc.focused .toc-item.expanded > .toc-title-box > .toc-expander > .icon { + transform: rotate(-90deg); +} + +/* Part colors fall back to same as chapter if not defined + Defined here and not in setcolors so that colors_ file can override as include + order is toc/colors/setcolors */ +:root { + --parttoc: var(--chaptertoc); + --parttoctext: var(--chaptertoctext); + --parttocactive: var(--documenttitle); + --parttoctextactive: var(--chaptertoctextactive); +} +/* But if browser supports, make parts very slightly darker than chapters */ +@supports (background: color-mix(in srgb, red 50%, blue)) { + :root { + --parttoc: color-mix(in srgb, var(--chaptertoc), black 15%); + } +} diff --git a/_static/pretext/css/toc_min.css b/_static/pretext/css/toc_min.css new file mode 100644 index 0000000..9bb2e47 --- /dev/null +++ b/_static/pretext/css/toc_min.css @@ -0,0 +1,144 @@ + +.ptx-toc { + /* IMPORTANT height must be calculated by javascript. */ + width: 240px; + margin: 0; + font-size: 14.72px; + overflow-y: auto; + overflow-x: hidden; +} + +/* Aligns toc to the top and side of the allotted space, respectively */ +.ptx-toc ul { + margin: 0px; + padding: 0px; + list-style-type: none; +} + + +/* Places codenumbers */ +.ptx-toc .codenumber { + position: absolute; + margin-right: 0; + margin-left: 0em; +/* + margin-top: 0.4px; +*/ + left: 0.3em; + display: inline-block; +} +/* no codenumbers on subsections */ +.ptx-toc ul.structural ul.structural a > .codenumber { + display: none; +} +.ptx-toc ul.structural .title { + margin-left: 1.4em; + display: inline-block; +} +.ptx-toc ul.structural ul.structural .title { + margin-left: 1.5em; +} +.ptx-toc ul.structural ul.structural .title:empty::after { + content: "empty heading!"; + font-weight: bold; +} +.ptx-toc ul.structural ul.structural ul.structural .title { + margin-left: 2.5em; + font-size: 90%; +} +.ptx-toc ul.structural ul.structural ul.structural ul.structural .title { + margin-left: 3.2em; + font-size: 90%; + font-style: italic; +} + +/* more specific than something in toc_default (obsolete comment?) */ +.ptx-toc ul.structural li ul.structural li ul.structural li:last-child { + margin-bottom: 0; + border-bottom: 1px solid #ddd; +} + +.ptx-toc .part > a .codenumber { + position: relative; + display: block; + float: left; + margin-right: 0.7em; +} +.ptx-toc .part > a .title { + display: block; + margin-left: 1em; +} + +.ptx-toc ul.structural li a { + position: relative; + display: block; + padding: 2.86957px; + padding: 0.2em; +// padding-left: 0.5em; + border-top: 1px solid #d1d1d1; + border-bottom: 1px solid #d1d1d1; + font-family: "PT Serif", "Times New Roman", Times, serif; + font-weight: bold; +} +.ptx-toc ul.structural ul.structural li a { + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: normal; +// padding-left: 2.0em; +} + +/* Sets spacing between section headings*/ +.ptx-toc > ul.structural > li:not(:first-child) { + margin-top: 0.3em; +} +/* But not at the start of a part */ +/* I cannot see that this actually does anything --DF */ +.ptx-toc > ul.structural > li.part + li, +.ptx-toc > ul.structural > li.frontmatter + li, +.ptx-toc > ul.structural > li.backmatter + li { + margin-top: 0; +} +/* Removes underlines from links in toc */ +.ptx-toc ul.structural li a, .ptx-toc ul.structural li a:link, .ptx-toc ul.structural li a:visited, .ptx-toc ul.structural li a:hover, .ptx-toc ul.structural li a:focus, .ptx-toc ul.structural li a:active { + text-decoration: none; +} + +/* +.ptx-toc > ul > li a, .ptx-toc > ul > li a:link, .ptx-toc > ul > li a:visited { + font-weight: bold; + font-family: "PT Serif", "Times New Roman", Times, serif; + padding-left: 0.2em; +} +*/ + +/* Ensures that there is no double border between subsections */ +.ptx-toc ul.structural li ul.structural a { + border-top: none; +} + +/* Allows both "top" and bottom border of a subsection to be highlighted on hover */ +.ptx-toc ul.structural li ul.structural a:hover { + border-top: 1px solid #3c110a; + margin-top: -1px; +} + +/* Removes the excess space between the last subsection and the next section (caused by +the margin on top of sections being used to space out adjacent sections) */ +.ptx-toc ul.structural li ul.structural li:last-child { + margin-bottom: -0.3em; +} + +/* Removes double border between last subsection and next section */ +.ptx-toc ul.structural li ul.structural li:last-child a { + border-bottom: none; +} + +.ptx-toc ul.structural li a:active { + box-shadow: rgba(0, 0, 0, 0.5) 0 2px 5px inset; +} + +.ptx-toc ul.structural li a.has-chevron { + padding-right: 2em; +} +.ptx-toc .toc-item { + position: relative; +} diff --git a/_static/pretext/css/toc_wide.css b/_static/pretext/css/toc_wide.css new file mode 100644 index 0000000..9bd7347 --- /dev/null +++ b/_static/pretext/css/toc_wide.css @@ -0,0 +1,36 @@ +@import url("toc_default.css"); + +.pretext .ptx-sidebar { + display: none; + width: 0; +} + +.pretext .ptx-sidebar { + position: sticky; + top: 36px; + z-index: 10; + height: 0; +} + +.pretext .ptx-sidebar.visible { + position: sticky; + top: 36px; + z-index: 10; + height: 0; +} + +.pretext .ptx-sidebar .ptx-toc { + width: 360px; + background-color: var(--page-color); + border: 1px solid var(--tocborder) +} + +.pretext .ptx-page .ptx-main { + margin-left: inherit; +} + +.ptx-toc::after { + height: auto; + max-width: 100px; + margin: 0 auto; +} diff --git a/_static/pretext/css/webwork.css b/_static/pretext/css/webwork.css new file mode 100644 index 0000000..79ff9f0 --- /dev/null +++ b/_static/pretext/css/webwork.css @@ -0,0 +1,72 @@ + +table.attemptResults { + margin-left: 2em; + background: #efefef; + padding: 0.2em; +} +table.attemptResults + .attemptResultsSummary { + margin-top: 1em; +} + +.problem-main-form { + margin-top: 1em; + background: #eeeeff; + padding: 0.5em; +} +td.ResultsWithoutError { + background: #9f9; +} +td.ResultsWithError { + background: #f99; +} + +tr th { + text-align: center; + padding: 0.2em 1em 0.2em 1em; +} +tr td { + text-align: center; +} +tr td:empty { + background: #fff; +} + +/* +table td { border-left: 1px solid #000; } +table td:first-child { border-left: none; } +*/ + +ol, ul { + margin-top: 0.75em !important; +} + +.problem { + padding: 1em; + border: 0.5px solid #aaa; + background: #fdfdfd; +} + +.problem a { + text-decoration: none; +} + +.knowl { + margin-left: 1em; + padding: 0.2em; + background: #efe; +} + +/* +.problem a.internal::after { + content: ""; + position: absolute; + top: 0; + bottom: 1px; + right: 2.4px; + left: 2.4px; + border-bottom: 1px dotted #9c2310; + transition-property: left, right; + transition-duration: 0ms; + z-index: 0; +} +*/ diff --git a/_static/pretext/js/answer.js b/_static/pretext/js/answer.js new file mode 100644 index 0000000..652dcd3 --- /dev/null +++ b/_static/pretext/js/answer.js @@ -0,0 +1,552 @@ + +function escapeHTML(text) { + if (!text) { return "" } + the_ans = text; + the_ans = the_ans.replace(/&/g, "&"); + the_ans = the_ans.replace(/<([a-zA-Z])/g, '< $1'); + + return the_ans +} +function uNescapeHTML(text) { + if (!text) { return "" } + the_ans = text; + the_ans = the_ans.replace(/< /g, "<"); + the_ans = the_ans.replace(/</g, "<"); + the_ans = the_ans.replace(/>/g, ">"); + the_ans = the_ans.replace(/&/g, "&"); + the_ans = the_ans.replace(/<([a-zA-Z])/g, "< $1"); + + return the_ans +} + +function dollars_to_slashparen(text) { + the_ans = text; + the_ans = the_ans.replace(/(^|\s|-)\$([^\$\f\r\n]+)\$(\s|\.|,|;|:|\?|!|$)/g, "$1\\($2\\)$3"); + //twice, for $5$-$6$ + the_ans = the_ans.replace(/(^|\s|-)\$([^\$\f\r\n]+)\$(\s|\.|,|;|:|\?|!|-|$)/g, "$1\\($2\\)$3"); + + return the_ans +} + +/* The structure of a reading question is an erticle with an id (this_ques_id), + containing: + #this_ques_id_text the answer given (in a div with that id) + #this_ques_id_text_hidden the answer in a raw form (in a hidden div) + #this_ques_id_text_input the answer in a textinput with that id + + Try to do all operations by id, and not by carrying objects around. +*/ + +var reading_questions = document.querySelectorAll("section.reading-questions article.exercise-like, #boelkins-ACS .main #content > section:first-of-type > section:first-of-type > .project-like li"); + +var reading_answers = {}; + +console.log('reading_questions.length', reading_questions.length); + +function make_submit_button() { + if (document.getElementById("rq_submit")) { // don't make the button if it already exists + console.log("button exists", document.getElementById("rq_submit")); + return + } + last_reading_question = reading_questions[reading_questions.length - 1]; + answer_button_holder = document.createElement('div'); + answer_button_holder.setAttribute('class', 'rq_submit_wrapper'); + answer_button_holder.innerHTML = rq_submit_button; + last_reading_question.insertAdjacentElement("afterend", answer_button_holder); +} + +function save_reading_questions() { + rq_data = {"action": "save", "user": uname, "pw": emanu, "pI": pageIdentifier, "type": "readingquestions", "rq": JSON.stringify(reading_questions_object)} + $.ajax({ + url: "https://aimath.org/cgi-bin/u/highlights.py", + type: "post", + data: JSON.stringify(rq_data), + dataType: "json", + success: function(data) { + console.log("something", data, "back from highlight"); + alert(data); + }, + error: function(errMsg) { + console.log("seems to be an error?",errMsg); + alert("Error\n" + errMsg); + } + }); + + console.log("just ajax sent", JSON.stringify(reading_questions_object)); +} + +// no point in handling reading questions if there are not any + +if (reading_questions.length) { + + // retrieve the existing reading questions, if they exist + var reading_questions_object_id = pageIdentifier + "___" + "rq"; + var reading_questions_object = localStorage.getObject(reading_questions_object_id); + var reading_questions_all_answered = false; + var reading_questions_submitted = false; + + if (!reading_questions_object) { + reading_questions_object = {} + } + + if (Object.keys(reading_questions_object).length >= reading_questions.length) { + console.log("Object.keys(reading_questions_object)",Object.keys(reading_questions_object)); + console.log("reading_questions", reading_questions); + console.log("all reading questions have previously been answered"); + reading_questions_all_answered = true; + } + + answer_css = document.createElement('style'); + answer_css.type = "text/css"; + answer_css.id = "highlight_css"; + document.head.appendChild(answer_css); + var css_for_ans = '#rq_submit { background: #FDD; padding: 3px 5px; border-radius: 0.5em}\n'; + css_for_ans += '#rq_submit.submitted { background: #EFE; color: #BBB}'; + css_for_ans += '.rq_submit_wrapper { margin-top: 0.5em; float: right}'; + answer_css.innerHTML = css_for_ans; + + rq_answer_label = ''; + this_rq_controls += 'preview'; +// this_rq_controls += 'delete'; + this_rq_controls += 'typing math?'; + this_rq_controls += '' + + var this_rq_answer_and_controls = document.createElement('div'); + this_rq_answer_and_controls.setAttribute('style', 'width:80%; padding-left:10%; padding-right:10%; margin-top:0.5em;'); + this_rq_answer_and_controls.setAttribute('class', 'rq_answer'); + this_rq_answer_and_controls.innerHTML = hidden_answer_div + answer_div + this_rq_controls; + console.log("appending to ", reading_question_id); + $('#'+reading_question_id).append(this_rq_answer_and_controls); + // this.parentNode.insertAdjacentElement("afterend", this_rq_answer_and_controls); + + /* typeset the math in the reading questions answers */ + // MathJax.Hub.Queue(["Typeset",MathJax.Hub]); + if (mjvers && mjvers < 3) { + MathJax.Hub.Queue(['Typeset', MathJax.Hub]); + } else if (mjvers > 3) { + MathJax.typesetPromise(); + } + + } else if(role == "instructor" || role == "student") { + + var this_answer_link = document.createElement('div'); + this_answer_link.innerHTML = rq_answer_label; + console.log("inserting afterend of",reading_question); + // reading_question.insertAdjacentElement("afterend", this_answer_link); + reading_question.append(this_answer_link); + } else { + + console.log("should not be here"); + + } + + } + + function allow_student_answers(){ + /* make a new blank area to answer a question */ + $('.readingquestion_make_answer.student').mousedown(function(e){ + console.log(".readingquestion_make_answer student"); +// $(this).addClass("hidecontrols"); + // var this_ques_id = this.parentNode.parentNode.id; + var this_ques_id = this.parentNode.parentNode.id; + var this_ques_id_text = this_ques_id + "_text"; + var this_ques_id_controls = this_ques_id + "_controls"; + console.log(".rq", this_ques_id); + answer_textarea = ''; + this_rq_controls += 'preview'; +// this_rq_controls += 'delete'; + this_rq_controls += 'typing math?'; + this_rq_controls += '' + + var this_rq_answer_and_controls = document.createElement('div'); + this_rq_answer_and_controls.setAttribute('class', 'rq_answer editing'); + this_rq_answer_and_controls.setAttribute('style', 'width:80%; padding-left:10%; padding-right:10%; margin-top:0.5em;'); + + this_rq_answer_and_controls.innerHTML = answer_textarea + this_rq_controls; + this.parentNode.insertAdjacentElement("afterend", this_rq_answer_and_controls); + + this.remove(); + + // MathJax.Hub.Queue(["Typeset",MathJax.Hub]); + + console.log("adding other keypress listener"); + var this_textarea = document.getElementById(this_ques_id_text + "_input"); + console.log("to", this_textarea); + this_textarea.addEventListener("keypress", function() { + // if(this_textarea.scrollTop != 0){ + // console.log("this_textarea.scrollHeight", this_textarea.scrollHeight, "this_textarea.scrollTop", this_textarea.scrollTop); + // console.log("this_textarea.clientHeight", this_textarea.clientHeight); + this_textarea.overflow = "scroll"; + // console.log("this_textarea.scrollHeight", this_textarea.scrollHeight, "this_textarea.scrollTop", this_textarea.scrollTop); + // console.log("this_textarea.clientHeight", this_textarea.clientHeight); + this_textarea.overflow = "hidden"; + // console.log("this_textarea.scrollHeight", this_textarea.scrollHeight, "this_textarea.scrollTop", this_textarea.scrollTop); + // console.log("this_textarea.getBoundingClientRect()", this_textarea.getBoundingClientRect()); + this_textarea.style.height = this_textarea.scrollHeight + "px"; + // } + }, false); + var tmp_id = this_ques_id_text + "_input"; + console.log("want focus to ", tmp_id); + console.log("which is ", $("#" +tmp_id)); + console.log("the active ", document.hasFocus(), "element is", document.activeElement); + console.log("or maybe it is ", $(":focus")); + $("#" + tmp_id).focus(); + document.getElementById(tmp_id).focus(); + console.log("the active ", document.hasFocus(), "element is", document.activeElement); + }); + } + allow_student_answers(); + + $('.readingquestion_make_answer.instructor').mousedown(function(e){ + console.log(".readingquestion_make_answer instructor", "instId", uname, "pI", pageIdentifier); + if (jQuery.isEmptyObject(reading_answers) || this.classList.contains("reload")) { + rq_data = {"action": "retrieve", "instId": uname, "pw": emanu, "pI": pageIdentifier, "type": "readingquestions"}; + // myjson = {"action": "retrieve", "type": "readingquestions", "instId": "100002000", "pI": "beezer-FCLA___FPm"} + + $.ajax({ + url: "https://aimath.org/cgi-bin/u/highlights.py", + type: "post", + data: JSON.stringify(rq_data), + dataType: "json", + async: false, + success: function(data) { + reading_answers = data; + // console.log("something", data, "back from highlight"); + // alert(data); + }, + error: function(errMsg) { + console.log("seems to be an error?",errMsg); + alert("Error\n" + errMsg); + } + }); + } +// var this_ques_id = this.parentNode.previousSibling.id; + var this_ques_id = this.parentNode.parentNode.id; + console.log("this_ques_id", this_ques_id); + var compiled_answers = ""; + var title_of_this_section = $("section > h2 > .title").html(); + title_of_this_section = title_of_this_section.replace(/ /g, "%20"); + title_of_this_section = title_of_this_section.replace(/\?/g, ""); + var number_of_this_rq = 1 + $("#" + this_ques_id).index(".exercise-like"); +// console.log("first title_of_this_section", title_of_this_section); +// console.log("first title_of_this_section.html()", title_of_this_section.html()); +// console.log("second title_of_this_section[0]", title_of_this_section[0]); + for(var j=0; j < reading_answers.length; ++j) { + var this_answer_all = reading_answers[j]; + var this_student_id = this_answer_all[0]; + var these_specific_answers = JSON.parse(this_answer_all[1]); + console.log("these_specific_answers", these_specific_answers); + console.log("this_answer_all[2]", this_answer_all[2]); + var this_submitted_time = JSON.parse(this_answer_all[2]); + // var this_submitted_time = this_answer_all[2]; + console.log("looking for this answer:", this_ques_id + "_text"); + var this_specific_answer = these_specific_answers[this_ques_id + "_text"]; + console.log("this_answer_all",this_answer_all); + console.log("j",j,"this_specific_answer", this_specific_answer); + console.log("this_specific_time", this_submitted_time); + this_specific_answer = dollars_to_slashparen(escapeHTML(this_specific_answer)) + if (!this_specific_answer) { + this_specific_answer = "no answer submitted"; + compiled_answers += '
'; + } else { + compiled_answers += '
'; + } + if (this_student_id.indexOf('@') > -1) { + this_student_id = '' + this_student_id + ''; + } + compiled_answers += '
' + this_student_id + '
'; + compiled_answers += '
' + this_submitted_time + '
'; + compiled_answers += '
' + this_specific_answer + '
'; + compiled_answers += '
\n'; + console.log(j, "j", these_specific_answers) + } + // if the answers are being reloaded, remove the previous answers + $("#" + this_ques_id + "_ans").remove(); + var answers_to_this_question = document.createElement('div'); + answers_to_this_question.setAttribute('class', 'compiled_answers'); + answers_to_this_question.setAttribute('id', this_ques_id + "_ans"); + +// this_rq_answer_and_controls.setAttribute('style', 'width:80%; margin-left:auto; margin-right:auto; margin-top:0.5em;'); +// this_rq_answer_and_controls.setAttribute('class', 'rq_answer'); + answers_to_this_question.innerHTML = compiled_answers; + $('#'+this_ques_id).append(answers_to_this_question); +// this.parentNode.remove(); + this.innerHTML = "Reload responses"; + $(this).addClass("reload"); +// MathJax.Hub.Queue(["Typeset",MathJax.Hub]); + if (mjvers && mjvers < 3) { + MathJax.Hub.Queue(['Typeset', MathJax.Hub]); + } else if (mjvers > 3) { + MathJax.typesetPromise(); + } + + // this.parentNode.insertAdjacentElement("afterend", this_rq_answe + + }); + + + function save_one_reading_question(this_ques_id) { + this_ques_id_text = this_ques_id + "_text"; + var this_ans_text = $("#" + this_ques_id_text + "_input"); + console.log("the value:", this_ans_text.value); +// var this_ques_id = this_ans.parentNode.previousSibling.previousSibling.id; + // var this_ques_id = this_ans.id; + console.log("this_ques_id", this_ques_id); +// console.log("this_rq_ans", this_rq_ans); + var this_ans_text_value = this_ans_text.val(); + console.log("this_ans_text_value", this_ans_text_value); + if ( /[^\x00-\x7F]/.test(this_ans_text_value)) { + this_ans_text_value = this_ans_text_value.replace(/[^\x00-\x7F]/g, "XX"); + alert("Illegal characters in answer have been replaced by XX"); + } + this_ans_text_value = $.trim(this_ans_text_value); // jQuery trim (some chrome on windows had trouble with trim) + // we have the contents of the answer, so save it to local storage + console.log("saving in local storage at", this_ques_id_text, "the answer", this_ans_text_value); + reading_questions_object[this_ques_id_text] = this_ans_text_value; + localStorage.setObject(reading_questions_object_id, reading_questions_object); + console.log("Object.keys(reading_questions_object)",Object.keys(reading_questions_object)); + console.log("reading_questions", reading_questions); + if (Object.keys(reading_questions_object).length >= reading_questions.length && uname != "guest" && role=="student") { + console.log("all reading questions have been answered"); + reading_questions_all_answered = true; + make_submit_button(); + } + + // and save a copy hidden on the page + console.log("looking for", this_ques_id + "_text_hidden"); + // when the initial answer box is created, there is no hidden version + if ( !document.getElementById(this_ques_id + "_text_hidden")) { + console.log("making a place to hide the answer"); + var hidden_answer_div = document.createElement('div'); + hidden_answer_div.setAttribute('id', this_ques_id + '_text_hidden'); + hidden_answer_div.setAttribute('class', 'tex2jax_ignore asciimath2jax_ignore'); + hidden_answer_div.setAttribute('style', 'display: none'); + console.log("this_ans_text", this_ans_text); + document.getElementById(this_ques_id_text + "_input").insertAdjacentElement("beforebegin", hidden_answer_div); + // hidden_answer_div.insertBefore(this_ans_text); + } + console.log("hiding the raw answer in", this_ques_id + "_text_hidden"); + document.getElementById(this_ques_id + "_text_hidden").innerHTML = escapeHTML(this_ans_text_value); + + //and show it on the page + var this_ans_static = document.createElement('div'); + this_ans_static.setAttribute('id', this_ques_id_text); + this_ans_static.setAttribute('class', 'given_answer has_am process-math processme'); + console.log("setting this_ans_static.innerHTML to", dollars_to_slashparen(escapeHTML(this_ans_text_value))); + this_ans_static.innerHTML = dollars_to_slashparen(escapeHTML(this_ans_text_value)) + " " + +// this_rq_ans.replaceWith(this_ans_static); + console.log("about to replace this_ans_text", this_ans_text); + this_ans_text.replaceWith(this_ans_static); + +// MathJax.Hub.Queue(["Typeset",MathJax.Hub]); + if (mjvers && mjvers < 3) { + MathJax.Hub.Queue(['Typeset', MathJax.Hub]); + } else if (mjvers > 3) { + MathJax.typesetPromise(); + } + + + console.log(" this_ans_text", this_ans_text); + + console.log("this_ans_static", this_ans_static); + + $(this_ans_static).parent().addClass("rq_answer"); + + $('#' + this_ques_id + "_controls").addClass("hidecontrols"); +// $(this_q).parent().parent().addClass("rq_answer"); + +/* + var edit_button = document.createElement('span'); + edit_button.setAttribute('class', "action edit_item rq_edit"); + edit_button.innerHTML = "edit"; + this.replaceWith(edit_button); +*/ + }; + + /* edit an existing answer */ + function edit_one_reading_question(this_ans) { + console.log(".rq_edit", this_ans); + // var this_ques_id = this.parentNode.previousSibling.id; + var this_ques_id = this_ans.parentNode.parentNode.id; + console.log("edditing this_ques_id", this_ques_id); + var this_ques_id_text = this_ques_id + "_text"; + // var this_rq_ans = this.parentNode.previousSibling; + var this_rq_ans = this_ans; +// var this_rq_ans_id = this_ans.id; + console.log("now this_ques_id_text", this_ques_id_text); + console.log(".rq_edit", this_ques_id); + console.log("this_rq_ans", this_rq_ans); + var this_rq_text = this_rq_ans.innerHTML; + console.log("looking for", this_ques_id + "_hidden"); + var this_rq_text_raw = uNescapeHTML(document.getElementById(this_ques_id + "_text_hidden").innerHTML); + console.log("this_rq_text_raw",this_rq_text_raw); + + //this is copied from above. need to eliminate repeated code + + var answer_textarea_editable = document.createElement('textarea'); + answer_textarea_editable.setAttribute('id', this_ques_id_text + "_input"); + answer_textarea_editable.setAttribute('class', 'rq_answer_text'); + answer_textarea_editable.setAttribute('rows', '3'); + answer_textarea_editable.setAttribute('style', 'width:95%; height: 44px;'); + + this_rq_ans.replaceWith(answer_textarea_editable); + + console.log("this_ans is",this_ans); + console.log("adding editing to the parent of thing with id", this_ques_id_text, "which is the parent of", $('#' + this_ques_id_text)); + $('#' + this_ques_id_text + "_input").parent().addClass("editing"); + + $('#' + this_ques_id + "_controls").removeClass("hidecontrols"); + +// WHY? $(this).parent().parent().removeClass("rq_answer"); + +/* var save_button = document.createElement('span'); + save_button.setAttribute('class', "action edit_item rq_save"); + save_button.innerHTML = "save"; + this.replaceWith(save_button); +*/ + + $('#' + this_ques_id + "_text_input").val(this_rq_text_raw); + + answer_textarea_editable.style.height = answer_textarea_editable.scrollHeight + "px"; + answer_textarea_editable.addEventListener("keypress", function() { + // if(answer_textarea_editable.scrollTop != 0){ + answer_textarea_editable.style.height = answer_textarea_editable.scrollHeight + "px"; + // } + }, false); + }; + + +/* handle saving when leaving an answer box, or editing an existing answer + when hovering over an existing answer */ + + $('body').on('click','.given_answer', function(){ +// $(this).children().last().removeClass("hidecontrols"); + edit_one_reading_question(this); + $(this).attr('z-index', '2000'); + }); + + $('body').on('mousedown','.rq_save', function(){ +// $(this).children().last().addClass("hidecontrols"); +// $(this).attr('z-index', ''); + // var this_rq = $(this).find(".given_answer"); +//ooooooooo var this_ques_id = this.parentNode.id; + var this_ques_id = this.parentNode.parentNode.parentNode.id; + console.log("id of this quesiton", this_ques_id); +// var this_rq = $(this).find(".rq_answer_text"); +// console.log("this_rq iiIIIIII", this_rq); + var this_current_answer = document.getElementById(this_ques_id + "_text_input"); + console.log("this_current_answer", this_current_answer); + console.log("this_current_answer.value", this_current_answer.value); + // console.log("this_rq IIIIiiii value", this_rq.value); +// save_one_reading_question(this_rq.parentNode.id); + save_one_reading_question(this_ques_id); + console.log("left answer area"); + $(this).removeClass("editing"); + }); + + $('body').on('click','.rq_delete', function(){ + console.log(".rq_delete"); + var this_ques_id = this.parentNode.parentNode.parentNode.id; + console.log(".rq_delete", this_ques_id); + $('#' + this_ques_id + "_controls").removeClass("hidecontrols"); +//and now put in controls + var this_answer_link = document.createElement('div'); + this_answer_link.innerHTML = rq_answer_label; + console.log("inserting afterend of",reading_question); + // reading_question.insertAdjacentElement("afterend", this_answer_link); + $(this).parent().parent().replaceWith(this_answer_link); + allow_student_answers(); + + + console.log("reading_questions_object", reading_questions_object); + console.log("this_ques_id + _text", this_ques_id + "_text"); + delete reading_questions_object[this_ques_id + "_text"]; + console.log("now reading_questions_object", reading_questions_object); + // localStorage.removeItem(this_ques_id); + localStorage.setObject(reading_questions_object_id, reading_questions_object); + }); + + if(reading_questions_all_answered && uname != "guest" && role=="student") { + make_submit_button(); + console.log("made submit button"); + } + + $('body').on('click','#rq_submit', function(){ + console.log("submitting rq answers"); + $('#rq_submit').addClass('submitted'); + document.getElementById('rq_submit').textContent = "Resubmit answers"; + save_reading_questions(); + }); + + $('body').on('click','.amhelp', function(){ + var amhelpmessage = "Write math formulas as AsciiMath inside `backticks`.\n"; + amhelpmessage += "For example:\nThe Pythagorean theorem says `sin^2(x) + cos^2(x) = 1`,\n"; + amhelpmessage += "The quadratic formula is `x = (-b +- sqrt(b^2 - 4ac))/(2a)`. \n"; + amhelpmessage += "Note the use of parentheses for grouping.\n"; + amhelpmessage += "Visit http://asciimath.org for a list of AsciiMath commands.\n\n"; + amhelpmessage += "You can also use LaTeX, with either slash-parentheses \\(...\\)\n"; + amhelpmessage += "or dollar signs $...$ as delimiters for inline math."; + alert(amhelpmessage) + }); + + if(reading_questions_all_answered && uname != "guest" && role=="student") { + make_submit_button(); + } +} diff --git a/_static/pretext/js/edit.js b/_static/pretext/js/edit.js new file mode 100644 index 0000000..1d7a66a --- /dev/null +++ b/_static/pretext/js/edit.js @@ -0,0 +1,4988 @@ + +editorLog = console.log; +// editorLog = function(){}; +debugLog = function(){}; +// debugLog = console.log; +//parseLog = function(){}; +parseLog = console.log; +errorLog = console.log; + +/* the structure of each object, and its realization as PreTeXt source or in HTML, + is recorded in the objectStructure dictionary. + +{"xml:id": new_id, "sourcetag": new_tag, "parent": parent_description, "title": ""} + +In pretext, pieces are of the form ["piecename", "tag"], while +in source, pieces are of the form ["piecename", "required_component"], while + +*/ + +editing_mode = 0; + +current_page = location.host+location.pathname; +debugLog("current_page", current_page); +chosen_edit_option_key = "edit_option".concat(current_page); +chosen_edit_option = readCookie(chosen_edit_option_key) || ""; +editing_mode = chosen_edit_option; /* delete one of those variables */ +debugLog("chosen_edit_option", chosen_edit_option, "chosen_edit_option", chosen_edit_option > 0); + + +objectStructure = { + "type": { + "html": { + "tag": "span", + "attributes": ['class="type"', 'data-parent_id="<&>xml:id<;>"', 'data-editable="70XX"', 'tabindex="-1"'], + "pieces": [["(capitalize,sourcetag)", ""]] + } + }, + "type-child": { + "html": { + "tag": "span", + "attributes": ['class="type"', 'data-editable="70YY"', 'tabindex="-1"'], + "pieces": [["(capitalize,sourcetag)", ""]] + // "pieces": [["(capitalize,type-contained)", ""]] + } + }, + "type-proof": { + "html": { + "tag": "span", + "attributes": ['class="type"', 'data-editable="70YY"', 'tabindex="-1"'], + "pieces": [["(literal,Proof)", ""]] + // "pieces": [["(capitalize,type-contained)", ""]] + } + }, + "sectiontype": { + "html": { + "tag": "span", + "attributes": ['class="type"'], // the type of a section is not editable? + "pieces": [["(capitalize,sourcetag)", ""]] + } + }, + "codenumber": { + "html": { + "tag": "span", + "attributes": ['class="codenumber"'], + "pieces": [["(codenumber,)", ""]] // maybe () was a bad idea? do we need a triple? + } + }, + "period": { + "html": { + "tag": "span", + "attributes": ['class="period"'], + "pieces": [["(period,)", ""]] + } + }, + "comma": { // used in bibliography + "html": { + "tag": "span", + "attributes": ['class="comma"'], + "pieces": [["(comma,)", ""]] + } + }, + "titleperiod": { + "html": { + "tag": "span", + "attributes": ['class="period"'], + "pieces": [["(titleperiod,)", ""]] + } + }, + "space": { + "html": { + "tag": "span", + "attributes": ['class="space"'], + "pieces": [["(space,)", ""]] + } + }, + "title": { + "html": { + "tag": "span", + "attributes": ['class="title"', 'data-editable="70"', 'tabindex="-1"'], + "pieces": [["title", ""]] + } + }, + "nbsp": { + "html": { + "tag": "", + "pieces": [["(literal, )", ""]], + }, + "pretext": { + "tag": "nbsp", + "pieces": [] + }, + "source": { + "pieces": [] + } + }, + "idx": { + "html": { + "tag": "", + "pieces": [], + }, + "pretext": { + "tag": "idx", + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "h": { + "html": { + "tag": "", + "pieces": [], + }, + "pretext": { + "tag": "h", + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + + "theorem_like_heading": { + "html": { + "tag": "h4", + "cssclass": "heading", + "attributes": ['class="<&>{cssclass}<;>"', 'data-parent_id="<&>xml:id<;>"'], + "pieces": [["{type}", ""], ["{space}", ""], ["{codenumber}", ""], ["{period}", ""], ["{space}", ""], ["{title}", ""], ["{titleperiod}", ""]] + // * means editable piece + } + }, + "proof_like_heading": { + "html": { + "tag": "h5", + "cssclass": "heading", + "attributes": ['class="<&>{cssclass}<;>"', 'xml:id="<&>xml:id<;>"'], + "pieces": [["{type-child}", ""], ["{period}", ""]] + } + }, + "proof_heading": { + "html": { + "tag": "h5", + "cssclass": "heading", + "attributes": ['class="<&>{cssclass}<;>"', 'xml:id="<&>xml:id<;>"'], + "pieces": [["{type-proof}", ""], ["{period}", ""]] + } + }, + "section_like_heading": { + "html": { + "tag": "h2", + "cssclass": "heading hide-type", + "attributes": ['class="<&>{cssclass}<;>"', 'data-parent_id="<&>xml:id<;>"'], + "pieces": [["{sectiontype}", ""], ["{codenumber}", ""], ["{space}", ""], ["{title}", ""]] + } + }, + "title_heading": { + "html": { + "tag": "h2", + "cssclass": "heading", + "attributes": ['class="<&>{cssclass}<;>"', 'data-parent_id="<&>xml:id<;>"'], + "pieces": [["{title}", ""], ["{period}", ""]] + } + }, + "task_like_heading": { + "html": { + "tag": "h6", + "cssclass": "heading", + "attributes": ['class="<&>{cssclass}<;>"', 'data-parent_id="<&>xml:id<;>"'], + "pieces": [["{codenumber}", ""], ["{space}", ""], ["{title}", ""]] + } + }, + "caption_like_heading": { + "html": { + "tag": "h5", + "cssclass": "captionheading", + "attributes": ['class="<&>{cssclass}<;>"', 'data-parent_id="<&>xml:id<;>"'], + "pieces": [["{type}", ""], ["{space}", ""], ["{codenumber}", ""], ["{period}", ""], ["{space}", ""]] + } + }, + "xref": { + "html": { + "tag": "span", + "attributes": ['class="ref tmp"', 'id="<&>xml:id<;>"', 'ref="<&>ref<;>"'], + "pieces": [["(literal,REFERENCE)", ""]], + }, + "pretext": { + "tag": "xref", + "attributes": ['ref="<&>ref<;>"', 'text="<&>text<;>"'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]], + "attributes": [["ref", "*"], ["text", ""],["detail",""],["first",""],["last",""]] + } + }, + "introduction": { + "html": { + "tag": "section", + "attributes": ['class="introduction"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'], + "pieces": [["content", ""]], + }, + "pretext": { + "tag": "introduction", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["title", "*"], ["content", "p"]] + } + }, + "conclusion": { + "html": { + "tag": "section", + "attributes": ['class="conclusion"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'], + "pieces": [["{proof_like_heading}", ""], ["content", ""]], + }, + "pretext": { + "tag": "conclusion", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["title", "*"], ["content", "p"]] + } + }, + + "worksheet": { + "html": { + "tag": "section", + "attributes": ['class="worksheet"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'], + "pieces": [["{section_like_heading}", ""], ["content", ""]], + }, + "pretext": { + "tag": "worksheet", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["title", "*"], ["content", "p"]] + } + }, + "section": { + "html": { + "tag": "section", + "attributes": ['class="section"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'], + "pieces": [["{section_like_heading}", ""], ["content", ""]], + }, + "pretext": { + "tag": "section", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["title", "*"], ["content", "p"]] + } + }, + "subsection": { + "html": { + "tag": "section", + "attributes": ['class="subsection"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'], + "pieces": [["{section_like_heading}", ""], ["content", ""]], + }, + "pretext": { + "tag": "subsection", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["title", "*"], ["content", "p"]] + } + }, + "paragraphs": { + "html": { + "tag": "section", + "attributes": ['class="paragraphs"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'], + "pieces": [["{title_heading}", ""], ["content", ""]], + }, + "pretext": { + "tag": "paragraphs", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["title", "*"], ["content", "p"]] + } + }, + "exercises": { + "html": { + "tag": "section", + "attributes": ['class="exercises"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'], + "pieces": [["{section_like_heading}", ""], ["content", ""]], + }, + "pretext": { + "tag": "exercises", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["title", "*"], ["content", "p"]] + } + }, + "exercisegroup": { + "html": { + "tag": "section", + "attributes": ['class="exercisegroup"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'], + "pieces": [["{section_like_heading}", ""], ["content", ""]], + }, + "pretext": { + "tag": "exercisegroup", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["title", "*"], ["content", "p"]] + } + }, + + + "page": { + "html": { + "tag": "section", + "attributes": ['class="onepage"', 'id="<&>xml:id<;>"', 'data-editable="PPP"', 'tabindex="-1"'], + "pieces": [["content", ""]], + }, + "pretext": { + "tag": "page", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", "p"]] + } + }, + "objectives": { + "html": { + "tag": "article", + "cssclass": "objectives", + "pieces": [["{proof_like_heading}", ""], ["content",""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "data_editable": "160" + }, + "pretext": { + "tag": "objectives", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", "p"]] + } + }, + + + + "p": { + "html": { + "tag": "p", + "pieces": [["content", ""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "99" + }, + "pretext": { + "tag": "p", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, +/* probably there is a better way to do it, but we have separate elements for p + that occur in + text // ip + math + text // mp + math + text // mp + math + text // fp +*/ + "ip": { + "html": { + "tag": "p", + "pieces": [["content", ""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "99" + }, + "pretext": { + "tag_opening": "\n\n'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "mp": { + "html": { + "tag": "p", + "pieces": [["content", ""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="mp"'], + "data_editable": "99" + }, + "pretext": { + "tag_opening": "", + "tag_closing": "", + "attributes": [], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "fp": { + "html": { + "tag": "p", + "pieces": [["content", ""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="fp"'], + "data_editable": "99" + }, + "pretext": { + "tag_opening": "", + "tag_closing": "\n

\n", + "attributes": [], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + + "li": { + "html": { + "tag": "li", + "pieces": [["content", ""]], + "attributes": ['id="<&>xml:id<;>"'], + "data_editable": "98aZ" + }, + "pretext": { + "tag": "li", + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["title", ""], ["content", "p"]] + } + }, + + "blockquote": { + "html": { + "tag": "blockquote", + "pieces": [["content", ""], ["attribution", ""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "cssclass": "blockquote", + "data_editable": "44?" + }, + "pretext": { + "tag": "blockquote", + "pieces": [["content", ""], ["attribution", "attribution"]], + }, + "source": { + "pieces": [["content", "p"], ["attribution", ""]] // attribution can contain a "line". come back to that + } + }, + + "list": { + "html": { + "tag": "ol", + "pieces": [["content", ""]], + "attributes": ['id="<&>xml:id<;>"', 'list-style-type="a"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "AAA" + }, + "pretext": { + "tag": "ol", + "pieces": [["content", ""]], + "attributes": ['label="A"'] + }, + "source": { + "pieces": [["title", ""], ["content", "li"]], + "attributes": [["label", "A"]] + } + }, + + "figure": { + "html": { + "tag": "figure", + "pieces": [["content",""],["{caption}", ""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "data_editable": "32", + "cssclass": "figure figure-like" + }, + "pretext": { + "tag": "figure", + "pieces": [["content"], ["{caption}"]], + "attributes": ['xml:id="<&>xml:id<;>"'] + }, + "source": { + "pieces": [["content", ""], ["captiontext", ""]], + "attributes": [] + } + }, + + "image": { + "html": { + "tag": "div", + "pieces": [["{bareimage}",""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"', 'style="width: <&>width<;>%; margin-right: <&>marginright<;>%; margin-left: <&>marginleft<;>%"'], + "data_editable": "31", + "cssclass": "image-box" + }, + "pretext": { + "tag": "image", + "pieces": [], + "attributes": ['xml:id="<&>xml:id<;>"', 'source="<&>source<;>"', 'alt="<&>alt<;>"', 'width="<&>width<;>%"', 'margins="<&>marginleft<;>% <&>marginright<;>%"'] + }, + "source": { + "pieces": [["",""]], + "attributes": [["source", ""], ["width", "40"], ["marginleft", "20"], ["marginright", "40"], ["alt", ""]] + } + }, + + "bareimage": { + "html": { + "tag": "img", + "pieces": [], + "attributes": ['src="<&>source<;>"', 'alt="<&>alt<;>"', 'class="contained"'], + } + }, + + "sidebyside": { + "html": { + "tag": "div", + "pieces": [["{sbsrow}",""]], + "attributes": ['id="<&>xml:id<;>"', 'class="<&>{cssclass}<;>"'], + "cssclass": "sidebyside" + }, + "pretext": { + "tag": "sidebyside", + "pieces": [["content", ""]], + "attributes": ['xml:id="<&>xml:id<;>"', 'margins="<&>marginleft<;>% <&>marginright<;>%"', 'width="<&>(percentlist,widths)<;>"'], + }, + "source": { + "pieces": [["content",""]], + "attributes": [["marginleft", ""], ["marginright", ""], ["widths", ""]] + } + }, + "sbsrow": { + "html": { + "tag": "div", + "pieces": [["content",""]], // ???? + "attributes": ['class="<&>{cssclass}<;>"', 'style="margin-right: <&>marginright<;>%; margin-left: <&>marginleft<;>%"'], + "data_editable": "89", + "cssclass": "sbsrow" + }, + "pretext": { + "tag": "", + "pieces": [["content",""]], + "attributes": [] + }, + "source": { + "pieces": [["content",""]], + "attributes": [["marginleft", "20"], ["marginright", "40"]] + } + }, + "sbspanel": { + "html": { + "tag": "div", + "pieces": [["content",""]], + "attributes": ['id="<&>xml:id<;>"', 'class="<&>{cssclass}<;>"', 'style="width:<&>(nthitem,widths)<;>%"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "90", + "cssclass": "sbspanel" + }, + "pretext": { + "tag": "stack", + "pieces": [["content", ""]], + "attributes": ['xml:id="<&>xml:id<;>"'] + }, + "source": { + "pieces": [["content",""]] + } + }, + + "proof": { + "html": { + "tag": "article", + "cssclass": "proof", + "pieces": [["{proof_heading}", ""], ["proof",""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "data_editable": "60" + }, + "pretext": { + "tag": "proof", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["proof", ""]] + }, + "source": { + "pieces": [["content", "p"]] + } + }, + "proof-standalone": { + "html": { + "tag": "article", + "cssclass": "proof", + "pieces": [["{XXXXXnorbeingusedXXXXXXX_proof_heading}", ""], ["content",""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "data_editable": "60" + }, + "pretext": { + "tag": "proof", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", "p"]] + } + }, + + "caption": { + "html": { + "tag": "figcaption", + "data_editable": "321", + // "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "attributes": ['id="<&>xml:id<;>"'], + "pieces": [["{caption_like_heading}", ""], ["{captiontext}",""]] + // "pieces": [["(literal, caption goes here)",""]] + }, + "pretext": { + "tag": "caption", + "attributes": [], + "pieces": [["captiontext", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "captiontext": { /* not used */ + "html": { + "tag": "p", + "data_editable": "321", + // "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], +// do it like editabe title? + "attributes": ['data-source_id="<&>xml:id<;>"', 'data-component="caption"', 'class="caption"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "pieces": [["captiontext",""]] + }, + "pretext": { + "tag": "", + "attributes": [], + "pieces": [["captiontext", ""]] + }, + "source": { + "pieces": [["captiontext", ""]] + } + }, + + "references": { + "html": { + "tag": "article", + "cssclass": "bib", + "data_editable": "33", + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "pieces": [["{section_like_heading}", ""], ["content",""]] + }, + "pretext": { + "tag": "references", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", ""], ["content",""]] + }, + "source": { + "pieces": [["title", ""], ["content",""]] + } + }, + +/* biblio, the items directly following it, and the refrences above, + are not usable at this time. references have to be handled in + a text editor. 3 Dec 2021 +*/ + "biblio": { + "html": { + "tag": "div", + "cssclass": "bibentry", + "data_editable": "333", + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "pieces": [["{bib-title}", ""], ["{journal}",""], ["{volume}",""], ["{number}",""], ["{author}",""], ["{pages}",""]] + }, + "pretext": { + "tag": "biblio", + "attributes": ['xml:id="<&>xml:id<;>"', 'type="raw"'], + "pieces": [["title", ""], ["journal",""], ["volume",""], ["number",""], ["author",""], ["pages",""]] + }, + "source": { + "pieces": [["title", ""], ["journal",""], ["volume",""], ["number",""], ["author",""], ["pages",""]] + } + }, + + "bib-title": { + "html": { + "tag": "i", + "pieces": [["title", "zz"]] + } + }, + "author": { + "html": { + "tag": "", + "pieces": [["author", ""], ["{comma}", ""]] + } + }, + "journal": { + "html": { + "tag": "", + "pieces": [["journal", ""]] + } + }, + "volume": { + "html": { + "tag": "b", + "pieces": [["volume", ""]] + } + }, + "pages": { + "html": { + "tag": "jjj", + "pieces": [["pages", ""]] + } + }, + "number": { + "html": { + "tag_opening": "no. ", + "tag_closing": " ", + "pieces": [["number", ""]] + } + }, + + "remark-like": { + "html": { + "tag": "article", + "cssclass": "remark-like", + "data_editable": "92", + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "pieces": [["{theorem_like_heading}", ""], ["statement",""]] + }, + "pretext": { + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["statement", "statement"]] + }, + "source": { + "pieces": [["title", ""], ["statement", "p"]] + } + }, + + "project-like-tasks": { + "html": { + "tag": "article", + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "cssclass": "project-like", + "data_editable": "194", + "pieces": [["{theorem_like_heading}", ""], ["content",""], ["tasks", ""]] + }, + "pretext": { + "tag": "sourcetag", + "pieces": [["title", "title"], ["content", ""], ["tasks", ""]], + "attributes": ['xml:id="<&>xml:id<;>"'] + }, + "source": { + "pieces": [["title", ""], ["content", "p"], ["tasks", ""]] + // "attributes": [["workspace", "0"]] + } + }, + "project-like": { + "html": { + "tag": "article", + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "cssclass": "project-like", + "data_editable": "94", + "pieces": [["{theorem_like_heading}", ""], ["statement",""], ["%hint%", "hint"], ["%answer%", "answer"], ["%solution%", "solution"], ["{workspace}", ""]] + }, + "pretext": { + "tag": "sourcetag", + "pieces": [["title", "title"], ["statement", "statement"], ["hint", "hint"], ["answer", "answer"], ["solution", "solution"]], + "attributes": ['xml:id="<&>xml:id<;>"', 'workspace="<&>workspace<;>"'] + }, + "source": { + "pieces": [["title", ""], ["statement", "p"], ["hint", ""], ["answer", ""], ["solution", ""]], + "attributes": [["workspace", "0"]] + } + }, + + "definition-like": { + "html": { + "tag": "article", + "cssclass": "definition-like", + "data_editable": "95a", + "pieces": [["{theorem_like_heading}", ""], ["statement", ""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'] + }, + "pretext": { + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["statement", "statement"]] + }, + "source": { + "pieces": [["title", ""], ["statement", "p"]] + } + }, + + "theorem-like": { + "html": { + "tag": "article", + "cssclass": "theorem-like", + "data_editable": "93", + "pieces": [["{theorem_like_heading}", ""], ["statement", ""], ["{proof}", ""]], + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'] + }, + "pretext": { + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["statement", "statement"], ["{proof}", ""]] + }, + "source": { + "pieces": [["title", ""], ["statement", "p"], ["proof", ""]] + } + }, + + "task": { + "html": { + "tag": "article", + "cssclass": "exercise-like task", + "data_editable": "94ZZZA", + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "pieces": [["{task_like_heading}", ""], ["statement",""], ["%hint%", "hint"], ["%answer%", "answer"], ["%solution%", "solution"], ["{workspace}", ""]] + }, + "pretext": { + "tag": "task", + "pieces": [["title", "title"], ["statement", "statement"], ["hint", ""], ["answer", ""], ["solution", ""]], + "attributes": ['workspace="<&>workspace<;>"'] + }, + "source": { + "pieces": [["title", ""], ["statement", "p"], ["hint", ""], ["answer", ""], ["solution", ""]], + "attributes": [["workspace", "0"]] + } + }, + +/* consolidate H/A/S */ + "hint": { + "html": { + "tag": "article", + "cssclass": "solution-like hint", + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "pieces": [["{proof_like_heading}", ""], ["content",""]], +// go back and make the lack of data_editable automatically make the contained p editable +/* "data_editable": "454", */ + "data_editable": "hhhh" + }, + "pretext": { + "tag": "hint", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["content", "p"]] + } + }, + "answer": { + "html": { + "tag": "article", + "cssclass": "solution-like answer", + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "pieces": [["{proof_like_heading}", ""], ["content",""]], +// go back and make the lack of data_editable automatically make the contained p editable +/* "data_editable": "454", */ + "data_editable": "hhhh" + }, + "pretext": { + "tag": "answer", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["content", "p"]] + } + }, + "solution": { + "html": { + "tag": "article", + "cssclass": "solution-like solution", + "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "pieces": [["{proof_like_heading}", ""], ["content",""]], +// go back and make the lack of data_editable automatically make the contained p editable +/* "data_editable": "454", */ + "data_editable": "hhhh" + }, + "pretext": { + "tag": "solution", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["title", "title"], ["content", ""]] + }, + "source": { + "pieces": [["content", "p"]] + } + }, + + "workspace": { + "html": { + "tag": "div", + "cssclass": "workspace", + "data_editable": "WwW", + "attributes": ['data-parent_id="<&>xml:id<;>"', 'data-space="<&>workspace<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'], + "pieces": [] + } + }, + + "term": { // need to mark it as inline + "html": { + "tag": "dfn", + "attributes": ['id="<&>xml:id<;>"', 'class="terminology"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "ttt", + "pieces": [["content", ""]] + }, + "pretext": { + "tag": "term", + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + + "em": { // need to mark it as inline + "html": { + "tag": "em", + "attributes": ['id="<&>xml:id<;>"', 'class="emphasis"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "eemm", + "pieces": [["content", ""]] + }, + "pretext": { + "tag": "em", + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "fn": { // need to mark it as inline + "html": { + "tag": "a", + "attributes": ['id="<&>xml:id<;>"', 'class="id-ref fn-knowl original"', 'data-knowl=" "', 'href=" "', 'data-refid="hk-<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "fnfnfn", +// "pieces": [["content", "sup"]] + "pieces": [["(literal,footnote)", "sup"]] + }, + "pretext": { + "tag": "fn", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "alert": { // need to mark it as inline + "html": { + "tag": "em", + "attributes": ['id="<&>xml:id<;>"', 'class="alert"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "aall", + "pieces": [["content", ""]] + }, + "pretext": { + "tag": "alert", + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "init": { // need to mark it as inline + "html": { + "tag": "abbr", + "attributes": ['id="<&>xml:id<;>"', 'class="initialism"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "iinniitt", + "pieces": [["content", ""]] + }, + "pretext": { + "tag": "init", + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "c": { // need to mark it as inline + "html": { + "tag": "code", + "attributes": ['id="<&>xml:id<;>"', 'class="code-inline tex2jax_ignore"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "ccoo", + "pieces": [["content", ""]] + }, + "pretext": { + "tag": "c", + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + + "ellipsis": { // need to mark it as inline + "html": { + "tag": "span", + "attributes": ['id="<&>xml:id<;>"', 'class="abbrev"', 'contenteditable="false"'], + "data_editable": "abbr", + "pieces": [["(literal,…)", ""]] + }, + "pretext": { + "tag": "ellipsis", + "pieces": [] + }, + "source": { + } + }, + "etc": { // need to mark it as inline + "html": { + "tag": "span", + "attributes": ['id="<&>xml:id<;>"', 'class="abbrev"', 'contenteditable="false"'], + "pieces": [["(literal,etc)", ""]] + }, + "pretext": { + "tag": "etc", + "pieces": [] + }, + "source": { + } + }, + + "q": { // need to mark it as inline + "html": { + "tag": "q", + "attributes": ['id="<&>xml:id<;>"', 'class="quote"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "qqq", + "pieces": [["content", ""]] + }, + "pretext": { + "tag": "q", + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + + "m": { // need to mark it as inline + "html": { + "tag_opening": "\\(", + "tag_closing": "\\)", + // "tag": "script", + // "attributes": ['type="math/tex"'], + "pieces": [["content", ""]] + }, + "pretext": { + "tag": "m", + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + + "me": { + "html": { + "tag": "div", + "attributes": ['id="<&>xml:id<;>"', 'class="displaymath process-math"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "42", + "pieces": [["{me_raw}", ""]] + }, + "pretext": { + "tag": "me", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "men": { + "html": { + "tag": "div", + "attributes": ['id="<&>xml:id<;>"', 'class="displaymath process-math"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "42", + "pieces": [["{me_raw}", ""]] + }, + "pretext": { + "tag": "men", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "md": { + "html": { + "tag": "div", + "attributes": ['id="<&>xml:id<;>"', 'class="displaymath process-math"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "42", + "pieces": [["{md_raw}", ""]] + }, + "pretext": { + "tag": "md", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "mdn": { + "html": { + "tag": "div", + "attributes": ['id="<&>xml:id<;>"', 'class="displaymath process-math"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'], + "data_editable": "42", + "pieces": [["{me_raw}", ""]] + }, + "pretext": { + "tag": "mdn", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + }, + "me_raw": { + "html": { + "tag_opening": "\\begin{equation*}", + "tag_closing": "\\end{equation*}", + "pieces": [["content", ""]] + } + }, + "md_raw": { + "html": { + "tag_opening": "\\begin{align*}", + "tag_closing": "\\end{align*}", + "pieces": [["content", ""]] + } + }, +// check if mrow is actually used + "mrow": { + "html": { + "tag_opening": "", + "tag_closing": "\\cr", + "data_editable": "422", + "pieces": [["content", ""]] + }, + "pretext": { + "tag": "mrow", + "attributes": ['xml:id="<&>xml:id<;>"'], + "pieces": [["content", ""]] + }, + "source": { + "pieces": [["content", ""]] + } + } + +} + +var environment_instances = { + "definition-like": ["definition", "conjecture", "axiom", "principle", "heuristic", "hypothesis", "assumption"], + "theorem-like": ["lemma", "proposition", "theorem", "corollary", "claim", "fact", "identity", "algorithm"], + "remark-like": ["remark", "warning", "note", "observation", "convention", "insight"], + "project-like-tasks": ["investigation", "exploration", "project"], + "project-like": ["exercise", "activity"] +} + +for (const [owner, instances] of Object.entries(environment_instances)) { + var data_editable_base = objectStructure[owner].html.data_editable; + var cssclass_base = objectStructure[owner].html.cssclass; + var source_pieces = objectStructure[owner].source.pieces; + var pretext_pieces = objectStructure[owner].pretext.pieces; + var pretext_attributes = (objectStructure[owner].pretext.attributes || []); + var source_attributes = (objectStructure[owner].source.attributes || []); + for (var j=0; j < instances.length; ++j) { + var this_tag = instances[j]; + objectStructure[this_tag] = { + "owner": owner, + "html": { + "tag": objectStructure[owner].html.tag, + "pieces": objectStructure[owner].html.pieces, + "attributes": objectStructure[owner].html.attributes, + "cssclass": cssclass_base + " " + this_tag, + "data_editable": data_editable_base + j.toString(), + "heading": objectStructure[owner].html.heading + }, + "pretext": { + "tag": this_tag, + "pieces": pretext_pieces, + "attributes": pretext_attributes + }, + "source": { + "tag": this_tag, + "pieces": source_pieces, + "attributes": source_attributes + } + } + } +} + +editorLog('objectStructure["exercise"]', objectStructure["exercise"]); + +var sidebyside_instances = { +"sbs": [["2 panels", "sbs2"], ["3 panels", "sbs3"], ["4 panels", "sbs4"]], +//"sbs2": [["full across XX", "sbs2_0_50_50_0"], ["gap but no margin", "sbs2_0_40_40_0"], ["spaced equally", "sbs2_5_40_40_5"]], +"sbs2": [["full across", "sbs_0_50_50_0"], ["gap but no margin", "sbs_0_45_45_0"], ["spaced equally", "sbs_5_40_40_5"]], +"sbs3": [["full across", "sbs_0_34_32_34_0"], ["gap but no margin", "sbs_0_28_28_38_0"], ["spaced equally", "sbs_5_25_26_25_5"]], +"sbs4": [["full across", "sbs_0_25_25_25_25_0"], ["gap but no margin", "sbs_0_20_20_20_20_0"], ["spaced equally", "sbs_3_18_18_18_18_3"]] +} + +Object.assign(objectStructure, sidebyside_instances); + +// shoudl we distinguish empty tags by format? +var always_empty_tags = ["img", "image", "xref"]; +// eventially xref will move to allowed_empty_tags +var allowed_empty_tags = ["div", "span", "p", "stack"]; +var tag_display = { /* the default is "block" */ + "inline": ["m", "em", "ellipsis", "span", "term", "dfn", "q", "c", "code", "alert", "nbsp", "xref", "idx", "h", "init"], + "title": ["title", "idx", "h1", "h2", "h3", "h4", "h5", "h6", "div", "usage", "image"], + "block-tight": [] // ["mp", "mrow"] +} + +inline_tags = tag_display["inline"]; +inline_math = ["m"]; +inline_abbrev = ["ellipsis", "ie", "eg", "etc"]; + +// contained_objects are a componnet of another object, not just buried in content +var contained_objects =["title", "statement", "caption", "captiontext", "proof", + "author", "journal", "volume", "number", "pages"]; + +function tag_type(tag) { + var this_type; + + if (["p", "ip", "mp", "fp"].includes(tag)) { this_type = "p" } + else if (["me", "men", "md", "mdn"].includes(tag)) { this_type = "md" } + else { this_type = tag } + + return this_type +} + +function process_value_from_source(fcn, piece, src) { + + editorLog(fcn, "process_value_from_source", piece, "in", src); + var content_raw = ""; + if (["literal", "codenumber", "period", "titleperiod", "space"].includes(fcn)) { + content_raw = piece; + } else { + if (piece in src) { + content_raw = src[piece] + } else { + if ("parent" in src) { + var parent_src = internalSource[src["parent"][0]]; + if (piece in parent_src) { + content_raw = parent_src[piece] + } else { + errorLog("Error: piece", piece, "fcn", fcn, "from", parent_src, "not in src or parent_src") + } + } else { + errorLog("at the top, or else there is an error") + } + } + } /* fcn != literal */ + +/* + if (typeof myVar == 'string') { + content_raw = content_raw.replace(/-standalone$/, "") // hack because we need alternate to sourcetag + } +*/ + if (fcn == "capitalize") { + content = content_raw.charAt(0).toUpperCase() + content_raw.slice(1); + } else if (fcn == "literal") { + editorLog("literally", piece); + // alert(piece); + content = piece + } else if (fcn == "space") { + content = content_raw + " " + } else if (fcn == "period") { + content = content_raw + "." + } else if (fcn == "comma") { + content = content_raw + "," + } else if (fcn == "titleperiod") { + if (src.title && !(/[!?]$/.test(src.title))) { + content = content_raw + "." + } + } else if (fcn == "percentlist") { + if (content_raw) { + content = content_raw.join("% ") + "%" + } else { + content = "MISSING" + "%" + } + } else if (fcn == "nthitem") { + + editorLog("calculating nthitem", piece, "from ", content_raw, "within", src); + var item_index = 0; // need to be its location among siblings + content = content_raw[item_index]; + } else if (fcn == "codenumber") { + editorLog(" CODENUMBER", src); + content = internalSource.root_data.number_base; + if (src["xml:id"] == top_level_id) { + // no need to add locan number + } else { + content += ".N" + } + } else { + content = content_raw + } + + return content +} + +$(".autopermalink > a").attr("tabindex", -1); + +var editable_objects = [["p", 99], ["ol", 97], ["ul", 96], ["article", 95], ["blockquote", 80], ["section", 66], + ["title", 20], ["caption", 890]]; +for(var j=0; j < editable_objects.length; ++j) { + $(editable_objects[j][0]).attr("data-editable", editable_objects[j][1]); + $(editable_objects[j][0]).attr("tabindex", -1); +} + +/* the code */ + +editorLog(" enabling edit"); + +user_level = "novice"; + +// we have to keep track of multiple consecutive carriage returns +this_char = ""; +prev_char = ""; +prev_prev_char = ""; + +// for resizing and layout changes +// clobal variables so we can adjust them dynamically +move_scale = 1; +magnify_scale = 1; + +final_added_object = ""; +previous_added_object = ""; + +// sometimes we have to prevent Tab from changing focus +this_focused_element = ""; +prev_focused_element = ""; +prev_prev_focused_element = ""; + +var menu_neutral_background = "#ddb"; +var menu_active_background = "#fdd"; + +var recent_editing_actions = []; // we unshift to this, so most recent edit is first. + // currently just a human-readable list +var ongoing_editing_actions = []; +var old_content = {}; // to hold old versions of changed materials + +// what will happen with internationalization? +var keyletters = ["KeyA", "KeyB", "KeyC", "KeyD", "KeyE", "KeyF", "KeyG", "KeyH", "KeyI", "KeyJ", "KeyK", "KeyL", "KeyM", "KeyN", "KeyO", "KeyP", "KeyQ", "KeyR", "KeyS", "KeyT", "KeyU", "KeyV", "KeyW", "KeyX", "KeyY", "KeyZ"]; + +var movement_location_options = []; +var movement_location = 0; +var first_move = true; // used when starting to move, because object no longer occupies its original location + +Storage.prototype.setObject = function(key, value) { +// this.setItem(key, JSON.stringify(value)); + this.setItem(key, JSON.stringify(value, function(key, val) { +// console.log("key", key, "value", value, "val", val); + return val.toFixed ? Number(val.toFixed(3)) : val; +})); +} + +Storage.prototype.getObject = function(key) { + var value = this.getItem(key); + return value && JSON.parse(value); +} + +function randomstring(len) { + if (!len) { len = 10 } + return "tMP" + (Math.random() + 1).toString(36).substring(2,len) +} + +function removeItemFromList(lis, value) { + var index = lis.indexOf(value); + if (index > -1) { + lis.splice(index, 1); + } + return lis; +} + +function rescale(width, max, margin_left, margin_right) { + var available_width = max - parseFloat(margin_left) - parseFloat(margin_right); + return width * 100 / available_width +} + +function spacemath_to_tex(text) { + thetext = text; + + thetext = thetext.replace(/ d([a-zA-Z])(\s|$)/, " \\,d$1$2"); + thetext = thetext.replace(/ *< */, " < "); + + return thetext +} + +function split_paragraphs(paragraph_content) { + + // does the textbox contain more than one paragraph? + var paragraph_content_list = paragraph_content.split("

"); + editorLog("there were", paragraph_content_list.length, "paragraphs, but some may be empty"); + for (var j=0; j < paragraph_content_list.length; ++j) { + editorLog("paragraph", j, "begins", paragraph_content_list[j].substring(0,20)) + } + + var paragraph_content_list_trimmed = []; + + for (var j=0; j < paragraph_content_list.length; ++j) { + // probably each paragraph is wrapped in meaningless div tags + var this_paragraph_contents_raw = paragraph_content_list[j]; + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<\/div>
/g, "\n"); + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/
/g, ""); + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<\/div>/g, ""); + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/ /g, " "); + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/ +
/g, "\n"); + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/
/g, "\n"); + this_paragraph_contents_raw = this_paragraph_contents_raw.trim(); + if (!this_paragraph_contents_raw) { editorLog("empty paragraph") } + else { paragraph_content_list_trimmed.push(this_paragraph_contents_raw) } + editorLog("this_paragraph_contents_raw", this_paragraph_contents_raw); + } + + if (!paragraph_content_list_trimmed.length ) { + // empty, so insert it and delete it later + paragraph_content_list_trimmed = [""]; + } + + return paragraph_content_list_trimmed +} + +var submenu_options = { // revise as these are handled previously +"math-like": [["me"], ["chem"], ["code"]], +"image-like": [["image"], ["video"], ["audio"]], +"aside-like": [["aside"], ["historical"], ["biographical"]], +"list-like": [["itemized list", "list"], ["dictionary list", "dl"], ["table"]], +"layout-like": [["side-by-side panels", "sbs"], ["assemblage"], ["biographical aside"], ["titled paragraph", "paragraphs"]], +"section-like": ["section", "subsection", "paragraphs", "rq", "exercises"], +"sbs": [["2 panels", "sbs2"], ["3 panels", "sbs3"], ["4 panels", "sbs4"]], +"list-like": [["itemized list", "list"], ["dictionary list", "dl"], ["table"]], +"example-like": ["example", "question", "problem"] +} + +Object.assign(submenu_options, sidebyside_instances); + +Object.assign(submenu_options, environment_instances); // wrong because string not list + // or not wrong, if the code is more clever + +/* need to distinguish between the list of objects of a type, + and the list of types that can go in a location. + OR, is it okay that these are all in one list? + It seems to not be okay, because the "blockquote" entry + says that only a "p" can go in a blockquote. But blockquote + is an entry under "quoted". +*/ +base_menu_for = { +"section": [["paragraph", "p"], + ["display math/chemistry/code", "math-like", "c"], + ["list or table", "list-like"], + ["example-like", "example-like"], + ["definition-like", "definition-like"], + ["theorem-like", "theorem-like"], + ["remark-like"], + ["project/exercise-like", "project-like", "j"], + ["image/video/sound", "image-like", "v"], + ["blockquote/poem/music/etc", "quoted"], + ["aside-like", "aside-like", "d"], + ["interactives"], + ["proof", "proof-standalone", "o"], + ["layout-like"], + ["section-like"], + // ["Save", "save"], + ["PreTeXt source", "source"]], + // need to unify section with paragraphs (when sections are managed by the CAT) +"paragraphs": [["paragraph", "p"], + ["display math/chemistry/code", "math-like", "c"], + ["list or table", "list-like"], + ["example-like", "example-like"], + ["definition-like", "definition-like"], + ["theorem-like", "theorem-like"], + ["remark-like"], + ["project/exercise-like", "project-like", "j"], + ["image/video/sound", "image-like", "v"], + ["blockquote/poem/music/etc", "quoted"], + ["aside-like", "aside-like", "d"], + ["interactives"], + ["proof", "proof-standalone", "o"], + ["layout-like"], + // ["Save", "save"], + ["PreTeXt source", "source"]], +"blockquote": [["paragraph", "p"]], +// "ol": [["list item", "li"]], +"article": [["paragraph", "p"], // this is for theorem-like and similar + ["math/chemistry/code", "math-like", "c"], + ["list or table", "list-like"], + ["image/video/sound", "image-like", "v"]], +"li": [["new list item", "li", "i"], + ["paragraph", "p"], + ["list or table", "list-like"], + ["math/chemistry/code", "math-like", "c"], + ["image/video/sound", "image-like", "v"]], +"p": [["emphasis-like"], ["formula"], ["abbreviation"], ["symbol"], ["ref or link", "ref"]] +} +base_menu_for["proof"] = base_menu_for["article"]; +base_menu_for["page"] = base_menu_for["section"]; + + +// not currently used +function past_edits() { + + var the_past_edits = []; + if(recent_editing_actions.length) { + the_past_edits = recent_editing_actions.map(x => [x.join(" ")])} + else { the_past_edits = [["no chnages yet"]] } + + return the_past_edits +} + +// this should be created from inner_menu_for +editing_container_for = { "p": 1, "ip": 1, "mp": 1, "fp": 1, + "theorem-like": ["theorem", "proposition", "lemma", "corollary", "claim", "fact", "identity", "algorithm"], + "definition-like": ["definition", "conjecture", "axiom", "hypothesis", "principle", "heuristic", "assumption"], +"remark-like": ["remark", "warning", "note", "observation", "convention", "insight"], +"example-like": ["example", "question", "problem"], +"exercise-like": ["exercise"], +"ol": ["item"], +"li": [""], +"list": [""], +"image": [""], +"sbs2": [""], +"sbs3": [""], +"sbs4": [""], +"source": 1, +"proof-standalone": [""], //just a guess +"proof": [""] //just a guess +} + +function make_current_editing_tree_from_id(theid) { + +//current_editing keeps track of where we are in the tree. maybe need a better name? + + editorLog(" OOOOO make_current_editing_tree_from_id", theid); + editorLog(" which has internalSource", internalSource[theid]); + editorLog(" within", internalSource); + editorLog(" and the DOM object is", document.getElementById(theid)); + // the existing current_editing know the top level id +// var top_id = current_editing["tree"][0][0].id; + var top_id = top_level_id; + + // but now we need to start over and go bottom-up + current_editing = { + "level": -1, + "location": [], + "tree": [ ] + } + + var current_id = theid; + var current_element = document.getElementById(current_id); + console.log("current_id", current_id, "current_element", current_element); + var selectable_parent, current_element_siblings, selectable_parent_id; + var ct=0; + while (current_id != top_id && ct < 10) { + ct += 1; + editorLog("ct", ct); + editorLog("looking to match current_element", current_element, "until we hit", top_id); + selectable_parent = current_element.parentElement.closest("[data-editable]"); + current_element_siblings = next_editable_of(selectable_parent, "children"); + current_id = selectable_parent.id; + editorLog("current_id", current_id); + current_editing["tree"].unshift(current_element_siblings); + editorLog("looking for", current_element, "in", current_element_siblings); + for (var j=0; j < current_element_siblings.length; ++j) { + if (current_element == current_element_siblings[j]) { + current_editing["level"] += 1; + current_editing["location"].unshift(j); + editorLog("this is item", j); + break + } else { + editorLog(current_element == current_element_siblings[j], "aaa", current_element,"zzz", current_element_siblings[j]) + } + } + current_element = selectable_parent + } + current_editing["level"] += 1; + current_editing["location"].unshift(0); + current_editing["tree"].unshift([document.getElementById(top_id)]); + + editorLog("built current_editing after", ct, "levels"); + editorLog("current_editing[level]", current_editing["level"]); + editorLog("current_editing[location]", current_editing["location"]); + editorLog("current_editing[tree]", current_editing["tree"]) + + editorLog(" OOOOO done with make_current_editing_tree_from_id", theid, document.getElementById(theid)); + +} + +function standard_title_form(object_id) { + var the_object = internalSource[object_id]; + var the_title = the_object.title; + + var title_form = '' + the_title + ''; + + return title_form +} +function standard_caption_form(object_id) { + var the_object = internalSource[object_id]; + editorLog("editing caption of object_id", object_id, "which contains", the_object); + var the_caption = the_object.caption; + + var caption_form = '' + the_caption + ''; + + return caption_form +} + + +function menu_options_for(object_id, component_type, level) { + // this should be a function of the object, not just its tag + // p in li vs p child of section, for example + var menu_for; + + if (!component_type) { component_type = internalSource[object_id]["sourcetag"] } + editorLog("component_tag", component_type); + if (level == "base") { + menu_for = base_menu_for + } else if (level == "move-or-delete") { + editorLog("C0 menu options for", component_type); + var m_d_options; + var component_parent = internalSource[object_id]["parent"][0]; + var component_parent_tag = internalSource[component_parent]["sourcetag"]; + if (component_type == "p" && component_parent_tag == "li") { + m_d_options = [ + ["move-local-p", "Move these words within this page"], + ["move-local-li", "Move this list item within this page"], + ["move-global", "Move this another page (not implemented yet)"], + ["delete", "Delete"] // does it matter whether there are other p in this li? + ]; + } else if(tag_type(component_type) == "p") { + m_d_options = [ + ["move-local-p", "Move this text within this page"], + ["move-global", "Move to another page (not implemented yet)"], + ["delete", "Delete"] + ]; + } else { + m_d_options = [ + ["move-local", "Move within this page"], + ["move-global", "Move to another page (not implemented yet)"], + ["delete", "Delete"] + ]; + } + var this_menu = ""; + for (var i=0; i < m_d_options.length; ++i) { + this_menu += '
  • ' + this_item_shortcut + ''); + } + } else { + this_menu += 'data-jump="' + this_item_name.charAt(0) + '"'; + } + if (i==0) { this_menu += ' id="choose_current"'} + this_menu += '>'; + + if (this_item_name.match(/^[a-z]/i)) { + first_character = this_item_name.charAt(0); + this_item_name = this_item_name.replace(first_character, "" + first_character + ""); + } + + this_menu += this_item_name + // little right triangle if there is a submenu + // if (this_item_label in inner_menu_for()) { this_menu += '
    ' } + if (this_item_label in submenu_options) { this_menu += '
    ' } + this_menu += '
  • '; + } + + return this_menu +} + +function top_menu_options_for(this_obj) { + editorLog("top menu options for aa", this_obj); + var this_id = this_obj.id; + +// maybe the "classList" in this function shoudl instead look at the internalSource? + + var this_list = ""; + + if (this_obj.classList.contains("heading")) { + var this_obj_parent = this_obj.parentElement; + editorLog("heading options for bbb", this_obj_parent); + var this_obj_parent_id = this_obj_parent.id; + var this_obj_parent_source = internalSource[this_obj_parent_id]; + var this_obj_environment = this_obj_parent_source["sourcetag"]; + + editorLog("this_obj_environment", this_obj_environment); + + this_list = '
  • Change the title
  • '; + this_list += '
  • Change "' + this_obj_environment + '" to
  • '; + } else { + var this_object_type = this_obj.tagName; // needs to examine other attributes and then look up a reasonable name +//consolidate this redundancy + this_obj_id = this_obj.id; + if (!this_obj_id) { + this_obj_id=this_obj.getAttribute("data-parent_id") + editorLog("now has id", this_obj_id); + } + this_obj_source = internalSource[this_obj_id]; + editorLog("this_obj_source", this_obj_source); + editorLog("this_obj", this_obj, "classList", this_obj.classList, "T/F", this_obj.classList.contains("image-box")); + this_obj_environment = this_obj_source["sourcetag"]; + if (this_object_type == "P" || this_obj.classList.contains("displaymath")) { + this_list = '
  • Edit ' + this_obj_environment + '
  • '; + var editable_children = next_editable_of(this_obj, "children"); + editorLog("editable_children", editable_children); + if (editable_children.length && !(this_object_type == "P")) { + this_list += '
  • Enter ' + this_obj_environment + '
  • '; + } + if (editable_children.length > 2 && (this_object_type == "SECTION")) { + this_list += '
  • Go to end of ' + this_obj_environment + '
  • '; + } + } else if (this_obj.classList.contains("image-box")) { + editorLog("found an image-box"); + this_list = '
  • Modify layout
  • '; + } else if (this_obj.classList.contains("sbspanel")) { + this_list = '
  • Modify layout
  • '; + } else { + this_list += '
  • Enter ' + this_obj_environment + '
  • '; + if (this_object_type == "SECTION") { + this_list += '
  • Go to end of ' + this_obj_environment + '
  • '; + } + } + + if (this_obj.classList.contains("sbspanel")) { + this_list += '
  • Insert in panel
  • '; + } + + if (this_obj.classList.contains("project-like")) { + this_list += '
  • Add a task
  • '; + } + + if (this_id != top_level_id) { + this_list += '
  • Insert before
  • '; + this_list += '
  • Insert after
  • '; + + this_list += '
  • Move or delete
  • '; + } + this_list += '
  • Metadata
  • '; + if (this_id != top_level_id) { + this_list += '
  • Revert
  • '; + } + if (previous_editing() && this_id == top_level_id) { + this_list += '
  • Resume previous editing
  • '; + } + this_list += '
  • Save
  • '; + this_list += '
  • Stop editing
  • '; + } + return this_list +} + +function edit_menu_from_current_editing(motion) { + // obviously we need to think a bit about current_editing and how it is used + var object_of_interest = current_editing["tree"][ current_editing["level"] ][ current_editing["location"][ current_editing["level"] ] ]; + edit_menu_for(object_of_interest, motion); +} + +function edit_menu_for(this_obj_or_id, motion) { + editorLog("make edit menu", motion, "for", this_obj_or_id); + + // delete the old menu, if it exists + if (document.getElementById('edit_menu_holder')) { + var current_menu = document.getElementById('edit_menu_holder'); + editorLog("current_menu", current_menu); + editorLog("this_choice", document.getElementById('enter_choice')); + if (this_choice = document.getElementById('enter_choice')) { + if (this_choice.getAttribute("data-location") == "stay") { + current_menu.previousSibling.classList.remove("may_leave") + } else { + current_menu.parentElement.classList.remove("may_select"); + current_menu.parentElement.classList.remove("may_enter"); + } + } + current_menu.parentElement.classList.remove("may_select"); + current_menu.parentElement.classList.remove("may_enter"); + current_menu.remove(); + } + + if (!this_obj_or_id) { + errorLog("error: empty this_obj_or_id", motion); + return "" + } else { + editorLog("this_obj_or_id", this_obj_or_id, "string?", typeof this_obj_or_id === 'string'); + editorLog("which has parent", this_obj_or_id.parentElement) + } + + console.log("this_obj_or_id", this_obj_or_id, typeof this_obj_or_id); + if (typeof this_obj_or_id === 'string') { + this_obj = document.getElementById(this_obj_or_id) + } else { + this_obj = this_obj_or_id + } + console.log("this_obj", this_obj); + var this_id = this_obj.id; +// this_obj = document.getElementById(this_obj); // because is is an id? Maybe need cases here + + if (motion == "entering") { + menu_location = "afterbegin"; + this_obj.classList.remove("may_leave"); + if (next_editable_of(this_obj, "children").length && !(this_obj.tagName == "P")) { + this_obj.classList.add("may_enter"); + } else { + this_obj.classList.add("may_select"); + } + if (inline_tags.includes(this_obj.tagName.toLowerCase())) { + this_obj.classList.add("inline"); + } + } else { menu_location = "afterend"; + this_obj.classList.remove("may_select"); + this_obj.classList.remove("may_enter"); + this_obj.classList.add("may_leave"); + editorLog("added may_leave to", this_obj) + } // when motion is 'leaving' + + var edit_menu_holder = document.createElement('div'); + edit_menu_holder.setAttribute('id', 'edit_menu_holder'); + edit_menu_holder.setAttribute('class', 'edit_menu_holder'); + edit_menu_holder.setAttribute('tabindex', '-1'); + editorLog("adding menu for", this_obj_or_id, "menu_location", menu_location); + editorLog("which has tag", this_obj.tagName); + editorLog("does", this_obj.classList, "include type", this_obj.classList.contains("type")); + + this_obj.insertAdjacentElement(menu_location, edit_menu_holder); + editorLog("added edit_menu_holder", document.getElementById("edit_menu_holder"), motion); + + var edit_option = document.createElement('span'); + edit_option.setAttribute('id', 'enter_choice'); + + if (motion == "entering") { + editorLog("inline_tags", inline_tags, "tag", this_obj.tagName.toLowerCase()); + editorLog("next_editable_of(this_obj, children)", next_editable_of(this_obj, "children")); + if (false && inline_tags.includes(this_obj.tagName.toLowerCase())) { + edit_option.innerHTML = "change this?"; + edit_option.setAttribute('data-location', 'inline'); + } else if (this_obj.classList.contains("type")) { + // e.g., changing "proposition" to "theorem" + // need to code this better: over-writing edit_option + edit_option = document.createElement('ol'); + edit_option.setAttribute('id', 'edit_menu'); + edit_option.setAttribute('class', 'edit_menu'); + this_obj_parent_id = this_obj.parentElement.parentElement.id; + this_obj_environment = internalSource[this_obj_parent_id]["sourcetag"]; + edit_option.innerHTML = '
  • Change "' + this_obj_environment + '" to
  • '; + edit_option.setAttribute('data-location', 'inline'); + } else if (this_obj.classList.contains("image-box")) { + edit_option.innerHTML = "modify this image layout, or add near here?"; + } else if (this_obj.classList.contains("sbspanel")) { + edit_option.innerHTML = "modify this panel layout, or change panel contents?"; + } else if (this_obj.classList.contains("title") || this_obj.classList.contains("caption")) { + var this_contained_type = "title"; + if (this_obj.classList.contains("caption")) { this_contained_type = "caption" } + edit_option = document.createElement('ol'); + edit_option.setAttribute('id', 'edit_menu'); + edit_option.setAttribute('class', 'edit_menu'); + editorLog("this_obj", this_obj); + editorLog("this_obj.innerHTML", this_obj.innerHTML); + editorLog("menu only?", this_obj.innerHTML == '
    '); + this_obj_parent_id = this_obj.parentElement.parentElement.id; + this_obj_environment = internalSource[this_obj_parent_id]["sourcetag"]; + if (this_obj.innerHTML == '
    ') { + edit_option.innerHTML = '
  • Add a ' + this_contained_type + '
  • '; + } else { + edit_option.innerHTML = '
  • Change ' + this_contained_type + '
  • '; + } + edit_option.setAttribute('data-location', 'inline'); + } else if ((this_obj.classList.contains("placeholder") && (this_obj.classList.contains("hint") || + this_obj.classList.contains("answer") || + this_obj.classList.contains("solution") || + this_obj.classList.contains("proof")) ) ) { + var theverb = "add" + var thenoun = this_obj.getAttribute("data-HAS"); + edit_option.setAttribute('id', 'choose_current'); + edit_option.setAttribute('data-env', thenoun); + edit_option.setAttribute('data-parent_id', this_obj.getAttribute("data-parent_id")); + edit_option.innerHTML = "" + theverb + "" + " " + thenoun; + } else if (this_obj.classList.contains('workspace')) { + edit_option.setAttribute('id', 'choose_current'); + edit_option.setAttribute('data-env', 'workspace'); + edit_option.setAttribute('data-action', 'modify'); + edit_option.setAttribute('data-parent_id', this_obj.getAttribute("data-parent_id")); + + edit_option.innerHTML = "" + "adjust" + "" + " " + "workspace"; + } else { + if (next_editable_of(this_obj, "children").length && this_obj.tagName != "P") { + editorLog("this_obj", this_obj); + if (this_id == top_level_id) { + edit_option.innerHTML = "enter this " + internalSource[this_obj.id]["sourcetag"] + "?"; + } else { + edit_option.innerHTML = "enter this " + internalSource[this_obj.id]["sourcetag"] + ", or add near here?"; + } + } else { + edit_option.innerHTML = "edit this passage, or add near here?"; + } + edit_option.setAttribute('data-location', 'next'); + } + } else { + edit_option.setAttribute('data-location', 'stay'); + edit_option.innerHTML = "continue editing this " + internalSource[this_obj.id]["sourcetag"]; + } + editorLog("edit_option", edit_option); + document.getElementById("edit_menu_holder").insertAdjacentElement("afterbegin", edit_option); + document.getElementById('edit_menu_holder').focus(); +} + +function next_editable_of(obj, relationship) { + var next_to_edit; + editorLog("finding", relationship, "editable of", obj); + if (relationship == "children") { + next_to_edit = $(obj).find(' > [data-editable], > .sidebyside > .sbsrow > [data-editable], > li > [data-editable], > .heading > [data-editable], > .hint > [data-editable], > .answer > [data-editable]') + } else if (relationship == "outer-block") { // for example, a direct child of a section + next_to_edit = $(obj).find(' > [data-editable]') + } else if (relationship == "inner-block") { // typically a paragraph + next_to_edit = $(obj).find('section > [data-editable], [data-editable="99"], [data-editable="42"]') + } else if (relationship == "li-only") { // typically a paragraph + next_to_edit = $(obj).find('li') + } else { + editorLog("unimplemented next_editable_of") + } + + editorLog("next_to_edit", next_to_edit); + return next_to_edit +} + +function create_new_internal_object(new_tag, new_id, parent_description) { + + var new_source = {"xml:id": new_id, "sourcetag": new_tag, "parent": parent_description, "title": ""} + + editorLog("create new internal object", new_tag, "new_id", new_id, "parent_description", parent_description); + editorLog("within", internalSource[parent_description[0]]); + if (new_tag.startsWith("sbs")) { // creating an sbs, which contains one sbsrow, which contains several sbspanels + new_source.sourcetag = "sidebyside"; + var sbs_layout = new_tag.split("_"); + var [margin_left, margin_right] = [sbs_layout[1], sbs_layout[sbs_layout.length - 1]]; + editorLog("sbs side margins", margin_left, "jj", margin_right); + new_source.marginleft = margin_left; + new_source.marginright = margin_right; + + var col_content = ""; + var widths = []; + for (var j=2; j <= sbs_layout.length - 2; ++j) { + widths.push(sbs_layout[j]); + var new_col_id = randomstring(); + col_content += "<&>" + new_col_id + "<;>"; + internalSource[new_col_id] = {"xml:id": new_col_id, "sourcetag": "sbspanel", + "content": "", "parent": [new_id, "content"]} + } + new_source.widths = widths; + new_source.content = col_content; + + editorLog("new sbs", new_source); + + } else { + + editorLog("new_tag", new_tag); + var thisstructure = objectStructure[new_tag]; + var thisownersourcestructure = {}; + if (!thisstructure) { errorLog(new_tag + " not implemented yet"); return "" } + if ("owner" in thisstructure) { + var thisownerstructure = objectStructure[thisstructure.owner]; + thisownersourcestructure = thisownerstructure.source; + } + var thissourcestructure = Object.assign({},thisownersourcestructure, thisstructure.source); + + editorLog("thissourcestructure", thissourcestructure); + + if ("attributes" in thissourcestructure) { + these_source_attributes = thissourcestructure.attributes; + for (var j=0; j < these_source_attributes.length; ++j) { + editorLog("adding", j, "attribute", these_source_attributes[j]); + new_source[these_source_attributes[j][0]] = these_source_attributes[j][1] + } + } + +/* here need to also use the owner structure */ + var these_source_pieces = thissourcestructure.pieces; + for (var j=0; j < these_source_pieces.length; ++j) { + editorLog("adding a piece", these_source_pieces[j]); + var [this_piece, this_piece_contains] = these_source_pieces[j]; + + if (this_piece_contains) { + var new_child_id = randomstring(); + new_source[this_piece] = "<&>" + new_child_id + "<;>"; + create_new_internal_object(this_piece_contains, new_child_id, [new_id, this_piece]); + } else { + new_source[this_piece] = "" + } + } + } + + editorLog("made the new_source", new_source); + + internalSource[new_id] = new_source; + + editorLog("parent_description", parent_description, "new_tag", new_tag, "new_id", new_id); + editorLog("internalSource", internalSource); + if (new_tag == "list") { + // do nothing, because it is the child "li" which we are really creating + // chack that: maybe do add, if the stack is in the proper order + } else if (tag_type(new_tag) == "p"){ + // p is the default, so no need to keep track of it + } else if (new_tag == "source"){ + // not really a tag + } else if (new_tag.startsWith("sbs")){ + ongoing_editing_actions.push(["new", "sbs", new_id]); + } else { + ongoing_editing_actions.push(["new", new_tag, new_id]); + } + return new_tag +} + +function show_source(sibling, relative_placement) { +// var current_source = document.getElementById("newpretextsource"); +// if (current_source) { editorLog("curr sou", current_source); alert("curr sour"); current_source.remove() } + var edit_placeholder = document.createElement("span"); + edit_placeholder.setAttribute('id', "newsource"); + sibling.insertAdjacentElement(relative_placement, edit_placeholder); + + editorLog("just added", edit_placeholder); + + var the_pretext_source = output_from_id("", top_level_id, "pretext"); + + the_pretext_source = the_pretext_source.replace(/\n\n/g, '\n'); + + // remove temporary ids + the_pretext_source = the_pretext_source.replace(/ xml:id="tMP[0-9a-z]+"/g, ''); + the_pretext_source = the_pretext_source.replace(/^ +$/mg, ''); // m = multiline + +// var the_old_source = document.getElementById("newsource"); +// if (the_old_source) { the_old_source.remove() } + edit_placeholder.insertAdjacentHTML('afterend', ''); +} + +// unify with show_source, and maybe make the clean up part of output_from_id +function save_source() { +// var current_source = document.getElementById("newpretextsource"); +// if (current_source) { editorLog("curr sou", current_source); alert("curr sour"); current_source.remove() } + editorLog(" QQ saving"); + + var the_pretext_source = output_from_id("", top_level_id, "pretext"); + + the_pretext_source = the_pretext_source.replace(/\n\n/g, '\n'); + // remove temporary ids + the_pretext_source = the_pretext_source.replace(/ xml:id="tMP[0-9a-z]+"/g, ''); + the_pretext_source = the_pretext_source.replace(/^ +$/mg, ''); // m = multiline + + editorLog(" RR saving", top_level_id, "which begins", the_pretext_source.substring(0,50)); + parent.save_file(top_level_id, the_pretext_source) +} + +function create_object_to_edit(new_tag, new_objects_sibling, relative_placement) { + + // when relative_placement is "afterbegin", the new_objects_sibling is actually its parent + editorLog("create object to edit", new_tag, new_objects_sibling, relative_placement); + // first insert a placeholder to edit-in-place + var new_id = randomstring(); + recent_editing_actions.push(["new", new_tag, new_id]); + // we won;t need all of these, so re-think when these are created + var edit_placeholder = document.createElement("span"); + edit_placeholder.setAttribute('id', new_id); + + // when adding an li, you are actually focused on somethign inside an li + // but, maybe that distinction shoud be mede before calling create object to edit ? + if (new_tag == "li") { new_objects_sibling = new_objects_sibling.parentElement } + + var sibling_id, parent_description, object_neighbor; + + if (["hint", "answer", "solution", "proof"].includes(new_tag)) { // this is only for the case that a solution does not already exist +// create_new + + sibling_id = new_objects_sibling.parentElement.id; + parent_description = [sibling_id, new_tag] + + editorLog(new_tag, "parent_description", parent_description); + object_neighbor = "" ; // will not be used + + } else if(new_objects_sibling.classList.contains("sbspanel")) { //bad hack! use internalCOntents! + sibling_id = new_objects_sibling.id; + editorLog("special case for empty sbspanel",sibling_id); + // alert("special sbspanel case"); + parent_description = [sibling_id, "content"] + object_neighbor = "" ; // will not be used??? + } else { + // and describe where it goes + editorLog("new_objects_sibling",new_objects_sibling); + sibling_id = new_objects_sibling.id; + parent_description = internalSource[sibling_id]["parent"]; + object_neighbor = new RegExp('(<&>' + sibling_id + '<;>)'); + } + + if (relative_placement == "afterbegin" && new_tag != "image") { // when adding to a sbs panel + // redo the condition so that it explicitly uses sbs + // redundant with the "special case" above? + // parent_description = [new_id, "content"]; + } + var object_neighbor = new RegExp('(<&>' + sibling_id + '<;>)'); + if (new_tag == "task" && !(new_objects_sibling.classList.contains("task"))) { + // when task is being added by selecting from the parent exercise + relative_placement = "atend"; + parent_description = [sibling_id, "tasks"]; + } + if (["hint", "answer", "solution", "proof"].includes(new_tag)) { // this is only for the case that a solution does not already exist + relative_placement = "replace"; + } + editorLog(new_tag, "parent_description", parent_description); + + // then create the empty internalSource for the new object + var new_obj = create_new_internal_object(new_tag, new_id, parent_description); + if (!new_obj) { return "" } + + // we have made the new object, but we still have to put it in the correct location + + var the_current_arrangement = internalSource[parent_description[0]][parent_description[1]]; + editorLog(" the_current_arrangement", the_current_arrangement); + editorLog(" from parent_description", parent_description, "internalSource[parent_description[0]]", internalSource[parent_description[0]]); + editorLog(" current_editing", current_editing); + +// maybe the changes to current_editing is different for lists? + + var neighbor_with_new = ''; + var current_level = current_editing["level"]; + var current_location = current_editing["location"][current_level]; + editorLog(" UUU current_editing", current_editing["level"], current_editing["location"].length, current_editing["tree"].length, current_editing["tree"][current_editing["level"]]) + if (relative_placement == "beforebegin" || relative_placement == "afterbegin") { + neighbor_with_new = '<&>' + new_id + '<;>' + '$1'; + } + else if (relative_placement == "afterend" || relative_placement == "beforeend"){ + neighbor_with_new = '$1' + '<&>' + new_id + '<;>' + current_location += 1 + } + editorLog("makking new_arrangement from", object_neighbor, "by", neighbor_with_new); + + if (relative_placement == "atend" || relative_placement == "replace" ) { + // this is not quire gight, but it works for hint/answer/solution + new_arrangement = the_current_arrangement + '<&>' + new_id + '<;>'; + } else if(the_current_arrangement) { + new_arrangement = the_current_arrangement.replace(object_neighbor, neighbor_with_new); + } else { + new_arrangement = '<&>' + new_id + '<;>'; + } + editorLog("which became", new_arrangement); +// alert("here"); + internalSource[parent_description[0]][parent_description[1]] = new_arrangement; + if (new_tag == "list") { + // current_editing["level"] += 1; + // current_editing["location"].push(0); + // current_editing["tree"].push([document.getElementById(new_p_id)]) + } else { + current_editing["location"][current_level] = current_location; + } + editorLog(" new_arrangement", new_arrangement); + editorLog("tried to insert", new_id, "next to", sibling_id, "in", the_current_arrangement) + editorLog(" updated current_editing", current_editing); + editorLog(" VVV current_editing", current_editing["level"], current_editing["location"].length, current_editing["tree"].length, current_editing["tree"][current_editing["level"]]) + editorLog("relative_placement", relative_placement, "edit_placeholder", edit_placeholder); + + if (relative_placement == "atend") { + new_objects_sibling.insertAdjacentElement("beforeend", edit_placeholder); + } else if (relative_placement == "replace") { + new_objects_sibling.replaceWith(edit_placeholder); + } else { + new_objects_sibling.insertAdjacentElement(relative_placement, edit_placeholder); + } + + return edit_placeholder +} + +function edit_in_place(obj, oldornew) { + // currentlt old_or_new is onlu use as "new" for a new li, so that we know + // to immediately make a new li to edit + // previous comment probebly wrong/out of date + + var thisID; + editorLog("in edit in place", obj); + if (thisID = obj.getAttribute("id")) { + editorLog("will edit in place id", thisID, "which is", obj); + thisTagName = obj.tagName.toLowerCase(); + } else { // editing somethign without an id, so probably is a title or caption + if (obj.classList.contains("heading")) { + editorLog("changing a heading"); + editorLog("except we don;t know how to do that") + } else { + errorLog("error: I don't know how to edit", obj) + } + return "" + } + + // this only works for paragraphs, + // which may be right, because existing content is mostly titles and paragraphs + if ( internalSource[thisID] ) { + var new_tag = internalSource[thisID]["sourcetag"]; + var new_id = thisID; // track down why new_id is in the code + editorLog("new_tag is", new_tag, "from thisID", thisID, "from", internalSource[thisID]); + if (tag_type(new_tag) == "p" || tag_type(new_tag) == "md") { // make into a category? + var this_content_container = document.createElement('div'); + this_content_container.setAttribute('id', "actively_editing"); + this_content_container.setAttribute('data-age', oldornew); + editorLog("thing with thisID", thisID, "is",document.getElementById(thisID)); + $("#" + thisID).replaceWith(this_content_container); + + var idOfEditText = 'editing' + '_input_text'; + var paragraph_editable = document.createElement('div'); + paragraph_editable.setAttribute('contenteditable', 'true'); + if (tag_type(new_tag) == "md") { + paragraph_editable.setAttribute('class', 'text_source displaymath_input'); + } else { + paragraph_editable.setAttribute('class', 'text_source paragraph_input'); + } + paragraph_editable.setAttribute('id', idOfEditText); + paragraph_editable.setAttribute('data-source_id', thisID); + paragraph_editable.setAttribute('data-parent_id', internalSource[thisID]["parent"][0]); + paragraph_editable.setAttribute('data-parent_component', internalSource[thisID]["parent"][1]); + + document.getElementById('actively_editing').insertAdjacentElement("afterbegin", paragraph_editable); + + editorLog("setting", $('#' + idOfEditText), "to have contents", internalSource[thisID]["content"]); + +// from https://stackoverflow.com/questions/21257688/paste-rich-text-into-content-editable-div-and-only-keep-bold-and-italics-formatt + +// figure out better how to do this as needed. + $('[contenteditable]').on('paste',function(e) { + e.preventDefault(); + var text = (e.originalEvent || e).clipboardData.getData('text/plain') || prompt('Paste something..'); + document.execCommand('insertText', false, text); + }); + the_contents = internalSource[thisID]["content"]; + the_contents = expand_condensed_source_html(the_contents, "edit"); + the_contents = the_contents.replace(/\\cr/g, "

    "); + $('#' + idOfEditText).html(the_contents); + document.getElementById(idOfEditText).focus(); + editorLog("made edit box for", thisID); + editorLog("which is", document.getElementById(idOfEditText)); + editorLog("Whth content CC" + document.getElementById(idOfEditText).innerHTML + "DD"); + editorLog("Whth content EE" + document.getElementById(idOfEditText).innerText + "FF"); + editorLog("Whth content GG" + document.getElementById(idOfEditText).textContent + "HH"); + this_char = ""; + prev_char = ""; + + } else if (new_tag == "image") { + var this_content_container = document.createElement('div'); + this_content_container.setAttribute('id', "actively_editing"); + this_content_container.setAttribute('data-age', oldornew); + this_content_container.setAttribute('style', "width:50%; margin-left:auto; margin-right: auto; padding: 2em 3em 3em 3em; background: #fed"); + $("#" + thisID).replaceWith(this_content_container); + + var idOfEditText = 'editing' + '_input_image'; + var image_editable = document.createElement('div'); + image_editable.setAttribute('contenteditable', 'true'); + image_editable.setAttribute('class', 'image_source'); + image_editable.setAttribute('id', idOfEditText); + image_editable.setAttribute('style', "background: #fff"); + image_editable.setAttribute('data-source_id', thisID); + image_editable.setAttribute('data-parent_id', internalSource[thisID]["parent"][0]); + image_editable.setAttribute('data-parent_component', internalSource[thisID]["parent"][1]); + + document.getElementById('actively_editing').insertAdjacentElement("afterbegin", image_editable); + + var edit_instructions = document.createElement('span'); + edit_instructions.setAttribute('style', "font-size: 90%"); + edit_instructions.innerHTML = "URL of image:" + document.getElementById('actively_editing').insertAdjacentElement("afterbegin", edit_instructions); + + document.getElementById(idOfEditText).focus(); + editorLog("made edit box for", thisID); + editorLog("which is", document.getElementById(idOfEditText)); + editorLog("Whth content CC" + document.getElementById(idOfEditText).innerHTML + "DD"); + editorLog("Whth content EE" + document.getElementById(idOfEditText).innerText + "FF"); + editorLog("Whth content GG" + document.getElementById(idOfEditText).textContent + "HH"); + this_char = ""; + prev_char = ""; + + } else { + + editorLog(new_tag, "create the object, then edit p in place", obj); + + var this_object = html_from_internal_id(new_id, ""); + var where_it_goes = document.getElementById(thisID); + where_it_goes.insertAdjacentHTML('afterend', this_object[0]); + where_it_goes.remove(); + var where_it_is = document.getElementById(thisID); + + + editorLog("added this_object", this_object); + editorLog("where it is", where_it_is); + + var this_source = internalSource[thisID]; + if (this_source.sourcetag == "sidebyside") { // generalize to container was added + editorLog("added an sbs", document.getElementById(thisID)); + editorLog("its .firstChild", document.getElementById(thisID).firstElementChild); + editorLog("its .firstChild.firstchild", document.getElementById(thisID).firstElementChild.firstElementChild); + var first_panel_id = document.getElementById(thisID).firstElementChild.firstElementChild.id; + editorLog("first_panel_id", first_panel_id, document.getElementById(first_panel_id)); + make_current_editing_tree_from_id(first_panel_id); + edit_menu_from_current_editing("entering"); + } else { + var empty_p_child = $(where_it_is).find("p"); + if (empty_p_child[0]) { + editorLog("found the empty p", empty_p_child); + editorLog("found the empty p[0]", empty_p_child[0]); + edit_in_place(empty_p_child[0], "new"); + } else { + errorLog("error: no empty p to edit") + } + } + } + + } else { + editorLog("Error: edit in place of object that is not already known", obj); + editorLog("What is known:", internalSource) + } +} + +function resume_editing() { + internalSource = previous_editing(); + replace_by_id(internalSource["root_data"]["id"], "html"); + edit_menu_for(top_level_id, "entering"); + console.log("editing resumed"); +} + +function replace_by_id(theid, format) { + + if (format != "html") { return "" } + + var this_object_new = output_from_id("",theid, format); + + console.log("id", theid); +// GO BACK AND REVISIT THE NEXT 3 LINES +// document.getElementById(theid).setAttribute("id", "delete_me"); +// document.getElementById("delete_me").insertAdjacentHTML('beforebegin', this_object_new); +// document.getElementById("delete_me").remove(); + +// need to also work with MJ3 +// MathJax.Hub.Queue(['Typeset', MathJax.Hub, document.getElementById(theid)]); + console.log("MathJax on", theid, document.getElementById(theid)); +// MathJax.typesetPromise(document.getElementById(theid)); + MathJax.typesetPromise(); + + console.log("adjusting workspace"); +window.setTimeout(adjustWorkspace, 1000); +} + +// temporary: need to unify img and sbs layout +function modify_by_id(theid, modifier) { + editorLog("modifying by id", theid); + if (internalSource[theid]["sourcetag"] == "sbspanel") { + modify_by_id_sbs(theid, modifier) + } else if (environment_instances["project-like"].includes(internalSource[theid]["sourcetag"]) + || internalSource[theid]["sourcetag"] == "task") { + modify_by_id_workspace(theid, modifier) + } else { + modify_by_id_image(theid, modifier) + } + save_edits() +} + +function modify_by_id_workspace(theid, modifier) { + + var the_height = internalSource[theid]["workspace"]; + editorLog("the_height", the_height, "from", internalSource[theid]); + +//modify: enlarge, shrink, enlargeslightly, shrinkslightly, done + + the_height = parseInt(the_height); + editorLog('the_height, ', the_height); + + if (modifier == "enlarge") { the_height += 10 } + else if (modifier == "shrink") { the_height -= 10 } + else if (modifier == "enlargeslightly") { the_height += 1 } + else if (modifier == "shrinkslightly") { the_height -= 1 } + + if (the_height < 0) { the_height = 0 } + + internalSource[theid]["workspace"] = the_height; + editorLog("the_height is now", the_height); + + var this_workspace = document.getElementById(theid).querySelector(".workspace"); + this_workspace.setAttribute("style", "height:" + the_height*10 + "px"); + this_workspace.setAttribute("data-space", the_height); +} + +function modify_by_id_image(theid, modifier) { + + var width = internalSource[theid]["width"]; + var marginleft = internalSource[theid]["marginleft"]; + var marginright = internalSource[theid]["marginright"]; + editorLog('width, , marginright, , marginleft', width, "mr", marginright, "ml", marginleft); + width = parseInt(width); + marginright = parseInt(marginright); + marginleft = parseInt(marginleft); + + var scale_direction = 1; + var moving_direction = 1; + if (modifier == "shrink") { scale_direction = -1 } + else if (modifier == "left") { moving_direction = -1 } + if ("enlarge shrink".includes(modifier)) { + if ((width >= 100 && scale_direction == 1) || (width <= 0 && scale_direction == -1)) { + editorLog("can't go above 100 or below 0"); + return + } else { + width += 2*scale_direction*magnify_scale; + } + if (marginleft > 0 && marginright > 0) { + marginleft += -1*scale_direction*magnify_scale; + marginright += -1*scale_direction*magnify_scale; + } else if (marginleft > 0) { + marginleft += -2*scale_direction*magnify_scale; + } else if (marginright > 0) { + marginright += -2*scale_direction*magnify_scale; + } else if (scale_direction < 0) { // applies when we shrink a 100 width image + marginleft += -1*scale_direction*magnify_scale; + marginright += -1*scale_direction*magnify_scale; + } else { + // do nothing: this is a placeholder which is reached when both margins are 0 + editorLog("already have no margins, width is", width); + } + } else if ("left right".includes(modifier)) { + editorLog("marginleft*moving_direction", marginleft*moving_direction, "marginright*moving_direction", marginright*moving_direction); + if ((marginleft > 0 && marginright > 0) || (marginright*moving_direction > 0) || (marginleft*moving_direction < 0)) { + marginleft += moving_direction*move_scale; + marginright += -1*moving_direction*move_scale; + } else { + // do nothing: this is a placeholder which is reached when both margins are 0 + // we choose to prioritize scale, so a 100% image cannot be shifted + editorLog("already at 100%, width is", width); + } + } + + var the_new_sizes = "width: " + width + "%;"; + the_new_sizes += "margin-right: " + marginright + "%;"; + the_new_sizes += "margin-left: " + marginleft + "%;"; + + internalSource[theid]["width"] = width; + internalSource[theid]["marginleft"] = marginleft; + internalSource[theid]["marginright"] = marginright; + + document.getElementById(theid).setAttribute("style", the_new_sizes); +} + +function modify_by_id_sbs(theid, modifier) { + + var this_panel_source = internalSource[theid]; +// var this_width = this_panel_source["width"]; + var this_sbs_id = this_panel_source["parent"][0]; + var this_sbs_source = internalSource[this_sbs_id]; + editorLog("this_sbs_source", this_sbs_source); + var marginleft = parseInt(this_sbs_source["marginleft"]); + var marginright = parseInt(this_sbs_source["marginright"]); + var these_siblings = this_sbs_source["content"]; + these_siblings = these_siblings.replace(/^\s*<&>\s*/, ""); + these_siblings = these_siblings.replace(/\s*<;>\s*$/, ""); + these_siblings = these_siblings.replace(/>\s*<"); + editorLog("these_siblings", these_siblings); + var these_siblings_list = these_siblings.split("<;><&>"); + var this_panel_index = these_siblings_list.indexOf(theid); + editorLog("this panel", theid, "is", this_panel_index, "within", these_siblings_list); + var these_panel_widths = this_sbs_source.widths; + var this_width = parseInt(these_panel_widths[this_panel_index]); + var total_width = 0; + editorLog("these html siblings",document.getElementById(these_siblings_list[0])," and ", document.getElementById(these_siblings_list[1])) + editorLog("these siblings source", internalSource[these_siblings_list[0]], "and", internalSource[these_siblings_list[1]]); + for(var j=0; j < these_siblings_list.length; ++j) { + // var t_wid = parseInt(internalSource[these_siblings_list[j]]["width"]); + var t_wid = parseInt(these_panel_widths[j]); + these_panel_widths[j] = t_wid; // put it back as an integer + editorLog("adding width", t_wid); + total_width += t_wid; + // these_panel_widths.push(t_wid); + } +// if (this_width != these_panel_widths[this_panel_index]) { +// errorLog("error: width", this_width, "not on list", these_panel_widths) +// } else { +// editorLog("width", this_width, "on list", these_panel_widths) +// } + + editorLog("occ", marginleft, "u", total_width, "pi", marginright, "total", marginleft + total_width + marginright, "ratio", marginright/total_width) + var remaining_space = 100 - (marginleft + total_width + marginright); + editorLog("remaining_space", remaining_space); + +//modify: enlarge, shrink, left, right, ??? done + +// make the data structure better, then delete this comment +// currently style looks like "width: 66%; margin-right: 17%; margin-left: 17%" + editorLog('width', this_width, "mr", marginright, "ml", marginleft); + + editorLog("modifier", modifier); + + var scale_direction = 1; + var moving_direction = 1; + + if (modifier == "enlargeall") { + editorLog("enlarging all", "remaining space", remaining_space); + if (remaining_space >= these_panel_widths.length) { + for (var j=0; j < these_panel_widths.length; ++j) { + these_panel_widths[j] += 1 + } + // probablu the next case handles the first case + } else if (remaining_space + marginleft + marginright >= these_panel_widths.length) { + for (var j=0; j < these_panel_widths.length; ++j) { + these_panel_widths[j] += 1 + } + var missing_length = these_panel_widths.length - remaining_space; + while (missing_length) { + missing_length -= 1; + if (missing_length % 2) { + if (marginleft) { marginleft -= 1 } + else { marginright -= 1 } + } else { + if (marginright) { marginright -= 1 } + else { marginleft -= 1 } + } + } + } else { + editorLog("Problem: not implemented yet") + } + } else if (modifier == "shrinkall") { + for (var j=0; j < these_panel_widths.length; ++j) { + if (these_panel_widths[j]) { these_panel_widths[j] -= 1 } + } + } else if (modifier == "enlarge") { + editorLog("enlarging one"); + if (remaining_space) { these_panel_widths[this_panel_index] += 1 } + } else if (modifier == "shrink") { + editorLog("shrinking one"); + if (these_panel_widths[this_panel_index]) { these_panel_widths[this_panel_index] -= 1 } + } else if (modifier == "leftplus") { + if (remaining_space) { marginleft += 1 } + } else if (modifier == "leftminus") { + if (marginleft) { marginleft -= 1 } + } else if (modifier == "rightplus") { + if (remaining_space) { marginright += 1 } + } else if (modifier == "rightminus") { + if (marginright) { marginright -= 1 } + } + editorLog("now these_panel_widths", these_panel_widths); + +// missing cases?? + + internalSource[this_sbs_id]["marginleft"] = marginleft; + internalSource[this_sbs_id]["marginright"] = marginright; + internalSource[this_sbs_id]["widths"] = these_panel_widths; + +// next is wrong, becuase the sbsrow does not have an id +/* + document.getElementById(this_sbs_id).style.marginLeft = marginleft + "%"; + document.getElementById(this_sbs_id).style.marginRight = marginright + "%"; +*/ + document.getElementById(theid).parentElement.style.marginLeft = marginleft + "%"; + document.getElementById(theid).parentElement.style.marginRight = marginright + "%"; + + for (var j=0; j < these_siblings_list.length; ++j) { + var this_id = these_siblings_list[j]; +// internalSource[this_id]["width"] = these_panel_widths[j]; + var width = rescale(these_panel_widths[j], 100, marginleft, marginright) + // document.getElementById(this_id).style.width = these_panel_widths[j] + "%"; + document.getElementById(this_id).style.width = width + "%"; + } + editorLog("NOW these html siblings",document.getElementById(these_siblings_list[0])," and ", document.getElementById(these_siblings_list[1])) + editorLog("NOW these siblings source", internalSource[these_siblings_list[0]], "and", internalSource[these_siblings_list[1]]); + editorLog("and internalSource[this_id]", internalSource[this_id]); + editorLog("and also internalSource[this_sbs_id]", internalSource[this_sbs_id]); +} + +function move_by_id_local(theid, thehandleid) { + // when moving an object within a page, we create a phantomobject that is manipulated + // the actual movement is handled by move_object(e) + + first_move = true; + + document.getElementById("edit_menu_holder").remove() + document.getElementById(theid).classList.remove("may_select"); + + moved_content = internalSource[theid]; + moved_content_tag = moved_content["sourcetag"]; + ongoing_editing_actions.push(["moved", moved_content_tag, theid]); + moved_parent_and_location = moved_content["parent"]; + editorLog("moving", theid); + editorLog("moved_parent_and_location", moved_parent_and_location); + // code duplicated elsewhere + var where_it_was = internalSource[moved_parent_and_location[0]][ moved_parent_and_location[1] ]; + editorLog("where_it_was", where_it_was); + var object_in_parent = '<&>' + theid + '<;>'; + var where_it_is = where_it_was.replace(object_in_parent, ""); + editorLog("where_it_is ZZ" + where_it_is + "EE"); + internalSource[moved_parent_and_location[0]][ moved_parent_and_location[1] ] = where_it_is; + + // but first, remember the initial location of the object + + moving_object = document.getElementById(theid); + editorLog("moving", moving_object, "within this page"); + editorLog("moving_id", theid); + editorLog("current_editing[tree][0]", current_editing["tree"][0]); + if (moved_content_tag == "li") { + movement_location_neighbors = next_editable_of(current_editing["tree"][0][0], "li-only"); + } else if (tag_type(moved_content_tag) == "p") { + movement_location_neighbors = next_editable_of(current_editing["tree"][0][0], "inner-block"); + } else { + movement_location_neighbors = next_editable_of(current_editing["tree"][0][0], "outer-block"); + } + editorLog("movement_location_neighbors", movement_location_neighbors); + var foundit = false; + var movement_location_tmp = 0; + for (var j=0; j < movement_location_neighbors.length; ++j) { + if (movement_location_neighbors[j] == moving_object) { + movement_location_tmp = j; + // delete the one which is being moved, because + // we are making a list of slots to place it, and its slot will still be there + // isn't there a better way to delete one item from a list? + movement_location_neighbors.splice(j, 1); + foundit = true; + break; + } + } + + if (!foundit) { errorLog("serious error: trying to move an object that is not movable", theid) } + + editorLog("movement_location_tmp", movement_location_tmp); + // a paragraph by itself in an item or a statement can have a new paragraph before or after it + movement_location_options = [[movement_location_neighbors[0], "beforebegin"], + [movement_location_neighbors[0], "afterend"]]; + movement_location = 0; + var movement_location_ct = 1; + for (var j=1; j < movement_location_neighbors.length; ++j) { + if (movement_location_tmp == j) { movement_location = movement_location_ct } + movement_location_ct += 1; + if (movement_location_neighbors[j-1].parentElement == movement_location_neighbors[j].parentElement) { + movement_location_options.push([movement_location_neighbors[j], "afterend"]) + } else { + movement_location_ct += 1; + movement_location_options.push([movement_location_neighbors[j], "beforebegin"]) + movement_location_options.push([movement_location_neighbors[j], "afterend"]) + } + } + editorLog("movement_location_ct", movement_location_ct); + editorLog("movement_location", movement_location); + + editorLog("made", movement_location_options.length, "movement_location_options", movement_location_options); + editorLog("from", movement_location_neighbors.length, "movement_location_neighbors", movement_location_neighbors); + + var the_phantomobject = document.createElement('div'); + the_phantomobject.setAttribute("id", "phantomobject"); + the_phantomobject.setAttribute("data-moving_id", theid); + the_phantomobject.setAttribute("data-handle_id", thehandleid); + the_phantomobject.setAttribute("class", "phantomobject move"); + the_phantomobject.setAttribute("tabindex", "-1"); + var these_instructions = '

    "shift-tab", or "up arrow", to move up

    '; + these_instructions += '

    "return" or "escape" to set in place

    '; + these_instructions += '

    "tab" or "down arrow" to move down

    '; + the_phantomobject.innerHTML = these_instructions; + // if we are moving a p which has parent li, and it is the only p there, then delete the parent li + // note: this will be wrong if there is other non-p siblings inside the li + var moving_object_replace = moving_object; + if (tag_type(moved_content_tag) == "p" && internalSource[moved_parent_and_location[0]]["sourcetag"] == "li") { + // check if that p is the only thing inside the li (so the li is empty when we move the p), and if so, + // remove that li from internalSource and also the HTML, and the reverence to it in internalSource + if (moving_object.parentElement.getElementsByTagName("p").length == 1) { + moving_object_replace = moving_object.parentElement + var now_empty_li_id = moved_parent_and_location[0]; + editorLog("list item now empty:", now_empty_li_id); + var now_empty_li_parent_and_location = internalSource[now_empty_li_id]["parent"]; + var where_it_was = internalSource[now_empty_li_parent_and_location[0]][ now_empty_li_parent_and_location[1] ]; + var object_in_parent = '<&>' + now_empty_li_id + '<;>'; + var where_it_is = where_it_was.replace(object_in_parent, ""); + delete internalSource[now_empty_li_id]; + editorLog("where_it_is II" + where_it_is + "OO"); + internalSource[now_empty_li_parent_and_location[0]][ now_empty_li_parent_and_location[1] ] = where_it_is; + } + } + moving_object_replace.replaceWith(the_phantomobject) + document.getElementById("phantomobject").focus(); +} + +function move_object(e) { + // we have alread set movement_location_options and movement_location + editorLog("movement_location",movement_location); + if ((e.code == "Tab" && e.shiftKey) || e.code == "ArrowUp") { // Shift-Tab up the page + e.preventDefault(); + if (movement_location == 0) { + alert("can't move past the top") + } else { + if (first_move) { first_move = false; } + movement_location -= 1 + } + } else if ((e.code == "Tab" || e.code == "ArrowDown") && !e.shiftKey) { + e.preventDefault(); + if (first_move) { first_move = false; editorLog("did first move") } + if (movement_location == movement_location_options.length - 1) { + alert("can't move past the bottom") + } else { + movement_location += 1 + } + } else if (e.code == "Escape" || e.code == "Enter" || e.code == "ArrowRight") { + e.preventDefault(); + editorLog(" decided where to put moving_object", moving_object); + var id_of_moving_object = document.getElementById('phantomobject').getAttribute("data-moving_id"); + editorLog("moving object started as", internalSource[id_of_moving_object]); + var handle_of_moving_object = document.getElementById('phantomobject').getAttribute("data-handle_id"); + document.getElementById('phantomobject').remove(); + var new_anchor_and_position = movement_location_options[movement_location] + editorLog("new_location_anchor",new_anchor_and_position); + new_anchor_and_position[0].insertAdjacentElement(new_anchor_and_position[1], moving_object); + + // the html appears to be updated, but we still need to update both the internal source: + var new_neighbor_id = new_anchor_and_position[0].id; + editorLog("new_neighbor_id", new_neighbor_id); + editorLog("which has source", internalSource[new_neighbor_id]); + var new_neighbor_rel_pos = new_anchor_and_position[1]; + var [new_neighbor_parent, new_neighbor_location] = internalSource[new_neighbor_id]["parent"]; + var new_neighbor_in_context = internalSource[new_neighbor_parent][new_neighbor_location]; + editorLog("new_neighbor_in_context was", new_neighbor_in_context); + var neighbor_tag = '<&>' + new_neighbor_id + '<;>'; + var neighbor_tag_re = new RegExp(neighbor_tag); + + var moving_object_tag = '<&>' + id_of_moving_object + '<;>'; + if (new_neighbor_rel_pos == "beforebegin") { + // new_neighbor_in_context.replace(neighbor_tag, moving_object_tag + "\n" + neighbor_tag) +// RegExp + new_neighbor_in_context = new_neighbor_in_context.replace(neighbor_tag_re, moving_object_tag + "\n" + neighbor_tag) + } else { + new_neighbor_in_context = new_neighbor_in_context.replace(neighbor_tag_re, neighbor_tag + "\n" + moving_object_tag) + } + editorLog("new_neighbor_in_context is", new_neighbor_in_context); + internalSource[new_neighbor_parent][new_neighbor_location] = new_neighbor_in_context; + internalSource[id_of_moving_object]["parent"] = [new_neighbor_parent, new_neighbor_location]; + editorLog("moving object ended as", internalSource[id_of_moving_object]); + + save_edits(); + + // and the navigation information + make_current_editing_tree_from_id(handle_of_moving_object); + + var most_recent_edit = ongoing_editing_actions.pop(); + recent_editing_actions.unshift(most_recent_edit); + + edit_menu_from_current_editing("entering"); + return + + } else { + editorLog("don't know how to move with", e.code) + } + + editorLog("now movement_location", movement_location); + var the_phantomobject = document.getElementById('phantomobject'); + movement_location_options[movement_location][0].insertAdjacentElement(movement_location_options[movement_location][1], the_phantomobject); + document.getElementById("phantomobject").focus(); +} + +function delete_by_id(theid, thereason) { + // reasons to delete something: author wants it deleted, it is empty, ... + // first delete the specific object + final_added_object = ""; + editorLog("deleting by theid", theid, "with content", internalSource[theid]); + var deleted_content = internalSource[theid]; + var parent_and_location = deleted_content["parent"]; + delete internalSource[theid]; + editorLog("deleted", theid, "so", theid in internalSource, "now", internalSource); + // and save what was deleted + if (theid in old_content) { + old_content[theid].push(deleted_content) + } else { + old_content[theid] = [deleted_content] + } + if (thereason != "newempty") { // not sure newempty can still happen + ongoing_editing_actions.push(["deleted ", deleted_content["sourcetag"], theid]); + } + // update the parent of the object + var current_level = current_editing["level"]; + var where_it_was = internalSource[parent_and_location[0]][ parent_and_location[1] ]; + var object_in_parent = '<&>' + theid + '<;>'; + var where_it_is = where_it_was.replace(object_in_parent, ""); + editorLog("where_it_is ZZ" + where_it_is + "EE"); + internalSource[parent_and_location[0]][ parent_and_location[1] ] = where_it_is; + // if the parent is empty, delete it + if (!(where_it_is.trim()) && (parent_and_location[1] == "content" || parent_and_location[1] == "statement")) { + editorLog(" deleted from within", internalSource[parent_and_location[0]]); + document.getElementById(theid).removeAttribute("data-editable"); // so it is invisible to next-editable-of as we delete its parent + if (internalSource[parent_and_location[0]][ "sourcetag" ] == "li") { + editorLog("not going up a level, because it is a list element") + } else { + current_editing["level"] -= 1; + } + delete_by_id(parent_and_location[0], thereason) + } else { // else, because the parent is going to be deleted, so no need to delete the child + // delete from the html + var current_index = current_editing["location"][current_level] + 1; // +1 because the deleted item is still in the current_editing tree + if (thereason == "empty" || thereason == "newempty") { + editorLog("removing from DOM", document.getElementById(theid)); + document.getElementById(theid).remove(); + current_index -= 1; + editorLog("current_index", current_index, "current_level", current_level); + editorLog(current_editing["tree"][ current_level ]); + // hack because adding a list (inside a defn?) is not updating the tree properly + if (current_index > current_editing["tree"][ current_level ].length - 1) { + current_index = current_editing["tree"][ current_level ].length - 1 + } + if (current_editing["tree"][ current_level ][ current_index ].id == theid) { + current_editing["tree"][ current_level ].splice(current_index, 1) + } + editorLog("empty or newempty", thereason) + } else { + editorLog("deleting for another reason", thereason) + document.getElementById("edit_menu_holder").remove() + document.getElementById(theid).setAttribute("id", "deleting"); + document.getElementById("deleting").removeAttribute("data-editable"); // so it is invisible to next-editable-of + setTimeout(() => { document.getElementById("deleting").remove(); }, 600); + } + + if (current_index >= current_editing["tree"][ current_level ].length) { + current_index = current_editing["tree"][ current_level ].length - 2; + } + editorLog("current_index", current_index, "in", current_editing["tree"][ current_level ]); + editorLog("object of interest", current_editing["tree"][ current_level ][ current_index ]); + editorLog("current_level", current_level, "on", current_editing["tree"]); + make_current_editing_tree_from_id(current_editing["tree"][ current_level ][ current_index].id); + edit_menu_from_current_editing("entering"); + } + save_edits() +} + + +var internalSource = { // currently the key is the HTML id + "root_data": {"id": "page-1", "number_base": "0.1" } +} + +/* top_level_id is a mistake: just use internalSource.root_data.id */ +var top_level_id = internalSource["root_data"]["id"]; + +var current_editing = { + "level": 0, + "location": [0], + "tree": [ [document.getElementById(top_level_id)] ] +} + + +function create_local_menu() { + +// this does not work, but local menu navigator would not have worked either + + editorLog("make local edit menu for", this_obj_id); + var local_menu_holder = document.createElement('div'); + local_menu_holder.setAttribute('id', 'local_menu_holder'); + local_menu_holder.setAttribute('tabindex', '-1'); + editorLog("adding local menu for", this_obj_id); + document.getElementById(this_obj_id).insertAdjacentElement("afterbegin", local_menu_holder); + + var enter_option = document.createElement('ol'); + enter_option.setAttribute('id', 'edit_menu'); + enter_option.setAttribute('class', 'edit_menu'); + + enter_option.innerHTML = menu_options_for(this_obj_id, "XunusedX", "base"); + + document.getElementById("local_menu_holder").insertAdjacentElement("afterbegin", enter_option); + +} + +function extract_internal_contents(some_text) { + + // some_text must be a paragraph with mixed content only contining + // non-nested tags + the_text = some_text; + editorLog(" xxxxxxxxxx the_text is", the_text); + editorLog("extract_internal_contents"); + + // delete class information + the_text = the_text.replace(/ class="[^"]"/g, ""); + + // inline from previous editing + editorLog("extracting where 'data-editable...'"); + the_text = the_text.replace(/<([^<]+) data-editable="[^"]+" tabindex="-1">(.*?)<[^<]+>/g, save_internal_cont); + editorLog("extracting where 'contenteditable...'"); + the_text = the_text.replace(/<([^<]+) contenteditable="false">(.*?)<[^<]+>/g, save_internal_cont); + // new $math$ + editorLog("extracting new $math$"); + the_text = the_text.replace(/(^|\s)\$([^\$]+)\$(\s|$|[.,!?;:])/mg, extract_new_math); + // new \\(math\\) + editorLog("extracting new \\(math\\)"); + the_text = the_text.replace(/(^|.)\\\(([^\$]+)\\\)(.|$)/g, extract_new_math); + // new math + editorLog("extracting new math"); + the_text = the_text.replace(/(^|.)<m>(.*?)<\/m>(.|$)/g, extract_new_math); + + // "..." to , which will then be processed + the_text = the_text.replace(/\.\.\./g, '<ellipsis\/>'); + // same for etc + the_text = the_text.replace(/(\s)etc\.?([^a-zA-Z])/g, '$1<etc\/>$2'); + + for (var j=0; j < inline_abbrev.length; ++j) { + var this_tag = inline_abbrev[j]; + editorLog("this_tag", this_tag); + var this_tag_search = "<(" + this_tag + ")\\/>"; + editorLog("searching for", this_tag_search); + var this_tag_search_re = new RegExp(this_tag_search,"g"); + the_text = the_text.replace(this_tag_search_re, extract_new_inline) + } + + // "quote" to quote, which will then be processed + the_text = the_text.replace(/(^|\s)"([^"]+)"(\s|$|[.,!?;:])/g, '$1<q>$2<\/q>$3'); + the_text = the_text.replace(/(^|\s)“([^”]+)”(\s|$|[.,!?;:])/g, '$1<q>$2<\/q>$3'); + the_text = the_text.replace(/(^|\s)‘([^’]+)’(\s|$|[.,!?;:])/g, '$1<q>$2<\/q>$3'); + + for (var j=0; j < inline_tags.length; ++j) { + var this_tag = inline_tags[j]; + editorLog("this_tag", this_tag); + var this_tag_search = "<(" + this_tag + ") *>" + "(.*?)" + "<\\/" + this_tag + ">"; + editorLog("searching for", this_tag_search); + var this_tag_search_re = new RegExp(this_tag_search,"g"); + the_text = the_text.replace(this_tag_search_re, extract_new_inline) + } + + return the_text +} + +function extract_new_math(match, sp_before, math_content, sp_after) { + var new_math_id = randomstring(); + internalSource[new_math_id] = { "xml:id": new_math_id, "sourcetag": "m", + "content": math_content} + return sp_before + "<&>" + new_math_id + "<;>" + sp_after +} +function extract_new_inline(match, the_tag, the_content) { + var new_id = randomstring(); + editorLog("extracting", the_content, "inside", the_tag); + internalSource[new_id] = { "xml:id": new_id, "sourcetag": the_tag, + "content": the_content}; + return "<&>" + new_id + "<;>" +} +function extract_new_abbrev(match, the_tag) { + var new_id = randomstring(); + editorLog("extracting", the_content, "inside", the_tag); + internalSource[new_id] = { "xml:id": new_id, "sourcetag": the_tag}; + return "<&>" + new_id + "<;>" +} + +// rename this next function +function save_internal_cont(match, contains_id, the_contents) { + this_id = contains_id.replace(/.*id="(.+?)".*/, '$1'); + + editorLog("id", this_id, "now has contents", the_contents); + if ("content" in internalSource[this_id]) { // not all objects have content + internalSource[this_id]["content"] = the_contents; + } else if (internalSource[this_id]["sourcetag"] == "xref") { + // this needs work once we have text="custom" references + internalSource[this_id]["ref"] = the_contents; + } + editorLog("all of it is now", internalSource[this_id]); + return "<&>" + this_id + "<;>" +} +function assemble_internal_version_changes(object_being_edited) { + editorLog("in assemble_internal_version_changes"); + editorLog("current active element to be saved", object_being_edited); + editorLog("which has parent", object_being_edited.parentElement); + editorLog("whose age is", object_being_edited.parentElement.getAttribute("data-age")); + + var oldornew = object_being_edited.parentElement.getAttribute("data-age"); + if (!oldornew) { oldornew = object_being_edited.getAttribute("data-age") } + editorLog(" OLDorNEW", oldornew); + + var possibly_changed_ids_and_entry = []; + var nature_of_the_change = ""; + +// var object_being_edited = document.activeElement; + var location_of_change = object_being_edited.parentElement; + var this_arrangement_of_objects = ""; + + if (object_being_edited.classList.contains("paragraph_input")) { + editorLog("found paragraph_input"); + nature_of_the_change = "replace"; + var paragraph_content = object_being_edited.innerHTML; + // editorLog("paragraph_content from innerHTML", paragraph_content); + paragraph_content = paragraph_content.trim(); + + var cursor_location = object_being_edited.selectionStart; + + editorLog("cursor_location", cursor_location, "out of", paragraph_content.length, "paragraph_content", paragraph_content); + + var parent_and_location = [object_being_edited.getAttribute("data-parent_id"), object_being_edited.getAttribute("data-parent_component")]; + editorLog("parent_and_location", parent_and_location); + editorLog("of ", object_being_edited); + + var prev_id = object_being_edited.getAttribute("data-source_id"); + editorLog("prev_id", prev_id); + editorLog("which contains", internalSource[prev_id]); + + // need to replace the below by split_paragraphs + + // does the textbox contain more than one paragraph? + var paragraph_content_list = paragraph_content.split("

    "); + editorLog("there were", paragraph_content_list.length, "paragraphs, but some may be empty"); + for (var j=0; j < paragraph_content_list.length; ++j) { + editorLog("paragraph", j, "begins", paragraph_content_list[j].substring(0,20)) + } + + var paragraph_content_list_trimmed = []; + + for (var j=0; j < paragraph_content_list.length; ++j) { + // probably each paragraph is wrapped in meaningless div tags + var this_paragraph_contents_raw = paragraph_content_list[j]; + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<\/div>
    /g, "\n"); + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/
    /g, ""); + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<\/div>/g, ""); + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/ /g, " "); + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/ +
    /g, "\n"); + this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/
    /g, "\n"); + this_paragraph_contents_raw = this_paragraph_contents_raw.trim(); + if (!this_paragraph_contents_raw) { editorLog("empty paragraph") } + else { paragraph_content_list_trimmed.push(this_paragraph_contents_raw) } + // editorLog("this_paragraph_contents_raw", this_paragraph_contents_raw); + editorLog("done transforming paragraph", j, "with object_being_edited",object_being_edited); + editorLog("which has contents", this_paragraph_contents_raw) + } + + if (!paragraph_content_list_trimmed.length ) { + // empty, so insert it and delete it later + paragraph_content_list_trimmed = [""]; + } + + for (var j=0; j < paragraph_content_list_trimmed.length; ++j) { + editorLog("_trimmed paragraph", j, "begins", paragraph_content_list_trimmed[j].substring(0,20)) + } + for (var j=0; j < paragraph_content_list_trimmed.length; ++j) { + var this_paragraph_contents = paragraph_content_list_trimmed[j]; + editorLog("this_paragraph_contents", this_paragraph_contents.substring(0,20)); + if (j == 0 && prev_id) { + if (prev_id in internalSource) { + // the content is referenced, so we update the referenced content + // need to check internal content, such as em or math + this_paragraph_contents = extract_internal_contents(this_paragraph_contents); + if (internalSource[prev_id]["content"] != this_paragraph_contents) { + if (internalSource[prev_id]["content"]) { + ongoing_editing_actions.push(["changed", "p", prev_id]); + } else if (this_paragraph_contents) { + ongoing_editing_actions.push(["new", "p", prev_id]); + } + internalSource[prev_id]["content"] = this_paragraph_contents; + editorLog("changed content of", prev_id) + } else if (!this_paragraph_contents) { // adding an empty paragraph + ongoing_editing_actions.push(["empty", "p", prev_id]); + } else { + // this means the contents are nonempty and unchanged, so don't record is as a change + } + possibly_changed_ids_and_entry.push([prev_id, "content", oldornew]); + this_arrangement_of_objects = internalSource[parent_and_location[0]][parent_and_location[1]]; + } else { + errorLog("error: existing tag from input", prev_id, "not in internalSource") + } + } else { // a newly created paragraph + var this_object_internal = {"sourcetag": "p", "title": ""}; //p don't have title + this_object_label = randomstring(); + this_object_internal["xml:id"] = this_object_label; + this_object_internal["parent"] = parent_and_location; + + // put the new p after the previous p in the string describing the neighboring contents + var object_before = new RegExp('(<&>' + prev_id + '<;>)'); + this_arrangement_of_objects = this_arrangement_of_objects.replace(object_before, '$1' + '\n<&>' + this_object_label + '<;>'); + prev_id = this_object_label; + + this_paragraph_contents = extract_internal_contents(this_paragraph_contents); + this_object_internal["content"] = this_paragraph_contents; + internalSource[this_object_label] = this_object_internal + editorLog("just inserted at label", this_object_label, "content starting", this_paragraph_contents.substring(0,11), "which is now", internalSource[this_object_label]); + ongoing_editing_actions.push(["added", "p", this_object_label]); +// here is where we can record that somethign is empty, hence should be deleted + possibly_changed_ids_and_entry.push([this_object_label, "content", "new"]); + } + } + editorLog("parent_and_location", parent_and_location); + editorLog("this_arrangement_of_objects was", internalSource[parent_and_location[0]][parent_and_location[1]]); + internalSource[parent_and_location[0]][parent_and_location[1]] = this_arrangement_of_objects; + editorLog("this_arrangement_of_objects is", this_arrangement_of_objects); + } else if (object_being_edited.classList.contains("displaymath_input")) { + editorLog("found displaymath_input"); + nature_of_the_change = "replace"; + var paragraph_content = object_being_edited.innerHTML; + // editorLog("paragraph_content from innerHTML", paragraph_content); + paragraph_content = paragraph_content.trim(); + + var cursor_location = object_being_edited.selectionStart; + + editorLog("cursor_location", cursor_location, "out of", paragraph_content.length, "paragraph_content", paragraph_content); + + var parent_and_location = [object_being_edited.getAttribute("data-parent_id"), object_being_edited.getAttribute("data-parent_component")]; + + editorLog("parent_and_location", parent_and_location); + editorLog("of ", object_being_edited); + + var prev_id = object_being_edited.getAttribute("data-source_id"); + editorLog("prev_id", prev_id); + editorLog("which contains", internalSource[prev_id]); + + // textbox may contain more than one paragraph + var paragraph_content_list = split_paragraphs(paragraph_content); + var this_paragraph_contents = paragraph_content_list.join("\n\\cr\n"); + this_paragraph_contents = extract_internal_contents(this_paragraph_contents); + + if (!internalSource[prev_id]["content"]) { + ongoing_editing_actions.push(["new", "md", prev_id]); + } else { + ongoing_editing_actions.push(["changed", "md", prev_id]); + } + + internalSource[prev_id]["content"] = this_paragraph_contents + possibly_changed_ids_and_entry.push([prev_id, "content", oldornew]); + + } else if (object_being_edited.getAttribute('data-component') == "title" || + object_being_edited.getAttribute('data-component') == "caption") { + + var this_content_type = object_being_edited.getAttribute('data-component'); + nature_of_the_change = "replace"; + var line_being_edited = object_being_edited; + var line_content = line_being_edited.innerHTML; + line_content = line_content.trim(); + editorLog("the content (is it a title or caption?) is", line_content); + var owner_of_change = object_being_edited.getAttribute("data-source_id"); + var component_being_changed = object_being_edited.getAttribute("data-component"); + editorLog("component_being_changed", component_being_changed, "within", owner_of_change); + if (internalSource[owner_of_change][component_being_changed]) { + ongoing_editing_actions.push(["changed", this_content_type, owner_of_change]); + } else { + ongoing_editing_actions.push(["added", this_content_type, owner_of_change]); + } + // update the title of the object + internalSource[owner_of_change][component_being_changed] = line_content; + possibly_changed_ids_and_entry.push([owner_of_change, this_content_type]); + + } else if (object_being_edited.classList.contains("image_source")) { + // currently this only handles images by URL. + // later do the case of uploading an image. + var image_src = object_being_edited.innerHTML; + + // what is the right way to do this? + image_src = image_src.replace(/
    /g, ""); + image_src = image_src.replace(/<\/div>/g, ""); + image_src = image_src.trim(); + editorLog("changing image src to", image_src); + + var image_being_changed = object_being_edited.getAttribute("data-source_id"); + editorLog("image_being_changed ", image_being_changed); + + if (internalSource[image_being_changed]["source"]) { + ongoing_editing_actions.push(["changed", "source", image_being_changed]); + } else { + ongoing_editing_actions.push(["added", "source", image_being_changed]); + } + internalSource[image_being_changed]["source"] = image_src; + editorLog("image being changed is", internalSource[image_being_changed]); + // possibly_changed_ids_and_entry.push([owner_of_change, "image"]); + possibly_changed_ids_and_entry.push([image_being_changed, "image"]); + + + } else if (inline_tags.includes(object_being_edited.tagName.toLowerCase())) { + editorLog(object_being_edited, "is inline, so processing parent"); + return assemble_internal_version_changes(object_being_edited.parentElement) + } else if (object_being_edited.classList.contains("edit_math_row")) { + nature_of_the_change = "replace"; + var line_being_edited = object_being_edited; + var line_content = line_being_edited.innerHTML; + line_content = line_content.trim(); + editorLog("the content (is it a title?) is", line_content); + var owner_of_change = object_being_edited.getAttribute("id"); + // var component_being_changed = object_being_edited.getAttribute("data-component"); + var component_being_changed = "content"; + editorLog("component_being_changed", component_being_changed, "within", owner_of_change); + // update the title of the object + if (internalSource[owner_of_change][component_being_changed]) { + ongoing_editing_actions.push(["changed", "mrow", owner_of_change]); + } else { + ongoing_editing_actions.push(["added", "mrow", owner_of_change]); + } + internalSource[owner_of_change][component_being_changed] = line_content; + possibly_changed_ids_and_entry.push([owner_of_change, "mrow"]); + + } else { + errorLog("trouble editing", object_being_edited, "AAA", object_being_edited.tagName.toLowerCase(), "not in", inline_tags); + alert("don;t know how to assemble internal_version_changes of " + object_being_edited.tagName) + } + editorLog("finished assembling internal version, which is now:",internalSource); + editorLog(" NUMBER of things chagnged:", possibly_changed_ids_and_entry.length); + return [nature_of_the_change, location_of_change, possibly_changed_ids_and_entry] +} + +function wrap_tag(tag, content, attribute_values) { + // tag is either an XML tag name, or [opening_tag, closing_tag] + + // layout: inline or block or title + // is this the right place to handle empty content? +// editorLog("calling wrap_tag", "tag", tag, "content", content, "attribute_values", attribute_values); + if (!content && !tag) { return "" } + if (!content && !always_empty_tags.includes(tag) && !allowed_empty_tags.includes(tag)) { return "" } + if (!tag) { return content } + + var opening_tag = closing_tag = ""; + + if (typeof tag == "string") { + if (tag) { + opening_tag = "<" + tag; + for (var j=0; j < attribute_values.length; ++j) { + opening_tag += ' ' + attribute_values[j] + } + closing_tag = ""; + } + if (!content && (always_empty_tags.includes(tag) || allowed_empty_tags.includes(tag))) { + opening_tag += "/>"; + closing_tag = ""; + } else { + opening_tag += ">"; + } + + if (tag_display["inline"].includes(tag)) { + // do nothing + } else if (tag_display["title"].includes(tag)) { + opening_tag = "\n" + opening_tag; + closing_tag = closing_tag + "\n" + } else if (tag_display["block-tight"].includes(tag)) { + // do nothing + } else { //the default + opening_tag = "\n" + opening_tag + "\n"; + if (closing_tag) { + closing_tag = "\n" + closing_tag + "\n" + } + } + } else if (tag) { + [opening_tag, closing_tag] = tag + for (var j=0; j < attribute_values.length; ++j) { + opening_tag += ' ' + attribute_values[j] + } + } else { + opening_tag = ""; + closing_tag = ""; + } + if (!opening_tag) { opening_tag = "" } + if (!closing_tag) { closing_tag = "" } + + if (content.includes("N.m")) { editorLog("3 ----- content",content); editorLog("opening_tag", opening_tag) } + + if (opening_tag.startsWith("(.*?)<;>/g, function (match, newid) { + if (newid.startsWith("{")) { + newid = newid.slice(1,-1); + if (newid in output_structure) { + return output_structure[newid] + } else { // don't want to return 'undefined' + return "" + } + } else if (newid.startsWith("(")) { + var this_piece = newid.slice(1,-1); + var this_fcn; + [this_fcn, this_piece] = this_piece.split(","); + return process_value_from_source(this_fcn, this_piece, the_object) + } else { + if (newid in the_object) { + return the_object[newid] + } else { + return "" + } + } + }); + editorLog(" attr_val", attr_val); + if (attr_val && !attr_val.includes('""')) { + output_attributes_values.push(attr_val) + } + } + + editorLog("output_structure", output_tag, "is", output_structure); + editorLog("output_attributes_values", output_attributes_values); + editorLog("output_structure.pieces", output_structure.pieces); + for (var j=0; j < output_structure.pieces.length; ++j) { + var this_piece_output = ""; + var [this_piece, this_tag] = output_structure.pieces[j]; + editorLog("output_structure", output_structure); + // when this_piece is provisional, then this_tag is actually the key for the required content + editorLog(j, "this_piece", this_piece, "this_tag", this_tag, "output_tag", output_tag); + if (this_piece.startsWith("{")) { + this_piece = this_piece.slice(1,-1); + this_piece_output += output_from_source(the_object, objectStructure[this_piece][format], format); + editorLog("wrapping in bracketed tag", this_tag); + the_answer += wrap_tag(this_tag, this_piece_output, []) + } else if (this_piece.startsWith("%")) { + // need to distinguish between the case where this object exists, + // and when it does not exist and we want a placeholder + this_piece = this_piece.slice(1,-1); + editorLog("% % % % % % % % % ", this_piece, "this_tag", this_tag, "the_object", the_object); + editorLog("% % % % % % % % % ", the_object[this_piece]); + editorLog("% % % % % % % % % ", the_object[this_tag]); + if (the_object[this_tag]) { + // var sub_object = {}; + +// Object.assign(sub_object, the_object); + + // sub_object['type-contained'] = this_tag; + // editorLog("sub_object", sub_object); + // this_piece_output = output_from_source(sub_object, objectStructure[this_piece][format], format); + this_piece_output = expand_condensed_source_html(the_object[this_tag],"html?"); + // this_piece_output = output_from_source(sub_object, objectStructure[this_piece][format], format); + the_answer += this_piece_output; + editorLog("this piece exists", this_piece, "this_piece_output", this_piece_output) + } else { + editorLog("making placeholder for", this_piece); + the_answer += wrap_tag("div", "", ['class="placeholder ' + this_piece + '"', 'data-parent_id="' + the_object['xml:id'] + '"', 'data-has="' + this_piece + '"', 'tabindex="-1"', 'data-editable="123456"', 'data-placeholder=""']) + } + } else if (this_piece.startsWith("(")) { + editorLog("whole this_piece", this_piece); + this_piece = this_piece.slice(1,-1); + var this_fcn; + [this_fcn, this_piece] = this_piece.split(","); + var this_content = process_value_from_source(this_fcn, this_piece, the_object) + editorLog(j, "parenthesized content", this_content, "this_piece", this_piece, "XX", this_tag) + the_answer += wrap_tag(this_tag, this_content, []) + } else if (this_piece in the_object) { + this_piece_output = output_from_text(the_object[this_piece], format); + if (format == "pretext" && output_tag == "md" && this_piece == "content") { + // convert \cr to mrow + this_piece_output = this_piece_output.replace(/\s*\\cr\b\s*/g, "\n\n"); + this_piece_output = "\n" + this_piece_output + "\n"; + } + the_answer += wrap_tag(this_tag, this_piece_output, []) + } else { + editorLog("missing piece:", this_tag, "with no", this_piece) + } + } + + // pretty print the output + if (format == "pretext" && !(inline_tags.includes(output_tag)) && !(inline_math.includes(output_tag))) { + the_answer = the_answer.replace(/(^|\n)( *(\w|<))/g, "$1 $2"); + } + the_answer = wrap_tag(output_tag, the_answer, output_attributes_values) +// editorLog("now the answer is", the_answer); + + return the_answer +} + +function output_from_text(text, format) { + editorLog("output_from_text of ", text, "with format", format); + if (text.includes("<&>")) { + // return text.replace(/\s*<&>(.*?)<;>\s*/g, function (match, newid) { return output_from_id(match, newid, format)}) + return text.replace(/<&>(.*?)<;>/g, function (match, newid) { return output_from_id(match, newid, format)}) + } else { + return text + } +} + +function output_from_id(match, the_id, format) { + var the_answer = ""; + editorLog("expanding the_id", the_id); + debugLog("expanding the_id", the_id); + var the_object = internalSource[the_id]; + if (!the_object) { + errorLog("error: no content for", the_id); + return the_id + } + var src_tag = the_object.sourcetag; + editorLog("the_object",the_object); + var output_structure; + if (src_tag in objectStructure) { + output_structure = objectStructure[src_tag][format]; + } else { + errorLog("error: unknown structure:", src_tag); + // so make reasonable assumptions about the structure + output_structure = { + "tag": src_tag, + "pieces": [["content", ""]] + } + } + + editorLog("output_structure", output_structure); + // var output_tag = output_structure.tag; + + the_answer = output_from_source(the_object, output_structure, format); + + return the_answer +} + +function expand_condensed_source_html(text, context) { + editorLog("iiiiiii in expand_condensed_source_html"); + if (text.includes("<&>")) { + editorLog(" qqqqq expand_condensed_source_html", text); + if (context == "edit") { + return text.replace(/<&>(.*?)<;>/g,expand_condensed_src_edit) + } else { + return text.replace(/<&>(.*?)<;>/g,expand_condensed_src_html) + } + } else { + editorLog("returning text XX" + text.substring(0,17) + "YY"); + editorLog("returning from expand_condensed_source_html"); + return text + } +} +function expand_condensed_src_html(match, the_id) { + return html_from_internal_id(the_id, "inner") +} +function expand_condensed_src_edit(match, the_id) { + return html_from_internal_id(the_id, "edit") +} + +function html_from_internal_id(the_id, is_inner) { + // the outer element needs to be constructed as document.createElement + // but the inner content is just plain text + // maybe saying it better: sometimes we want to create an object and + // insert it into the DOM. Other times we just want to construct the + // HTML markup fo rthe object and return that. + var the_object = internalSource[the_id]; + editorLog("making html of", the_object, "is_inner", is_inner, "the_id", the_id); + var sourcetag = the_object["sourcetag"]; + editorLog("which has tag", sourcetag); + + editorLog("m in inline_math", inline_math.includes("m")); + + var html_of_this_object; + var the_html_objects = []; + + if (sourcetag == "image") { + html_of_this_object = output_from_id("", the_id, "html"); + editorLog("html_of_this_object", html_of_this_object); + the_html_objects.push(html_of_this_object); + } else if (tag_type(sourcetag) == "p") { + html_of_this_object = output_from_id("", the_id, "html"); + editorLog("html_of_this_object", html_of_this_object); + the_html_objects.push(html_of_this_object); + } else if (inline_math.includes(sourcetag) && is_inner == "edit") { + // here we are assuming the tag is 'm' + var opening_tag = ''; + return opening_tag + spacemath_to_tex(the_object["content"]) + closing_tag + } else if (["me","men"].includes(sourcetag) && is_inner == "edit") { + var opening_tag = '
    '; + return opening_tag + spacemath_to_tex(the_object["content"]) + closing_tag + } else if (["md","mdn"].includes(sourcetag) && is_inner == "edit") { + var opening_tag = '
    '; + this_content = the_object["content"].replace(/<&>(.*?)<;>/g,expand_condensed_src_edit); + this_content = this_content.replace("MROWsepARATOR", "\n yyyy \n"); + return opening_tag + this_content + closing_tag + } else if (["mrow"].includes(sourcetag) && is_inner == "edit") { + var opening_tag = '
    '; + return opening_tag + "MROW" + spacemath_to_tex(the_object["content"]) + closing_tag + } else if (sourcetag == "xref" && is_inner == "edit") { + // here we are assuming the tag is 'm' + var opening_tag = ''; + return opening_tag + the_object["ref"] + closing_tag + } else { + html_of_this_object = output_from_id("", the_id, "html"); + editorLog("html_of_this_object", html_of_this_object); + the_html_objects.push(html_of_this_object); + + } + + editorLog(" RRRR returning the_html_objects", the_html_objects); + +// the_html_objects = the_html_objects.replace("MROWsepARATOR", "\n\\cr\n"); + return the_html_objects +} + +function insert_html_version(these_changes) { + + var nature_of_the_change = these_changes[0]; + var location_of_change = these_changes[1]; + var possibly_changed_ids_and_entry = these_changes[2]; + + editorLog("nature_of_the_change", nature_of_the_change); + editorLog("location_of_change", location_of_change); + editorLog("possibly_changed_ids_and_entry", possibly_changed_ids_and_entry); + + if (!possibly_changed_ids_and_entry.length) { + editorLog("nothing to change"); + // return "" + } + // we make HTML version of the objects with ids possibly_changed_ids_and_entry, + // and then insert those into the page. + +// here is where we detect deleting? +// or is that after this function is done? + if (nature_of_the_change != "replace") { + editorLog("should be replace, since it is the edit form we are replacing"); + } + + var object_as_html = ""; + var this_object_id, this_object_entry, this_object_oldornew, this_object; + + editorLog(" there are", possibly_changed_ids_and_entry.length, "items to process"); + + for (var j=0; j < possibly_changed_ids_and_entry.length; ++j) { + this_object_id = possibly_changed_ids_and_entry[j][0]; + this_object_entry = possibly_changed_ids_and_entry[j][1]; + this_object_oldornew = possibly_changed_ids_and_entry[j][2]; + editorLog("j=", j, "this thing", possibly_changed_ids_and_entry[j]); + this_object = internalSource[this_object_id]; + editorLog(j, "this_object", this_object); + if (tag_type(this_object["sourcetag"]) == "p" || this_object["sourcetag"] == "li" || tag_type(this_object["sourcetag"]) == "md") { + + var this_new_object = html_from_internal_id(this_object_id); + editorLog("inserting",this_new_object,"before",location_of_change); + location_of_change.insertAdjacentHTML('beforebegin', this_new_object[0]); + object_as_html = document.getElementById(this_object_id); + + } else if (this_object_entry == "title") { + var object_as_html = document.createElement('span'); + object_as_html.setAttribute("class", "title"); + object_as_html.setAttribute('data-editable', 20); + object_as_html.setAttribute('tabindex', -1); + // next line should apply a transform to the source + object_as_html.innerHTML = this_object[this_object_entry]; + editorLog("inserting",object_as_html,"before",location_of_change); + // location_of_change is the .header . We want it to be the .title + location_of_change = location_of_change.querySelector("#actively_editing"); + editorLog("now location_of_change",location_of_change); + location_of_change.insertAdjacentElement('beforebegin', object_as_html); + } else if (this_object_entry == "caption") { + console.log("Error: don't know what to do with 'caption'") + } else if (this_object_entry == "image") { + editorLog("image, this_object", this_object); + var this_new_object = html_from_internal_id(this_object_id); + editorLog("inserting",this_new_object,"before",location_of_change); + location_of_change.insertAdjacentHTML('beforebegin', this_new_object[0]); + object_as_html = document.getElementById(this_object_id); + + } else { + editorLog("trouble making", this_object); + } + MathJax.typesetPromise(); +// MathJax.Hub.Queue(['Typeset', MathJax.Hub, this_object_id]); + } + location_of_change.remove(); + + editorLog("returning from insert html version", object_as_html); + // call mathjax, in case the new content contains math + return object_as_html // the most recently added object, which we may want to + // do something, like add an editing menu +} // insert html version + +function save_edits() { + + var currentState = internalSource; + + editorLog("saving", currentState); + localStorage.setObject("savededits", currentState); + return ""; +} + +function previous_editing() { + var old_internal_source = localStorage.getObject("savededits"); + return (old_internal_source || "") +} + +function local_editing_action(e) { + editorLog("in local editing action for" ,e.code); + var most_recent_edit; + if (e.code == "Escape" || e.code == "Enter") { + editorLog("I saw a Rettttt"); + if (document.activeElement.getAttribute('data-component') == "title" || + document.activeElement.getAttribute('data-component') == "caption") { + editorLog("probably saving a ", document.activeElement.getAttribute('data-component')); + e.preventDefault(); + these_changes = assemble_internal_version_changes(document.activeElement); + final_added_object = insert_html_version(these_changes); + most_recent_edit = ongoing_editing_actions.pop(); + recent_editing_actions.unshift(most_recent_edit); + editorLog("most_recent_edit should be title change", most_recent_edit); + editorLog("final_added_object", final_added_object); + this_char = ""; + prev_char = ""; + save_edits(); + + // .title is in a .heading, and neither have an id + make_current_editing_tree_from_id(final_added_object.parentElement.parentElement.id); + edit_menu_from_current_editing("entering"); + +// editing_input_image + } else if (e.code == "Escape" || (prev_char.code == "Enter" && prev_prev_char.code == "Enter") || document.getElementById("editing_input_image")) { + editorLog("need to save"); +editorLog(" HHH current_editing", current_editing, "with active element", document.activeElement); + + e.preventDefault(); + this_char = ""; + prev_char = ""; + these_changes = assemble_internal_version_changes(document.activeElement); + editorLog(" CCC these_changes", these_changes); + editorLog(" CCC0 these_changes[0]", these_changes[0]); + editorLog("ongoing_editing_actions", ongoing_editing_actions); + editorLog("actively_editing", document.getElementById("actively_editing")); +editorLog(" III current_editing", current_editing, current_editing["tree"][current_editing["level"]]); + previous_added_object = final_added_object; + final_added_object = insert_html_version(these_changes); + editorLog("final_added_object, previous_added_object", final_added_object, previous_added_object); +editorLog(" LLL current_editing", current_editing, current_editing["tree"][current_editing["level"]]); + editorLog("the final_added_object", final_added_object); + editorLog("the actively_editing", document.getElementById("actively_editing")); + editorLog("OO", ongoing_editing_actions.length, " ongoing_editing_actions", ongoing_editing_actions); +/* + editorLog("ongoing_editing_actions[0]", ongoing_editing_actions[0]); + editorLog("ongoing_editing_actions[0][2]", ongoing_editing_actions[0][2]); +*/ + // maybe this next if only handles when we delete by removing the letters in a p? + if (these_changes[0] == "empty") { + editorLog("NN", ongoing_editing_actions.length, " ongoing_editing_actions", ongoing_editing_actions); + editorLog("ongoing_editing_actions[0]", ongoing_editing_actions[0]); + editorLog("ongoing_editing_actions[0][2]", ongoing_editing_actions[0][2]); + editorLog(" going to delete", these_changes[2][0]); + // this is sort-of a hack to detext the end of inserting li + if (ongoing_editing_actions.length == 2 && + ongoing_editing_actions[1][0] == "empty" && + ongoing_editing_actions[1][1] == "p" && + ongoing_editing_actions[0][0] == "new" && + ongoing_editing_actions[0][1] == "li") { + ongoing_editing_actions.pop(); // content was empty, so there is no editing action + ongoing_editing_actions.pop(); + delete_by_id(these_changes[2][0][0], "newempty"); + current_editing["location"][current_editing["level"]] -= 1 + final_added_object = previous_added_object; // this approach makes the updating of current_editing moot? + } else { + delete_by_id(these_changes[2][0][0], "empty"); + } + editorLog("MM", ongoing_editing_actions.length, " ongoing_editing_actions", ongoing_editing_actions); + for (var j=0; j= 0; --j) { + editorLog(" X", j, "the_whole_object[j]", the_whole_object[j]); + document.getElementById("actively_editing").insertAdjacentElement("afterend", the_whole_object[j]) + MathJax.typesetPromise(); + // MathJax.Hub.Queue(['Typeset', MathJax.Hub, the_whole_object[j]]); + } + + editorLog("here is where we need to update current_editing", "parent:", this_parent,"which is",document.getElementById(this_parent[0]), "level:", current_editing["level"], "loation:", current_editing["location"], "tree:", current_editing["tree"]); + $("#actively_editing").remove(); + +editorLog(" DDD current_editing", current_editing, current_editing["tree"][current_editing["level"]]); + + } + + most_recent_edit = ["","",""]; + while (ongoing_editing_actions.length) { + most_recent_edit = ongoing_editing_actions.pop(); + recent_editing_actions.unshift(most_recent_edit); + editorLog(" most_recent_edit", most_recent_edit); + } + editorLog(" 8888 final_added_object", final_added_object); + + save_edits() + + // is this in the right place? + editorLog("most_recent_edit", most_recent_edit); + + // sometimes, such as when adding items to a list, you want to + // automatically start adding something else. + // maybe refactor theorem to add proof after? + if (most_recent_edit[1] == "li") { // added to a list, so try adding again + // note that when adding an li, the neichbor is a p within the actual li neighbor + var new_obj = create_object_to_edit("li", document.getElementById(most_recent_edit[2]).firstElementChild, "afterend") + edit_in_place(new_obj, "new"); + editorLog("now editing the assumed new li"); +editorLog(" GGG current_editing", current_editing, current_editing["tree"][current_editing["level"]]); + + } else { + + editorLog("re-making the tree from final_added_object", final_added_object); + make_current_editing_tree_from_id(final_added_object.id); + editorLog("and then adding a menu"); + edit_menu_from_current_editing("entering"); + } + + } else if ( document.getElementById("actively_editing")) { + document.getElementById("actively_editing").remove(); + // were actively editing, and now just re-making the menu + edit_menu_from_current_editing("entering"); + } else { + // default makng the menu + edit_menu_from_current_editing("entering"); + } + } // esc or enter enter enter + editorLog ("processed an enter"); + } // esc or enter + else { + editorLog("e.code was not one of those we were looking for", e) + } + editorLog("leaving local editing action") +} + +function main_menu_navigator(e) { // we are not currently editing + // so we are building the menu, and possibly moving aroung the document, + //for the user to decide what/how to edit + +// There are 3 modes: +// #enter_choice, data-location="next" +// #enter_choice, data-location="stay" +// above means we are deciding whenter to edit/enter/leave and object, or to move on +// #choose_current +// 3rd option means we already have a menu + + if (document.getElementById("enter_choice")) { + theEnterChoice = document.getElementById("enter_choice"); + editorLog("enter_choice", e); + var theMotion = theEnterChoice.getAttribute("data-location"); + var object_of_interest; + if (theMotion == "stay") { + object_of_interest = theEnterChoice.parentElement.previousSibling; + } else { + object_of_interest = theEnterChoice.parentElement.parentElement; + } + editorLog(" MMN: want to", theMotion, "on", object_of_interest, "from", theEnterChoice) + + editorLog("current_editing", current_editing); + editorLog("theEnterChoice", theEnterChoice); + var current_level = current_editing["level"]; + var current_location = current_editing["location"][current_level]; + var current_siblings = current_editing["tree"][current_level]; + editorLog("current_level", current_level, "current_location", current_location, "current_siblings", current_siblings); + + if ((e.code == "Tab" || e.code == "ArrowDown") && !e.shiftKey) { + e.preventDefault(); + if (current_level == 0) { // at the top, so no "next" object + return "" + } + // go to next sibling, or stage to exit if on last sibling + if (current_location == (current_siblings.length - 1)) { // on last sibling + editorLog("on last sibling, level was", current_level,"siblings was", current_siblings, "tree", current_editing["tree"]); + editorLog("current_location was", current_location); + current_level -= 1; + current_location = current_editing["location"][current_level]; + current_editing["level"] = current_level; + current_editing["location"][current_level] = current_location; + current_siblings = current_editing["tree"][current_level]; + editorLog("current_location is", current_location); + editorLog("stay menu A"); + object_of_interest.classList.remove("may_leave"); + object_of_interest.classList.remove("may_elect"); + edit_menu_from_current_editing("leaving") + } else { + editorLog("moving to the next editable sibling"); + editorLog("level was", current_level,"siblings was", current_siblings, "tree", current_editing["tree"]); + editorLog("current_location was", current_location); + editorLog(current_location, "was", current_editing); + current_location += 1; + object_of_interest.classList.remove("may_leave"); + object_of_interest.classList.remove("may_elect"); + editorLog("current_location is", current_location); + editorLog("stay menu B"); + current_editing["location"][current_level] = current_location; + editorLog(current_location, "is", current_editing); + edit_menu_from_current_editing("entering") + } + } else if ((e.code == "Tab" && e.shiftKey) || e.code == "ArrowUp") { // Shift-Tab to prevous object + e.preventDefault(); + // go to previous sibling, or up one if on first sibling + editorLog("Arrow Up:", "current_location", current_location, "current_level", current_level); + if (theMotion == "stay") { // about to leave, to return to the top of that region + edit_menu_from_current_editing("entering") + } else if (current_location == 0) { + if (!current_level) { // already at the top, so nowhere to go, so do nothing + editorLog("at the top, so can't go up"); + return "" + } + current_level -= 1; + current_editing["level"] = current_level; + current_location = current_editing["location"][current_level]; + editorLog("AA new current_location", current_location, " current_editing['tree']", current_editing["tree"]); + editorLog(" current_editing['tree'][0]", current_editing["tree"][0]); + current_siblings = current_editing["tree"][current_level]; + editorLog("current_siblings", current_siblings); + edit_menu_from_current_editing("entering") + } else { + current_location -= 1; + current_editing["location"][current_level] = current_location; + editorLog("current_siblings", current_siblings); + editorLog("BB new current_location", current_location, "at level", current_level, " current_editing['tree']", current_editing["tree"]); + edit_menu_from_current_editing("entering") + } + } else if (e.code == "Escape" || e.code == "ArrowLeft") { + e.preventDefault(); + if (current_level == 0) { return "" } // already at the top, so nowhere to go, so do nothing +// copied from A1 + editorLog("At ArrowLeft, level was", current_level, "with location", current_editing["location"], "and tree", current_editing["tree"][current_level]); + current_level -= 1; + current_editing["level"] = current_level; + current_location = current_editing["location"][current_level]; + current_siblings = current_editing["tree"][current_level]; + editorLog("now level id", current_level, "with location", current_editing["location"], "and tree", current_editing["tree"][current_level]); + edit_menu_from_current_editing("entering") + } else if (e.code == "Enter" || e.code == "ArrowRight") { + e.preventDefault(); + if (theMotion == "stay") { + edit_menu_from_current_editing("entering"); + return "" + } + var edit_submenu = document.createElement('ol'); + edit_submenu.setAttribute('id', 'edit_menu'); + edit_submenu.setAttribute('class', 'edit_menu'); + + var to_be_edited = object_of_interest; + editorLog("to_be_edited", to_be_edited); + edit_submenu.innerHTML = top_menu_options_for(to_be_edited); + $("#enter_choice").replaceWith(edit_submenu); + document.getElementById('choose_current').focus(); + } + editorLog(" Just handled the case of enter_choice"); + return "" + + } else if (document.getElementById("choose_current")) { + var theChooseCurrent = document.getElementById("choose_current"); + var dataLocation = theChooseCurrent.getAttribute("data-location"); // may be null + var dataAction = theChooseCurrent.getAttribute("data-action"); // may be null + var dataModifier = theChooseCurrent.getAttribute("data-modifier"); // may be null + var dataEnv = theChooseCurrent.getAttribute("data-env"); // may be null + // a hack because of how the menus were originally set up + if (dataEnv == "save") { dataAction = "save" } + var dataEnvParent = theChooseCurrent.getAttribute("data-env-parent"); // may be null + var object_of_interest; + if (document.getElementById("edit_menu_holder")) { + object_of_interest = document.getElementById("edit_menu_holder").parentElement + } else if (document.getElementById("local_menu_holder")) { + object_of_interest = document.getElementById("local_menu_holder").parentElement + } else { + editorLog("something is confused: should be a menu, but isn't"); + if (theChooseCurrent.id) { + make_current_editing_tree_from_id(theChooseCurrent.id); + object_of_interest = theChooseCurrent + } else { + make_current_editing_tree_from_id(theChooseCurrent.parentElement.id); + object_of_interest = theChooseCurrent.parentElement + } + editorLog("made entering menu for", object_of_interest); + edit_menu_from_current_editing("entering") + } + current_level = current_editing["level"]; + current_location = current_editing["location"][current_level]; + current_siblings = current_editing["tree"][current_level]; + editorLog("in choose_current", dataLocation, "of", object_of_interest); + editorLog("dataAction ", dataAction); + editorLog("dataLocation ", dataLocation); + // we have an active menu, and have selected an item + // there are three main sub-cases, depending on whether there is a data-location attribute, + // a data-action attribute, or a data-env attribute. + // That is the primary order in which those attributes are considered + // however, some actions (such as Tab and shift-Tab) are the same + // in each sub-case (because all we are doing is moving up and down the + // current list of options), so we handle those first. + + if ((e.code == "Tab" || e.code == "ArrowDown") && !e.shiftKey) { + e.preventDefault(); + next_menu_item = theChooseCurrent.nextSibling; + editorLog("theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item); + if (!next_menu_item) { next_menu_item = theChooseCurrent.parentNode.firstChild } + editorLog("theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item); + if (theChooseCurrent == next_menu_item) { //only one item on menu, so Tab shold move to the next editable item + // if last editable child, go up one + if (current_location == (current_siblings.length - 1)) { + current_level -= 1; + current_location = current_editing["location"][current_level]; + current_editing["level"] = current_level; + current_editing["location"][current_level] = current_location; + edit_menu_from_current_editing("leaving") + } else { + current_location += 1; + editorLog("single item menu, current_location now", current_location); + current_editing["location"][current_level] = current_location; + edit_menu_from_current_editing("entering"); + } + } + theChooseCurrent.removeAttribute("id"); + editorLog("theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item); + next_menu_item.setAttribute("id", "choose_current"); + editorLog("setting focus on",next_menu_item); + next_menu_item.focus(); + } // Tab + else if ((e.code == "Tab" && e.shiftKey) || e.code == "ArrowUp") { // Shift-Tab to prevous object + e.preventDefault(); + editorLog("just saw a", e.code); + editorLog("focus is on", $(":focus")); + editorLog("saw an",e.code); + next_menu_item = theChooseCurrent.previousSibling; + editorLog("W1 theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item); + if (!next_menu_item) { next_menu_item = theChooseCurrent.parentNode.lastChild } + editorLog("W2 theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item); + if (theChooseCurrent == next_menu_item) { //only one item on menu, so Shift-Tab shold move to previous or up one level + if (current_editing["location"][ current_editing["level"] ] == 0) { + current_editing["level"] -= 1; + } else { + current_editing["location"][ current_editing["level"] ] -= 1; + } + editorLog("single item menu, current_level now", current_level); + edit_menu_from_current_editing("entering"); + } else { + theChooseCurrent.removeAttribute("id"); + editorLog("W3 theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item); + theChooseCurrent.classList.remove("chosen"); + next_menu_item.setAttribute("id", "choose_current"); + editorLog("setting focus on",next_menu_item); + next_menu_item.focus(); + } + } + else if (e.code == "Escape" || e.code == "ArrowLeft") { + editorLog("processing ESC"); + editorLog("At ArrowLeft, level was", current_level, "xx", current_editing["level"], "with location", current_editing["location"], "and tree", current_editing["tree"][current_level]); + // I think the next if can never be true, because of how to route keystrokes + if (document.getElementById("local_menu_holder")) { // hack for when the interface gets confused + document.getElementById("local_menu_holder").remove() + } else { + editorLog("W4 theChooseCurrent", theChooseCurrent); + // need to go up one level in the menu + var previous_menu_item = theChooseCurrent.parentElement.parentElement; // li > ol > li + if (previous_menu_item.id == "edit_menu_holder") { + var thenewchoice = ''; + thenewchoice += 'edit or add nearby'; + thenewchoice += ''; + previous_menu_item.innerHTML = thenewchoice + } else { + theChooseCurrent.parentElement.remove(); + previous_menu_item.classList.remove('chosen'); + previous_menu_item.parentElement.classList.remove('past'); + previous_menu_item.setAttribute("id", "choose_current"); + previous_menu_item.focus(); + } + } + } + else if (keyletters.includes(e.code)) { + key_hit = e.code.toLowerCase().substring(3); // remove forst 3 characters, i.e., "key" + editorLog("key_hit", key_hit); + theChooseCurrent = document.getElementById('choose_current'); + editorLog('theChooseCurrent', theChooseCurrent ); + editorLog( $(theChooseCurrent) ); + // there can be multiple data-jump, so use ~= to find if the one we are looking for is there + // and start from the beginning in case the match is earlier (make the second selector better) + if ((next_menu_item = $(theChooseCurrent).nextAll('[data-jump~="' + key_hit + '"]:first')[0]) || + (next_menu_item = $(theChooseCurrent).prevAll('[data-jump~="' + key_hit + '"]:last')[0])) { // check there is a menu item with that key + theChooseCurrent.removeAttribute("id", "choose_current"); + next_menu_item.setAttribute("id", "choose_current"); + next_menu_item.focus(); + } else { + // not sure what to do if an irrelevant key was hit + editorLog("that key does not match any option") + } + } + +// Now only Enter and ArrowRight are meaningful in this context. +// The effect will depend on the other attributes of #choose_current: +// dataLocation, dataAction, dataEnv + + else if (e.code == "Enter" || e.code == "ArrowRight") { + e.preventDefault(); + if (dataLocation) { + if (dataLocation == "enter") { // we are moving down into an object + + editorLog("theChooseCurrent", theChooseCurrent); + var object_to_be_entered = object_of_interest; + editorLog("object_to_be_entered", object_to_be_entered); + object_to_be_entered.classList.remove("may_select"); + object_to_be_entered.classList.remove("may_enter"); + object_to_be_entered.classList.remove("may_leave"); + editorLog('next_editable_of(object_to_be_entered, "children")'); + editableChildren = next_editable_of(object_to_be_entered, "children"); + current_level += 1; + current_editing["level"] = current_level; + current_editing["location"][current_level] = 0; + current_editing["tree"][current_level] = editableChildren; + editorLog("current_editing", current_editing); + + editorLog("object_to_be_entered", object_to_be_entered); + editorLog("with some children", editableChildren); + // put menu on the item at the top of the block_we_are_reentering + // this is a repeat of a Tab case, so consolidate + editorLog("menu place 10"); + editorLog("document.activeElement", document.activeElement); + + editorLog("menu on", editableChildren[0]); + edit_menu_for(editableChildren[0], "entering"); + + return "" + // combine the next with previous, because the ony difference is which object receives focus + } else if (dataLocation == "end") { // move to the end of an object + + editorLog("theChooseCurrent", theChooseCurrent); + var object_to_be_entered = object_of_interest; + editorLog("object_to_be_entered", object_to_be_entered); + object_to_be_entered.classList.remove("may_select"); + object_to_be_entered.classList.remove("may_enter"); + object_to_be_entered.classList.remove("may_leave"); + editorLog('next_editable_of(object_to_be_entered, "children")'); + editableChildren = next_editable_of(object_to_be_entered, "children"); + var num_editableChildren = editableChildren.length; + current_level += 1; + current_editing["level"] = current_level; + // current_editing["location"][current_level] = 0; + current_editing["location"][current_level] = num_editableChildren - 1; + current_editing["tree"][current_level] = editableChildren; + editorLog("current_editing", current_editing); + + editorLog("object_to_be_entered", object_to_be_entered); + editorLog("with some children", editableChildren); + // put menu on the item at the top of the block_we_are_reentering + // this is a repeat of a Tab case, so consolidate + editorLog("menu place 10end"); + editorLog("document.activeElement", document.activeElement); + + editorLog("menu on", editableChildren[num_editableChildren - 1]); + edit_menu_for(editableChildren[num_editableChildren - 1], "entering"); + + return "" + } else if ((dataLocation == "beforebegin") || (dataLocation == "afterend") || (dataLocation == "afterbegin")) { // should be the only other options + theChooseCurrent.parentElement.classList.add("past"); + theChooseCurrent.removeAttribute("id"); + theChooseCurrent.classList.add("chosen"); + + var parent_id = document.getElementById('edit_menu_holder').parentElement.parentElement.id; + if (!parent_id) { + editorLog(document.getElementById('edit_menu_holder').parentElement.parentElement, "has no id, so going down one level"); + parent_id = document.getElementById('edit_menu_holder').parentElement.id; + } + editorLog("making a menu for", parent_id); + var edit_submenu = document.createElement('ol'); + edit_submenu.innerHTML = menu_options_for(parent_id, "", "base"); + editorLog("just inserted inner menu_options_for(" + parent_id + ")", menu_options_for(parent_id, "", "base")); + theChooseCurrent.insertAdjacentElement("beforeend", edit_submenu); + document.getElementById('choose_current').focus(); + editorLog("focus is on", $(":focus")); + + return "" + } else { + editorLog("Error: unknown dataLocation:", dataLocation) + } + } // dataLocation + + else if (dataAction) { + if (dataAction == "edit") { + editorLog("going to edit", object_of_interest); + edit_in_place(object_of_interest, "old"); + } else if (dataAction == "replace") { // no longer used? + editorLog("replace", object_of_interest, "by id", object_of_interest.id); + replace_by_id(object_of_interest.id, "html") + } else if (dataAction == "stop_editing") { + editorLog("stop_editing", object_of_interest, "by id", object_of_interest.id); + replace_by_id(object_of_interest.id, "html") + eraseCookie(chosen_edit_option_key) + } else if (dataAction == "save") { + save_source(); + edit_menu_from_current_editing("entering"); + } else if (dataAction == "resume") { + editorLog("resuming previous editing session"); + resume_editing() + } else if (dataAction == "change-env-to") { + // shoudl use dataEnv ? + var new_env = theChooseCurrent.getAttribute("data-env"); + editorLog("changing environment to", new_env); + // #edit_menu_holder is in span.type, inside .heading, inside article + to_be_edited = document.getElementById('edit_menu_holder').parentElement.parentElement.parentElement; + editorLog("to_be_edited", to_be_edited); + var id_of_object = to_be_edited.id; + var this_object_source = internalSource[id_of_object]; + editorLog("current envoronemnt", this_object_source); + var old_env = internalSource[id_of_object]["sourcetag"]; + internalSource[id_of_object]["sourcetag"] = new_env; + recent_editing_actions.push([old_env, new_env, id_of_object]); + editorLog("the change was", "changed " + old_env + " to " + new_env + " " + id_of_object); + var the_whole_object = html_from_internal_id(id_of_object); + editorLog("B: the_whole_object", the_whole_object); + $("#" + id_of_object).replaceWith(the_whole_object[0]); // later handle multiple additions + editorLog("just edited", $("#" + id_of_object)); + // since we changed an object which is in + editorLog("curent_editing level", current_editing["level"], "with things", current_editing["tree"][current_editing["level"]]); + current_editing["level"] -= 1; + current_editing["tree"][current_editing["level"]] = next_editable_of(document.getElementById(id_of_object).parentElement, "children"); + editorLog("now curent_editing level", current_editing["level"], "with things", current_editing["tree"][current_editing["level"]]); + edit_menu_from_current_editing("entering"); + return "" + + } else if (dataAction == 'change-env') { + // #edit_menu_holder is in span.type, inside .heading, inside article + current_env = document.getElementById('edit_menu_holder').parentElement.parentElement.parentElement; + current_env_id = current_env.id; + + theChooseCurrent.parentElement.classList.add("past"); + theChooseCurrent.removeAttribute("id"); + theChooseCurrent.classList.add("chosen"); + + var edit_submenu = document.createElement('ol'); + editorLog("J1 lookinh for menu options for", current_env_id); + edit_submenu.innerHTML = menu_options_for(current_env_id, "", "change"); + editorLog("just inserted inner menu_options_for(parent_type)", menu_options_for(current_env_id, "", "change")); + theChooseCurrent.insertAdjacentElement("beforeend", edit_submenu); + document.getElementById('choose_current').focus(); + editorLog("focus is on", $(":focus")); + } else if (dataAction == 'modify') { + // #edit_menu_holder is in span.type, inside .heading, inside article + current_env = document.getElementById('edit_menu_holder').parentElement; + current_env_id = current_env.id; + + if (!dataModifier) { + theChooseCurrent.parentElement.classList.add("past"); + theChooseCurrent.removeAttribute("id"); + theChooseCurrent.classList.add("chosen"); + + var edit_submenu = document.createElement('ol'); + // this may only hapen when adjusting workspace: + if (!current_env_id) { + edit_submenu.setAttribute('id', 'edit_menu'); + edit_submenu.setAttribute('class', 'edit_menu'); + current_env_id = current_env.getAttribute("data-parent_id"); + editorLog("current_env_id", current_env_id); + } + editorLog("J2a looking for menu options for", current_env_id); + edit_submenu.innerHTML = menu_options_for(current_env_id, "", "modify"); + editorLog("just inserted inner menu_options_for(parent_type)", menu_options_for(current_env_id, "", "modify")); + if (theChooseCurrent.tagName == "SPAN") { // when adjusting workspace + theChooseCurrent.replaceWith(edit_submenu); + } else { + theChooseCurrent.insertAdjacentElement("beforeend", edit_submenu); + } + document.getElementById('choose_current').focus(); + editorLog("focus is on", $(":focus")); + } else if (dataModifier == "done") { + edit_menu_from_current_editing("entering"); + } else if (dataModifier == "arrows") { + // setup_arrow_modify() // is different for images and SBSs + } else { + // this may only hapen when adjusting workspace: + if (!current_env_id) { + current_env_id = current_env.getAttribute("data-parent_id"); + editorLog("current_env_id from parent", current_env_id); + } + modify_by_id(current_env_id, dataModifier) + } + } else if (dataAction == "move-or-delete") { + // almost all repeats from dataAction == 'change-env' + // except for current_env and menu options for. Consolidate + // maybe also separate actions which give anotehr menu, from actions which change content + current_env = document.getElementById('edit_menu_holder').parentElement; + editorLog("current_env", current_env); + current_env_id = current_env.id; + + theChooseCurrent.parentElement.classList.add("past"); + theChooseCurrent.removeAttribute("id"); + theChooseCurrent.classList.add("chosen"); + + var edit_submenu = document.createElement('ol'); + editorLog("J3 looking for menu options for", current_env_id); + edit_submenu.innerHTML = menu_options_for(current_env_id, "", "move-or-delete"); + editorLog("just inserted inner menu_options_for(parent_type)", menu_options_for(current_env_id, "", "move-or-delete")); + theChooseCurrent.insertAdjacentElement("beforeend", edit_submenu); + document.getElementById('choose_current').focus(); + editorLog("focus is on", $(":focus")); + } else if (dataAction == "delete") { + current_env = document.getElementById('edit_menu_holder').parentElement; + editorLog("current_env", current_env); + current_env_id = current_env.id; + delete_by_id(current_env_id, "choice") + } else if (["move-local", "move-local-p", "move-local-li"].includes(dataAction)) { + current_env = document.getElementById('edit_menu_holder').parentElement; + current_env_id = current_env.id; + handle_env_id = current_env_id; // we were focused on that p, even though + // we are moving an li. Later refocus on p + if (dataAction == "move-local-li") { + current_env.classList.remove("may_select"); + current_env = current_env.parentElement; + current_env.classList.add("may_select"); + current_env_id = current_env.id; + } + editorLog("current_env", current_env); + move_by_id_local(current_env_id, handle_env_id) + } else if (dataAction == "change-title") { + var this_heading = document.getElementById('edit_menu_holder').parentElement.parentElement; + var this_env_id = this_heading.getAttribute("data-parent_id"); + var new_title_form = standard_title_form(this_env_id); + document.getElementById('edit_menu_holder').parentElement.insertAdjacentHTML("afterend",new_title_form); + document.getElementById('edit_menu_holder').parentElement.remove(); + editorLog("change-title in progress") + document.getElementById('actively_editing').focus(); + } else if (dataAction == "change-caption") { + alert("editing captions not implemented yet"); + return ; + var this_caption = document.getElementById('edit_menu_holder').parentElement; + var this_env_id = this_caption.getAttribute("data-source_id"); + var new_title_form = standard_caption_form(this_env_id); + document.getElementById('edit_menu_holder').parentElement.insertAdjacentHTML("afterend",new_title_form); + document.getElementById('edit_menu_holder').parentElement.remove(); + editorLog("change-caption in progress") + document.getElementById('actively_editing').focus(); + } else { + editorLog("unknown dataAction", dataAction); + alert("I don;t know what to do llllllll dataAction " + dataAction) + } + } // dataAction + else if (dataEnv) { // this has to come after dataAction, because if both occur, + // dataAction says to do something, and dataEnv says what to do + e.preventDefault(); // was this handled earlier? + editorLog("in dataEnv", dataEnv); + editorLog("selected a menu item with no action and no location"); + $("#choose_current").parent().addClass("past"); + editorLog("apparently selected", theChooseCurrent); + theChooseCurrent.removeAttribute("id"); + theChooseCurrent.setAttribute('class', 'chosen'); + + // if (dataEnv in inner_menu_for()) { // object names a collection, so make submenu + if (dataEnv in submenu_options) { // object names a collection, so make submenu + editorLog("making a menu for", dataEnv); + var edit_submenu = document.createElement('ol'); + edit_submenu.innerHTML = menu_options_for("", dataEnv, "inner"); + theChooseCurrent.insertAdjacentElement("beforeend", edit_submenu); + document.getElementById('choose_current').focus(); + + // determine whether both of these next cases can occur + } else if (dataEnv in objectStructure || dataEnvParent in objectStructure) { + // we just selected an action, so do it + // that probably involves adding something before or after a given object + editorLog("making a new", dataEnv, "within", dataEnvParent); + + var before_after = $("#edit_menu_holder > #edit_menu > .chosen").attr("data-location"); + + if (dataEnv == "source") { + alert(" making source"); + show_source(object_of_interest, before_after); + edit_menu_from_current_editing("entering"); + return + // } else if (dataEnv == "save") { + // save_source(); + // edit_menu_from_current_editing("entering"); + } + editorLog("create object to edit",dataEnv, object_of_interest, before_after); + var new_obj = create_object_to_edit(dataEnv, object_of_interest, before_after); + if (!new_obj) { edit_menu_from_current_editing("entering"); return "" } + editorLog("new_obj", new_obj); + edit_in_place(new_obj, "new"); + var new_obj_id = new_obj.id; + editorLog("are we editing id", new_obj_id); + editorLog("are we editing", new_obj); + editorLog(" JJJ current_editing", current_editing["level"], current_editing["location"].length, current_editing["tree"].length, current_editing["tree"][current_editing["level"]]); + editorLog(" current_editing", current_editing); + object_of_interest.classList.remove("may_select"); + object_of_interest.classList.remove("may_enter"); + if (tmp = document.getElementById('edit_menu_holder')) { tmp.remove() } + if (dataEnv.startsWith("sbs")) { + editorLog("added sbs, now add to it", new_obj_id); + editorLog("document.getElementById(new_obj_id)", document.getElementById(new_obj_id)); + var first_panel_id = document.getElementById(new_obj_id).firstElementChild.firstElementChild.id; + editorLog("first_panel_id", first_panel_id, document.getElementById(first_panel_id)); + make_current_editing_tree_from_id(first_panel_id); + edit_menu_from_current_editing("entering"); + } + } else { + editorLog("Error: unknown dataEnv", dataEnv); + editorLog("Or maybe unknown dataEnvParent", dataEnvParent); + editorLog("moving up the menu -- not"); + alert("Sorry, not implemented yet!"); + theChooseCurrent.classList.remove("chosen"); + theChooseCurrent.parentElement.classList.remove("past"); + theChooseCurrent.setAttribute("id", "choose_current"); + } + } + } // // dataEnv + else { + editorLog("key that is not meaningful when navigating a menu:", e.code) + } + } +} // main menu navigator + +editorLog("adding tab listener"); + +document.addEventListener('keydown', logKeyDown); + +function logKeyDown(e) { + if (e.code == "ShiftLeft" || e.code == "ShiftRight" || e.code == "Shift") { return } + prev_prev_char = prev_char; + prev_char = this_char; + this_char = e; + editorLog("logKey",e,"XXX",e.code); + editorLog("are we editing", document.getElementById('actively_editing')); + editorLog("is there already an edit menu?", document.getElementById('edit_menu_holder')); + + var input_region = document.activeElement; + editorLog("input_region", input_region); + // if we are writing something, keystrokes usually are just text input + if (document.getElementById('actively_editing')) { + editorLog(" we are actively editing"); + + if (e.code == "Tab" && !document.getElementById('local_menu_holder')) { + // disabled for now + e.preventDefault(); + return "" + create_local_menu() + } else if (document.getElementById('local_menu_holder')) { + main_menu_navigator(e); + } else { + local_editing_action(e) + } + + } else if (document.getElementById('phantomobject')) { + var the_phantomobject = document.getElementById('phantomobject'); + + if (the_phantomobject.classList.contains('move')) { + move_object(e) + } else { + alert("do not know what to do with that") + } + } else { + main_menu_navigator(e); + } +} + +document.addEventListener('focus', function() { +// editorLog('focused:', document.activeElement) +// editorLog('which has content XX' + document.activeElement.innerHTML + "VV") + prev_prev_focused_element = prev_focused_element; + prev_focused_element = this_focused_element; + this_focused_element = document.activeElement; + $('.in_edit_tree').removeClass('in_edit_tree'); +// $(':focus').parent().addClass('in_edit_tree'); + $('#edit_menu_holder:first-child').parent().addClass('in_edit_tree'); + $('#edit_menu_holder').prev().addClass('in_edit_tree'); +/* + var edit_tree = $(':focus').parents(); + // put little lines on teh right, to show the local heirarchy + for (var i=0; i < edit_tree.length; ++i) { + if (edit_tree[i].getAttribute('id') == "content") { break } + edit_tree[i].classList.add('in_edit_tree') + } +*/ +}, true); + +function initialize_editing(xml_st) { + + createCookie(chosen_edit_option_key,1,0.01); + // console.log("QQQQQQQQ", xml_st, "PPPPPPPPPP"); + // Space Math uses a blank line to indicate mrows + xml_st = xml_st.replace(/<\/mrow>\s*/g, " \n\\cr\n "); + xml_st = xml_st.replace(//g, " "); + xml_st = xml_st.replace(/<\/mrow>/g, " "); + + xmlToObject(xml_st); + record_children(sourceobj); + internalSource = re_transform_source(); + + console.log("mostly done initializing"); + console.log(internalSource); + + current_editing = { + "level": 0, + "location": [0], + // "tree": [ [document.getElementById(top_level_id)] ] + "tree": [ [internalSource.root_data.id] ] + } + console.log("initial current_editing", current_editing); + + e_tree = current_editing["tree"]; + editorLog("e_tree", e_tree); + e_level = current_editing["level"]; + editorLog("e_level", e_level); + e_location = current_editing["location"]; + editorLog("e_location", e_location); + console.log(" making the initial menu for", e_tree[e_level][e_location]); + +// document.getElementById("content").firstElementChild.setAttribute("id", internalSource.root_data.id); + + console.log("replacing by id", internalSource.root_data.id); + replace_by_id(internalSource.root_data.id, "html"); + + edit_menu_for(e_tree[e_level][e_location], "entering") + + console.log("internalSource internalSource internalSource internalSource internalSource internalSource", internalSource); + + // done rebulding HTML, so now process math + // NOT CURRENTLY DOING ANYTHING???? + console.log("ready to edit, so typeset the math"); + document.getElementById("content").classList.add("canedit"); + MathJax.typesetPromise(); +} + +var this_source_txt; +var source_url = window.location.href; +source_url = source_url.replace(/(#|\?).*/, ""); +source_url = source_url.replace(/html$/, "ptx"); +fetch(source_url).then( + function(u){ return u.text();} + ).then( + function(text){ + this_source_txt = text; + // console.log("ppppppppppp this_source_txt",this_source_txt) + if (this_source_txt.includes("404 Not")) { + console.log("Error: source unavailable") + } else if (this_source_txt.includes(" 0) { +// bad code because I dopied and was too lazy to rewrite + parseLog(xml.nodeName, "has attributes", xml.attributes); + for (var j = 0; j < xml.attributes.length; j++) { + var attribute = xml.attributes.item(j); + if (attribute.nodeName == "permid") { this_id = attribute.nodeValue } + // these look backward, but that seems to be how PTX does it currently + if (!this_id && attribute.nodeName == "xml:id") { this_id = attribute.nodeValue } + } + } + if (!this_id) { + this_id = randomstring() + } + return this_id +} + +var sourceobj = {}; +var new_top_id = ""; + +function xmlToObject(xml_st) { + var xml; + if (typeof xml_st == "string") { + // parseLog("xml starts", xml_st.slice(0,50)); + parser = new DOMParser(); + xml = parser.parseFromString(xml_st, "text/xml"); +// xml = $.parseXML(xml_st); + } else { + xml = xml_st + } + + parseLog("xml", xml); + parseLog("xml.nodeName", xml.nodeName, "xml.nodeType", xml.nodeType); +// var obj = {}; + var this_id = ""; + var this_node_content = xml.nodeValue; + + if (xml.nodeType == 9) { // document + xml = xml.documentElement; + } + + parseLog("this_node_content", this_node_content); + + if (xml.nodeType == 1) { // element + this_id = xml_id_of(xml); + if (!new_top_id) { + new_top_id = this_id; + top_level_id = new_top_id; + sourceobj["root_data"] = {"id": new_top_id, "number_base": "X.Y"} + } + parseLog("found this_id", this_id); + var this_entry = {}; + this_entry["xml:id"] = this_id; + if (["ol", "ul", "dl"].includes(xml.nodeName)) { + this_entry["sourcetag"] = "list" +/* + } else if (["me", "men"].includes(xml.nodeName)){ + this_entry["sourcetag"] = "displaymath" +*/ + } else { + this_entry["sourcetag"] = xml.nodeName; + } + + this_node_content = ""; + if (xml.hasChildNodes()) { + for (var i = 0; i < xml.childNodes.length; i++) { + var item = xml.childNodes.item(i); + if (item.nodeType == 8) { + //comment, so skip + } else if (item.nodeType == 3) { // text + this_node_content += item.nodeValue + } else if (item.nodeType == 1) { // element + var sub_node_id = xmlToObject(item); // the contents, in certain cases + if (contained_objects.includes(item.nodeName)) { + this_entry[item.nodeName] = sub_node_id + } else { + this_node_content += "<&>" + sub_node_id + "<;>" + } + } else { + parseLog("what to do with this node?", item) + } + } + } + if (this_node_content) { + this_entry["content"] = this_node_content.trim(); + } + + if (xml.attributes.length > 0) { + // parseLog(xml.nodeName, "has attributes", xml.attributes); + for (var j = 0; j < xml.attributes.length; j++) { + var attribute = xml.attributes.item(j); + if (attribute.nodeName == "source") { this_entry["source"] = attribute.nodeValue } + else if (attribute.nodeName == "ref") { this_entry["ref"] = attribute.nodeValue } + else if (attribute.nodeName == "text") { this_entry["text"] = attribute.nodeValue } + // width for images, widths for sbs + else if (attribute.nodeName == "width") { + var widthvalue = attribute.nodeValue; + if (widthvalue.endsWith("%")) { widthvalue = widthvalue.slice(0,-1); } + this_entry["width"] = widthvalue + } else if (attribute.nodeName == "margins") { + var marginsvalues = attribute.nodeValue.split(' '); + if (marginsvalues.length == 1) { + var margin = marginsvalues[0]; + if (margin.endsWith("%")) { margin = margin.slice(0,-1); } + this_entry["marginleft"] = margin; + this_entry["marginright"] = margin; + } else if (marginsvalues.length == 2) { + var [marginleft, marginright] = marginsvalues; + if (marginleft.endsWith("%")) { marginleft = marginleft.slice(0,-1); } + if (marginright.endsWith("%")) { marginright = marginright.slice(0,-1); } + this_entry["marginleft"] = marginleft; + this_entry["marginright"] = marginright; + } else { + console.log("Error: too many margins in", xml) + } + } + } + } + // The CAT expects a width and margins on an image, but those myght not be + // specified in the source. So add those if not present. + if (xml.nodeName == "image") { + console.log("image attributes", xml.attributes, "ddd", xml.attributes["source"]); + if (!xml.attributes["width"]) { + console.log("no width"); + this_entry["width"] = 100; + } + if (!xml.attributes["margins"]) { + console.log("no margins"); + this_entry["marginleft"] = 0; + this_entry["marginright"] = 0; + } + } + + if (xml.attributes) { + parseLog(xml, "has attributes", xml.attributes) + } +// parseLog("item", item); + if (contained_objects.includes(xml.nodeName)) { + return this_node_content + } else { + sourceobj[this_id] = this_entry + return this_id + } + } else if (xml.nodeType == 8) { + // comment node, so do nothing + this_node_content = "" + } else if (xml.nodeType == 3) { // text + // can this, or the previous case, actually happen? + } else { + console.log("failed to deal with", xml) + } +} + +function record_children(internal_src) { + for (key in internal_src) { + var this_item = internal_src[key]; + if ("content" in this_item) { // skip empty tags + var this_content = this_item["content"]; + parseLog("this_content", this_content); + var child_items = this_content.match(/<&>.*?<;>/g) || ""; + for (var j=0; j < child_items.length; ++j) { + var this_child = child_items[j].slice(3,-3); + parseLog("this_child", this_child, "has a parent", key); + internal_src[this_child]["parent"] = [key, "content"] + } + } + // need to handle content and statement better + if ("statement" in this_item) { // skip empty tags + var this_statement = this_item["statement"]; + // parseLog("this_statement", this_statement); + var child_items = this_statement.match(/<&>.*?<;>/g) || ""; + for (var j=0; j < child_items.length; ++j) { + var this_child = child_items[j].slice(3,-3); + // parseLog("this_child", this_child, "has a parent", key); + internal_src[this_child]["parent"] = [key, "statement"] + } + } + if ("proof" in this_item) { // skip empty tags + var this_proof = this_item["proof"]; + // parseLog("this_statement", this_statement); + var child_items = this_proof.match(/<&>.*?<;>/g) || ""; + for (var j=0; j < child_items.length; ++j) { + var this_child = child_items[j].slice(3,-3); + // parseLog("this_child", this_child, "has a parent", key); + internal_src[this_child]["parent"] = [key, "proof"] + } + } + } + return internal_src +} + +// transofrm again, to un-wrap list in p + +/* rewrite with sourceobj not global */ +function re_transform_source() { + var ids_to_delete = []; + for (var id in sourceobj) { + var this_item = sourceobj[id]; + if (this_item["sourcetag"] == "list") { + // I think this takes the list out of its parent p, + // but I forgot to write this comment when I first wrote the code. + parseLog("found a list", this_item); + var [parent_id, parent_content] = this_item["parent"]; + parseLog("with parent", sourceobj[parent_id]); + if (sourceobj[parent_id]["sourcetag"] == "p") { + var [parent_parent_id, parent_parent_content] = sourceobj[parent_id]["parent"]; + parseLog("with parents parent", sourceobj[parent_parent_id]); + // need to skip the intermediate parent + var old_p_p_content = sourceobj[parent_parent_id][parent_parent_content]; + var new_p_p_content = old_p_p_content.replace("<&>" + parent_id + "<;>", "<&>" + id + "<;>"); + sourceobj[parent_parent_id][parent_parent_content] = new_p_p_content; + sourceobj[id]["parent"] = [parent_parent_id, parent_parent_content]; + // then eliminate the intermediate parent + parseLog("deleting", parent_id); + // delete sourceobj[parent_id]; + ids_to_delete.push(parent_id); + parseLog("now sourceobj[parent_parent_id]", sourceobj[parent_parent_id]) + } + } else if (this_item["sourcetag"] == "image") { + if ("width" in this_item && !("marginleft" in this_item)) { + parseLog("no width in" + this_item["xml:id"]) + var width = parseInt(this_item["width"]); + var margins = (100 - width)*0.5; + this_item["marginleft"] = margins; + this_item["marginright"] = margins; + } + } else if (["md", "mdn", "me", "men"].includes(this_item["sourcetag"])) { + // to handle the case of more than one displaymath in a p, + // we do it in two passes. First we just record the ids of the me/men's. + // Then we simplify the problem by handling the displaymath in the + // order they occur. + parseLog("found displaymath", this_item); + parseLog("with parent", sourceobj[this_item["parent"][0]]); + var displaymath_id= this_item["xml:id"]; + if ("includedmath" in sourceobj[this_item["parent"][0]]) { + sourceobj[this_item["parent"][0]]["includedmath"].push("<&>" + displaymath_id + "<;>") + } else { + sourceobj[this_item["parent"][0]]["includedmath"] = ["<&>" + displaymath_id + "<;>"] + } + } else if (["caption"].includes(this_item["sourcetag"])) { + parseLog("found a caption", this_item); + var [parent_id, parent_content] = this_item["parent"]; + parseLog("with parent", sourceobj[parent_id]); + if (sourceobj[parent_id]["sourcetag"] == "figure") { + var old_p_content = sourceobj[parent_id][parent_content]; + var new_p_content = old_p_content.replace("<&>" + id + "<;>", ""); + sourceobj[parent_id][parent_content] = new_p_content; + sourceobj[parent_id]["captiontext"] = sourceobj[id]["content"]; + // then eliminate the caption object, because now it is an attribute of a figure + // delete sourceobj[id]; + ids_to_delete.push(id); + parseLog("now sourceobj[parent_id]", sourceobj[parent_id]) +alert("testing") + } else { alert("error: caption not in figure") } + } + } + // now go through and fix the "p" containing displaymath + for (var id in sourceobj) { + var this_item = sourceobj[id]; + if (this_item["sourcetag"] == "p") { + if ("includedmath" in this_item) { + console.log("found includedmath", this_item); + var outer_parent = this_item["parent"]; + var context_of_outer_parent = sourceobj[outer_parent[0]][outer_parent[1]]; + console.log("this item id", id, "with parent", outer_parent, "in context", context_of_outer_parent); + var these_includedmath = this_item["includedmath"]; + var this_content = this_item["content"]; + var these_includedmath_index = []; + for (var j=0; j < these_includedmath.length; ++j) { + var this_math_tag = these_includedmath[j]; + these_includedmath_index.push([this_content.indexOf(this_math_tag),this_math_tag]); + console.log("this_math_tag", this_math_tag, "has index", this_content.indexOf(this_math_tag)) + } + these_includedmath_index.sort(); + parseLog("sorted list", these_includedmath_index) + + // var displaymath_parent_original_content = sourceobj[outer_parent[0]]["content"]; + parseLog("ocntent before splitting up", context_of_outer_parent); + this_math_tag = these_includedmath_index[0][1]; + parseLog("this_math_tag", this_math_tag); + var this_math_id = this_math_tag.slice(3,-3); + parseLog("this_math_id", this_math_id); + parseLog("with source", sourceobj[this_math_id]); + // move punctuation inside the display math + // (for easier editing. move it back out later) + var find_char_after = new RegExp('^(.*' + this_math_tag + ")(.)\s*(.*)$", "s"); + var char_after = this_content.replace(find_char_after, "$2"); + if ([".", ",", ";", ":"].includes(char_after)) { + console.log("found punctuation", char_after); + this_content = this_content.replace(find_char_after, "$1$3"); // go back an omit white space + sourceobj[this_math_id]["content"] += char_after + } + // the original p ends at the first displaymath + var displaymath_id_and_before = new RegExp('^.*' + this_math_tag, "s"); // s = dotAll + var displaymath_id_and_after = new RegExp(this_math_tag + '.*$', "s"); + sourceobj[id]["content"] = + this_content.replace(displaymath_id_and_after, ""); + sourceobj[id]["sourcetag"] = "ip" + this_content = this_content.replace(displaymath_id_and_before, ""); + parseLog("updated this_content", this_content); + // the first displaymath now has a different parent + sourceobj[this_math_id]["parent"] = outer_parent; + // that parent needs to know where to put the first displaymath + context_of_outer_parent = context_of_outer_parent.replace("<&>" + id + "<;>", "<&>" + id + "<;>" + "\n" + this_math_tag); + parseLog("updated context_of_outer_parent", context_of_outer_parent); + sourceobj[outer_parent[0]][outer_parent[1]] = context_of_outer_parent; + // here need to check if this_content is nonempty (after removing trailing white space + var new_id = "XXXX" + randomstring(); + sourceobj[new_id] = {"xml:id":new_id, "sourcetag": "mp"}; + sourceobj[new_id]["content"] = this_content; + sourceobj[new_id]["parent"] = outer_parent; + context_of_outer_parent = context_of_outer_parent.replace(this_math_tag, this_math_tag + "\n" + "<&>" + new_id + "<;>"); + sourceobj[outer_parent[0]][outer_parent[1]] = context_of_outer_parent; + for (var j=1; j < these_includedmath_index.length; ++j) { + this_math_tag = these_includedmath_index[j][1]; + this_math_id = this_math_tag.slice(3,-3); + + // move punctuation inside the display math + // (for easier editing. move it back out later) + var find_char_after = new RegExp('^(.*' + this_math_tag + ")(.)\s*(.*)$", "s"); + var char_after = this_content.replace(find_char_after, "$2"); + if ([".", ",", ";", ":"].includes(char_after)) { + console.log("found punctuation", char_after); + this_content = this_content.replace(find_char_after, "$1$3"); // go back an omit white space + sourceobj[this_math_id]["content"] += char_after + } + + displaymath_id_and_before = new RegExp('^.*' + this_math_tag, "s"); // s = dotAll + displaymath_id_and_after = new RegExp(this_math_tag + '.*$', "s"); + sourceobj[new_id]["content"] = this_content.replace(displaymath_id_and_after, ""); + this_content = this_content.replace(displaymath_id_and_before, ""); + // this displaymath now has a different parent + sourceobj[this_math_id]["parent"] = outer_parent; + // that parent needs to know where to put the first displaymath + context_of_outer_parent = context_of_outer_parent.replace("<&>" + new_id + "<;>", "<&>" + new_id + "<;>" + "\n" + this_math_tag); + sourceobj[outer_parent[0]][outer_parent[1]] = context_of_outer_parent; + // omit next if this_content is only white space + new_id = "XXXX" + randomstring(); + sourceobj[new_id] = {"xml:id":new_id, "sourcetag": "mp"}; + sourceobj[new_id]["content"] = this_content; + sourceobj[new_id]["parent"] = outer_parent; + context_of_outer_parent = context_of_outer_parent.replace(this_math_tag, this_math_tag + "\n" + "<&>" + new_id + "<;>"); + sourceobj[outer_parent[0]][outer_parent[1]] = context_of_outer_parent; + } + sourceobj[new_id]["sourcetag"] = "fp" + } + } + } + // trim leading white space in paragraph content + for (var id in sourceobj) { + var this_item = sourceobj[id]; + if (["p", "ip", "mp", "fp"].includes(this_item["sourcetag"])) { + var this_content = sourceobj[id]["content"]; + this_content = this_content.replace(/\n +/g, "\n"); + sourceobj[id]["content"] = this_content; + } else if (["me", "men", "md", "mdn"].includes(this_item["sourcetag"])) { + var this_content = sourceobj[id]["content"]; + this_content = this_content.replace(/\n +/g, "\n "); + sourceobj[id]["content"] = this_content; + } + // next also needs table (or whatever it is that has a caption) + if (["figure"].includes(this_item["sourcetag"])) { + editorLog("adjusting a figure", this_item); + // ??? next line should involve captiontext instead of caption ? + var this_caption = sourceobj[id]["caption"]; + this_caption = this_caption.replace(/\n +/g, "\n"); + sourceobj[id]["captiontext"] = this_caption; + } + } + + for (var j=1; j < ids_to_delete.length; ++j) { + // delete sourceobj[ids_to_delete[j]] + } + + return sourceobj; +} + diff --git a/_static/pretext/js/highlight.js b/_static/pretext/js/highlight.js new file mode 100644 index 0000000..98f906a --- /dev/null +++ b/_static/pretext/js/highlight.js @@ -0,0 +1,480 @@ + +/* +highlight_css = document.createElement('style'); +highlight_css.type = "text/css"; +highlight_css.id = "highlight_css"; +document.head.appendChild(highlight_css); +var css_for_hl = 'span.hl { background: yellow; }\n'; +css_for_hl += '#hlmenu { position: absolute; top: 300px; left: 200px;}\n'; +css_for_hl += '#hlmenu { padding: 8px; background: #FFF; }\n'; +css_for_hl += '#hlmenu { box-shadow: 8px 10px 5px #888; border: 1px solid #aaa;}\n'; +css_for_hl += '#hlmenu .hldelete { background: #fdd; }'; +css_for_hl += '#hlmenu .hldelete:hover { background: #fbb; }'; +css_for_hl += '#hlmenu .hlcopy { background: #ddf; }'; +css_for_hl += '#hlmenu .hlcopy:hover { background: #bbf; }'; +css_for_hl += '#hlmenu .dismiss:hover { background: #ff9; }'; +css_for_hl += '#hlmenu > div { padding: 4px; font-size: 90%}'; +highlight_css.innerHTML = css_for_hl; +*/ + +hlmenu = document.createElement('div'); +hlmenu.id = "hlmenu"; +hlmenu.style.display = "none"; +hlmenu_contents = '
    copy to clipboard
    \n'; +hlmenu_contents += '
    delete highlight
    \n'; +hlmenu_contents += '
    dismiss menu
    '; +hlmenu.innerHTML = hlmenu_contents; +document.body.appendChild(hlmenu); + +var all_highlights = localStorage.getObject("all_highlights"); +if (!all_highlights) { + console.log("no highlights on this page",all_highlights); + all_highlights= {}; +} else { + console.log("highlights already",all_highlights); +} + +console.log("all_highlights.keys()", Object.keys(all_highlights)); +console.log("waiting for MathJax"); +MathJax.Hub.Register.StartupHook("End",function () { + // need to wait for MathJax, because MathJax changes the number of nodes in a paragraph + console.log("MathJax is done"); + display_all_highlights(all_highlights, Object.keys(all_highlights), 0); +}); + + +/* +for (var key in all_highlights) { + var this_key = key; + var these_highlights = all_highlights[key]; + console.log("adding highlights to", key); +// await display_highlights_on(key, all_highlights[key], 0) + for (var i=0; i< these_highlights.length; ++i) { + hl = these_highlights[i]; + console.log("inserting highlight",i,"which is",hl, "on", key); + // display_one_highlight(key, hl); +//fails because + setTimeout(function() { display_one_highlight(this_key, hl)}, i*2000); + + } +} +*/ + +function index_of_child(child) { + var i = 0; + while( (child = child.previousSibling) != null ) + {i++ } + return i +} + +function increment_id(list_of_things_with_ids) { // assume ids are of the form xxxxNN with N a digit and x a non-digit + console.log("incrementing id on", list_of_things_with_ids); + if (list_of_things_with_ids.length == 0) { + return 0 + } + + id_start = list_of_things_with_ids[0]["id"].replace(/^(.*?)[0-9]+$/, "$1"); + current_endings = []; + for (var i=0; i < list_of_things_with_ids.length; ++i) { + current_endings.push(list_of_things_with_ids[i]["id"].replace(/^.*?([0-9]+)$/, "$1")); + } + console.log("existing id endings", current_endings); + current_max = Math.max(...current_endings); + return id_start + (parseInt(current_max) + 1) +} + +function enclosing_p_or_li(obj) { + console.log("obj.tagName", obj.tagName, "ggg",obj); + if (!obj) { + console.log("problem with previous object"); + return null + } + else if (obj.tagName == 'P' || obj.tagName == 'LI') { + return obj + } + return enclosing_p_or_li(obj.parentNode) +} + +// If you just loop ofer the highlights to add them, +// you end up with a race condition because each highlight changes +// the structure of the paragraph. +async function display_one_highlight(parent_id, hl) { + var the_parent = document.getElementById(parent_id); + if (!the_parent) { + console.log("this id not on this page:", parent_id); + return + } + console.log("setting", hl, "on", parent_id); + var st_node_ind = hl['start_nn']; + var st_offset = hl['start_offset']; + var end_node_ind = hl['end_nn']; + var end_offset = hl['end_offset']; + console.log("st_node_ind", st_node_ind, "st_offset", st_offset, "end_node_ind", end_node_ind, "end_offset", end_offset); + // other error checks: same parent + if (st_offset < 0 || st_node_ind > the_parent.childNodes.length || end_node_ind > the_parent.childNodes.length || st_offset > the_parent.childNodes[st_node_ind].textContent.length || end_offset < 0 || end_offset > the_parent.childNodes[end_node_ind].textContent.length) { + console.log("highlight data inconsistent with paragraph structure that contains", the_parent.childNodes.length, "nodes"); + return + } + + let this_range = document.createRange(); + console.log("setting this_range.setStart", the_parent.childNodes[st_node_ind], "with offset", st_offset, "out of", the_parent.childNodes[st_node_ind].textContent.length); + this_range.setStart(the_parent.childNodes[st_node_ind], st_offset); + this_range.setEnd(the_parent.childNodes[end_node_ind], end_offset); + var inside_part = document.createElement("span") + inside_part.classList.add("hl"); + inside_part.id = hl['id']; + console.log("inside_part", inside_part, "going inside this_range",this_range); + console.log("in the_parent",the_parent); + this_range.surroundContents(inside_part); + return; +} + +//var display_highlights_on = function(parent_id, highlights_on, ind) { +async function display_highlights_on(parent_id, highlights_on, ind) { + console.log("display_highlights_on", parent_id, "xxxx", ind, "out of", highlights_on.length); + if (ind < highlights_on.length) { + console.log("about to display one highlight, number", ind, "on", parent_id); + await display_one_highlight(parent_id, highlights_on[ind]); + ++ind; + await display_highlights_on(parent_id, highlights_on, ind) + } + return; +} + +async function display_all_highlights(every_highlight, hl_p_keys, i) { + console.log("making hl on", hl_p_keys[i]); + if (i < hl_p_keys.length) { + await display_highlights_on(hl_p_keys[i], every_highlight[hl_p_keys[i]], 0); + ++i; + await display_all_highlights(every_highlight, hl_p_keys, i) + } + return; +} + +var DELAY = 500, clicks = 0, timer = null; +$("p[id], li[id]").on("click", function(e) { + clicks++; //count clicks + + if(clicks === 1) { + + if (e.target.classList.contains("hl")) { + modifyhighlight(e); + clicks = 0; + } else { + timer = setTimeout(function() { + newhighlight() + clicks = 0; //after action performed, reset counter + }, DELAY); + + } + + + } else if (clicks === 2) { + timer2 = setTimeout(function() { + clearTimeout(timer); + // alert("Double Click"); + clicks = 0; + }, DELAY/2); + } else { + clearTimeout(timer); //prevent single-click action + clearTimeout(timer2); //prevent double-click action + // alert("Triple Click"); //perform triple-click action + clicks = 0; //after action performed, reset counter + } +}); + +function save_highlights() { + hl_data = {"action": "save", "user": uname, "pw": emanu, "bookID": bodyID, "type": "highlights", "hl": JSON.stringify(all_highlights)} + $.ajax({ + url: "https://aimath.org/cgi-bin/u/highlights.py", + type: "post", + data: JSON.stringify(hl_data), + dataType: "json", + success: function(data) { + console.log("something", data, "back from highlight"); + // alert(data); + }, + error: function(errMsg) { + console.log("seems to be an error?",errMsg); + // alert("Error\n" + errMsg); + } + }); + + console.log("just ajax sent", JSON.stringify(reading_questions_object)); +} + +function newhighlight() { + var this_selection = window.getSelection(); + console.log("UUUUUUUUUUUUUUUUUUUUUUUUUUU"); + console.log("selection", this_selection, "as string", this_selection.toString(), "length", this_selection.toString().length); + if(this_selection.toString().length >= 3) { + console.log("this_selection", this_selection); + console.log("this_selection parentNode", this_selection.parentNode); + + num_selected_ranges = this_selection.rangeCount; + console.log("this_selection.rangeCount", this_selection.rangeCount); + console.log("this_selection.getRangeAt(0)", this_selection.getRangeAt(0)); + console.log("this_selection.getRangeAt(num_selected_ranges)", this_selection.getRangeAt(num_selected_ranges-1)); + console.log("this_selection.getRangeAt(0).startContainer", this_selection.getRangeAt(0).startContainer); + console.log("this_selection.getRangeAt(0).endContainer", this_selection.getRangeAt(0).endContainer); + console.log("this_selection.getRangeAt(-1).startContainer", this_selection.getRangeAt(num_selected_ranges-1).startContainer); + console.log("this_selection.getRangeAt(-1).endContainer", this_selection.getRangeAt(num_selected_ranges-1).endContainer); + console.log("start equals end", this_selection.getRangeAt(0).startContainer == this_selection.getRangeAt(0).endContainer); + console.log("this_selection.getRangeAt(0).startContainer.parent", this_selection.getRangeAt(0).startContainer.parentNode); + console.log("this_selection.getRangeAt(0).endContainer.parent", this_selection.getRangeAt(0).endContainer.parentNode); + starting_parent = enclosing_p_or_li(this_selection.getRangeAt(0).startContainer); + starting_parent_id = starting_parent.id; + ending_parent_id = enclosing_p_or_li(this_selection.getRangeAt(num_selected_ranges-1).endContainer).id; + console.log("starting parent", enclosing_p_or_li(this_selection.getRangeAt(0).startContainer)); + console.log("starting_parent.childNodes", starting_parent.childNodes); + console.log("starting_parent.childNodes.length", starting_parent.childNodes.length); + console.log("ending parent", enclosing_p_or_li(this_selection.getRangeAt(0).endContainer)); + console.log("index of starting node", index_of_child(this_selection.getRangeAt(0).startContainer)); + console.log("which is", starting_parent.childNodes[index_of_child(this_selection.getRangeAt(0).startContainer)]); + console.log("index of ending node", index_of_child(this_selection.getRangeAt(num_selected_ranges-1).endContainer)); + console.log("which is", starting_parent.childNodes[index_of_child(this_selection.getRangeAt(num_selected_ranges-1).endContainer)]); + console.log("XXXXXXXXXXXXXXXXXXXXXXX"); + starting_node = this_selection.getRangeAt(0); + starting_node_container = starting_node.startContainer; + starting_node_number = index_of_child(starting_node_container); + starting_node_offset = starting_node.startOffset; + console.log("starting_node", starting_node, "starting_node_container", starting_node_container); + console.log("starting_parent.childNodes[0]", starting_parent.childNodes[0]); + ending_node = this_selection.getRangeAt(num_selected_ranges-1); + ending_node_container = ending_node.endContainer; + console.log("ending_node", ending_node, "ending_node_container", ending_node_container); + ending_node_number = index_of_child(ending_node_container); + ending_node_offset = ending_node.endOffset; + console.log("selection starts at character number", starting_node.startOffset, "in node number", index_of_child(starting_node), "of node", starting_node.startContainer, "within", starting_node.startContainer.parentNode,"which is", starting_node); + console.log("selection ends at character number", ending_node.endOffset, "in node number", index_of_child(ending_node_container), "of node", ending_node.endContainer, "within", ending_node.endContainer.parentNode, "which is", ending_node); + +// let this_range = document.createRange(); +// this_range.setStart(starting_parent.childNodes[starting_node_number], starting_node_offset); +// this_range.setEnd(document.getElementById(starting_parent_id).childNodes[ending_node_number], ending_node_offset); +// test_inside_part=document.createElement("span") +// test_inside_part.classList.add("gggg"); +// this_range.surroundContents(test_inside_part); + console.log("num_selected_ranges", num_selected_ranges, "starting_parent_id", starting_parent_id, "ending_parent_id", ending_parent_id); + this_selection.empty(); + console.log("starting_parent_id", starting_parent_id, "ending_parent_id", ending_parent_id); + if (starting_parent_id != ending_parent_id) { + alert("Highlights must be within\none paragraph or list item."); + return "" + } + if (starting_parent != starting_node_container.parentNode) { + starting_node_number = index_of_child(starting_node_container.parentNode) - 1; + console.log("new starting node",starting_node_number, " which is", starting_parent.childNodes[starting_node_number]); + starting_node_offset = starting_parent.childNodes[starting_node_number].length; + } + if (starting_parent != ending_node_container.parentNode) { + ending_node_number = index_of_child(ending_node_container.parentNode) + 1; + console.log("new edngin node",ending_node_number, " which is", starting_parent.childNodes[ending_node_number]); + ending_node_offset = 0; + } + console.log("starting_parent eq st cont parent", starting_parent == starting_node_container.parentNode, "starting_parent eq end cont parent", starting_parent == ending_node_container.parentNode); +// display_one_highlight(starting_parent_id, starting_node_number, starting_node_offset, ending_node_number, ending_node_offset); +// console.log("this_range", this_range); + this_highlight = {"start_nn": starting_node_number, + "start_offset": starting_node_offset, + "end_nn": ending_node_number, + "end_offset": ending_node_offset}; + if (starting_parent_id in all_highlights) { + console.log("the starting_parent_id", starting_parent_id, "is already in all_highlights", all_highlights); + new_id = increment_id(all_highlights[starting_parent_id]); + this_highlight['id'] = new_id; + all_highlights[starting_parent_id].push(this_highlight) + } else { + this_highlight['id'] = starting_parent_id + "-" + "hl" + 1; + all_highlights[starting_parent_id] = [this_highlight] + } + display_one_highlight(starting_parent_id, this_highlight); + localStorage.setObject("all_highlights", all_highlights); + + if (uname != "guest" && role=="student") { + console.log("saving highlights"); + save_highlights(); + } + console.log("all_highlights", all_highlights); + return ""; + } +} + +function modifyhighlight(e) { + this_hl = e.target; + console.log("clicked hl", this_hl.id); + + var x = e.clientX, y = e.clientY; + console.log("x", x, "y", y); + document.getElementById("hlmenu").style.top = (y - 10 + $(window).scrollTop()) + 'px'; + document.getElementById("hlmenu").style.left = (x + 20) + 'px'; + document.getElementById("hlmenu").style.display = 'block'; + document.getElementsByClassName("hlcopy")[0].setAttribute("data-hlid", this_hl.id); + document.getElementsByClassName("hldelete")[0].setAttribute("data-hlid", this_hl.id); +// tooltipSpan.style.left = (x + 20) + 'px'; + + var parent_id = this_hl.id.replace(/^(.*)-[^\-]*$/, "$1"); + var number_of_this_highlight = this_hl.id.slice(-1); + var these_highlights = all_highlights[parent_id]; + var this_highlight = these_highlights[number_of_this_highlight-1]; + console.log("parent id", parent_id, "nunber",number_of_this_highlight); + var num_child_nodes = this_hl.childNodes.length; + console.log("which has", this_hl.childNodes.length, "child nodes"); + for (var i=0; i < num_child_nodes; ++i) { + console.log(i, "node is", this_hl.childNodes[i]) + } + console.log("highlights on this item",all_highlights[parent_id], "of which we clicked", these_highlights[number_of_this_highlight - 1], +"number", number_of_this_highlight, "out of", these_highlights.length ); + for (var i=0; i 0) { + all_highlights[parent_id] = new_highlights + } else { + delete all_highlights[parent_id] + } + + localStorage.setObject("all_highlights", all_highlights); + + + // hide the current highlight + $(hl_to_delete).replaceWith(hl_to_delete.innerHTML); + + document.getElementById(parent_id).normalize(); // because a previous step creates adjacent text nodes + + document.getElementById("hlmenu").style.display = 'none'; +}); + +$('body').on('click','.dismiss', function(e){ + console.log(".dismiss of",this); + the_parent = this.closest("[id]"); + the_parent.style.display = 'none'; +}); diff --git a/_static/pretext/js/instructor.js b/_static/pretext/js/instructor.js new file mode 100644 index 0000000..df5a43c --- /dev/null +++ b/_static/pretext/js/instructor.js @@ -0,0 +1,131 @@ + +var icon = { + "warning": "⚠️ ", + "commentary": "☕", + "media": "▶", + "tip": "📣", + "worksheet": "📄", + "assesment": "A+", + "slides": "📻", + "outcomes": "✓" +}; + +var html_words_of = { + "warning": "Common pitfall", + "commentary": "Alert", + "media": "An amusing demo", + "tip": "Tip: discussion point", + "worksheet": "Worksheet:", + "assesment": "Sample exam:", + "slides": "Slides:", + "outcomes": "Learning outcomes" +} + +//
       Word PTX PDF
    ", + +var type_name = { + "warning": "warning", + "commentary": "commentary", + "media": "media", + "tip": "tip", + "worksheet": "worksheet", + "assesment": "assesment", + "slides": "slides", + "outcomes": "outcomes" +}; + +console.log("in instructor.js", role, "role", logged_in, "logged_in"); + +if (role=="instructor") { + console.log(" loading instructor resources"); + + var instructor_resources = document.querySelectorAll(".instructor"); + + console.log('instructor_resources.length', instructor_resources.length); + + var icons_on_this_page = []; + + for (var j=0; j < instructor_resources.length; ++j) { + var instructor_resource = instructor_resources[j]; + var instructor_resource_parent_id = instructor_resource.parentNode.id; + console.log(" XXXXXXXXXXXX instructor_resource.parentNode", instructor_resource.parentNode); + console.log("instructor_resource_parent_id", instructor_resource_parent_id); + if(instructor_resource_parent_id) { + } else { + instructor_resource_parent_id = instructor_resource.parentNode.parentNode.id; + } + + this_type = instructor_resource.getAttribute("data-resource"); + this_icon = icon[this_type]; + var id_of_this_icon = "resourceid" + j; + icons_on_this_page.push([type_name[this_type], this_icon, id_of_this_icon]); + + console.log("this_type", this_type, "this_icon", this_icon, "html_words_of[this_type]", html_words_of[this_type]); + this_item_with_resource = document.getElementById(instructor_resource_parent_id); + console.log("instructor_resource_parent_id", instructor_resource_parent_id, "this_item_with_resource", this_item_with_resource); + + var this_margin_resource = document.createElement('div'); + this_margin_resource.setAttribute('class', 'marginresource'); + this_margin_resource.setAttribute('id', id_of_this_icon); + this_margin_resource.innerHTML = "" + this_icon + ""; + if(!(this_title = instructor_resource.getAttribute("title"))) { + this_title = html_words_of[this_type] + } + if(instructor_resource.hasAttribute("data-content")) { + this_content = instructor_resource.getAttribute("data-content"); + this_title = '' + this_title + ''; + } + var links_html = "" + if(instructor_resource.hasAttribute("data-links")) { + var this_links = instructor_resource.getAttribute("data-links"); + these_links = this_links.split(";"); + links_html = '' + console.log(" OOOOOOOOOOOOOO these_links", these_links, "these_links.length", these_links.length); + if(these_links.length > 0) { + console.log("these_links[0]", these_links[0]); + } + tmpJ = these_links.length; + console.log("tmpJ", tmpJ); + for(var jj=0; jj < these_links.length; ++jj) { + console.log( " UUUUUUUUUUUUUu these_links[jj]", these_links[jj]); + this_type_and_link = these_links[jj].split(","); + if(jj>0) { links_html += ", " } + links_html += '' + this_type_and_link[0] + ''; + } + links_html += 'XX'; + console.log("done adding links to title"); + } + this_title = '' + this_title + if(links_html) { + this_title += links_html + } + this_title += ''; + this_margin_resource.innerHTML += this_title; +// this_item_with_resource.insertBefore(this_margin_resource); + this_item_with_resource.insertBefore(this_margin_resource, this_item_with_resource.firstChild); + console.log("appended to ",this_item_with_resource); + } + + icons_on_this_page.sort(); + + var icon_legend_for_this_page = document.createElement('div'); + var prev_icon = ""; + var icon_list = '' + "" + icons_on_this_page[0][0] + ": "; + for (var j=0; j < icons_on_this_page.length; ++j) { + next_icon = icons_on_this_page[j][1]; + if(j > 0 && next_icon !== prev_icon) { + icon_list += '' + "
    "; + icon_list += '' + "" + icons_on_this_page[j][0] + ": "; + icon_list += '' + next_icon + ''; + } else { + icon_list += '' + next_icon + ''; + } + prev_icon = next_icon; + } + icon_list += ''; + + icon_legend_for_this_page.setAttribute('class', 'iconlegend'); + icon_legend_for_this_page.innerHTML = icon_list + document.body.appendChild(icon_legend_for_this_page); + +} // if logged in as instructor diff --git a/_static/pretext/js/lib/jquery.espy.min.js b/_static/pretext/js/lib/jquery.espy.min.js new file mode 100644 index 0000000..31cffd1 --- /dev/null +++ b/_static/pretext/js/lib/jquery.espy.min.js @@ -0,0 +1,195 @@ + +(function(b, u, v) { + function x(b, f, e) { + b = (b + "").match(/^(-?[0-9]+)(%)?$/); + if (!b) return !1; + var c = parseInt(b[1], 10); + b[2] && (c *= f / 100); + return 0 > c ? f + c + (e || 0) : c + } + + function y(k, f) { + function e() { + function b() { + g = +new Date; + f.apply(e, t); + c && (c = clearTimeout(c)) + } + var e = this, + q = +new Date - g, + t = arguments; + c && (c = clearTimeout(c)); + q > k ? b() : c = setTimeout(b, k - q) + } + var c, g = 0; + b.guid && (e.guid = f.guid = f.guid || b.guid++); + return e + } + b.Espy = function(k, f, e) { + function c(a, d) { + b.isPlainObject(a) && (d = a, a = null); + b.extend(t.prototype, d); + null !== a && (w = a) + } + + function g(a) { + if (a = + q(a)) { + var d = a.$el.offset()[a.settings.horizontal ? "left" : "top"] - p.offset[a.settings.horizontal ? "left" : "top"], + h = a.$el[a.settings.horizontal ? "outerWidth" : "outerHeight"](); + b.extend(a, { + start: d, + elSize: h, + end: d + h + }) + } + } + + function r(a) { + // console.log("r(a) with a = ", a); + if (a === v) b.each(m, r); + else if (a = q(a)) { + var d = p[a.settings.horizontal ? "width" : "height"], + h = x(a.settings.size, d), + d = p[a.settings.horizontal ? "left" : "top"] + x(a.settings.offset, d, -h), + c = d + h, + h = a.settings.contain ? d <= a.start && c >= a.end ? "inside" : d + h / 2 > a.start + a.elSize / 2 ? a.settings.horizontal ? "left" : + "up" : a.settings.horizontal ? "right" : "down" : d > a.start && d < a.end || c > a.start && c < a.end || d <= a.start && c >= a.start || d <= a.end && c >= a.end ? "inside" : d > a.end ? a.settings.horizontal ? "left" : "up" : a.settings.horizontal ? "right" : "down"; + a.state !== h && (a.state = h, "function" === typeof w && w.call(a.el, "inside" === h, h), "function" === typeof a.callback && a.callback.call(a.el, "inside" === h, h)) + } + } + + function s(a) { + if (m.hasOwnProperty(a)) return a; + if (b.isPlainObject(a) && m.hasOwnProperty(a.id)) return a.id; + a = b(a)[0]; + var d = !1; + b.each(m, function(b, + c) { + c.el === a && (d = b) + }); + return d + } + + // console.log("nothing yet"); + function q(a) { + return (a = s(a)) ? m[a] : !1 + } + "function" !== typeof f && (e = f, f = 0); + // console.log("k was", k); + var t = function(a) { + b.extend(this, a) + }, + u = function(a, d, c, e) { + this.id = a; + this.el = d; + this.$el = b(d); + this.callback = c; + this.settings = new t(e); + this.configure = function(a, d) { + b.isPlainObject(a) && (d = a, a = null); + b.extend(this.settings, d); + null !== a && (this.callback = a) + } + }, + n = this, + l = b(k); + // console.log("l", l, "l==window", l[0]==window); + k = b.fn.espy.defaults; + // console.log("k is", k); + var w, m = {}, + z = 0; + // because window.offset() is not defined in jQuery 3 (why?!?!?!), + // we have to treat that as a special case (DF 1/28/19) + if (l[0]==window) { offSET = { top: 0, left: 0 } } + else { offSET = l.offset() } + var p = { + top: l.scrollTop(), + left: l.scrollLeft(), + width: l.innerWidth(), + height: l.innerHeight(), + offset: offSET +/* + offset: l.offset() || { + top: 0, + left: 0 + } +*/ + }; + // console.log("p", p); + c(f, b.extend({}, k, e)); + n.add = function(a, d, c) { + b.isPlainObject(d) && (c = d, d = 0); + b(a).each(function(a, b) { + var e = s(b) || "s" + z++; + m[e] = new u(e, b, d, c); + g(e); + r(e) + }) + }; + n.configure = function(a, d, e) { + "function" === typeof a ? (d = a, a = null, b.isPlainObject(d) && (e = d, d = null)) : b.isPlainObject(a) ? (e = a, d = a = null) : b.isPlainObject(d) && (e = d, d = null); + null === a ? (c(d, e), b.each(m, function(a, b) { + g(b) + })) : b(a).each(function(a, b) { + var c = q(b); + c && (c.configure(d, e), g(b)) + }) + }; + n.reload = function(a) { + a === v ? b.each(m, function() { + g(this.id) + }) : + b(a).each(function(a, b) { + var c = s(b); + c && (g(c), r(c)) + }) + }; + n.remove = function(a) { + b(a).each(function(a, b) { + var c = s(b); + c && delete m[c] + }) + }; + n.destroy = function() { + l.off(".espy"); + m = {}; + n = v + }; + n.resize = function() { + b.each(m, function() { + this.reloadOnResize && g(this) + }); + p.width = l.innerWidth(); + p.height = l.innerHeight(); + r() + }; + l.on("scroll.espy", y(k.delay, function() { + p.top = l.scrollTop(); + p.left = l.scrollLeft(); + r() + })); + l.on("resize.espy", y(k.delay, function() { + n.resize() + })) + }; + b.fn.espy = function(k, f) { + var e, c; + e = f && f.context || u; + var g = b.data(e, + "espy") || b.data(e, "espy", new b.Espy(e)); + "string" !== typeof k ? g.add(this, k, f) : (e = k, c = Array.prototype.slice.call(arguments), c[0] = this, "function" === typeof g[e] && g[e].apply(g, c)); + return this + }; + b.fn.espy.defaults = { + delay: 100, + context: window, + horizontal: 0, + offset: 0, + size: "100%", + contain: 0, + reloadOnResize: !0 + } +})(jQuery, window); + + diff --git a/_static/pretext/js/lib/jquery.min.js b/_static/pretext/js/lib/jquery.min.js new file mode 100644 index 0000000..4d9b3a2 --- /dev/null +++ b/_static/pretext/js/lib/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w("' + + `` + + '' + + '' + + '' + + '' + + ''; + + // Determine javascript and css dependencies + const extra_css_files = []; + const extra_js_files = []; + //if (data.rh_result.flags.extra_js_files) { + // for (const jsFile of data.rh_result.flags.extra_js_files) { + // if (jsFile.file == "js/apps/GraphTool/graphtool.min.js" || jsFile.file == "js/apps/Scaffold/scaffold.js") { + // extra_css_files.push({ file: 'js/vendor/bootstrap/css/bootstrap.css', external: '0' }); + // extra_css_files.push({ file: 'themes/math4/math4.css', external: '0' }); + // extra_js_files.push({ file: 'js/vendor/bootstrap/js/bootstrap.js', external: '0' }); + // } + // } + //} + + if (data.rh_result.flags.extra_css_files) data.rh_result.flags.extra_css_files.unshift(...extra_css_files); + else data.rh_result.flags.extra_css_files = extra_css_files; + for (const cssFile of data.rh_result.flags.extra_css_files) { + iframeContents += ''; + } + + if (data.rh_result.flags.extra_js_files) data.rh_result.flags.extra_js_files.unshift(...extra_js_files); + else data.rh_result.flags.extra_js_files = extra_js_files; + for (const jsFile of data.rh_result.flags.extra_js_files) { + iframeContents += ''; + } + + iframeContents += + '' + + '' + + '' + + `` + + '
    ' + form.outerHTML + '
    ' + + ''; + + let iframe; + // If there is no action this is the initialization call. + if (!action) { + // Create the iframe. + iframe = document.createElement('iframe'); + iframe.style.width = '1px'; + iframe.style.minWidth = '100%'; + iframe.classList.add('problem-iframe'); + + // Hide the static problem + ww_container.querySelector('.problem-contents').classList.add('hidden-content'); + + if (activate_button != null) { + // Make sure the iframe follows the activate button in the DOM + activate_button.after(iframe); + } else { + ww_container.prepend(iframe); + } + + iFrameResize({ checkOrigin: false, scrolling: 'omit', heightCalculationMethod: 'min' }, iframe); + + iframe.addEventListener('load', () => { + // Set up form submission from inside the iframe. + const iframeForm = iframe.contentDocument.getElementById(ww_id + '-form'); + iframeForm.addEventListener('submit', (e) => { + handleWW(ww_id, "check"); + e.preventDefault(); + }); + + iframe.contentDocument.querySelectorAll('.collapse.in').forEach(collapse => collapse.classList.add('expanded')); + iframe.contentWindow.jQuery('.collapse').on('shown', function(e) { if (e.target != this) return; this.classList.add('expanded'); }); + iframe.contentWindow.jQuery('.collapse').on('hide', function(e) { if (e.target != this) return; this.classList.remove('expanded'); }); + + iframe.contentDocument.querySelectorAll("button.ww-feedback[data-content]").forEach(button => { + iframe.contentWindow.jQuery(button).popover("show"); + const content = iframe.contentDocument.getElementById(button.id.replace("-feedback-button", "-content")); + const popover = content.parentNode.parentNode; + popover.id = button.id.replace("-feedback-button", "-feedback") + button.setAttribute('aria-describedby', popover.id); + if (button.previousElementSibling) + button.previousElementSibling.setAttribute('aria-describedby', popover.id); + popover.querySelector('.arrow').remove(); + const title = popover.querySelector('.popover-title'); + if (button.dataset.emptyContent) { + title.style.borderBottomWidth = 0; + content.parentNode.remove(); + } + if (title.textContent == localize_correct + '!') title.classList.add('correct'); + }); + iframe.contentWindow.MathJax.startup.promise.then(() => iframe.contentWindow.MathJax.typesetPromise(['.popover', '.popover-content'])); + }); + } else { + iframe = ww_container.querySelector('.problem-iframe'); + } + + iframe.srcdoc = iframeContents; + + iframe.addEventListener('load', () => { + // Remove the loader overlay + loader.remove(); + }, { once: true }) + + // Place focus on the problem. + ww_container.focus() + }); +} + +function WWshowCorrect(ww_id, answers) { + const ww_container = document.getElementById(ww_id); + const iframe = ww_container.querySelector('.problem-iframe'); + + const body = iframe.contentDocument.getElementById(ww_id + '-body') + $("body").trigger("runestone_show_correct", { + "ww_id": ww_id, + "answers": answers + }); + + let inputs = body.querySelectorAll("input:not([type=hidden])"); + for (const input of inputs) { + const name = input.name; + const span_id = `${ww_id}-${name}-correct`; + + if (input.type == 'text' && answers[name] && !(iframe.contentDocument.getElementById(span_id))) { + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + feedbackButton.remove(); + iframe.contentWindow.jQuery(feedbackButton).popover("hide"); + } + label = iframe.contentDocument.getElementById(`${span_id}-label`); + if (label) { + label.parentElement.insertBefore(input, label); + label.remove(); + } + input.type = "hidden"; + // we need to convert things like < in answers to < + const correct_ans_text = iframe.contentDocument.createElement('div'); + correct_ans_text.innerHTML = answers[name].correct_ans; + input.value = correct_ans_text.textContent; + const show_span = iframe.contentDocument.createElement('span'); + show_span.id = span_id; + show_span.appendChild(answers[name].correct_ans_latex_string + ? iframe.contentDocument.createTextNode('\\(' + answers[name].correct_ans_latex_string + '\\)') + : iframe.contentDocument.createTextNode(answers[name].correct_ans)); + input.parentElement.insertBefore(show_span, input); + } + + if (input.type == 'radio' && answers[name]) { + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + feedbackButton.remove(); + iframe.contentWindow.jQuery(feedbackButton).popover("hide"); + } + correct_value = answers[name].correct_choice; + if (input.value == correct_value) input.checked = true; + } + } + + const hiddenInputs = body.querySelectorAll("input[type=hidden]"); + for (const input of hiddenInputs) { + const name = input.name; + if (!input.nextElementSibling) continue; + const graphtoolContainer = input.nextElementSibling.nextElementSibling; + if (graphtoolContainer && answers[name] && graphtoolContainer.classList.contains('graphtool-container')) { + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + feedbackButton.remove(); + iframe.contentWindow.jQuery(feedbackButton).popover("hide"); + } + const correct_ans_div = iframe.contentDocument.createElement('div'); + input.parentElement.insertBefore(correct_ans_div, graphtoolContainer); + graphtoolContainer.style.display = 'none'; + input.value = answers[name].correct_ans; + iframe.contentWindow.jQuery(correct_ans_div).html(answers[name].correct_ans_latex_string); + const script = iframe.contentDocument.createElement('script'); + script.textContent = correct_ans_div.querySelector('script').textContent + .replace('\nwindow.addEventListener("DOMContentLoaded",', '(') + .replace(/;\n$/, '();'); + iframe.contentDocument.body.appendChild(script); + } + } + + let selects = body.querySelectorAll("select:not([type=hidden])"); + for (const select of selects) { + const name = select.name; + const span_id = `${ww_id}-${name}-correct`; + if (answers[name] && !iframe.contentDocument.getElementById(span_id)) { + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + feedbackButton.remove(); + iframe.contentWindow.jQuery(feedbackButton).popover("hide"); + } + select.style.display = "none"; + select.value = answers[name].correct_ans; + const show_span = iframe.contentDocument.createElement('span'); + show_span.id = span_id; + show_span.appendChild(answers[name].correct_ans_latex_string + ? iframe.contentDocument.createTextNode('\\(' + answers[name].correct_ans_latex_string + '\\)') + : iframe.contentDocument.createTextNode(answers[name].correct_ans)); + select.parentElement.insertBefore(show_span, select); + } + } + + // run MathJax on our new rendering + // FIXME: We only need to typeset the added elements, not the entire body. + const mathjaxTypesetScript = iframe.contentDocument.createElement('script'); + mathjaxTypesetScript.textContent = 'MathJax.startup.promise.then(() => MathJax.typesetPromise([document.body]));'; + iframe.contentDocument.body.appendChild(mathjaxTypesetScript); +} + +function resetWW(ww_id) { + const ww_container = document.getElementById(ww_id); + const activate_button = document.getElementById(ww_id + '-button'); + + ww_container.dataset.current_seed = ww_container.dataset.seed; + + iframe = ww_container.querySelector('.problem-iframe'); + iframe.remove(); + + ww_container.querySelector('.problem-contents').classList.remove('hidden-content'); + + ww_container.querySelector('.problem-buttons.webwork').remove(); + ww_container.querySelector('.problem-buttons').classList.remove('hidden-content'); + // if the newer activate button is there (but hidden) bring it back too + if (activate_button != null) {activate_button.classList.remove('hidden-content');}; +} + +function adjustSrcHrefs(container,ww_domain) { + container.querySelectorAll('[href]').forEach((node) => { + const href = node.attributes.href.value; + if (href !== '#' && !href.match(/^[a-z]+:\/\//i)) node.href = ww_domain + '/' + href; + }); + container.querySelectorAll('[src]').forEach((node) => { + node.src = ww_domain + '/' + node.attributes.src.value; + }); +} + +function translateHintSol(ww_id, body_div, ww_domain, b_ptx_has_hint, b_ptx_has_solution, hint_label_text, solution_label_text) { + // the problem text may come with "hint"s and "solution"s + // each one is an "a" with content "Hint" or "Solution", and an attribute with base64-encoded HTML content + // the WeBWorK knowl js would normally handle this, but we want PreTeXt knowl js to handle it + // so we replace the "a" with the content that should be there for PTX knowl js + // also if hint/sol were missing from the static version, we want these removed here + + const ww_container = document.getElementById(ww_id); + + const hintsolnodes = document.evaluate("//p[a/b]", body_div, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); + if (hintsolnodes) { + let solutionlikewrapper; + for (let i = 0; i < hintsolnodes.snapshotLength; i++) { + const hintsolp = hintsolnodes.snapshotItem(i); + if (!hintsolp) continue; + const hintSolType = hintsolp.textContent.trim().toLowerCase().replace(':', ''); + + if (hintsolp.previousElementSibling.textContent.trim() != 'Hint:' && hintsolp.previousElementSibling.textContent.trim() != 'Solution:') { + solutionlikewrapper = document.createElement('div'); + solutionlikewrapper.classList.add('webwork', 'solutions'); + hintsolp.parentNode.insertBefore(solutionlikewrapper, hintsolp); + } + + if ((hintSolType == 'solution' && !b_ptx_has_solution) || (hintSolType == 'hint' && !b_ptx_has_hint)) continue; + + const knowlDetails = document.createElement('details'); + knowlDetails.classList.add(hintSolType); + knowlDetails.classList.add('solution-like'); + knowlDetails.classList.add('born-hidden-knowl'); + + const knowlSummary = document.createElement('summary'); + const summaryLabel = document.createElement('span'); + summaryLabel.classList.add('type'); + summaryLabel.innerHTML = hintSolType == 'hint' ? hint_label_text : solution_label_text; + knowlSummary.appendChild(summaryLabel); + knowlDetails.appendChild(knowlSummary); + + const knowlContents = document.createElement('div'); + knowlContents.classList.add(hintSolType); + knowlContents.classList.add('solution-like'); + knowlContents.innerHTML = hintsolp.firstElementChild.dataset.knowlContents; + knowlDetails.appendChild(knowlContents); + + adjustSrcHrefs(knowlContents, ww_domain) + solutionlikewrapper.appendChild(knowlDetails); + } + } + for (let i = 0; i < hintsolnodes.snapshotLength; i++) { + hintsolnodes.snapshotItem(i).remove(); + } +} + +function cloneAttributes(target, source) { + [...source.attributes].forEach( attr => { target.setAttribute(attr.nodeName ,attr.nodeValue) }); +} + +function createFeedbackButton(id, title, content) { + const feedbackButton = document.createElement('button'); + feedbackButton.dataset.title = title; + feedbackButton.dataset.content = `
    ${content || ''}
    `; + if (!content) feedbackButton.dataset.emptyContent = '1'; + const contentSpan = document.createElement('span'); + contentSpan.style.fontWeight = 1000; + contentSpan.textContent = '\uD83D\uDDE9' + feedbackButton.appendChild(contentSpan); + feedbackButton.type = 'button'; + feedbackButton.classList.add('ww-feedback'); + feedbackButton.style.borderRadius = 0; + + feedbackButton.id = `${id}-feedback-button`; + feedbackButton.dataset.html = true; + feedbackButton.dataset.placement = 'bottom'; + feedbackButton.dataset.trigger = 'click'; + + return feedbackButton; +} diff --git a/_static/pretext/js/pretext-webwork/2.17/pretext-webwork.js b/_static/pretext/js/pretext-webwork/2.17/pretext-webwork.js new file mode 100644 index 0000000..d4ff265 --- /dev/null +++ b/_static/pretext/js/pretext-webwork/2.17/pretext-webwork.js @@ -0,0 +1,1057 @@ +//Critical: +// TODO: Think about what should be done for an essay question. + +//Accessibility: + +//Enhancement: +// TODO: In a scaffold problem, adjust the green bar for when one part is correct. +// TODO: Have randomize check that new seed is actually producing new HTML. +// TODO: Don't offer randomize or button unless we know a new version can be produced after trying a few seeds. +// TODO: In a staged problem, Make Interactive button is adjacent to solution knowls; move it. +// TODO: MathQuill +// TODO: Image pop up. +// TODO: Deal with singleResult MultiAnswer problems. + +//Styling: +// TODO: Review all styling in all scenarios (staged/not, correct/partly-correct/incorrect/blank, single/multiple) +// TODO: Sean: I think I'd like to see a slightly larger font size on the buttons + +function handleWW(ww_id, action) { + const ww_container = document.getElementById(ww_id); + const ww_domain = ww_container.dataset.domain; + const ww_problemSource = ww_container.dataset.problemsource; + const ww_sourceFilePath = ww_container.dataset.sourcefilepath; + const ww_course_id = ww_container.dataset.courseid; + const ww_user_id = ww_container.dataset.userid; + const ww_course_password = ww_container.dataset.coursepassword; + const localize_correct = ww_container.dataset.localizeCorrect || "Correct"; + const localize_incorrect = ww_container.dataset.localizeIncorrect || "Incorrect"; + const localize_blank = ww_container.dataset.localizeBlank || "Blank"; + const localize_submit = ww_container.dataset.localizeSubmit || "Submit"; + const localize_check_responses = ww_container.dataset.localizeCheckResponses || "Check Responses"; + const localize_reveal = ww_container.dataset.localizeReveal || "Reveal"; + const localize_randomize = ww_container.dataset.localizeRandomize || "Randomize"; + const localize_reset = ww_container.dataset.localizeReset || "Reset"; + const runestone_logged_in = (typeof eBookConfig !== 'undefined' && eBookConfig.username !== ''); + // will be null on pages generated prior to late December 2022 + const activate_button = document.getElementById(ww_id + '-button') + + // Set the current seed + if (!action) { + ww_container.dataset.current_seed = ww_container.dataset.seed; + if (runestone_logged_in) { + ww_container.dataset.current_seed = webworkSeedHash(eBookConfig.username + ww_container.dataset.current_seed); + } + } + else if (action == 'randomize') ww_container.dataset.current_seed = Number(ww_container.dataset.current_seed) + 100; + + let loader = document.createElement('div'); + loader.style.position = 'absolute'; + loader.style.left = 0; + loader.style.top = 0; + loader.style.backgroundColor = 'rgba(0.2, 0.2, 0.2, 0.4)'; + loader.style.color = 'white'; + loader.style.width = '100%'; + loader.style.height = '100%'; + loader.style.display = 'flex'; + loader.style.alignItems = 'center'; + loader.style.justifyContent = 'center'; + loader.tabIndex = -1; + const loaderText = document.createElement('span'); + loaderText.textContent = 'Loading'; + loaderText.style.fontSize = '2rem'; + loader.appendChild(loaderText); + ww_container.appendChild(loader); + loader.focus(); + + if (!action) { + // Determine if static version shows hints, solutions, or answers and save that information in the container dataset for later runs. + ww_container.dataset.hasHint = ww_container.getElementsByClassName('hint').length > 0; + ww_container.dataset.hasSolution = ww_container.getElementsByClassName('solution').length > 0; + ww_container.dataset.hasAnswer = ww_container.getElementsByClassName('answer').length > 0; + // Get (possibly localized) label text for hints and solutions. + ww_container.dataset.hintLabelText = ww_container.dataset.hasHint == 'true' + ? ww_container.querySelectorAll('.hint-knowl span.type, details.hint span.type')[0].textContent : 'Hint'; + ww_container.dataset.solutionLabelText = ww_container.dataset.hasSolution == 'true' + ? ww_container.querySelectorAll('.solution-knowl span.type, details.solution span.type')[0].textContent : 'Solution'; + + ww_container.tabIndex = -1; + } + + let url; + + if (action == 'check') { + const iframe = ww_container.querySelector('.problem-iframe'); + const formData = new FormData(iframe.contentDocument.getElementById(ww_id + "-form")); + const params = new URLSearchParams(formData); + url = new URL(ww_domain + '/webwork2/html2xml?' + params.toString()) + url.searchParams.append("answersSubmitted", '1'); + url.searchParams.append('WWsubmit', "1"); + } else { + url = new URL(ww_domain + '/webwork2/html2xml'); + url.searchParams.append("problemSeed", ww_container.dataset.current_seed); + if (ww_problemSource) url.searchParams.append("problemSource", ww_problemSource); + else if (ww_sourceFilePath) url.searchParams.append("sourceFilePath", ww_sourceFilePath); + url.searchParams.append("answersSubmitted", '0'); + url.searchParams.append("displayMode", "MathJax"); + url.searchParams.append("courseID", ww_course_id); + url.searchParams.append("userID", ww_user_id); + url.searchParams.append("course_password", ww_course_password); + url.searchParams.append("outputformat", "raw"); + // note ww_container.dataset.hasSolution is a string, possibly 'false' which is true + url.searchParams.append("showSolutions", ww_container.dataset.hasSolution == 'true' ? '1' : '0'); + url.searchParams.append("showHints", ww_container.dataset.hasHint == 'true' ? '1' : '0'); + url.searchParams.append("problemUUID",ww_id); + } + + // get the json and do stuff with what we get + $.getJSON(url.toString(), (data) => { + // Create the form that will contain the text and input fields of the interactive problem. + const form = document.createElement("form"); + form.id = ww_id + "-form"; + + // Create a div for the problem text. + const body_div = document.createElement("div"); + body_div.id = ww_id + "-body"; + body_div.classList.add("exercise", "exercise-like"); + body_div.lang = data.lang; + body_div.dir = data.dir; + + // Dump the problem text, answer blanks, etc. + body_div.innerHTML = data.rh_result.text; + + // Replace all hn headings with h6 headings. + for (const tag_name of ['h6', 'h5', 'h4', 'h3', 'h2', 'h1']) { + const headings = body_div.getElementsByTagName(tag_name); + for (heading of headings) { + const new_heading = document.createElement("h6"); + new_heading.innerHTML = heading.innerHTML; + cloneAttributes(new_heading, heading); + new_heading.classList.add('webwork-part'); + heading.replaceWith(new_heading); + } + } + + adjustSrcHrefs(body_div, ww_domain); + + translateHintSol(ww_id, body_div, ww_domain, + ww_container.dataset.hasHint == 'true', ww_container.dataset.hasSolution == 'true', + ww_container.dataset.hintLabelText, ww_container.dataset.solutionLabelText) + + // insert previous answers + if (runestone_logged_in) { + const answersObject = (wwList[ww_id.replace(/-ww-rs$/,'')].answers ? wwList[ww_id.replace(/-ww-rs$/,'')].answers : {'answers' : [], 'mqAnswers' : []}); + const mqAnswers = answersObject.mqAnswers; + for (const mqAnswer in mqAnswers) { + const mqInput = body_div.querySelector('input[id=' + mqAnswer + ']'); + if (mqInput && mqInput.value == '') { + mqInput.setAttribute('value', mqAnswers[mqAnswer]); + } + } + const answers = answersObject.answers; + for (const answer in answers) { + const input = body_div.querySelector('input[id=' + answer + ']'); + if (input && input.value == '') { + input.setAttribute('value', answers[answer]); + } + if (input && input.type.toUpperCase() == 'RADIO') { + const buttons = body_div.querySelectorAll('input[name=' + answer + ']'); + for (const button of buttons) { + if (button.value == answers[answer]) { + button.setAttribute('checked', 'checked'); + } + } + } + if (input && input.type.toUpperCase() == 'CHECKBOX') { + const checkboxes = body_div.querySelectorAll('input[name=' + answer + ']'); + for (const checkbox of checkboxes) { + // This is not a bulletproof approach if the problem used input values that are weird + // For example, with commas in them + // However, we are stuck with WW providing answers[answer] as a string like `[value0, value1]` + // and note that it is not `["value0", "value1"]`, so we cannot cleanly parse it into an array + let checkbox_regex = new RegExp('(\\[|, )' + checkbox.value + '(, |\\])'); + if (answers[answer].match(checkbox_regex)) { + checkbox.setAttribute('checked', 'checked'); + } + } + } + var select = body_div.querySelector('select[id=' + answer + ']'); + if (select && answers[answer]) { + // answers[answer] may be wrapped in \text{...} that we want to remove, since value does not have this. + let this_answer = answers[answer]; + if (/^\\text\{.*\}$/.test(this_answer)) {this_answer = this_answer.match(/^\\text\{(.*)\}$/)[1]}; + let quote_escaped_answer = this_answer.replace(/"/g, '\\"'); + const option = body_div.querySelector(`select[id="${answer}"] option[value="${quote_escaped_answer}"]`); + if (option) {option.setAttribute('selected', 'selected')}; + } + } + } + + // insert our cleaned up problem text + form.appendChild(body_div); + + // Set up hidden input fields that the form uses + const wwInputs = { + problemSeed: data.inputs_ref.problemSeed, + problemUUID: data.inputs_ref.problemUUID, + psvn: data.inputs_ref.psvn, + courseName: ww_course_id, + courseID: ww_course_id, + userID: ww_user_id, + course_password: ww_course_password, + displayMode: "MathJax", + session_key: data.rh_result.session_key, + outputformat: "raw", + language: data.formLanguage, + showSummary: data.showSummary, + // note ww_container.dataset.hasSolution is a string, possibly 'false' which is true + showSolutions: ww_container.dataset.hasSolution == 'true' ? '1' : '0', + showHints: ww_container.dataset.hasHint == 'true' ? '1' : '0', + forcePortNumber: data.forcePortNumber + }; + + if (ww_sourceFilePath) wwInputs.sourceFilePath = ww_sourceFilePath; + else if (ww_problemSource) wwInputs.problemSource = ww_problemSource; + + for (const wwInputName of Object.keys(wwInputs)) { + const input = document.createElement('input'); + input.type = 'hidden'; + input.name = wwInputName; + input.value = wwInputs[wwInputName]; + form.appendChild(input); + } + + // Prepare answers object + const answers = {}; + // id the answers even if we won't populate them + Object.keys(data.rh_result.answers).forEach(function(id) { + answers[id] = {}; + }, data.rh_result.answers); + if (ww_container.dataset.hasAnswer == 'true') { + // Update answer data + Object.keys(data.rh_result.answers).forEach(function(id) { + answers[id] = { + correct_ans: this[id].correct_ans, + correct_ans_latex_string: this[id].correct_ans_latex_string, + correct_choice: this[id].correct_choice, + correct_choices: this[id].correct_choices, + }; + }, data.rh_result.answers); + } + + let buttonContainer = ww_container.querySelector('.problem-buttons.webwork'); + // Create the submission buttons if they have not yet been created. + if (!buttonContainer) { + // Hide the original div that contains the old make active button. + ww_container.querySelector('.problem-buttons').classList.add('hidden-content'); + // And the newer activate button if it is there + if (activate_button != null) {activate_button.classList.add('hidden-content');}; + + // Create a new div for the webwork buttons. + buttonContainer = document.createElement('div'); + buttonContainer.classList.add('problem-buttons', 'webwork'); + if (activate_button != null) { + // Make sure the button container follows the activate button in the DOM + activate_button.after(buttonContainer); + } else { + ww_container.prepend(buttonContainer); + } + + // Check button + const check = document.createElement("button"); + check.type = "button"; + check.id = ww_id + '-check'; + check.style.marginRight = "0.25rem"; + check.classList.add('webwork-button'); + + // Adjust if more than one answer to check + const answerCount = body_div.querySelectorAll("input:not([type=hidden])").length + + body_div.querySelectorAll("select:not([type=hidden])").length; + + check.textContent = runestone_logged_in ? localize_submit : localize_check_responses; + check.addEventListener('click', () => handleWW(ww_id, "check")); + + buttonContainer.appendChild(check); + + // Show correct answers button if original PTX has answer knowl. + if (ww_container.dataset.hasAnswer == 'true') { + const correct = document.createElement("button"); + correct.classList.add("show-correct", 'webwork-button'); + correct.type = "button"; + correct.style.marginRight = "0.25rem"; + correct.textContent = localize_reveal; + correct.addEventListener('click', () => WWshowCorrect(ww_id, answers)); + buttonContainer.appendChild(correct); + } + + // randomize button + const randomize = document.createElement("button") + randomize.type = "button"; + randomize.classList.add('webwork-button'); + randomize.style.marginRight = "0.25rem"; + randomize.textContent = localize_randomize; + randomize.addEventListener('click', () => handleWW(ww_id, 'randomize')); + buttonContainer.appendChild(randomize) + + // reset button + const reset = document.createElement("button") + reset.type = "button" + reset.classList.add('webwork-button'); + reset.textContent = localize_reset; + reset.addEventListener('click', () => resetWW(ww_id)); + buttonContainer.appendChild(reset) + } else { + // Update the click handler for the show correct button. + if (ww_container.dataset.hasAnswer == 'true') { + const correct = buttonContainer.querySelector('.show-correct'); + const correctNew = correct.cloneNode(true); + correctNew.addEventListener('click', () => WWshowCorrect(ww_id, answers)); + correct.replaceWith(correctNew); + } + } + + if (action == 'check') { + // Runestone trigger + // TODO: condition on platform=Runestone + $("body").trigger('runestone_ww_check', data) + + const inputs = body_div.querySelectorAll("input:not([type=hidden])"); + for (const input of inputs) { + const name = input.name; + if (input.type == 'text' && answers[name]) { + const score = data.rh_result.answers[name].score; + let headline = ''; + let correctClass = ''; + if (score >= 1) { + headline = localize_correct + '!'; + correctClass = 'correct'; + } else if (score > 0 && score < 1) { + headline = `${Math.round(score * 100)}% ${localize_correct}.`; + correctClass = 'partly-correct'; + } else if (data.rh_result.answers[name].student_ans == '') { + headline = localize_blank + '.'; + correctClass = 'blank'; + } else if (score <= 0) { + headline = localize_incorrect + '.'; + correctClass = 'incorrect'; + } + let title = `${headline}`; + let message = (data.rh_result.answers[name].ans_message ? data.rh_result.answers[name].ans_message : ''); + input.classList.add(correctClass); + // make a span that contains feedback + feedbackSpan = document.createElement('span'); + feedbackSpan.id = `${ww_id}-${name}-feedback`; + feedbackHeadline = document.createElement('span'); + feedbackHeadline.id = `${ww_id}-${name}-headline`; + feedbackHeadline.textContent = headline; + feedbackSpan.appendChild(feedbackHeadline); + feedbackMessage = document.createElement('span'); + feedbackMessage.id = `${ww_id}-${name}-message`; + feedbackMessage.textContent = message; + feedbackSpan.appendChild(feedbackMessage); + // make a non breaking span to surround input, sr span, and feedback button + let nbSpan = document.createElement('span'); + nbSpan.classList.add("nobreak"); + input.parentNode.insertBefore(nbSpan, input); + nbSpan.appendChild(input); + // put a visibly hidden (screen-reader only) span with feedback + let srSpan = document.createElement('span'); + srSpan.classList.add("visually-hidden"); + srSpan.appendChild(feedbackSpan); + nbSpan.appendChild(srSpan); + // give the feedback to sr users immediately + input.setAttribute('aria-describedby',`${ww_id}-${name}-feedback`); + // make the feedback button + srSpan.after(createFeedbackButton(`${ww_id}-${name}`, title, message)); + + } + + if (input.type.toUpperCase() == 'RADIO' && answers[name]) { + const score = data.rh_result.answers[name].score; + const student_ans = data.rh_result.answers[name].student_value || data.rh_result.answers[name].student_ans; + const correct_ans = data.rh_result.answers[name].correct_choice || data.rh_result.answers[name].correct_ans; + if (input.value == student_ans) { + if (score == 1) { + input.parentNode.classList.add('correct'); + } else { + input.parentNode.classList.add('incorrect'); + } + const feedbackButton = createFeedbackButton(`${ww_id}-${name}`, + (student_ans == correct_ans) + ? `${localize_correct}` : `${localize_incorrect}.`) + feedbackButton.style.marginRight = '0.25rem'; + input.after(feedbackButton); + } + } + + if (input.type.toUpperCase() == 'CHECKBOX' && answers[name]) { + const score = data.rh_result.answers[name].score; + const student_ans = data.rh_result.answers[name].student_ans; + const correct_ans = data.rh_result.answers[name].correct_ans; + if (input.value == data.rh_result.answers[name].firstElement) { + const checkbox_div = input.parentNode.parentNode; + if (score == 1) { + checkbox_div.classList.add('correct'); + } else { + checkbox_div.classList.add('incorrect'); + } + const feedbackButton = createFeedbackButton(`${ww_id}-${name}`, + (student_ans == correct_ans) + ? `${localize_correct}` : `${localize_incorrect}.`) + checkbox_div.insertBefore(feedbackButton, checkbox_div.firstChild); + } + } + } + + const hiddenInputs = body_div.querySelectorAll("input[type=hidden]"); + for (const input of hiddenInputs) { + const name = input.name; + if (!input.nextElementSibling) continue; + const graphtoolContainer = input.nextElementSibling.nextElementSibling; + if (graphtoolContainer && answers[name] && graphtoolContainer.classList.contains('graphtool-container')) { + graphtoolContainer.style.position = 'relative'; + const score = data.rh_result.answers[name].score; + let title = ''; + if (score == 1) { + title = `${localize_correct}`; + } else if (score > 0 && score < 1) { + title = `${Math.round(score * 100)}% ${localize_correct}.`; + } else if (data.rh_result.answers[name].student_ans == '') { + // do nothing if the submitted answer is blank and the problem has not already been scored as correct + continue; + } else if (score == 0) { + title = `${localize_incorrect}.`; + } + + const feedbackButton = createFeedbackButton(`${ww_id}-${name}`, title, data.rh_result.answers[name].ans_message); + feedbackButton.style.position = 'absolute'; + feedbackButton.style.left = '100%'; + feedbackButton.style.top = 0; + feedbackButton.style.marginLeft = '0.5rem'; + feedbackButton.dataset.bsContainer = 'body'; + graphtoolContainer.appendChild(feedbackButton); + if (score == 1) { + graphtoolContainer.classList.add('correct'); + } else { + graphtoolContainer.classList.add('incorrect'); + } + + } + } + + const selects = body_div.querySelectorAll("select:not([type=hidden])"); + for (const select of selects) { + const name = select.name; + const score = data.rh_result.answers[name].score; + let title = ''; + if (score == 1) { + headline = localize_correct + '!'; + correctClass = 'correct'; + } else { + headline = localize_incorrect + '.'; + correctClass = 'incorrect'; + } + select.classList.add(correctClass); + title = `${headline}`; + // make a span that contains feedback + feedbackSpan = document.createElement('span'); + feedbackSpan.id = `${ww_id}-${name}-feedback`; + feedbackHeadline = document.createElement('span'); + feedbackHeadline.id = `${ww_id}-${name}-headline`; + feedbackHeadline.textContent = headline; + feedbackSpan.appendChild(feedbackHeadline); + // make a non breaking span to surround select, sr span, and feedback button + let nbSpan = document.createElement('span'); + nbSpan.classList.add("nobreak"); + select.parentNode.insertBefore(nbSpan, select); + nbSpan.appendChild(select); + // put a span around select since select does not support ::after pseudo elements + let psSpan = document.createElement('span'); + psSpan.classList.add("select-wrapper", correctClass); + select.parentNode.insertBefore(psSpan, select); + psSpan.appendChild(select); + // put a visibly hidden (screen-reader only) span with feedback + let srSpan = document.createElement('span'); + srSpan.classList.add("visually-hidden"); + srSpan.appendChild(feedbackSpan); + nbSpan.appendChild(srSpan); + // give the feedback to sr users immediately + select.setAttribute('aria-describedby',`${ww_id}-${name}-feedback`); + // make the feedback button + srSpan.after(createFeedbackButton(`${ww_id}-${name}`, title)); + } + } + + let iframeContents = '' + + '' + + `` + + '' + + '' + + '' + + ''; + + // Determine javascript and css dependencies + const extra_css_files = []; + const extra_js_files = []; + //if (data.rh_result.flags.extra_js_files) { + // for (const jsFile of data.rh_result.flags.extra_js_files) { + // if (jsFile.file == "js/apps/GraphTool/graphtool.min.js" || jsFile.file == "js/apps/Scaffold/scaffold.js") { + // extra_css_files.push({ file: 'js/vendor/bootstrap/css/bootstrap.css', external: '0' }); + // extra_css_files.push({ file: 'themes/math4/math4.css', external: '0' }); + // extra_js_files.push({ file: 'js/vendor/bootstrap/js/bootstrap.js', external: '0' }); + // } + // } + //} + + if (data.extra_css_files) data.extra_css_files.unshift(...extra_css_files); + else data.extra_css_files = extra_css_files; + for (const cssFile of data.extra_css_files) { + if (/knowl/.test(cssFile.file)) continue; + iframeContents += ''; + } + + if (data.extra_js_files) data.extra_js_files.unshift(...extra_js_files); + else data.extra_js_files = extra_js_files; + for (const jsFile of data.extra_js_files) { + if (/knowl/.test(jsFile.file)) continue; + iframeContents += ''; + } + + iframeContents += + '' + + '' + + '' + + `` + + '
    ' + form.outerHTML + '
    ' + + ''; + + let iframe; + // If there is no action this is the initialization call. + if (!action) { + // Create the iframe. + iframe = document.createElement('iframe'); + iframe.style.width = '1px'; + iframe.style.minWidth = '100%'; + iframe.classList.add('problem-iframe'); + + // Hide the static problem + ww_container.querySelector('.problem-contents').classList.add('hidden-content'); + + if (activate_button != null) { + // Make sure the iframe follows the activate button in the DOM + activate_button.after(iframe); + } else { + ww_container.prepend(iframe); + } + + iFrameResize({ checkOrigin: false, scrolling: 'omit', heightCalculationMethod: 'min' }, iframe); + + iframe.addEventListener('load', () => { + // Set up form submission from inside the iframe. + const iframeForm = iframe.contentDocument.getElementById(ww_id + '-form'); + iframeForm.addEventListener('submit', (e) => { + handleWW(ww_id, "check"); + e.preventDefault(); + }); + + iframe.contentDocument.querySelectorAll('.collapse.in').forEach(collapse => collapse.classList.add('expanded')); + iframe.contentWindow.jQuery('.collapse').on('shown', function(e) { if (e.target != this) return; this.classList.add('expanded'); }); + iframe.contentWindow.jQuery('.collapse').on('hide', function(e) { if (e.target != this) return; this.classList.remove('expanded'); }); + + iframe.contentDocument.querySelectorAll("button.ww-feedback[data-bs-content]").forEach(button => { + const bsPopover = new iframe.contentWindow.bootstrap.Popover(button, { + html: true, + placement: 'bottom', + fallbackPlacements: [], + trigger: 'click', + customClass: 'result-popover' + (button.dataset.emptyContent ? ' nocontent' : '') + }); + bsPopover.show(); + const content = iframe.contentDocument.getElementById(button.id.replace("-feedback-button", "-content")); + const popover = content.parentNode.parentNode; + bsPopover.hide(); + + /*button.addEventListener('shown.bs.popover', () => { + // Note that the button itself has the aria-describedby attribute set by bootstrap automatically. + button.previousElementSibling?.setAttribute('aria-describedby', popover.id); + });*/ + + button.addEventListener('click', () => bsPopover.show(), { once: true }); + + popover.querySelector('.popover-arrow').remove(); + const title = popover.querySelector('.popover-header'); + if (button.dataset.emptyContent) content.parentNode.remove(); + if (title.textContent == localize_correct + '!') title.classList.add('correct'); + }); + iframe.contentWindow.MathJax.startup.promise.then(() => iframe.contentWindow.MathJax.typesetPromise(['.popover', '.popover-content'])); + }); + } else { + iframe = ww_container.querySelector('.problem-iframe'); + } + + iframe.srcdoc = iframeContents; + + iframe.addEventListener('load', () => { + // Remove the loader overlay + loader.remove(); + }, { once: true }) + + // Place focus on the problem. + ww_container.focus() + }); +} + +function WWshowCorrect(ww_id, answers) { + const ww_container = document.getElementById(ww_id); + const iframe = ww_container.querySelector('.problem-iframe'); + + const body = iframe.contentDocument.getElementById(ww_id + '-body') + $("body").trigger("runestone_show_correct", { + "ww_id": ww_id, + "answers": answers + }); + + let inputs = body.querySelectorAll("input:not([type=hidden])"); + for (const input of inputs) { + const name = input.name; + const span_id = `${ww_id}-${name}-correct`; + + if (input.type == 'text' && answers[name] && !(iframe.contentDocument.getElementById(span_id))) { + const input_id = input.id; + const mq_span = iframe.contentDocument.getElementById(`mq-answer-${input_id}`); + if (mq_span) { + mq_span.style.display = 'none'; + } + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + iframe.contentWindow.bootstrap.Popover.getInstance(feedbackButton)?.hide(); + feedbackButton.remove(); + } + label = iframe.contentDocument.getElementById(`${span_id}-label`); + if (label) { + label.parentElement.insertBefore(input, label); + label.remove(); + } + input.type = "hidden"; + // we need to convert things like < in answers to < + const correct_ans_text = iframe.contentDocument.createElement('div'); + correct_ans_text.innerHTML = answers[name].correct_ans; + input.value = correct_ans_text.textContent; + const show_span = iframe.contentDocument.createElement('span'); + show_span.id = span_id; + show_span.appendChild(answers[name].correct_ans_latex_string + ? iframe.contentDocument.createTextNode('\\(' + answers[name].correct_ans_latex_string + '\\)') + : iframe.contentDocument.createTextNode(answers[name].correct_ans)); + input.parentElement.insertBefore(show_span, input); + } + + if (input.type.toUpperCase() == 'RADIO' && answers[name]) { + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + iframe.contentWindow.bootstrap.Popover.getInstance(feedbackButton)?.hide(); + feedbackButton.remove(); + } + const correct_ans = answers[name].correct_choice || answers[name].correct_ans; + if (input.value == correct_ans) { + input.checked = true; + //input.setAttribute('checked', 'checked'); + } else { + input.checked = false; + } + } + + if (input.type.toUpperCase() == 'CHECKBOX' && answers[name]) { + const correct_choices = answers[name].correct_choices; + if (correct_choices.includes(input.value)) { + input.checked = true; + // input.setAttribute('checked', 'checked'); + } else { + input.checked = false; + // input.setAttribute('checked', false); + } + } + } + + const hiddenInputs = body.querySelectorAll("input[type=hidden]"); + for (const input of hiddenInputs) { + const name = input.name; + if (!input.nextElementSibling) continue; + const graphtoolContainer = input.nextElementSibling.nextElementSibling; + if (graphtoolContainer && answers[name] && graphtoolContainer.classList.contains('graphtool-container')) { + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + iframe.contentWindow.bootstrap.Popover.getInstance(feedbackButton)?.hide(); + feedbackButton.remove(); + } + const correct_ans_div = iframe.contentDocument.createElement('div'); + input.parentElement.insertBefore(correct_ans_div, graphtoolContainer); + graphtoolContainer.style.display = 'none'; + input.value = answers[name].correct_ans; + iframe.contentWindow.jQuery(correct_ans_div).html(answers[name].correct_ans_latex_string); + const script = iframe.contentDocument.createElement('script'); + script.textContent = correct_ans_div.querySelector('script').textContent + .replace('\nwindow.addEventListener("DOMContentLoaded",', '(') + .replace(/;\n$/, '();'); + iframe.contentDocument.body.appendChild(script); + } + } + + let selects = body.querySelectorAll("select:not([type=hidden])"); + for (const select of selects) { + const name = select.name; + const span_id = `${ww_id}-${name}-correct`; + if (answers[name] && !iframe.contentDocument.getElementById(span_id)) { + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + iframe.contentWindow.bootstrap.Popover.getInstance(feedbackButton)?.hide(); + feedbackButton.remove(); + } + select.style.display = "none"; + select.value = answers[name].correct_ans; + const show_span = iframe.contentDocument.createElement('span'); + show_span.id = span_id; + show_span.appendChild(answers[name].correct_ans_latex_string + ? iframe.contentDocument.createTextNode('\\(' + answers[name].correct_ans_latex_string + '\\)') + : iframe.contentDocument.createTextNode(answers[name].correct_ans)); + select.parentElement.insertBefore(show_span, select); + } + } + + // run MathJax on our new rendering + // FIXME: We only need to typeset the added elements, not the entire body. + const mathjaxTypesetScript = iframe.contentDocument.createElement('script'); + mathjaxTypesetScript.textContent = 'MathJax.startup.promise.then(() => MathJax.typesetPromise([document.body]));'; + iframe.contentDocument.body.appendChild(mathjaxTypesetScript); +} + +function resetWW(ww_id) { + const ww_container = document.getElementById(ww_id); + const activate_button = document.getElementById(ww_id + '-button'); + + ww_container.dataset.current_seed = ww_container.dataset.seed; + + iframe = ww_container.querySelector('.problem-iframe'); + iframe.remove(); + + ww_container.querySelector('.problem-contents').classList.remove('hidden-content'); + + ww_container.querySelector('.problem-buttons.webwork').remove(); + ww_container.querySelector('.problem-buttons').classList.remove('hidden-content'); + // if the newer activate button is there (but hidden) bring it back too + if (activate_button != null) {activate_button.classList.remove('hidden-content');}; +} + +function adjustSrcHrefs(container,ww_domain) { + container.querySelectorAll('[href]').forEach((node) => { + const href = node.attributes.href.value; + if (href !== '#' && !href.match(/^[a-z]+:\/\//i)) node.href = ww_domain + '/' + href; + }); + container.querySelectorAll('[src]').forEach((node) => { + node.src = new URL(node.attributes.src.value, ww_domain).href; + }); +} + +function translateHintSol(ww_id, body_div, ww_domain, b_ptx_has_hint, b_ptx_has_solution, hint_label_text, solution_label_text) { + // the problem text may come with "hint"s and "solution"s + // Each one is an "a" with the class ".knowl" and the data-type attribute of either "hint" or "solution". + // the WeBWorK knowl js would normally handle this, but we want PreTeXt knowl js to handle it + // so we replace the "a" with the content that should be there for PTX knowl js + // also if hint/sol were missing from the static version, we want these removed here + + const hintSols = body_div.querySelectorAll('.knowl[data-type="hint"],.knowl[data-type="solution"]'); + let solutionlikewrapper; + for (const hintSol of hintSols) { + const hintsolp = hintSol.parentNode; + if (!hintsolp) continue; + const hintsolpp = hintsolp.parentNode; //the div that contains each p with a knowl anchor + const hintSolType = hintSol.dataset.type; + + if (hintsolpp.querySelectorAll(".webwork.solutions").length == 0) + { + solutionlikewrapper = document.createElement('div'); + solutionlikewrapper.classList.add('webwork', 'solutions'); + hintsolpp.insertBefore(solutionlikewrapper, hintsolp); + } + + if ((hintSolType == 'solution' && !b_ptx_has_solution) || + (hintSolType == 'hint' && !b_ptx_has_hint)) + continue; + + const knowlDetails = document.createElement('details'); + knowlDetails.classList.add(hintSolType); + knowlDetails.classList.add('solution-like'); + knowlDetails.classList.add('born-hidden-knowl'); + + const knowlSummary = document.createElement('summary'); + const summaryLabel = document.createElement('span'); + summaryLabel.classList.add('type'); + summaryLabel.innerHTML = hintSolType == 'hint' ? hint_label_text : solution_label_text; + knowlSummary.appendChild(summaryLabel); + knowlDetails.appendChild(knowlSummary); + + const knowlContents = document.createElement('div'); + knowlContents.classList.add(hintSolType); + knowlContents.classList.add('solution-like'); + knowlContents.innerHTML = hintsolp.firstElementChild.dataset.knowlContents; + knowlDetails.appendChild(knowlContents); + + adjustSrcHrefs(knowlContents, ww_domain) + solutionlikewrapper.appendChild(knowlDetails); + } + for (const hintSol of hintSols) { + hintSol.parentNode?.remove(); + } +} + +function cloneAttributes(target, source) { + [...source.attributes].forEach( attr => { target.setAttribute(attr.nodeName ,attr.nodeValue) }); +} + +function createFeedbackButton(id, title, content) { + const feedbackButton = document.createElement('button'); + feedbackButton.dataset.bsTitle = title; + feedbackButton.dataset.bsContent = `
    ${content || ''}
    `; + if (!content) feedbackButton.dataset.emptyContent = '1'; + const contentSpan = document.createElement('span'); + contentSpan.innerHTML = ``; + feedbackButton.appendChild(contentSpan); + feedbackButton.type = 'button'; + feedbackButton.classList.add('ww-feedback'); + + feedbackButton.id = `${id}-feedback-button`; + feedbackButton.dataset.bsToggle = 'popover'; + + return feedbackButton; +} + +function webworkSeedHash(string) { + var hash = 0, i, chr; + if (string.length === 0) return hash; + for (i = 0; i < string.length; i++) { + chr = string.charCodeAt(i); + hash = ((hash << 5) - hash) + chr; + hash |= 0; //Convert to 32bit integer + } + return Math.abs(hash); +}; diff --git a/_static/pretext/js/pretext-webwork/2.18/pretext-webwork.js b/_static/pretext/js/pretext-webwork/2.18/pretext-webwork.js new file mode 100644 index 0000000..d4ff265 --- /dev/null +++ b/_static/pretext/js/pretext-webwork/2.18/pretext-webwork.js @@ -0,0 +1,1057 @@ +//Critical: +// TODO: Think about what should be done for an essay question. + +//Accessibility: + +//Enhancement: +// TODO: In a scaffold problem, adjust the green bar for when one part is correct. +// TODO: Have randomize check that new seed is actually producing new HTML. +// TODO: Don't offer randomize or button unless we know a new version can be produced after trying a few seeds. +// TODO: In a staged problem, Make Interactive button is adjacent to solution knowls; move it. +// TODO: MathQuill +// TODO: Image pop up. +// TODO: Deal with singleResult MultiAnswer problems. + +//Styling: +// TODO: Review all styling in all scenarios (staged/not, correct/partly-correct/incorrect/blank, single/multiple) +// TODO: Sean: I think I'd like to see a slightly larger font size on the buttons + +function handleWW(ww_id, action) { + const ww_container = document.getElementById(ww_id); + const ww_domain = ww_container.dataset.domain; + const ww_problemSource = ww_container.dataset.problemsource; + const ww_sourceFilePath = ww_container.dataset.sourcefilepath; + const ww_course_id = ww_container.dataset.courseid; + const ww_user_id = ww_container.dataset.userid; + const ww_course_password = ww_container.dataset.coursepassword; + const localize_correct = ww_container.dataset.localizeCorrect || "Correct"; + const localize_incorrect = ww_container.dataset.localizeIncorrect || "Incorrect"; + const localize_blank = ww_container.dataset.localizeBlank || "Blank"; + const localize_submit = ww_container.dataset.localizeSubmit || "Submit"; + const localize_check_responses = ww_container.dataset.localizeCheckResponses || "Check Responses"; + const localize_reveal = ww_container.dataset.localizeReveal || "Reveal"; + const localize_randomize = ww_container.dataset.localizeRandomize || "Randomize"; + const localize_reset = ww_container.dataset.localizeReset || "Reset"; + const runestone_logged_in = (typeof eBookConfig !== 'undefined' && eBookConfig.username !== ''); + // will be null on pages generated prior to late December 2022 + const activate_button = document.getElementById(ww_id + '-button') + + // Set the current seed + if (!action) { + ww_container.dataset.current_seed = ww_container.dataset.seed; + if (runestone_logged_in) { + ww_container.dataset.current_seed = webworkSeedHash(eBookConfig.username + ww_container.dataset.current_seed); + } + } + else if (action == 'randomize') ww_container.dataset.current_seed = Number(ww_container.dataset.current_seed) + 100; + + let loader = document.createElement('div'); + loader.style.position = 'absolute'; + loader.style.left = 0; + loader.style.top = 0; + loader.style.backgroundColor = 'rgba(0.2, 0.2, 0.2, 0.4)'; + loader.style.color = 'white'; + loader.style.width = '100%'; + loader.style.height = '100%'; + loader.style.display = 'flex'; + loader.style.alignItems = 'center'; + loader.style.justifyContent = 'center'; + loader.tabIndex = -1; + const loaderText = document.createElement('span'); + loaderText.textContent = 'Loading'; + loaderText.style.fontSize = '2rem'; + loader.appendChild(loaderText); + ww_container.appendChild(loader); + loader.focus(); + + if (!action) { + // Determine if static version shows hints, solutions, or answers and save that information in the container dataset for later runs. + ww_container.dataset.hasHint = ww_container.getElementsByClassName('hint').length > 0; + ww_container.dataset.hasSolution = ww_container.getElementsByClassName('solution').length > 0; + ww_container.dataset.hasAnswer = ww_container.getElementsByClassName('answer').length > 0; + // Get (possibly localized) label text for hints and solutions. + ww_container.dataset.hintLabelText = ww_container.dataset.hasHint == 'true' + ? ww_container.querySelectorAll('.hint-knowl span.type, details.hint span.type')[0].textContent : 'Hint'; + ww_container.dataset.solutionLabelText = ww_container.dataset.hasSolution == 'true' + ? ww_container.querySelectorAll('.solution-knowl span.type, details.solution span.type')[0].textContent : 'Solution'; + + ww_container.tabIndex = -1; + } + + let url; + + if (action == 'check') { + const iframe = ww_container.querySelector('.problem-iframe'); + const formData = new FormData(iframe.contentDocument.getElementById(ww_id + "-form")); + const params = new URLSearchParams(formData); + url = new URL(ww_domain + '/webwork2/html2xml?' + params.toString()) + url.searchParams.append("answersSubmitted", '1'); + url.searchParams.append('WWsubmit', "1"); + } else { + url = new URL(ww_domain + '/webwork2/html2xml'); + url.searchParams.append("problemSeed", ww_container.dataset.current_seed); + if (ww_problemSource) url.searchParams.append("problemSource", ww_problemSource); + else if (ww_sourceFilePath) url.searchParams.append("sourceFilePath", ww_sourceFilePath); + url.searchParams.append("answersSubmitted", '0'); + url.searchParams.append("displayMode", "MathJax"); + url.searchParams.append("courseID", ww_course_id); + url.searchParams.append("userID", ww_user_id); + url.searchParams.append("course_password", ww_course_password); + url.searchParams.append("outputformat", "raw"); + // note ww_container.dataset.hasSolution is a string, possibly 'false' which is true + url.searchParams.append("showSolutions", ww_container.dataset.hasSolution == 'true' ? '1' : '0'); + url.searchParams.append("showHints", ww_container.dataset.hasHint == 'true' ? '1' : '0'); + url.searchParams.append("problemUUID",ww_id); + } + + // get the json and do stuff with what we get + $.getJSON(url.toString(), (data) => { + // Create the form that will contain the text and input fields of the interactive problem. + const form = document.createElement("form"); + form.id = ww_id + "-form"; + + // Create a div for the problem text. + const body_div = document.createElement("div"); + body_div.id = ww_id + "-body"; + body_div.classList.add("exercise", "exercise-like"); + body_div.lang = data.lang; + body_div.dir = data.dir; + + // Dump the problem text, answer blanks, etc. + body_div.innerHTML = data.rh_result.text; + + // Replace all hn headings with h6 headings. + for (const tag_name of ['h6', 'h5', 'h4', 'h3', 'h2', 'h1']) { + const headings = body_div.getElementsByTagName(tag_name); + for (heading of headings) { + const new_heading = document.createElement("h6"); + new_heading.innerHTML = heading.innerHTML; + cloneAttributes(new_heading, heading); + new_heading.classList.add('webwork-part'); + heading.replaceWith(new_heading); + } + } + + adjustSrcHrefs(body_div, ww_domain); + + translateHintSol(ww_id, body_div, ww_domain, + ww_container.dataset.hasHint == 'true', ww_container.dataset.hasSolution == 'true', + ww_container.dataset.hintLabelText, ww_container.dataset.solutionLabelText) + + // insert previous answers + if (runestone_logged_in) { + const answersObject = (wwList[ww_id.replace(/-ww-rs$/,'')].answers ? wwList[ww_id.replace(/-ww-rs$/,'')].answers : {'answers' : [], 'mqAnswers' : []}); + const mqAnswers = answersObject.mqAnswers; + for (const mqAnswer in mqAnswers) { + const mqInput = body_div.querySelector('input[id=' + mqAnswer + ']'); + if (mqInput && mqInput.value == '') { + mqInput.setAttribute('value', mqAnswers[mqAnswer]); + } + } + const answers = answersObject.answers; + for (const answer in answers) { + const input = body_div.querySelector('input[id=' + answer + ']'); + if (input && input.value == '') { + input.setAttribute('value', answers[answer]); + } + if (input && input.type.toUpperCase() == 'RADIO') { + const buttons = body_div.querySelectorAll('input[name=' + answer + ']'); + for (const button of buttons) { + if (button.value == answers[answer]) { + button.setAttribute('checked', 'checked'); + } + } + } + if (input && input.type.toUpperCase() == 'CHECKBOX') { + const checkboxes = body_div.querySelectorAll('input[name=' + answer + ']'); + for (const checkbox of checkboxes) { + // This is not a bulletproof approach if the problem used input values that are weird + // For example, with commas in them + // However, we are stuck with WW providing answers[answer] as a string like `[value0, value1]` + // and note that it is not `["value0", "value1"]`, so we cannot cleanly parse it into an array + let checkbox_regex = new RegExp('(\\[|, )' + checkbox.value + '(, |\\])'); + if (answers[answer].match(checkbox_regex)) { + checkbox.setAttribute('checked', 'checked'); + } + } + } + var select = body_div.querySelector('select[id=' + answer + ']'); + if (select && answers[answer]) { + // answers[answer] may be wrapped in \text{...} that we want to remove, since value does not have this. + let this_answer = answers[answer]; + if (/^\\text\{.*\}$/.test(this_answer)) {this_answer = this_answer.match(/^\\text\{(.*)\}$/)[1]}; + let quote_escaped_answer = this_answer.replace(/"/g, '\\"'); + const option = body_div.querySelector(`select[id="${answer}"] option[value="${quote_escaped_answer}"]`); + if (option) {option.setAttribute('selected', 'selected')}; + } + } + } + + // insert our cleaned up problem text + form.appendChild(body_div); + + // Set up hidden input fields that the form uses + const wwInputs = { + problemSeed: data.inputs_ref.problemSeed, + problemUUID: data.inputs_ref.problemUUID, + psvn: data.inputs_ref.psvn, + courseName: ww_course_id, + courseID: ww_course_id, + userID: ww_user_id, + course_password: ww_course_password, + displayMode: "MathJax", + session_key: data.rh_result.session_key, + outputformat: "raw", + language: data.formLanguage, + showSummary: data.showSummary, + // note ww_container.dataset.hasSolution is a string, possibly 'false' which is true + showSolutions: ww_container.dataset.hasSolution == 'true' ? '1' : '0', + showHints: ww_container.dataset.hasHint == 'true' ? '1' : '0', + forcePortNumber: data.forcePortNumber + }; + + if (ww_sourceFilePath) wwInputs.sourceFilePath = ww_sourceFilePath; + else if (ww_problemSource) wwInputs.problemSource = ww_problemSource; + + for (const wwInputName of Object.keys(wwInputs)) { + const input = document.createElement('input'); + input.type = 'hidden'; + input.name = wwInputName; + input.value = wwInputs[wwInputName]; + form.appendChild(input); + } + + // Prepare answers object + const answers = {}; + // id the answers even if we won't populate them + Object.keys(data.rh_result.answers).forEach(function(id) { + answers[id] = {}; + }, data.rh_result.answers); + if (ww_container.dataset.hasAnswer == 'true') { + // Update answer data + Object.keys(data.rh_result.answers).forEach(function(id) { + answers[id] = { + correct_ans: this[id].correct_ans, + correct_ans_latex_string: this[id].correct_ans_latex_string, + correct_choice: this[id].correct_choice, + correct_choices: this[id].correct_choices, + }; + }, data.rh_result.answers); + } + + let buttonContainer = ww_container.querySelector('.problem-buttons.webwork'); + // Create the submission buttons if they have not yet been created. + if (!buttonContainer) { + // Hide the original div that contains the old make active button. + ww_container.querySelector('.problem-buttons').classList.add('hidden-content'); + // And the newer activate button if it is there + if (activate_button != null) {activate_button.classList.add('hidden-content');}; + + // Create a new div for the webwork buttons. + buttonContainer = document.createElement('div'); + buttonContainer.classList.add('problem-buttons', 'webwork'); + if (activate_button != null) { + // Make sure the button container follows the activate button in the DOM + activate_button.after(buttonContainer); + } else { + ww_container.prepend(buttonContainer); + } + + // Check button + const check = document.createElement("button"); + check.type = "button"; + check.id = ww_id + '-check'; + check.style.marginRight = "0.25rem"; + check.classList.add('webwork-button'); + + // Adjust if more than one answer to check + const answerCount = body_div.querySelectorAll("input:not([type=hidden])").length + + body_div.querySelectorAll("select:not([type=hidden])").length; + + check.textContent = runestone_logged_in ? localize_submit : localize_check_responses; + check.addEventListener('click', () => handleWW(ww_id, "check")); + + buttonContainer.appendChild(check); + + // Show correct answers button if original PTX has answer knowl. + if (ww_container.dataset.hasAnswer == 'true') { + const correct = document.createElement("button"); + correct.classList.add("show-correct", 'webwork-button'); + correct.type = "button"; + correct.style.marginRight = "0.25rem"; + correct.textContent = localize_reveal; + correct.addEventListener('click', () => WWshowCorrect(ww_id, answers)); + buttonContainer.appendChild(correct); + } + + // randomize button + const randomize = document.createElement("button") + randomize.type = "button"; + randomize.classList.add('webwork-button'); + randomize.style.marginRight = "0.25rem"; + randomize.textContent = localize_randomize; + randomize.addEventListener('click', () => handleWW(ww_id, 'randomize')); + buttonContainer.appendChild(randomize) + + // reset button + const reset = document.createElement("button") + reset.type = "button" + reset.classList.add('webwork-button'); + reset.textContent = localize_reset; + reset.addEventListener('click', () => resetWW(ww_id)); + buttonContainer.appendChild(reset) + } else { + // Update the click handler for the show correct button. + if (ww_container.dataset.hasAnswer == 'true') { + const correct = buttonContainer.querySelector('.show-correct'); + const correctNew = correct.cloneNode(true); + correctNew.addEventListener('click', () => WWshowCorrect(ww_id, answers)); + correct.replaceWith(correctNew); + } + } + + if (action == 'check') { + // Runestone trigger + // TODO: condition on platform=Runestone + $("body").trigger('runestone_ww_check', data) + + const inputs = body_div.querySelectorAll("input:not([type=hidden])"); + for (const input of inputs) { + const name = input.name; + if (input.type == 'text' && answers[name]) { + const score = data.rh_result.answers[name].score; + let headline = ''; + let correctClass = ''; + if (score >= 1) { + headline = localize_correct + '!'; + correctClass = 'correct'; + } else if (score > 0 && score < 1) { + headline = `${Math.round(score * 100)}% ${localize_correct}.`; + correctClass = 'partly-correct'; + } else if (data.rh_result.answers[name].student_ans == '') { + headline = localize_blank + '.'; + correctClass = 'blank'; + } else if (score <= 0) { + headline = localize_incorrect + '.'; + correctClass = 'incorrect'; + } + let title = `${headline}`; + let message = (data.rh_result.answers[name].ans_message ? data.rh_result.answers[name].ans_message : ''); + input.classList.add(correctClass); + // make a span that contains feedback + feedbackSpan = document.createElement('span'); + feedbackSpan.id = `${ww_id}-${name}-feedback`; + feedbackHeadline = document.createElement('span'); + feedbackHeadline.id = `${ww_id}-${name}-headline`; + feedbackHeadline.textContent = headline; + feedbackSpan.appendChild(feedbackHeadline); + feedbackMessage = document.createElement('span'); + feedbackMessage.id = `${ww_id}-${name}-message`; + feedbackMessage.textContent = message; + feedbackSpan.appendChild(feedbackMessage); + // make a non breaking span to surround input, sr span, and feedback button + let nbSpan = document.createElement('span'); + nbSpan.classList.add("nobreak"); + input.parentNode.insertBefore(nbSpan, input); + nbSpan.appendChild(input); + // put a visibly hidden (screen-reader only) span with feedback + let srSpan = document.createElement('span'); + srSpan.classList.add("visually-hidden"); + srSpan.appendChild(feedbackSpan); + nbSpan.appendChild(srSpan); + // give the feedback to sr users immediately + input.setAttribute('aria-describedby',`${ww_id}-${name}-feedback`); + // make the feedback button + srSpan.after(createFeedbackButton(`${ww_id}-${name}`, title, message)); + + } + + if (input.type.toUpperCase() == 'RADIO' && answers[name]) { + const score = data.rh_result.answers[name].score; + const student_ans = data.rh_result.answers[name].student_value || data.rh_result.answers[name].student_ans; + const correct_ans = data.rh_result.answers[name].correct_choice || data.rh_result.answers[name].correct_ans; + if (input.value == student_ans) { + if (score == 1) { + input.parentNode.classList.add('correct'); + } else { + input.parentNode.classList.add('incorrect'); + } + const feedbackButton = createFeedbackButton(`${ww_id}-${name}`, + (student_ans == correct_ans) + ? `${localize_correct}` : `${localize_incorrect}.`) + feedbackButton.style.marginRight = '0.25rem'; + input.after(feedbackButton); + } + } + + if (input.type.toUpperCase() == 'CHECKBOX' && answers[name]) { + const score = data.rh_result.answers[name].score; + const student_ans = data.rh_result.answers[name].student_ans; + const correct_ans = data.rh_result.answers[name].correct_ans; + if (input.value == data.rh_result.answers[name].firstElement) { + const checkbox_div = input.parentNode.parentNode; + if (score == 1) { + checkbox_div.classList.add('correct'); + } else { + checkbox_div.classList.add('incorrect'); + } + const feedbackButton = createFeedbackButton(`${ww_id}-${name}`, + (student_ans == correct_ans) + ? `${localize_correct}` : `${localize_incorrect}.`) + checkbox_div.insertBefore(feedbackButton, checkbox_div.firstChild); + } + } + } + + const hiddenInputs = body_div.querySelectorAll("input[type=hidden]"); + for (const input of hiddenInputs) { + const name = input.name; + if (!input.nextElementSibling) continue; + const graphtoolContainer = input.nextElementSibling.nextElementSibling; + if (graphtoolContainer && answers[name] && graphtoolContainer.classList.contains('graphtool-container')) { + graphtoolContainer.style.position = 'relative'; + const score = data.rh_result.answers[name].score; + let title = ''; + if (score == 1) { + title = `${localize_correct}`; + } else if (score > 0 && score < 1) { + title = `${Math.round(score * 100)}% ${localize_correct}.`; + } else if (data.rh_result.answers[name].student_ans == '') { + // do nothing if the submitted answer is blank and the problem has not already been scored as correct + continue; + } else if (score == 0) { + title = `${localize_incorrect}.`; + } + + const feedbackButton = createFeedbackButton(`${ww_id}-${name}`, title, data.rh_result.answers[name].ans_message); + feedbackButton.style.position = 'absolute'; + feedbackButton.style.left = '100%'; + feedbackButton.style.top = 0; + feedbackButton.style.marginLeft = '0.5rem'; + feedbackButton.dataset.bsContainer = 'body'; + graphtoolContainer.appendChild(feedbackButton); + if (score == 1) { + graphtoolContainer.classList.add('correct'); + } else { + graphtoolContainer.classList.add('incorrect'); + } + + } + } + + const selects = body_div.querySelectorAll("select:not([type=hidden])"); + for (const select of selects) { + const name = select.name; + const score = data.rh_result.answers[name].score; + let title = ''; + if (score == 1) { + headline = localize_correct + '!'; + correctClass = 'correct'; + } else { + headline = localize_incorrect + '.'; + correctClass = 'incorrect'; + } + select.classList.add(correctClass); + title = `${headline}`; + // make a span that contains feedback + feedbackSpan = document.createElement('span'); + feedbackSpan.id = `${ww_id}-${name}-feedback`; + feedbackHeadline = document.createElement('span'); + feedbackHeadline.id = `${ww_id}-${name}-headline`; + feedbackHeadline.textContent = headline; + feedbackSpan.appendChild(feedbackHeadline); + // make a non breaking span to surround select, sr span, and feedback button + let nbSpan = document.createElement('span'); + nbSpan.classList.add("nobreak"); + select.parentNode.insertBefore(nbSpan, select); + nbSpan.appendChild(select); + // put a span around select since select does not support ::after pseudo elements + let psSpan = document.createElement('span'); + psSpan.classList.add("select-wrapper", correctClass); + select.parentNode.insertBefore(psSpan, select); + psSpan.appendChild(select); + // put a visibly hidden (screen-reader only) span with feedback + let srSpan = document.createElement('span'); + srSpan.classList.add("visually-hidden"); + srSpan.appendChild(feedbackSpan); + nbSpan.appendChild(srSpan); + // give the feedback to sr users immediately + select.setAttribute('aria-describedby',`${ww_id}-${name}-feedback`); + // make the feedback button + srSpan.after(createFeedbackButton(`${ww_id}-${name}`, title)); + } + } + + let iframeContents = '' + + '' + + `` + + '' + + '' + + '' + + ''; + + // Determine javascript and css dependencies + const extra_css_files = []; + const extra_js_files = []; + //if (data.rh_result.flags.extra_js_files) { + // for (const jsFile of data.rh_result.flags.extra_js_files) { + // if (jsFile.file == "js/apps/GraphTool/graphtool.min.js" || jsFile.file == "js/apps/Scaffold/scaffold.js") { + // extra_css_files.push({ file: 'js/vendor/bootstrap/css/bootstrap.css', external: '0' }); + // extra_css_files.push({ file: 'themes/math4/math4.css', external: '0' }); + // extra_js_files.push({ file: 'js/vendor/bootstrap/js/bootstrap.js', external: '0' }); + // } + // } + //} + + if (data.extra_css_files) data.extra_css_files.unshift(...extra_css_files); + else data.extra_css_files = extra_css_files; + for (const cssFile of data.extra_css_files) { + if (/knowl/.test(cssFile.file)) continue; + iframeContents += ''; + } + + if (data.extra_js_files) data.extra_js_files.unshift(...extra_js_files); + else data.extra_js_files = extra_js_files; + for (const jsFile of data.extra_js_files) { + if (/knowl/.test(jsFile.file)) continue; + iframeContents += ''; + } + + iframeContents += + '' + + '' + + '' + + `` + + '
    ' + form.outerHTML + '
    ' + + ''; + + let iframe; + // If there is no action this is the initialization call. + if (!action) { + // Create the iframe. + iframe = document.createElement('iframe'); + iframe.style.width = '1px'; + iframe.style.minWidth = '100%'; + iframe.classList.add('problem-iframe'); + + // Hide the static problem + ww_container.querySelector('.problem-contents').classList.add('hidden-content'); + + if (activate_button != null) { + // Make sure the iframe follows the activate button in the DOM + activate_button.after(iframe); + } else { + ww_container.prepend(iframe); + } + + iFrameResize({ checkOrigin: false, scrolling: 'omit', heightCalculationMethod: 'min' }, iframe); + + iframe.addEventListener('load', () => { + // Set up form submission from inside the iframe. + const iframeForm = iframe.contentDocument.getElementById(ww_id + '-form'); + iframeForm.addEventListener('submit', (e) => { + handleWW(ww_id, "check"); + e.preventDefault(); + }); + + iframe.contentDocument.querySelectorAll('.collapse.in').forEach(collapse => collapse.classList.add('expanded')); + iframe.contentWindow.jQuery('.collapse').on('shown', function(e) { if (e.target != this) return; this.classList.add('expanded'); }); + iframe.contentWindow.jQuery('.collapse').on('hide', function(e) { if (e.target != this) return; this.classList.remove('expanded'); }); + + iframe.contentDocument.querySelectorAll("button.ww-feedback[data-bs-content]").forEach(button => { + const bsPopover = new iframe.contentWindow.bootstrap.Popover(button, { + html: true, + placement: 'bottom', + fallbackPlacements: [], + trigger: 'click', + customClass: 'result-popover' + (button.dataset.emptyContent ? ' nocontent' : '') + }); + bsPopover.show(); + const content = iframe.contentDocument.getElementById(button.id.replace("-feedback-button", "-content")); + const popover = content.parentNode.parentNode; + bsPopover.hide(); + + /*button.addEventListener('shown.bs.popover', () => { + // Note that the button itself has the aria-describedby attribute set by bootstrap automatically. + button.previousElementSibling?.setAttribute('aria-describedby', popover.id); + });*/ + + button.addEventListener('click', () => bsPopover.show(), { once: true }); + + popover.querySelector('.popover-arrow').remove(); + const title = popover.querySelector('.popover-header'); + if (button.dataset.emptyContent) content.parentNode.remove(); + if (title.textContent == localize_correct + '!') title.classList.add('correct'); + }); + iframe.contentWindow.MathJax.startup.promise.then(() => iframe.contentWindow.MathJax.typesetPromise(['.popover', '.popover-content'])); + }); + } else { + iframe = ww_container.querySelector('.problem-iframe'); + } + + iframe.srcdoc = iframeContents; + + iframe.addEventListener('load', () => { + // Remove the loader overlay + loader.remove(); + }, { once: true }) + + // Place focus on the problem. + ww_container.focus() + }); +} + +function WWshowCorrect(ww_id, answers) { + const ww_container = document.getElementById(ww_id); + const iframe = ww_container.querySelector('.problem-iframe'); + + const body = iframe.contentDocument.getElementById(ww_id + '-body') + $("body").trigger("runestone_show_correct", { + "ww_id": ww_id, + "answers": answers + }); + + let inputs = body.querySelectorAll("input:not([type=hidden])"); + for (const input of inputs) { + const name = input.name; + const span_id = `${ww_id}-${name}-correct`; + + if (input.type == 'text' && answers[name] && !(iframe.contentDocument.getElementById(span_id))) { + const input_id = input.id; + const mq_span = iframe.contentDocument.getElementById(`mq-answer-${input_id}`); + if (mq_span) { + mq_span.style.display = 'none'; + } + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + iframe.contentWindow.bootstrap.Popover.getInstance(feedbackButton)?.hide(); + feedbackButton.remove(); + } + label = iframe.contentDocument.getElementById(`${span_id}-label`); + if (label) { + label.parentElement.insertBefore(input, label); + label.remove(); + } + input.type = "hidden"; + // we need to convert things like < in answers to < + const correct_ans_text = iframe.contentDocument.createElement('div'); + correct_ans_text.innerHTML = answers[name].correct_ans; + input.value = correct_ans_text.textContent; + const show_span = iframe.contentDocument.createElement('span'); + show_span.id = span_id; + show_span.appendChild(answers[name].correct_ans_latex_string + ? iframe.contentDocument.createTextNode('\\(' + answers[name].correct_ans_latex_string + '\\)') + : iframe.contentDocument.createTextNode(answers[name].correct_ans)); + input.parentElement.insertBefore(show_span, input); + } + + if (input.type.toUpperCase() == 'RADIO' && answers[name]) { + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + iframe.contentWindow.bootstrap.Popover.getInstance(feedbackButton)?.hide(); + feedbackButton.remove(); + } + const correct_ans = answers[name].correct_choice || answers[name].correct_ans; + if (input.value == correct_ans) { + input.checked = true; + //input.setAttribute('checked', 'checked'); + } else { + input.checked = false; + } + } + + if (input.type.toUpperCase() == 'CHECKBOX' && answers[name]) { + const correct_choices = answers[name].correct_choices; + if (correct_choices.includes(input.value)) { + input.checked = true; + // input.setAttribute('checked', 'checked'); + } else { + input.checked = false; + // input.setAttribute('checked', false); + } + } + } + + const hiddenInputs = body.querySelectorAll("input[type=hidden]"); + for (const input of hiddenInputs) { + const name = input.name; + if (!input.nextElementSibling) continue; + const graphtoolContainer = input.nextElementSibling.nextElementSibling; + if (graphtoolContainer && answers[name] && graphtoolContainer.classList.contains('graphtool-container')) { + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + iframe.contentWindow.bootstrap.Popover.getInstance(feedbackButton)?.hide(); + feedbackButton.remove(); + } + const correct_ans_div = iframe.contentDocument.createElement('div'); + input.parentElement.insertBefore(correct_ans_div, graphtoolContainer); + graphtoolContainer.style.display = 'none'; + input.value = answers[name].correct_ans; + iframe.contentWindow.jQuery(correct_ans_div).html(answers[name].correct_ans_latex_string); + const script = iframe.contentDocument.createElement('script'); + script.textContent = correct_ans_div.querySelector('script').textContent + .replace('\nwindow.addEventListener("DOMContentLoaded",', '(') + .replace(/;\n$/, '();'); + iframe.contentDocument.body.appendChild(script); + } + } + + let selects = body.querySelectorAll("select:not([type=hidden])"); + for (const select of selects) { + const name = select.name; + const span_id = `${ww_id}-${name}-correct`; + if (answers[name] && !iframe.contentDocument.getElementById(span_id)) { + const feedbackButton = iframe.contentDocument.getElementById(`${ww_id}-${name}-feedback-button`); + if (feedbackButton) { + iframe.contentWindow.bootstrap.Popover.getInstance(feedbackButton)?.hide(); + feedbackButton.remove(); + } + select.style.display = "none"; + select.value = answers[name].correct_ans; + const show_span = iframe.contentDocument.createElement('span'); + show_span.id = span_id; + show_span.appendChild(answers[name].correct_ans_latex_string + ? iframe.contentDocument.createTextNode('\\(' + answers[name].correct_ans_latex_string + '\\)') + : iframe.contentDocument.createTextNode(answers[name].correct_ans)); + select.parentElement.insertBefore(show_span, select); + } + } + + // run MathJax on our new rendering + // FIXME: We only need to typeset the added elements, not the entire body. + const mathjaxTypesetScript = iframe.contentDocument.createElement('script'); + mathjaxTypesetScript.textContent = 'MathJax.startup.promise.then(() => MathJax.typesetPromise([document.body]));'; + iframe.contentDocument.body.appendChild(mathjaxTypesetScript); +} + +function resetWW(ww_id) { + const ww_container = document.getElementById(ww_id); + const activate_button = document.getElementById(ww_id + '-button'); + + ww_container.dataset.current_seed = ww_container.dataset.seed; + + iframe = ww_container.querySelector('.problem-iframe'); + iframe.remove(); + + ww_container.querySelector('.problem-contents').classList.remove('hidden-content'); + + ww_container.querySelector('.problem-buttons.webwork').remove(); + ww_container.querySelector('.problem-buttons').classList.remove('hidden-content'); + // if the newer activate button is there (but hidden) bring it back too + if (activate_button != null) {activate_button.classList.remove('hidden-content');}; +} + +function adjustSrcHrefs(container,ww_domain) { + container.querySelectorAll('[href]').forEach((node) => { + const href = node.attributes.href.value; + if (href !== '#' && !href.match(/^[a-z]+:\/\//i)) node.href = ww_domain + '/' + href; + }); + container.querySelectorAll('[src]').forEach((node) => { + node.src = new URL(node.attributes.src.value, ww_domain).href; + }); +} + +function translateHintSol(ww_id, body_div, ww_domain, b_ptx_has_hint, b_ptx_has_solution, hint_label_text, solution_label_text) { + // the problem text may come with "hint"s and "solution"s + // Each one is an "a" with the class ".knowl" and the data-type attribute of either "hint" or "solution". + // the WeBWorK knowl js would normally handle this, but we want PreTeXt knowl js to handle it + // so we replace the "a" with the content that should be there for PTX knowl js + // also if hint/sol were missing from the static version, we want these removed here + + const hintSols = body_div.querySelectorAll('.knowl[data-type="hint"],.knowl[data-type="solution"]'); + let solutionlikewrapper; + for (const hintSol of hintSols) { + const hintsolp = hintSol.parentNode; + if (!hintsolp) continue; + const hintsolpp = hintsolp.parentNode; //the div that contains each p with a knowl anchor + const hintSolType = hintSol.dataset.type; + + if (hintsolpp.querySelectorAll(".webwork.solutions").length == 0) + { + solutionlikewrapper = document.createElement('div'); + solutionlikewrapper.classList.add('webwork', 'solutions'); + hintsolpp.insertBefore(solutionlikewrapper, hintsolp); + } + + if ((hintSolType == 'solution' && !b_ptx_has_solution) || + (hintSolType == 'hint' && !b_ptx_has_hint)) + continue; + + const knowlDetails = document.createElement('details'); + knowlDetails.classList.add(hintSolType); + knowlDetails.classList.add('solution-like'); + knowlDetails.classList.add('born-hidden-knowl'); + + const knowlSummary = document.createElement('summary'); + const summaryLabel = document.createElement('span'); + summaryLabel.classList.add('type'); + summaryLabel.innerHTML = hintSolType == 'hint' ? hint_label_text : solution_label_text; + knowlSummary.appendChild(summaryLabel); + knowlDetails.appendChild(knowlSummary); + + const knowlContents = document.createElement('div'); + knowlContents.classList.add(hintSolType); + knowlContents.classList.add('solution-like'); + knowlContents.innerHTML = hintsolp.firstElementChild.dataset.knowlContents; + knowlDetails.appendChild(knowlContents); + + adjustSrcHrefs(knowlContents, ww_domain) + solutionlikewrapper.appendChild(knowlDetails); + } + for (const hintSol of hintSols) { + hintSol.parentNode?.remove(); + } +} + +function cloneAttributes(target, source) { + [...source.attributes].forEach( attr => { target.setAttribute(attr.nodeName ,attr.nodeValue) }); +} + +function createFeedbackButton(id, title, content) { + const feedbackButton = document.createElement('button'); + feedbackButton.dataset.bsTitle = title; + feedbackButton.dataset.bsContent = `
    ${content || ''}
    `; + if (!content) feedbackButton.dataset.emptyContent = '1'; + const contentSpan = document.createElement('span'); + contentSpan.innerHTML = ``; + feedbackButton.appendChild(contentSpan); + feedbackButton.type = 'button'; + feedbackButton.classList.add('ww-feedback'); + + feedbackButton.id = `${id}-feedback-button`; + feedbackButton.dataset.bsToggle = 'popover'; + + return feedbackButton; +} + +function webworkSeedHash(string) { + var hash = 0, i, chr; + if (string.length === 0) return hash; + for (i = 0; i < string.length; i++) { + chr = string.charCodeAt(i); + hash = ((hash << 5) - hash) + chr; + hash |= 0; //Convert to 32bit integer + } + return Math.abs(hash); +}; diff --git a/_static/pretext/js/pretext.js b/_static/pretext/js/pretext.js new file mode 100644 index 0000000..ba58683 --- /dev/null +++ b/_static/pretext/js/pretext.js @@ -0,0 +1,165 @@ +/******************************************************************************* + * pretext.js + ******************************************************************************* + * The main front-end controller for PreTeXt documents. + * + * Homepage: pretextbook.org + * Repository: https://github.com/PreTeXtBook/JS_core + * + * Authors: David Farmer, Rob Beezer + * + ******************************************************************************* + */ + +function scrollTocToActive() { + pagefilename = window.location.href; + pagefilename = pagefilename.match(/[^\/]*$/)[0]; + possibletocentries = document.querySelectorAll('#ptx-toc a[href="' + pagefilename + '"]'); + if (possibletocentries.length == 0) { + console.log("linked below a subsection"); + pagefilename = pagefilename.match(/^[^\#]*/)[0]; + possibletocentries = document.querySelectorAll('#ptx-toc a[href="' + pagefilename + '"]'); + } + if (possibletocentries.length == 0) { + console.log("error, cannot find", pagefilename, "in TOC"); + return + } + possibletocentries[0].scrollIntoView({block: "center"}); + possibletocentries[0].classList.add("active");} + +function toggletoc() { + thesidebar = document.getElementById("ptx-sidebar"); + if (thesidebar.classList.contains("hidden") || thesidebar.classList.contains("visible")) { + thesidebar.classList.toggle("hidden"); + thesidebar.classList.toggle("visible"); + } else if (thesidebar.offsetParent === null) { /* not currently visible */ + thesidebar.classList.toggle("visible"); + } else { + thesidebar.classList.toggle("hidden"); + } + scrollTocToActive(); +} + +window.addEventListener("load",function(event) { + thetocbutton = document.getElementsByClassName("toc-toggle")[0]; + thetocbutton.addEventListener('click', () => toggletoc() ); +}); + +window.addEventListener("load",function(event) { + scrollTocToActive(); +}); + +/* jump to next page if reader tries to scroll past the bottom */ +// var hitbottom = false; +// window.onscroll = function(ev) { +// if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) { +// // you're at the bottom of the page +// console.log("Bottom of page"); +// if (hitbottom) { +// console.log("hit bottom again"); +// thenextbutton = document.getElementsByClassName("next-button")[0]; +// thenextbutton.click(); +// } else { +// hitbottom = true; +// /* only jump to next page if hard scroll in quick succession */ +// window.scrollBy(0, -20); +// setTimeout(function (){ hitbottom = false }, 1000); +// } +// } +// }; + + +//----------------------------------------------------------------------------- +// Dynamic TOC logic +//----------------------------------------------------------------------------- + +//item is assumed to be expander in toc-item +function toggleTOCItem(expander) { + let listItem = expander.closest(".toc-item"); + listItem.classList.toggle("expanded"); + let expanded = listItem.classList.contains("expanded"); + + let itemType = getTOCItemType(listItem); + if(expanded) { + expander.title = "Close" + (itemType !== "" ? " " + itemType : ""); + } else { + expander.title = "Expand" + (itemType !== "" ? " " + itemType : ""); + } + + //should be one of each... for/of for safety and built in null avoidance + for (const childUL of listItem.querySelectorAll(":scope > ul.toc-item-list")) { + for (const childItem of childUL.querySelectorAll(":scope > li.toc-item")) { + if(expanded) { + childItem.classList.add("visible"); + childItem.classList.remove("hidden"); + } else { + childItem.classList.remove("visible"); + childItem.classList.add("hidden"); + } + } + } +} + +//finds item type from classes or empty string on failure +function getTOCItemType(item) { + //Type should be class that looks like toc-X where X is not item. Find it and return X + for(let className of item.classList) { + if(className !== "toc-item" && className.length > 3 && className.slice(0,4) === "toc-") + return className.slice(4); + } + return ""; +} + +//finds depth of toc-item as defined by number .toc-item-lists it is in +function getTOCItemDepth(item) { + let depth = 0; + let curParent = item.closest(".toc-item-list"); + while(curParent !== null) { + depth++; + curParent = curParent.parentElement.closest(".toc-item-list"); + } + return depth; +} + +window.addEventListener("DOMContentLoaded", function(event) { + if(document.querySelector(".ptx-toc.focused") === null) + return; //only in focused mode + + let maxDepth = 1000; //how deep TOC goes + //check toc for depth class and get value from there + for(let className of document.querySelector(".ptx-toc").classList) + if(className.length > 5 && className.slice(0,5) === "depth") + maxDepth = Number(className.slice(5)); + + let preexpandedLevels = 1; //how many levels to preexpand + let tocDataSet = document.querySelector(".ptx-toc").dataset; + if(typeof tocDataSet.preexpandedLevels !== 'undefined') + preexpandedLevels = Number(tocDataSet.preexpandedLevels); + + let tocItems = document.querySelectorAll(".ptx-toc ul.structural > .toc-item"); + for (const tocItem of tocItems) { + let hasChildren = tocItem.querySelector('ul.structural') !== null; + let depth = getTOCItemDepth(tocItem); + + if(hasChildren && depth < maxDepth) { + let expander = document.createElement("button"); + expander.classList.add('toc-expander'); + expander.classList.add('toc-chevron-surround'); + expander.title = 'toc-expander'; + expander.innerHTML = ''; + tocItem.querySelector(".toc-title-box").append(expander); + expander.addEventListener('click', () => { + toggleTOCItem(expander); + }); + + let isActive = tocItem.classList.contains("contains-active") || tocItem.classList.contains("active"); + let preExpanded = isActive || depth < preexpandedLevels; + let itemType = getTOCItemType(tocItem); + if(preExpanded) { + toggleTOCItem(expander); + } else { + expander.title = "Expand" + (itemType !== "" ? " " + itemType : ""); + } + } + } +}); \ No newline at end of file diff --git a/_static/pretext/js/pretext_add_on.js b/_static/pretext/js/pretext_add_on.js new file mode 100644 index 0000000..85a100f --- /dev/null +++ b/_static/pretext/js/pretext_add_on.js @@ -0,0 +1,984 @@ +/******************************************************************************* + * pretext_add_on.js + ******************************************************************************* + * Javascript for supplementary material in PreTeXt documents. + * + * Homepage: pretextbook.org + * Repository: https://github.com/PreTeXtBook/JS_core + * + * Authors: David Farmer, Rob Beezer, Alex Jordan + * + ******************************************************************************* + */ + +/* +console.log("thisbrowser.userAgent", window.navigator.userAgent); +*/ + +var minivers = "0"; +if (typeof miniversion !== 'undefined') { + console.log("typeof miniversion", typeof miniversion, "dddd", typeof miniversion == 'undefined'); + minivers = miniversion.toString(); +} +console.log(" minivers", minivers); + +/* scrollbar width from https://stackoverflow.com/questions/13382516/getting-scroll-bar-width-using-javascript */ +function getScrollbarWidth() { + var outer = document.createElement("div"); + outer.style.visibility = "hidden"; + outer.style.width = "100px"; + outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps + + document.body.appendChild(outer); + + var widthNoScroll = outer.offsetWidth; + // force scrollbars + outer.style.overflow = "scroll"; + + // add innerdiv + var inner = document.createElement("div"); + inner.style.width = "100%"; + outer.appendChild(inner); + + var widthWithScroll = inner.offsetWidth; + + // remove divs + outer.parentNode.removeChild(outer); + + return widthNoScroll - widthWithScroll; +} + +/* + generate permalink description +*/ +function permalinkDescription(elem) { + var retStr; + var typeStr = ""; + var nodeName = elem.nodeName; + if (elem.classList.contains("para")) { + if (elem.parentElement.nodeName == "LI") { nodeName = 'LI' } + else { nodeName = 'P' } + } + var isExerciseGroup = false; + if ((nodeName == 'P') && (elem.parentElement.parentElement.classList.contains("exercisegroup"))) { + isExerciseGroup = true; + } + // the data we need will be either in an element with class .heading or in a figcaption element + // but for: + // exercisegroup -- the heading element will be further up the tree + // hidden knowl -- the heading element will be further down the tree (this is the 'a > .heading' selector) + // figcaption (figure-like) -- we are already in the figcaption node + var headerNode; + if (isExerciseGroup) { + headerNode = elem.parentElement.parentElement.querySelector(':scope > .heading'); + } else if (nodeName == 'FIGCAPTION') { + headerNode = elem; + } else { + headerNode = elem.querySelector(':scope > .heading, :scope > figcaption, :scope > a > .heading'); + } + var numberStr = ""; + var numberSep = " "; + var titleStr = ""; + var typeStr = ""; + var resultNodes; + if (nodeName == 'P') { + if (isExerciseGroup) { + typeStr = "Exercise Group"; + } else { + typeStr = "Paragraph"; + } + } else if (nodeName == 'LI') { + typeStr = "List item"; + + } else if (!headerNode) { + // handles assemblages with no title + var className = elem.className.split(' ')[0] + typeStr = className.charAt(0).toUpperCase() + className.slice(1); + } else { + if ((nodeName == 'ARTICLE') && (elem.classList.contains('exercise')) ) { + typeStr = "Exercise"; + } else if ((nodeName == 'ARTICLE') && (elem.classList.contains('task')) ) { + typeStr = elem.parentElement.firstElementChild.getAttribute('data-description'); + numberSep = ""; + } else { + resultNodes = headerNode.getElementsByClassName("type"); + if (resultNodes.length > 0) { + typeStr = resultNodes[0].innerText; + } + } + } + typeStr = typeStr || ""; // hack because of error from https://pretextbook.org/examples/sample-article/html/interesting-corollary.html#p-206 + if (headerNode) { + if (typeStr.length > 0) { + resultNodes = headerNode.getElementsByClassName("codenumber"); + if (resultNodes.length > 0) { + numberStr = resultNodes[0].innerText; + } + } + resultNodes = headerNode.getElementsByClassName("title"); + if (resultNodes.length > 0) { + titleStr = resultNodes[0].innerText; + } + } + retStr = typeStr; + if ((typeStr.length > 0) && (numberStr.length > 0)) { + retStr += numberSep + numberStr; + } + if (titleStr.length > 0) { + if (retStr.length > 0) { + if (typeStr != titleStr) { + retStr += ": " + titleStr; + } + } else { + retStr = titleStr; + } + } + var lastChr = retStr.charAt(retStr.length - 1); + if ((lastChr == '.') || (lastChr == ':')) { + retStr = retStr.slice(0,retStr.length - 1); + } + return retStr; +} + +/* + copy permalink address to clipboard + requires browser support, otherwise does nothing +*/ +async function copyPermalink(elem) { + // structure borrowed from https://flaviocopes.com/clipboard-api/ +// elem.preventDefault(); + if (!navigator.clipboard) { + // Clipboard API not available + console.log("Error: Clipboard API not available"); + return + } + console.log("copying permalink for", elem); + var linkNode = elem.querySelector(':scope > a'); + if (!linkNode) { + console.log("Error: Something went wrong finding permalink URL") + return + } + const this_permalink_url = linkNode.getAttribute('href'); + const this_permalink_description = elem.getAttribute('data-description'); + var link = "" + this_permalink_description + ""; + var msg_link = "" + this_permalink_description + ""; + var text_fallback = this_permalink_description + " \r\n" + this_permalink_url; + var copy_success = true; + try { + // NOTE: this method will only work in Firefox if the user has + // dom.events.asyncClipboard.clipboardItem + // set to true in their about:config. + // Annoyingly, this setting is turned off by default. + // If that setting is off, this try block will fail and we'll use the + // fallback method lower down instead. + await navigator.clipboard.write([ + new ClipboardItem({ + 'text/html': new Blob([link], { type: 'text/html' }), + 'text/plain': new Blob([text_fallback], { type: 'text/plain' }), + }) + ]); + } catch (err) { + console.log('Permalink-to-clipboard using ClipboardItem failed, falling back to clipboard.writeText', err); + copy_success = false; + } + if (! copy_success) { + try { + await navigator.clipboard.writeText(text_fallback); + } catch (err) { + console.log('Permalink-to-clipboard using clipboard.writeText failed', err); + console.error('Failed to copy link to clipboard!'); + return + } + } + + console.log(`copied '${this_permalink_url}' to clipboard`); + // temporary element to alert user that link was copied + let copied_msg = document.createElement('p'); + copied_msg.setAttribute('role', 'alert'); + copied_msg.className = "permalink-alert"; + copied_msg.innerHTML = "Link to " + msg_link + " copied to clipboard"; + elem.parentElement.insertBefore(copied_msg, elem); + // show confirmation for a couple seconds + await new Promise((resolve, reject) => setTimeout(resolve, 1500)); + copied_msg.remove(); + +} + +window.addEventListener("load",function(event) { + $(".aside-like").click(function(){ + $(this).toggleClass("front"); + }); +/* if you click a knowl in an aside, the 'front' stays the + same because it toggles twice. A more elegant solution is welcome */ + $(".aside-like a").click(function(){ + $(this).closest(".aside-like").toggleClass("front"); + }); + +/* temporary, so that aside-like knowls open in the body of the document */ +/* later the addafter will be inserted by PTX? */ + $("a").each(function() { + if($(this).parents('.aside-like').length) { + $(this).attr("addafter", "#" + $(this).closest('.aside-like').attr('id') ); + $(this).closest('.aside-like').attr("tabindex", "0"); + } + }); + + /* click an image to magnify */ + $('body').on('click','.image-box > img:not(.draw_on_me):not(.mag_popup), .sbspanel > img:not(.draw_on_me):not(.mag_popup), figure > img:not(.draw_on_me):not(.mag_popup), figure > div > img:not(.draw_on_me):not(.mag_popup)', function(){ + var img_big = document.createElement('div'); + img_big.setAttribute('style', 'background:#fff;'); + img_big.setAttribute('class', 'mag_popup_container'); + img_big.innerHTML = ''; + // place_to_put_big_img = $(this).parents(".sbsrow, figure, li").last(); + place_to_put_big_img = $(this).parents(".image-box, .sbsrow, figure, li, .cols2 article:nth-of-type(2n)").last(); + // for .cols2, the even ones have to go inside the previous odd one + if (place_to_put_big_img.prop("tagName") == "ARTICLE") { + place_to_put_big_img = place_to_put_big_img.prev().children().first(); + } + $(img_big).insertBefore(place_to_put_big_img); + }); + + /* click the big image to make it go away */ + $('body').on('click','img.mag_popup', function(){ + this.parentNode.remove(); + }); + + /* add ids to p that have none */ + p_no_id = document.querySelectorAll('.main p:not([id])'); + for (var n=p_no_id.length - 1; n >= 0; --n) { + e = p_no_id[n]; + if (e.hasAttribute('id')) { +/* + console.log(e, "was id'd in a previous round"); +*/ + continue + } +/* +console.log("this is e", e); +*/ + if (e.classList.contains('watermark')) { + console.log(e, "skipping the watermark"); + continue + } +/* + console.log("\n XXXXXXXXX p with no id", e); +*/ + prev_p = $(e).prevAll("p"); + console.log("prev_p", prev_p, "xx"); + if(prev_p.length == 0) { + console.log(" PPP problem: prev_p has no length:", prev_p); + continue + } + console.log("which has id", prev_p[0].id); + var parts_found = 1; + var parts_to_id = [e]; + for (var i=0; i < prev_p.length; ++i) { + this_previous = prev_p[i]; + console.log("i", i, "this_previous", this_previous, "id", this_previous.id, "???", this_previous.hasAttribute('id')) + if (!this_previous.hasAttribute('id')) { + parts_to_id.unshift(this_previous) + } + else { + base_id = this_previous.id; + console.log("base_id", base_id); + console.log("ready to add id to", parts_to_id); + for (var j=0; j < parts_to_id.length; ++j) { + ++parts_found; + var next_id = base_id + "-part" + parts_found.toString(); + console.log("parts_found", parts_found, "next_id", next_id); + parts_to_id[j].setAttribute("id", next_id); + } + break // because we found the id that is the base for the missing ids + } + } + } + + if (document.querySelector('body.standalone')) { + console.log("no permalinks on standalone pages") + } else { + console.log(" adding permalinks"); + /* add permalinks to all sections and articles */ + /* the main section p is just for legacy pre div.para html */ + items_needing_permalinks = document.querySelectorAll('main section:not(.introduction), main section .para, main section p, main section article, main section > figure.table-like, main section > figure.figure-like > figcaption, main section .exercisegroup article, main section .exercisegroup, main section article.exercise, main section .discussion-like, main section article.paragraphs > figure.table-like, main section article.paragraphs > figure.figure-like, section > details'); + // items_needing_permalinks = document.querySelectorAll('body section article'); + this_url = window.location.href.split('#')[0]; + permalink_word = "🔗"; + for (var i = 0; i < items_needing_permalinks.length; i++) { + this_item = items_needing_permalinks[i]; + var this_anchor = this_item.id; + if (Boolean(this_item.closest(".parsons"))) { continue } /* parsons block */ + if (Boolean(this_item.closest("details"))) { continue } /* hidden in details */ + if (this_item.parentElement.classList.contains("lines")) { continue } /* parsons block */ + if (getComputedStyle(this_item).display == "inline") { continue } /* inline paragraph at start of article, for example*/ + try { + if(this_item.closest(".hidden-content")) {continue} + } catch { + // do nothing, because we are just avoiding permalinks on born-hidden knowls + } + if (this_item.tagName == "FIGCAPTION") { this_anchor = this_item.parentElement.id } + if (this_item.classList.contains("para")) { + if (this_item.id == "") { + // should be .para inside .para.logical + this_anchor = this_item.parentElement.id; + if(this_item.parentElement.parentElement.nodeName == "LI") { + // we actually had a para inside a para.logical inside an li + this_anchor = "" //this_item.parentElement.parentElement.id; + } + } else if (this_item.parentElement.nodeName == "LI") { + // this_anchor = this_item.parentElement.id; + this_anchor = ""; + } + } + if(this_anchor) { + this_file_name = this_url.split('/').pop().split(".")[0]; + this_permalink_url = this_url; + if (this_file_name !== this_anchor) + this_permalink_url += "#" + this_anchor; + const this_permalink_description = permalinkDescription(this_item); + this_permalink_container = document.createElement('div'); + this_permalink_container.setAttribute('class', 'autopermalink'); + this_permalink_container.setAttribute('onclick', 'copyPermalink(this)'); + this_permalink_container.setAttribute('data-description', this_permalink_description); + // this_permalink_container.innerHTML = '' + permalink_word + ''; + this_permalink_container.innerHTML = '' + permalink_word + ''; + this_item.insertAdjacentElement("afterbegin", this_permalink_container) + } else { +/* + console.log(" no permalink, because no id", this_item) +*/ + } + } + } + + // first of these is for pre-overhaul html. Delete when possible + $(".pretext-content .autopermalink a").on("click", function(event){ + event.preventDefault(); + }); + $(".ptx-content .autopermalink a").on("click", function(event){ + event.preventDefault(); + }); + + console.log("adding video popouts"); + all_iframes = document.querySelectorAll('body iframeXXXX'); + // for now, we just want the iframes that hace youtube in the src + for (var i = 0; i < all_iframes.length; i++) { + this_item = all_iframes[i]; + this_item_src = this_item.src; + // console.log("this_item_src", this_item_src); + if(this_item_src.includes("youtube")) { + this_item_id = this_item.id; + this_item_width = this_item.width; + this_item_height = this_item.height; + if(this_item_height < 150) { continue } + console.log("found a youtube video on", this_item_id); + var empty_div = document.createElement('div'); + var this_videomag_container = document.createElement('div'); + parent_tag = this_item.parentElement.tagName; + if(parent_tag == "FIGURE") { + this_videomag_container.setAttribute("class", "videobig"); + } else { + this_videomag_container.setAttribute("class", "videobig nofigure"); + } +/* + this_videomag_container.setAttribute('class', 'videobig'); +*/ + this_videomag_container.setAttribute('video-id', this_item_id); + this_videomag_container.setAttribute('data-width', this_item_width); + this_videomag_container.setAttribute('data-height', this_item_height); + this_videomag_container.innerHTML = 'fit width'; + +/* replace this with a surrounding div, for placement, containing a inline-block so the background looks right */ + this_item.insertAdjacentElement("beforebegin", empty_div); // because of hard-coded permalinks being inline-block */ + this_item.insertAdjacentElement("beforebegin", this_videomag_container); + this_item.insertAdjacentElement("beforebegin", empty_div); // because of hard-coded permalinks being inline-block */ + } + } + +/* replace this with a single class fo rthe button, with supplementary classes that say to shrink or grow */ + $(".videobig").click(function(){ + parent_video_id = this.getAttribute("video-id"); + console.log("clicked videobig for", parent_video_id); + this_video = document.getElementById(parent_video_id); + console.log("make big: ", this_video); + original_width = this.getAttribute("data-width"); + original_height = this.getAttribute("data-height"); + + browser_width = $(window).width(); + width_ratio = browser_width/original_width; + console.log("the browser is wider by a factor of",width_ratio); + this_video.setAttribute("width", width_ratio*original_width); + this_video.setAttribute("height", width_ratio*original_height); + this_video.setAttribute("style", "position:relative; left:-260px; z-index:1000"); + + this.setAttribute("class", "videosmall"); + this.innerHTML = "make small"; + $(".videosmall").click(function(){ + console.log("clicked videosmall"); + parent_video_id = this.getAttribute("video-id"); + this_video = document.getElementById(parent_video_id); + original_width = this.getAttribute("data-width"); + original_height = this.getAttribute("data-height"); + + this_video.removeAttribute("style"); + this_video.setAttribute("width", original_width); + this_video.setAttribute("height", original_height); + this.setAttribute("class", "videobig"); + this.innerHTML = "fit width"; + }); + }); + +}, +false); + +/* for the random WW problems */ + +function updateURLParameter(url, param, paramVal){ + var newAdditionalURL = ""; + var tempArray = url.split("?"); + var baseURL = tempArray[0]; + var additionalURL = tempArray[1]; + var temp = ""; + if (additionalURL) { + tempArray = additionalURL.split("&"); + for (var i=0; i 3 && !thisid.includes("-part") && !thisid.startsWith("fn-")) || thisid.startsWith("p-") ) ) { + $( this ).addClass("newstuff"); + console.log(" found new", this) + } + }) + } else { + console.log("not preview", window.location.href); + } +}); + +/* +window.addEventListener("load",function(event) { +// setTimeout( function() { + console.log("changein play color"); + $('figure > div.onclick > svg > path').attr('fill', '#0000aa'); + $('path').attr('fill', '#0000aa') +// }, 5000) +}); +*/ + +window.addEventListener("load",function(event) { + document.onkeyup = function(event) + { + var e = (!event) ? window.event : event; + switch(e.keyCode) + { + case 13: //CR + just_hit_escape = false; + if($(document.activeElement).hasClass("aside-like")) { + $(document.activeElement).toggleClass("front") + } else if ($(document.activeElement).hasClass("workspace")) { + process_workspace() + } + case 27: //esc + // var parent_sage_cell = $(this).closest(".sagecell_editor"); + var parent_sage_cell = document.activeElement.closest(".sagecell_editor"); + if (parent_sage_cell && !just_hit_escape) { + console.log("staying in the sage cell", parent_sage_cell, document.activeElement) + just_hit_escape = true; + setTimeout(function(){ just_hit_escape = false }, 1000); + // console.log("parent_sage_cell", parent_sage_cell); + // if ($(parent_sage_cell).hasClass('sagecell_editor')) { + // console.log("I am trapped in a sage cell", $(document.activeElement).closest(".sagecell_editor")); + // console.log($(document.activeElement)); + // var this_sage_cell = $(document.activeElement).closest(".sagecell_editor"); + // this_sage_cell.next().focus; + // } + // else + } else + if(knowl_focus_stack.length > 0 ) { + most_recently_opened = knowl_focus_stack.pop(); + knowl_focus_stack_uid.pop(); + most_recently_opened.focus(); + console.log("moved back one knowl"); + } else { + console.log("no open knowls being tracked"); + break; + } + break; + } +}; +}, +false); + +// a hack for hosted tracking + +window.addEventListener("load",function(event) { + if($('body').attr('id') == "judson-AATA") { + console.log(" found AATA"); + console.log(" looking for id"); + if (typeof eBookConfig !== 'undefined') { + if(eBookConfig['username']) { + aa_id = "run" + eBookConfig['username']; + ut_id = eBookConfig['username']; + console.log(" done looking for id", ut_id); +var newscript = document.createElement('script'); + newscript.type = 'text/javascript'; + newscript.async = true; + newscript.src = 'https://pretextbook.org/js/' + '0.13' + '/' + 'trails' + '.js'; + var allscripts = document.getElementsByTagName('script'); + var s = allscripts[allscripts.length - 1]; + console.log('s',s); + console.log("adding a script", newscript); + s.parentNode.insertBefore(newscript, s.nextSibling); + trail = true; + console.log(" done adding script"); + } else { + console.log(" did not find username"); + } + } else { + console.log(" did not find eBookConfig") + } + } +}); + +function loadResource(type, file) { + /* type should be js or css */ + if (typeof js_version === 'undefined') { js_version = '0.2' } + if (typeof css_version === 'undefined') { css_version = '0.6' } + var newresource, allresources, s; + var linktype = "script"; + if (type == "css") { linktype = "link" } + newresource = document.createElement(linktype); + + if (type == "css") { + newresource.type = 'text/css'; + newresource.rel = 'stylesheet'; + newresource.href = 'https://pretextbook.org/css/' + css_version + '/' + file + '.css'; + newresource.href += '?minivers=' + minivers; + } else if (type == "js") { + newresource.type = 'text/javascript'; +// newscript.async = true; + newresource.src = 'https://pretextbook.org/js/' + js_version + '/' + file + '.js'; + newresource.src += '?minivers=' + minivers; + } else { + console.log("unknown resource type", type, "for", file); + return + } + + allresources = document.getElementsByTagName(linktype); + s = allresources[allresources.length - 1]; + console.log('s',s); + console.log("adding a resource", newresource); + s.parentNode.insertBefore(newresource, s.nextSibling); +} + + +window.addEventListener("load",function(event) { + if(false && $('body').attr('id') == "pretext-SA") { + console.log(" found DMOI"); + if (typeof uname === "undefined") { uname = "" } + console.log("aaaa", uname, " uname"); + if(uname == "editor") { + loadResource('js', 'edit'); + } else { + console.log("not enabling editing") + } + /* } else if ($('body').attr('id') == "pugetsound-SW") { */ + } else if (false && window.location.href.includes("soundwriting.pugetsound")) { +/* a bunch of temporary exploration for a Sound Writing survey */ + console.log("please take our survey"); + console.log(window.location.href); + console.log(window.location.href.includes("soundwriting.pugetsound")); + + loadResource("js", "login"); + loadResource("css", "features"); + setTimeout( loadResource("js", "survey"), 1000); /* I know: sloppy */ + + // } else if ((typeof online_editable !== 'undefined') && online_editable) { + } else if (false && $('body').attr('id') == "pretext-SA") { + loadResource('css', 'features'); + loadResource('js', 'login') + loadResource('js', 'edit'); + } else { + var this_source_txt; + var source_url = window.location.href; + source_url = source_url.replace(/(#|\?).*/, ""); + source_url = source_url.replace(/html$/, "ptx"); + if (typeof sourceeditable !== 'undefined') { + fetch(source_url).then( + function(u){ return u.text();} + ).then( + function(text){ + this_source_txt = text; + if (this_source_txt.includes("404 Not")) { + console.log("Editing not enabled: source unavailable") + } else { + loadResource('css', 'features'); + loadResource('css', 'edit'); + loadResource('js', 'login') + loadResource('js', 'edit'); + } + } + ); + } else { + console.log("Source file unavailable: editing not possible") + } + } + +}); + +// this is to open every knowl on a page +// (this code is not actually used anywhere) +window.addEventListener("load",function(event) { + if($('body').hasClass("braillesample")) { + var knowl_id_counterX = 0; + console.log(" found braillesample"); + var all_knowls = $('[data-knowl]'); + console.log("found", all_knowls.length, "knowls"); + console.log("which are", all_knowls); + for (var j=1; j < all_knowls.length; ++j) { + console.log(j, "un-knowling", all_knowls[j]); + console.log("attr", $(all_knowls[j]).attr("data-knowl")); + $knowl = $(all_knowls[j]); + if(!$knowl.attr("data-knowl-uid")) { + $knowl.attr("data-knowl-uid", knowl_id_counterX); + knowl_id_counterX++; + } + knowl_click_handler($knowl); + // knowl_click_handler($(all_knowls[j])) + } +}}); + +// when the anchor is a knowl, open it +window.addEventListener("load",function(event) { + if (window.location.hash.length) { + let id = window.location.hash.substring(1); + var the_anchor = document.getElementById(id); + console.log("id", id, "the_anchor", the_anchor); + if (the_anchor.tagName == "ARTICLE") { + var contained_knowl = the_anchor.querySelector("a[data-knowl]"); + if (contained_knowl && contained_knowl.parentElement == the_anchor) { + console.log("found a knowl", contained_knowl); + // knowl_click_handler($(contained_knowl)) + contained_knowl.click() + } + } else if (the_anchor.hasAttribute("data-knowl")) { + the_anchor.click() + } else { + // if it is a hidden knowl, find the knowl and open it + var this_hidden_content = the_anchor.closest(".hidden-content"); + if (this_hidden_content) { + console.log("linked to a hidden knowl with this_hidden_content", this_hidden_content); + var the_refid = this_hidden_content.id; + var this_knowl = document.querySelector('[data-refid="' + the_refid + '"]'); + this_knowl.click() + } + } + } +}); + +/* .onepage worksheets adjust workspace to fit printed page length */ + +function scaleWorkspaceIn(obj, subobj, scale, tmporfinal) { + console.log("initial height", obj.clientHeight); + these_workspaces = subobj.querySelectorAll('.workspace'); + if (obj != subobj) { + console.log("distinct subobj", obj, subobj); + console.log("these_workspaces", these_workspaces); + /* this is starting to look like a hack */ + if (subobj.classList.contains("workspace")) { //we were given one workspace + console.log("we were handed a workspace"); + these_workspaces = [subobj] + } + console.log("now these_workspaces", these_workspaces); + } + for (var j=0; j 13) { + console.log("showing extra space"); + var this_proportion_scaledX = 12*this_proportion_number; + this_work.style.background = "linear-gradient( #eef 0px, #eef " + this_proportion_scaledX + "px, #eef " + this_proportion_scaledX + "px, #99f " + (this_proportion_scaledX + 5) + "px, #99f " + (this_proportion_scaledX + 5) + "px, #99f 100%)"; + // this_work.style.background = "linear-gradient( #eef 0px, #eef 200px, #eef 200px, #99f 205px, #99f 205px, #99f 100%)"; + } else { + this_work.style.background = null; + } + if (tmporfinal == "final") { + var enclosingspace = this_work.parentElement.parentElement; + console.log("enclosingspace was", enclosingspace) + if (enclosingspace.tagName == "ARTICLE") { + enclosingspace = enclosingspace.parentElement; + console.log("enclosingspace is now", enclosingspace) + } + var enclosingspacebottom = enclosingspace.getBoundingClientRect()["bottom"]; + /* there should be an easier way to do this */ + /* when the enclosing parent has padding, we want to ignore that */ + enclosingspacepadding = parseFloat(getComputedStyle(enclosingspace)["padding-bottom"].slice(0, -2)); + enclosingspacebottom = enclosingspacebottom - enclosingspacepadding; + console.log(enclosingspace, "enclosingspace padding-bottom", getComputedStyle(enclosingspace)["padding-bottom"]); + var lastsibling = enclosingspace.lastElementChild; + var lastworkspacebottom = lastsibling.getBoundingClientRect()["bottom"]; + console.log("XX", this_work, "oo", enclosingspace, "pp", enclosingspacebottom, "xx", lastworkspacebottom, "diff", enclosingspacebottom - lastworkspacebottom); + if (enclosingspacebottom - lastworkspacebottom < 5) { + this_work.classList.add("tight") + } else { + this_work.classList.remove("tight") + } +/* + console.log(this_work.parentElement, "iparent rectangle", this_work.parentElement.getBoundingClientRect()) + console.log(this_work.parentElement.parentElement, "parent parent rectangle", this_work.parentElement.parentElement.getBoundingClientRect()) +*/ + } + } + return obj.clientHeight +} + +function adjustWorkspace() { + + console.log("adjusting workspace"); + $(".workspace").attr("contenteditable", "true"); + document.execCommand("defaultParagraphSeparator", false, "br"); + + var all_pages = document.querySelectorAll('body .worksheet .onepage'); + var a = 14.0; + var b = 10.0; + var heightA, heightB, this_item; + + var pagelayout = "letter"; + if (document.body.classList.contains("a4")) { pagelayout = "a4" } + + var pageheight = []; + + for (var i = 0; i < all_pages.length; i++) { + /* for assigning page height later */ + if (pagelayout == "a4") { pageheight.push(1320) } + else { pageheight.push(1243) } + + this_item = all_pages[i]; + if (i == 0) { this_item.classList.add("firstpage") } + /* not else if: could be one-page worksheet */ + if (i == all_pages.length - 1) { this_item.classList.add("lastpage") } + console.log(this_item.getBoundingClientRect(), "ccc", this_item); + console.log(this_item.parentElement.getBoundingClientRect(), "ddd", this_item.parentElement); + } + for (var i = 0; i < all_pages.length; i++) { + this_item = all_pages[i]; + + /* not sure if this is the place to do it, but the first page might + have items before it, and the last page mught have items after it */ + var worksheetData = this_item.parentElement.getBoundingClientRect(); + var pageData = this_item.getBoundingClientRect(); + console.log("worksheetData", worksheetData, "pageData", pageData); + var pageExtraHeight = 0; + if (this_item.classList.contains("firstpage")) { + console.log("this_item",this_item.getBoundingClientRect(),this_item.getBoundingClientRect()["y"]); + console.log("this_item parent",this_item.parentElement.getBoundingClientRect(),this_item.parentElement.getBoundingClientRect()["y"]); + pageExtraHeight += pageData["top"] - worksheetData["top"]; /* 45 for padding */ + } + if (this_item.classList.contains("lastpage")) { + pageExtraHeight += worksheetData["bottom"] - pageData["bottom"]; + } + // pageExtraHeight += 150; + pageheight[i] -= pageExtraHeight + console.log("worksheetData", worksheetData, "pageData", pageData); + console.log(i, "i", pageExtraHeight, "pageExtraHeight"); + + heightA = scaleWorkspaceIn(this_item, this_item, a, "tmp"); + heightB = scaleWorkspaceIn(this_item, this_item, b, "tmp"); + console.log("heights", heightA, " xx ", heightB, "oo", this_item); + console.log(i, "goal height", pageheight[i]); + /* a magicscale makes the output the height of the minimum specified input */ + var magicscale = 12; + +/* + heightA += pageExtraHeight; + heightB += pageExtraHeight; +*/ + + if (heightA != heightB) { +/* + magicscale = (1328 - 2*height10 + 1*height20)/(height20 - height10) + magicscale = (1324 - 2*height10 + 1*height20)/(height20 - height10) +*/ + magicscale = (pageheight[i]*(a - b) + b*heightA - a*heightB)/(heightA - heightB); +/* + if (pagelayout == "a4") { + magicscale = (1413*(a - b) + b*heightA - a*heightB)/(heightA - heightB) + } else if (pagelayout == "letter") { + magicscale = (1324*(a - b) + b*heightA - a*heightB)/(heightA - heightB) + } else { + console.log("Error: unknown pagelayout", pagelayout) + } +*/ + + } + console.log("magicscale", magicscale, "of", this_item); + scaleWorkspaceIn(this_item, this_item, magicscale, "final"); + all_pages[i].setAttribute("style", 'height: ' + pageheight[i].toString() + 'px'); + + var this_height = this_item.clientHeight; + console.log(this_height, "ttt", this_item); + console.log(this_item.getBoundingClientRect(), "222ccc", this_item); + console.log(this_item.parentElement.getBoundingClientRect(), "222ddd", this_item.parentElement); + + +// alert("part of one page"); + /* now go back and see if any of the squashed non-tight items can be expanded */ + var these_squashed = this_item.querySelectorAll('.squashed:not(.tight)'); + console.log("these_squashed", these_squashed); + console.log('are squashed by', magicscale); + for (var j=0; j < these_squashed.length; ++j) { + var this_q = these_squashed[j]; + heightA = scaleWorkspaceIn(this_item, this_q, 12, "tmp"); + console.log("heightA", heightA); + if (heightA <= this_height) { + scaleWorkspaceIn(this_item, this_q, 12, "final"); + } else { + scaleWorkspaceIn(this_item, this_q, magicscale, "final"); + } + } + } + console.log("finished adjusting workspace"); +} + +function urlattribute() { + var this_urlstub = window.location.hostname; + document.body.setAttribute("data-urlstub", this_urlstub); +} + +window.addEventListener("load",function(event) { + + if (document.body.classList.contains("worksheet")) { + console.log("begin adjusting workspace"); + + var born_hidden_knowls = document.querySelectorAll('article > a[data-knowl]'); + console.log("born_hidden_knowls", born_hidden_knowls); + for (var j=0; j < born_hidden_knowls.length; ++j) { + born_hidden_knowls[j].click() + } + /* not the right way: need to figure out what this needs to wait for */ + window.setTimeout(adjustWorkspace, 1000); + + window.setTimeout(urlattribute, 1500); + } +// console.log("done adjusting workspace"); + +}); + +/* +window.setInterval(function(){ + console.log('$(":focus")', $(":focus")); +}, 5000); +*/ + diff --git a/_static/pretext/js/pretext_search.js b/_static/pretext/js/pretext_search.js new file mode 100644 index 0000000..7485132 --- /dev/null +++ b/_static/pretext/js/pretext_search.js @@ -0,0 +1,307 @@ + +// next comment is out of date: there are more search options +// from lunr-pretext-search-index.js we will have either +// var ptx_lunr_search_style = "default"; +// or +// var ptx_lunr_search_style = "reference"; + +// since there is only one search box now, this can be simplified +function doSearch(searchlocation="A") { + // Get the search terms from the input text box + var terms; + if(searchlocation == "A") { + terms = document.getElementById("ptxsearch").value; + } else { + terms = document.getElementById("ptxsearchB").value; + } + + localStorage.setItem('last-search-terms', JSON.stringify({terms: terms, time: Date.now()})); + + // Where do we want to put the results? + let resultArea = document.getElementById("searchresults") + resultArea.innerHTML = ""; // clear out any previous results + // assume AND for multiple words + var searchterms = terms; + if(searchlocation == "B") { + document.getElementById("ptxsearch").value = searchterms + console.log("ptxsearch value", document.getElementById("ptxsearch").value); + } else { + searchterms = terms; + } + + searchterms = searchterms.toLowerCase().trim(); + let pageResult = []; + if(searchterms != "") { + pageResult = ptx_lunr_idx.query((q) => { + for(let term of searchterms.split(' ')) { + q.term(term, { fields: ["title"], boost: 20 }); //exact title match with 20x weight + q.term(term, { wildcard: lunr.Query.wildcard.TRAILING, fields: ["title"], boost: 10 }); //inexact title 10x weight + q.term(term, { fields: ["body"], boost: 5 }); //exact body 5x weight + q.term(term, { wildcard: lunr.Query.wildcard.TRAILING, fields: ["body"] }); //inexact body + } + }); + } + // Number the documents from first to last so we can order the results by their + // position in the book. + snum = 0; + for (let doc of ptx_lunr_docs) { + doc.snum = snum; + snum += 1; + } + + //Limit to a sane number of results - otherwise search like 'e' matches every page + const MAX_RESULTS = 100; + let numUnshown = (pageResult.length > MAX_RESULTS) ? pageResult.length - MAX_RESULTS : 0; + pageResult.slice(0, MAX_RESULTS); + + // Transfer meta data from the document to the results to make it easy to add + // our lists later. + augmentResults(pageResult, ptx_lunr_docs); + pageResult.sort(comparePosition); + addResultToPage(terms, pageResult, ptx_lunr_docs, numUnshown, resultArea); + MathJax.typeset(); +} + +// Find the entry for a search result in the original document index +function findEntry(resultId, db) { + for (const page of db) { + if (page.id === resultId) { + return page; + } + } + return resultId; +} + +function augmentResults(result, docs) { + for (let res of result) { + let info = findEntry(res.ref, docs); + res.number = info.number; + res.type = info.type; + res.title = info.title; + res.url = info.url; + res.level = info.level; + res.snum = info.snum; + res.score = parseFloat(res.score); + + //extra score multiplier based on level - prioritize sections over subsections/exercises/etc... + const LEVEL_WEIGHTS = [3, 2, 1.5] + if( res.level < 2 ) + res.score *= LEVEL_WEIGHTS[res.level]; + + res.body = ''; + //Add body snippets and highlights + const REVEAL_WINDOW = 30; + let titleMarked = false; + for (const hit in res.matchData.metadata) { + if(res.matchData.metadata[hit].title) { + //only show one match in title as locations change after first markup + if(!titleMarked) { + if(!res.matchData.metadata[hit].title.position) + continue; + let positionData = res.matchData.metadata[hit].title.position[0]; + const startClipInd = positionData[0]; + const endClipInd = positionData[0] + positionData[1]; + res.title = res.title.substring(0, endClipInd) + '' + res.title.substring(endClipInd); + res.title = res.title.substring(0, startClipInd) + '' + res.title.substring(startClipInd); + titleMarked = true; + } + } else if (res.matchData.metadata[hit].body) { + if(!res.matchData.metadata[hit].body.position) + continue; + const bodyContent = info.body; + let positionData = res.matchData.metadata[hit].body.position[0]; + const startInd = positionData[0] - REVEAL_WINDOW; + const endInd = positionData[0] + positionData[1] + REVEAL_WINDOW; + const startClipInd = positionData[0]; + const endClipInd = positionData[0] + positionData[1]; + let resultSnippet = (startInd > 0 ? '...' : '' ) + bodyContent.substring(startInd, startClipInd); + resultSnippet += '' + bodyContent.substring(startClipInd, endClipInd) + ''; + resultSnippet += bodyContent.substring(endClipInd, endInd) + (endInd < bodyContent.length ? '...' : '' ) + '
    '; + res.body += resultSnippet; + } + } + } +} + +function rearrangedArray(arry) { + // return a new array which is arry (with depth) sorted according to meas, + // again as an array with depth. + // "with depth'' means that large children drag along their parents. + let newarry = []; + let startind = 0; + let numtograb = 0; +let ct = 1; + while (arry.length > 0 && ct < 500) { +++ct; // just in case something goes wrong + const locofmax = maxLocation(arry) + let segmentstart = locofmax; + let segmentlength = 1; + while (arry[segmentstart].level == "2") { + --segmentstart + } + while (segmentstart + segmentlength < arry.length && arry[segmentstart + segmentlength].level == "2") { + ++segmentlength + } +// console.log("locofmax", locofmax, "starting", segmentstart, "going", segmentlength, "from", arry.length); + newarry.push(...arry.splice(segmentstart,segmentlength)); + } +// console.log("newarry", newarry); + return newarry +} +function maxLocation(arry) { + let maxloc = 0; + let maxvalsofar = -1; + for (let index = 0; index < arry.length; ++index) { + if (arry[index].score > maxvalsofar) { + maxloc = index; + maxvalsofar = arry[index].score + } + } + return maxloc +} + +function comparePosition(a, b) { + if (a.snum < b.snum) { + return -1; + } + if (a.snum > b.snum) { + return 1; + } + return 0; +} +function compareScoreDesc(a, b) { + if (a.score < b.score) { + return 1; + } + if (a.score > b.score) { + return -1; + } + return 0; +} + +function addResultToPage(searchterms, result, docs, numUnshown, resultArea) { + /* backward compatibility for old html */ + if (document.getElementById("searchempty")) { + document.getElementById("searchempty").style.display = "none"; + } + let len = result.length; + console.log("first result", result[0]); + if (len == 0) { + if (document.getElementById("searchempty")) { + document.getElementById("searchempty").style.display = "block"; + } else { + let noresults = document.createElement("div"); + noresults.classList.add("noresults"); + search_no_results_string = "No results were found" + noresults.innerHTML = search_no_results_string + "."; + // console.log("the new variable", search_results_heading_string); + resultArea.appendChild(noresults); + } + document.getElementById("searchresultsplaceholder").style.display = null; + return + } +// console.log("result",result); + let allScores = result.map(function (r) { return r.score }); +// console.log(typeof allScores[0], "allScores",allScores); + allScores.sort((a,b) => (a - b)); + allScores.reverse(); +// console.log("allScores, sorted",allScores); + +// let high = result[Math.floor(len*0.25)].score; +// let med = result[Math.floor(len*0.5)].score; +// let low = result[Math.floor(len*0.75)].score; + // sort the results by their position in the book, not their score + let high = allScores[Math.floor(len*0.20)]; + let med = allScores[Math.floor(len*0.40)]; + let low = allScores[Math.floor(len*0.75)]; + if (ptx_lunr_search_style == "reference") { + result = rearrangedArray(result); + } + let indent = "1"; + let currIndent = indent; + let origResult = resultArea; + // Create list entries indenting as needed. + for (const res of result) { + let link = document.createElement("a") + // add a class so we can colorize the results based on their rank in terms + // of search score. + if (res.score >= high) { + link.classList.add("high_result") + } else if (res.score >= med) { + link.classList.add("medium_result") + } else if (res.score >= low) { + link.classList.add("low_result") + } else { + link.classList.add("no_result") + } + currIndent = res.level; + if (currIndent > indent) { + indent = currIndent; + let ilist = document.createElement("ul") + ilist.classList.add("detailed_result"); + resultArea.appendChild(ilist); + resultArea = ilist; + } else if (currIndent < indent) { + resultArea = origResult; + indent = currIndent; + } + link.href = `${res.url}`; + link.innerHTML = `${res.type} ${res.number} ${res.title}`; + let clip = document.createElement("div"); + clip.classList.add("search-result-clip"); + clip.innerHTML = `${res.body}`; + let bullet = document.createElement("li"); + bullet.classList.add('search-result-bullet'); + bullet.appendChild(link); + bullet.appendChild(clip); + let p = document.createElement("text"); + p.classList.add('search-result-score'); + p.innerHTML = ` (${res.score.toFixed(2)})`; + bullet.appendChild(p); + resultArea.appendChild(bullet); + } + //Could print message about how many results are not shown. No way to localize it though... + // if(numUnshown > 0) { + // let bullet = document.createElement("li"); + // bullet.classList.add('search-results-bullet'); + // bullet.classList.add('search-results-unshown-count'); + // let p = document.createElement("text"); + // p.innerHTML = `${parseInt(numUnshown)} unshown results...`; + // bullet.appendChild(p); + // resultArea.appendChild(bullet); + // } + document.getElementById("searchresultsplaceholder").style.display = null; + MathJax.typesetPromise(); +} + + +function showHelp() { + let state = document.getElementById("helpme").style.display; + if (state == "none") { + document.getElementById("helpme").style.display = "block"; + document.getElementById("helpbutt").innerHTML = "Hide Help" + } else { + document.getElementById("helpme").style.display = "none"; + document.getElementById("helpbutt").innerHTML = "Show Help" + } +} + + +window.addEventListener("load",function(event) { + document.getElementById("searchbutton").addEventListener('click', (e) => { + document.getElementById('searchresultsplaceholder').style.display = null; + let searchInput = document.getElementById("ptxsearch"); + searchInput.value = JSON.parse(localStorage.getItem("last-search-terms")).terms; + searchInput.select(); + doSearch(); + }); + + document.getElementById("ptxsearch").addEventListener('input', (e) => { + doSearch(); + }); + + document.getElementById("closesearchresults").addEventListener('click', (e) => { + document.getElementById('searchresultsplaceholder').style.display = 'none'; + document.getElementById('searchbutton').focus(); + }); +}); \ No newline at end of file diff --git a/_static/pretext/js/ptx_search.js b/_static/pretext/js/ptx_search.js new file mode 100644 index 0000000..39dc149 --- /dev/null +++ b/_static/pretext/js/ptx_search.js @@ -0,0 +1,112 @@ +function doSearch() { + // Get the search terms from the input text box + let terms = document.getElementById("ptxsearch").value; + // Where do we want to put the results? + let resultArea = document.getElementById("searchresults") + resultArea.innerHTML = ""; // clear out any previous results + // do the search using the provided index + let pageResult = ptx_lunr_idx.search(terms); + // Number the documents from first to last so we can order the results by their + // position in the book. + snum = 0; + for (let doc of ptx_lunr_docs) { + doc.snum = snum; + snum += 1; + } + // Transfer meta data from the document to the results to make it easy to add + // our lists later. + augmentResults(pageResult, ptx_lunr_docs); + addResultToPage(pageResult, ptx_lunr_docs, resultArea); + MathJax.typeset(); +} + +// Find the entry for a search result in the original document index +function findEntry(resultId, db) { + for (const page of db) { + if (page.id === resultId) { + return page; + } + } + return resultId; +} + +function augmentResults(result, docs) { + for (let res of result) { + let info = findEntry(res.ref, docs); + res.number = info.number; + res.type = info.type; + res.title = info.title; + res.url = info.url; + res.level = info.level; + res.snum = info.snum; + } +} + + +function comparePosition(a, b) { + if (a.snum < b.snum) { + return -1; + } + if (a.snum > b.snum) { + return 1; + } + return 0; +} + +function addResultToPage(result, docs, resultArea) { + let len = result.length + let high = result[Math.floor(len*0.25)].score; + let med = result[Math.floor(len*0.5)].score; + let low = result[Math.floor(len*0.75)].score; + // sort the results by their position in the book, not their score + result = result.sort(comparePosition) + let indent = "1"; + let currIndent = indent; + let origResult = resultArea; + // Create list entries indenting as needed. + for (const res of result) { + let link = document.createElement("a") + // add a class so we can colorize the results based on their rank in terms + // of search score. + if (res.score >= high) { + link.classList.add("high_result") + } else if (res.score >= med) { + link.classList.add("medium_result") + } else if (res.score >= low) { + link.classList.add("low_result") + } + currIndent = res.level; + if (currIndent > indent) { + indent = currIndent; + let ilist = document.createElement("ul") + ilist.classList.add("detailed_result"); + resultArea.appendChild(ilist); + resultArea = ilist; + } else if (currIndent < indent) { + resultArea = origResult; + indent = currIndent; + } + let bullet = document.createElement("li") + bullet.style.marginTop = "5px"; + link.href = `${res.url}`; + link.innerHTML = `${res.type} ${res.number} ${res.title}`; + bullet.appendChild(link) + let p = document.createElement("text"); + p.innerHTML = ` (${res.score.toFixed(2)})`; + bullet.appendChild(p); + resultArea.appendChild(bullet); + } + +} + + +function showHelp() { + let state = document.getElementById("helpme").style.display; + if (state == "none") { + document.getElementById("helpme").style.display = "block"; + document.getElementById("helpbutt").innerHTML = "Hide Help" + } else { + document.getElementById("helpme").style.display = "none"; + document.getElementById("helpbutt").innerHTML = "Show Help" + } +} \ No newline at end of file diff --git a/_static/pretext/js/user_preferences.js b/_static/pretext/js/user_preferences.js new file mode 100644 index 0000000..b5a63c6 --- /dev/null +++ b/_static/pretext/js/user_preferences.js @@ -0,0 +1,510 @@ + +editorLog = console.log; +// editorLog = function(){}; +debugLog = function(){}; +// debugLog = console.log; +//parseLog = function(){}; +parseLog = console.log; +errorLog = console.log; + +/* the structure of each object, and its realization as PreTeXt source or in HTML, + is recorded in the objectStructure dictionary. + +{"xml:id": new_id, "sourcetag": new_tag, "parent": parent_description, "title": ""} + +In pretext, pieces are of the form ["piecename", "tag"], while +in source, pieces are of the form ["piecename", "required_component"], while + +*/ + +editing_mode = 0; + +current_page = location.host+location.pathname; +debugLog("current_page", current_page); +chosen_edit_option_key = "edit_option".concat(current_page); +/* +chosen_edit_option = readCookie(chosen_edit_option_key) || ""; +editing_mode = chosen_edit_option; +*/ +chosen_edit_option = "PLACEHOLDER"; +debugLog("chosen_edit_option", chosen_edit_option, "chosen_edit_option", chosen_edit_option > 0); + +var font_families = { + 'RS': "'Roboto Serif', serif;", + 'OS': "'Open Sans', sans-serif;" +} + +var font_vals = { + // 'face': 'serif', + 'size': [12, 8, 20], + 'height': [135, 80, 200], + 'wspace': [0, -10,20], + 'lspace': [0, -20,20], + 'wdth': [100, 50, 150], + 'wght': [400, 100, 1000] +} + +function fontcss(fvals) { +console.log("in fontcss",fvals); + var csskeys = Object.keys(fvals); + var this_style = ""; + for (var j=0; j < csskeys.length; ++j) { + this_key = csskeys[j]; + document.getElementById("the" + this_key).innerHTML = fvals[this_key][0]; + +console.log("in fontcss", this_key, "with value", fvals[this_key][0], "/10", fvals[this_key][0]/10.0); + if (this_key == 'size') { + this_style += "font-size: " + fvals[this_key][0].toString() + "pt; " + } else if (this_key == 'height') { + this_style += "line-height: " + (fvals[this_key][0]/100.0).toString() + "; " + } else if (this_key == 'lspace') { + this_style += "letter-spacing: " + (fvals[this_key][0]/200.0).toString() + "rem; " + } else if (this_key == 'wspace') { + this_style += "word-spacing: " + (fvals[this_key][0]/50.0).toString() + "rem; " + } + } + + this_style += "font-variation-settings: "; + for (var j=0; j < csskeys.length; ++j) { + this_key = csskeys[j]; + + if (this_key == 'wdth') { + this_style += "'wdth' " + fvals[this_key][0].toString() + "," + } else if (this_key == 'wght') { + this_style += "'wght' " + fvals[this_key][0].toString() + "," + } + } + this_style = this_style.slice(0, -1); + this_style += ";"; + +console.log("returning this_style", this_style); + return this_style +} + +function choice_options(this_choice) { + console.log("choice_options of", this_choice); + val_dict = prefs_menu_vals[this_choice]; + console.log("val_dict", val_dict); + var these_keys = Object.keys(val_dict); + these_keys.sort(); + var these_choices = ""; + for (var j=0; j < these_keys.length; ++j) { + this_key = these_keys[j]; + these_choices += '
  • '; + these_choices += val_dict[this_key]; + these_choices += '
  • '; + } + return these_choices +} + + +// we have to keep track of multiple consecutive carriage returns +this_char = ""; +prev_char = ""; +prev_prev_char = ""; + +// sometimes we have to prevent Tab from changing focus +this_focused_element = ""; +prev_focused_element = ""; +prev_prev_focused_element = ""; + +var menu_neutral_background = "#ddb"; +var menu_active_background = "#fdd"; + +var recent_editing_actions = []; // we unshift to this, so most recent edit is first. + // currently just a human-readable list +var ongoing_editing_actions = []; +var old_content = {}; // to hold old versions of changed materials + +// what will happen with internationalization? +var keyletters = ["KeyA", "KeyB", "KeyC", "KeyD", "KeyE", "KeyF", "KeyG", "KeyH", "KeyI", "KeyJ", "KeyK", "KeyL", "KeyM", "KeyN", "KeyO", "KeyP", "KeyQ", "KeyR", "KeyS", "KeyT", "KeyU", "KeyV", "KeyW", "KeyX", "KeyY", "KeyZ"]; + +var movement_location_options = []; +var movement_location = 0; +var first_move = true; // used when starting to move, because object no longer occupies its original location + +Storage.prototype.setObject = function(key, value) { +// this.setItem(key, JSON.stringify(value)); + this.setItem(key, JSON.stringify(value, function(key, val) { +// console.log("key", key, "value", value, "val", val); + return val.toFixed ? Number(val.toFixed(3)) : val; +})); +} + +Storage.prototype.getObject = function(key) { + var value = this.getItem(key); + return value && JSON.parse(value); +} + +function randomstring(len) { + if (!len) { len = 10 } + return "tMP" + (Math.random() + 1).toString(36).substring(2,len) +} + +function removeItemFromList(lis, value) { + var index = lis.indexOf(value); + if (index > -1) { + lis.splice(index, 1); + } + return lis; +} + + +function textNodesUnder(node){ + var all = []; + for (node=node.firstChild;node;node=node.nextSibling){ + if (node.nodeType==3) { all.push([3, node]) } + else if (node.nodeType==1) { + all.push([1, node]) + var thistag = node.cloneNode().outerHTML; + console.log("thistag", thistag); + [thisopen, thisclose] = thistag.split("><"); + thisopen += ">"; thisclose += "<"; + thisinsides = textNodesUnder(node.cloneNode().innerHTML); +// all.push([0, thisopen]); + for (var j=0; j < thisinsides.length; ++j) { +// all.push(thisinsides[j]) + } +// all.push([0, thisclose]); + } +// probably we only want direct children +// else all = all.concat(textNodesUnder(node)); + } + return all; +} + +function wordsAllWrapped(node) { + var these_text_nodes = textNodesUnder(node); + console.log("node", node); + console.log("these_text_nodes", these_text_nodes); + for (var j=0; j < these_text_nodes.length; ++j) { + var this_text_node = these_text_nodes[j]; + var thistype = this_text_node[0]; + var thisnode = this_text_node[1]; + if (thistype == 3) { + // var these_node_words_and_spaces = these_text_nodes[j].nodeValue.split(/(\s+)/); + var these_node_words_and_spaces = thisnode.nodeValue.split(/(\s+)/); + console.log("these_node_words_and_spaces", these_node_words_and_spaces); + var spanned_words = ""; + for (var k=0; k < these_node_words_and_spaces.length; ++k) { + spanned_words += '' + these_node_words_and_spaces[k] + "" + } + var wass_text = document.createElement('div'); + wass_text.setAttribute('class', 'wastext'); + wass_text.innerHTML = spanned_words; + // these_text_nodes[j].nodeValue = spanned_words + thisnode.replaceWith(wass_text); + wass_text.outerHTML = wass_text.innerHTML + } else if (thistype == 1) { + // // leave it there, but make sure we know about it + // thisnode.classList.add("oneelement") + if (thisnode.classList.contains("process-math") || + thisnode.classList.contains("autopermalink") || + thisnode.classList.contains("latex-logo") || + thisnode.classList.contains("heading") || + // should we instead check for tags that *can* contain line breaks? + ["A", "CODE", "PRE"].includes(thisnode.tagName)) { + //wrap it in a span.oneword + var word_wrapper = document.createElement('span'); + word_wrapper.setAttribute('class', 'oneword'); + thisnode.parentNode.insertBefore(word_wrapper, thisnode); + word_wrapper.appendChild(thisnode); + } else { + wordsAllWrapped(thisnode) + } + } + } +} + +function linesAllWrapped() { + + // var testID = "p-446"; + // var testNode = document.getElementById(testID); + // var all_para = document.querySelectorAll(".para"); + // var all_para = document.querySelectorAll("SECTION P"); + var all_para = document.querySelectorAll("SECTION .para:not(.logical)"); + for (var pj = 0; pj < all_para.length; ++pj) { + testNode = all_para[pj]; + wordsAllWrapped(testNode); + console.log(" wordsAllWrapped", pj, "of", testNode); + + var these_words = document.querySelectorAll(".oneword, .oneelement"); + var this_line = []; + var all_lines = ""; + var current_height = these_words[0].getBoundingClientRect().bottom; + var word_depth = 0; + for (var j=0; j < these_words.length; ++j) { + // next line is an error if the paragraphs starts with an element + var this_word = these_words[j]; + var this_parent = this_word.parentElement; + if (this_word.classList.contains("oneword")) { + this_height = this_word.getBoundingClientRect().bottom; + if ( (Math.abs(this_height - current_height) < 10) && j > 0) { + if (this_parent == testNode && word_depth == 0) { + this_line.push(this_word.innerHTML) + } else { +console.log(word_depth, ":",this_parent == testNode, "this_parent", this_parent.tagName, "ccc", this_parent.ClassList, "xxx", this_word.innerHTML); + if (word_depth == 0) { +console.log("opening the tag", this_parent.tagName,"parent", this_parent,"of",this_word.innerHTML); + var parent_classlist = this_parent.classList; +console.log("parent_classlist", parent_classlist, "first", parent_classlist[0], "length", parent_classlist.length); + // did not work. why? var parent_classes = parent_classlist.join(" "); + this_line.push('<' + this_parent.tagName + ' class="' + parent_classlist[0] + '">'); + this_line.push(this_word.innerHTML); + word_depth += 1 + + } else { + this_line.push(this_word.innerHTML); + } + if (this_word.nextElementSibling == null) { +console.log("closing the tag", this_parent.tagName); + // need to close the wrapping element + this_line.push(""); + word_depth -= 1; + if (word_depth > 0 && this_word.parentElement.nextElementSibling == null) { + this_line.push(""); + word_depth -= 1; + } + } + } + } else { + html_line_contents = ""; + for (var k=0; k < this_line.length; ++k) { + html_line_contents += this_line[k] + } + // hack which only handles up to depth 2 + if (word_depth > 0) { + html_line_contents += "" + } + if (word_depth > 1) { + html_line_contents += "" + } + console.log("made", html_line_contents); + all_lines += '
    ' + html_line_contents + '
    '; + current_height = this_height; + this_line = [this_word.innerHTML]; + if (word_depth > 0) { + this_line.unshift('<' + this_parent.tagName + ' class="' + this_parent.classList[0] + '">') + } + if (word_depth > 1) { + this_line.unshift('<' + this_parent.tagName + ' class="' + this_parent.parentElement.classList[0] + '">') + } + } + } else { // we have an html node + this_line.push(this_word.outerHTML) + } + } + // partial last line may be dangling + // bug: need to fix closing tags at the end? maybe rely on automatic closure + if (this_line.length > 0) { + html_line_contents = ""; + for (var k=0; k < this_line.length; ++k) { + html_line_contents += this_line[k] + } + all_lines += '
    ' + html_line_contents + '
    ' + } + testNode.innerHTML = all_lines + } +} + +editorLog("adding tab listener"); + +document.addEventListener('keydown', logKeyDown); + +function nextsibligntabbable(startingplace, where) { + var candidate = startingplace.nextElementSibling; + if (where == "previous" ) { candidate = startingplace.previousElementSibling } + + while (candidate) { +console.log("candidate A", candidate); + if (candidate.hasAttribute("tabindex")) { return candidate } +console.log("candidate B", candidate); + if (where == "next" ) { candidate = candidate.nextElementSibling } + else { candidate = candidate.previousElementSibling } + } +} + +function logKeyDown(e) { + if (e.code == "ShiftLeft" || e.code == "ShiftRight" || e.code == "Shift") { return } + prev_prev_char = prev_char; + prev_char = this_char; + this_char = e; + debugLog("logKey",e,"XXX",e.code); + + var input_region = document.activeElement; + debugLog("input_region", input_region); + + if (input_region.id == "user-preferences-button") { + if (e.code == "Enter") { + document.getElementById("preferences_menu_holder").classList.toggle("hidden") + } else if (e.code == "Tab") { +console.log("tabbing to main pref menu", document.getElementById("preferences_menu_holder").firstElementChild); +console.log("tabbing to main pref menu", document.getElementById("preferences_menu_holder").firstElementChild.firstElementChild); + e.preventDefault(); + document.getElementById("preferences_menu_holder").firstElementChild.firstElementChild.focus() + } + } else if (input_region.hasAttribute("data-env")) { + var this_submenu = input_region.getElementsByTagName("ol")[0]; +console.log("this_submenu C", this_submenu); + if ((e.code == "Enter") || (e.code == "ArrowRight")) { +console.log("selecting",input_region, "which has", input_region.getElementsByTagName("ol"), "first",input_region.getElementsByTagName("ol")[0]); + this_submenu.classList.toggle("hidden") + input_region.classList.toggle("selected") + input_region.parentElement.classList.toggle("active") + } else if (e.code == "Tab" && e.shiftKey) { + e.preventDefault(); + if (input_region.classList.contains("selected")) { + this_submenu.classList.loggle("hidden"); + input_region.classList.loggle("selected"); + } else { // cycle up through the elements + // previous_sibling = input_region.previousElementSibling; + previous_sibling = nextsibligntabbable(input_region, "previous"); + if (previous_sibling) { previous_sibling.focus() } + else { + document.getElementById("preferences_menu_holder").classList.toggle("hidden"); + document.getElementById("user-preferences-button").focus(); + } + } + } else if (e.code == "Tab") { + e.preventDefault(); + if (input_region.classList.contains("selected")) { + var firstchild = this_submenu.firstElementChild; + if (firstchild.hasAttribute("tabindex")) { + firstchild.focus() + } else { + nextsibligntabbable(firstchild, "next").focus() + } + } else { // cycle through the elements +// next_sibling = input_region.nextElementSibling; + next_sibling = nextsibligntabbable(input_region, "next"); + if (next_sibling) { next_sibling.focus() } + else { + document.getElementById("preferences_menu_holder").classList.toggle("hidden"); + document.getElementById("user-preferences-button").focus(); + } + } + } + } else if (input_region.hasAttribute("data-val")) { +console.log("input_region", input_region); +console.log("input_regionparentElement", input_region.parentElement); + if ((e.code == "Enter") || (e.code == "ArrowRight")) { +console.log("font_vals is", font_vals); + var dataval = input_region.getAttribute("data-val"); + var datachange = input_region.getAttribute("data-change"); +console.log("dataval", dataval, "datachange",datachange); + if (input_region.parentElement.classList.contains("fonts")) { + font_vals[dataval][0] += parseFloat(datachange); + if (font_vals[dataval][0] < font_vals[dataval][1]) { font_vals[dataval][0] = font_vals[dataval][1] } + else if (font_vals[dataval][0] > font_vals[dataval][2]) { font_vals[dataval][0] = font_vals[dataval][2] } +console.log("font_vals are", font_vals); +console.log("css font_vals", fontcss(font_vals)); + var new_style = fontcss(font_vals); + var paras = document.getElementsByClassName('para'); + for (i = 0; i < paras.length; i++) { + paras[i].setAttribute('style', new_style); + } + } else if (input_region.parentElement.classList.contains("fontfamily")) { + document.body.setAttribute("data-font", datachange); + var checks = document.getElementsByClassName('ffcheck'); + for (i = 0; i < checks.length; i++) { + checks[i].innerHTML = ''; + } + document.getElementById("the" + datachange).innerHTML = "✔️"; + } else if (input_region.parentElement.classList.contains("avatar")) { + var checks = document.getElementsByClassName('avatarcheck'); + for (i = 0; i < checks.length; i++) { + checks[i].innerHTML = ''; + } + document.getElementById("theavatarbutton").innerHTML = dataval; + document.getElementById("the" + dataval).innerHTML = "✔️"; + + } else if (input_region.parentElement.classList.contains("atmosphere")) { + document.body.setAttribute("data-atmosphere", dataval); + var checks = document.getElementsByClassName('atmospherecheck'); + for (i = 0; i < checks.length; i++) { + checks[i].innerHTML = ''; + } + document.getElementById("the" + dataval).innerHTML = "✔️"; + + } else if (input_region.parentElement.classList.contains("ruler")) { + // could be motion or actual ruler + if (["mouse", "arrow", "eye"].includes(dataval)) { + document.body.setAttribute("data-motion", dataval); + var checks = document.getElementsByClassName('motioncheck'); + for (i = 0; i < checks.length; i++) { + checks[i].innerHTML = ''; + } + document.getElementById("the" + dataval).innerHTML = "✔️"; + } else { + if (!document.body.hasAttribute("data-ruler")) { + linesAllWrapped() + } + document.body.setAttribute("data-ruler", dataval); + var checks = document.getElementsByClassName('rulercheck'); + for (i = 0; i < checks.length; i++) { + checks[i].innerHTML = ''; + } + document.getElementById("the" + dataval).innerHTML = "✔️"; + } + + } + } else if (e.code == "Tab" && e.shiftKey) { + e.preventDefault(); +// previous_sibling = input_region.previousElementSibling; + previous_sibling = nextsibligntabbable(input_region, "previous"); + +console.log("previous_sibling",previous_sibling); + if (previous_sibling) { previous_sibling.focus() } + else { + input_region.parentElement.parentElement.parentElement.classList.toggle("active"); + input_region.parentElement.parentElement.classList.toggle("selected"); + input_region.parentElement.parentElement.focus(); + input_region.parentElement.classList.toggle("hidden"); + } + } else if (e.code == "Tab") { + e.preventDefault(); + // next_sibling = input_region.nextElementSibling; + next_sibling = nextsibligntabbable(input_region, "next"); + if (next_sibling) { next_sibling.focus() } + else { + input_region.parentElement.parentElement.parentElement.classList.toggle("active"); + input_region.parentElement.parentElement.classList.toggle("selected"); + input_region.parentElement.parentElement.focus(); + input_region.parentElement.classList.toggle("hidden"); + } + } + } + + + return; + + editorLog("input_region", input_region); + // if we are writing something, keystrokes usually are just text input + if (document.getElementById('actively_editing')) { + editorLog(" we are actively editing"); + + if (e.code == "Tab" && !document.getElementById('local_menu_holder')) { + // disabled for now + e.preventDefault(); + return "" + create_local_menu() + } else if (document.getElementById('local_menu_holder')) { + main_menu_navigator(e); + } else { + local_editing_action(e) + } + + } else if (document.getElementById('phantomobject')) { + var the_phantomobject = document.getElementById('phantomobject'); + + if (the_phantomobject.classList.contains('move')) { + move_object(e) + } else { + alert("do not know what to do with that") + } + } else { + console.log("calling main_menu_navigator"); + main_menu_navigator(e); + } +} + diff --git a/about-sage.html b/about-sage.html new file mode 100644 index 0000000..fed2c76 --- /dev/null +++ b/about-sage.html @@ -0,0 +1,276 @@ + + + + + + + + + + +Intro to Sage + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 1.1 Intro to Sage +

    +
    You can run and edit the Sage code directly in the SageMathCells embedded in this webpage. All the cells on the same page share the same memory. Be sure to run the cells in order. If you run the cells on a given page out of order, you may get unexpected results.
    +
    Notice how Sage builds on Python. Valid Python is also valid Sage. Sage adds many feature that are well suited for mathematical computation. Before we get started with discrete math, let’s see how we can use Sage as a calculator.
    +
    +
    +
    +
    +
    +
    +
    + + + diff --git a/backmatter-2.html b/backmatter-2.html new file mode 100644 index 0000000..d748b6d --- /dev/null +++ b/backmatter-2.html @@ -0,0 +1,245 @@ + + + + + + + + + + +Colophon + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    + + + + diff --git a/backmatter.html b/backmatter.html new file mode 100644 index 0000000..63c3bdc --- /dev/null +++ b/backmatter.html @@ -0,0 +1,242 @@ + + + + + + + + + + +Backmatter + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    + + + + diff --git a/cardinality.html b/cardinality.html new file mode 100644 index 0000000..13cbe04 --- /dev/null +++ b/cardinality.html @@ -0,0 +1,274 @@ + + + + + + + + + + +Cardinality + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 2.2 Cardinality +

    +
    To find the cardinality of a set, we use the cardinality() function.
    +
    +
    Alternatively, we can also use the len() function, built into Python. Instead of returning a Sage Integer, this will return a Python int.
    +
    +
    In many cases, using Sage classes and functions will provide more functionality.
    +
    +
    +
    +
    + + + diff --git a/ch-combinatorics.html b/ch-combinatorics.html new file mode 100644 index 0000000..0e7fc0e --- /dev/null +++ b/ch-combinatorics.html @@ -0,0 +1,257 @@ + + + + + + + + + + +Combinatorics + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    + + + + diff --git a/ch-functions.html b/ch-functions.html new file mode 100644 index 0000000..99015d0 --- /dev/null +++ b/ch-functions.html @@ -0,0 +1,260 @@ + + + + + + + + + + +Functions + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    + + + + diff --git a/ch-getting-started.html b/ch-getting-started.html new file mode 100644 index 0000000..348f159 --- /dev/null +++ b/ch-getting-started.html @@ -0,0 +1,266 @@ + + + + + + + + + + +Getting Started + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Chapter 1 Getting Started +

    +
    Welcome to our introduction to SageMath (also referred to as Sage). This chapter is designed for learners of all backgrounds—whether you’re new to programming or aiming to expand your mathematical toolkit. There are various options for running Sage, including the SageMathCell, CoCalc, and a local installation. The easiest way to get started is to use the SageMathCell embedded directly in this book. We will also cover how to use CoCalc, a cloud-based platform that provides a collaborative environment for running Sage code.
    Sage is a free open-source mathematics software system that integrates various
     1 
    doc.sagemath.org/html/en/reference/spkg/
    open-source mathematics software packages. We’ll cover the basics, including SageMath’s syntax, data types, variables, and debugging techniques. Our goal is to equip you with the foundational knowledge needed to explore mathematical problems and programming concepts in an accessible and straightforward manner.
    Join us as we explore the capabilities of SageMath!
    +
    +
    + + + diff --git a/ch-logic.html b/ch-logic.html new file mode 100644 index 0000000..809156f --- /dev/null +++ b/ch-logic.html @@ -0,0 +1,261 @@ + + + + + + + + + + +Logic + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    + + + + diff --git a/ch-relations.html b/ch-relations.html new file mode 100644 index 0000000..1bfbb07 --- /dev/null +++ b/ch-relations.html @@ -0,0 +1,263 @@ + + + + + + + + + + +Relations + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    + + + + diff --git a/ch-set-theory.html b/ch-set-theory.html new file mode 100644 index 0000000..5b39299 --- /dev/null +++ b/ch-set-theory.html @@ -0,0 +1,261 @@ + + + + + + + + + + +Set Theory + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    + + + + diff --git a/creating-sets.html b/creating-sets.html new file mode 100644 index 0000000..f6a86e9 --- /dev/null +++ b/creating-sets.html @@ -0,0 +1,289 @@ + + + + + + + + + + +Creating Sets + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 2.1 Creating Sets +

    +

    +Subsection 2.1.1 Sage Math Set +

    +
    We can create a set by inserting a list within a Set() function, with an uppercase S. We create a list with square brackets []. Notice when we print the set, the elements are ordered and the duplicates are ignored.
    +
    +
    We can ask Sage to compare two sets to see if they are equal or not. We can use the == operator to compare two values. A single equal sign = and double equal sign == have different meanings.
    +
    The equality operator == is used to ask Sage if two values are the same. Sage compares the values on each side of the operator and returns the boolean value. The == operator returns True if the sets are equal and False if they are not equal.
    +
    The assignment operator = is used to assign a value to a variable. The value on the right side of the operator is assigned to the variable on the left side.
    +
    +
    Since sets remove duplicates, the two sets are equal.
    +
    If you are familiar with Python, you may have used a Python set with a lower case s. Even though Sage supports Python sets, we will be using Sage Set for the added features. Be sure to define Sets() with an upper case S.

    +Subsection 2.1.2 Set Builder Notation +

    +
    Instead of explicitly listing the elements of a set, we can use a set builder notation to define a set. The set builder notation is a way to define a set by describing the properties of its elements.
    +
    +
    Iteration is a way to repeat a block of code multiple times and can be used to automate repetitive tasks. We could have created the same set by typing C = Set([2, 4, 6, 8, 10]). Imagine if we wanted to create a set of even numbers between 1 and 100. It would be much easier to use iteration.
    +

    +Subsection 2.1.3 Subsets +

    +
    To list all the subsets included in this set, we can use the Subsets() function to generate all the subsets and then use the Set() function to display the sets of subsets.
    +
    +
    +
    + + + diff --git a/data-types.html b/data-types.html new file mode 100644 index 0000000..3dc596e --- /dev/null +++ b/data-types.html @@ -0,0 +1,331 @@ + + + + + + + + + + +Data Types + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 1.4 Data Types +

    +
    Let’s ask sage what type of object this is.
    +
    +Strings: Sequence of characters used for text. You can use single or double quotes.
    +
    +
    +True and False boolean values.
    +
    +
    +Lists: Ordered mutable collections of items within a pair of square brackets []. If an object is mutable, the value can be changed after it is created.
    +
    +
    +Tuples: Ordered, immutable collections within a pair of parenthesis (). If an object is immutable, the value cannot be changed after it is created.
    +
    +
    +set: sets() with lowercase s are built into Python. Python sets are collections of unique items within a pair of curly braces {}.
    +
    +
    +Set is a built-in Sage class. It is similar to a Python set, with added functionality for mathematical operations.
    +
    +
    +Dictionaries: Collections of key-value pairs.
    +
    +
    In the following example Sage does not evaluate an approximation of sqrt(2) * log(3). Sage will retain the symbolic value for accuracy.
    +
    +
    +
    + + + diff --git a/debugging.html b/debugging.html new file mode 100644 index 0000000..b583ede --- /dev/null +++ b/debugging.html @@ -0,0 +1,291 @@ + + + + + + + + + + +Debugging + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 1.6 Debugging +

    +
    When you learn how to program you will make many mistakes. This will always be part of the process. Please try your best to get comfortable with making mistakes and experimenting. Over time you will learn to recognize how to correct these mistakes quicker. Reading error messages is an essential element of programming. Sometimes error messages are helpful and descriptive. Other times they will seem confusing and will become more clear over time and with practice. Let’s make some mistakes together!
    +
    +
    Why didn’t this print Hello, World! to the screen? Sage told us we have a SyntaxError. In this case we are not too concerned with the meaning of invalid decimal literal. The problem is with how we named our variable. It turns out there are rules about naming identifiers.
    +
    +
    Rules for naming identifiers in Python:
    +
      +
    • Identifiers cannot start with a digit.
    • +
    • Identifiers are case-sensitive.
    • +
    • +
      Identifiers can include:
      +
        +
      • letters (a - z, A - Z)
      • +
      • digits (0 - 9)
      • +
      • underscore character _ +
      • +
      +
    • +
    • Do not use spaces, punctuation or special characters when naming identifiers.
    • +
    • Keywords cannot be used as identifiers.
    • +
    +
    +
    Let’s use an acceptable identifier to name our variable.
    +
    +
    Here are some more keywords that cannot be used for variable names
    +
    +False, None, True, and, as, assert, async, await, break, class, continue, def, del, elif, else, except, finally, for, from, global, if, import, in, is, lambda, nonlocal, not, or, pass, raise, return, try, while, with, yield.
    +
    Here is another error:
    +
    +
    It looks like we have a NameError. We also know that Hello is not defined. In this case Sage thinks that Hello is a variable because there are no parenthesis around it.
    +
    +
    + + + diff --git a/digraphs.html b/digraphs.html new file mode 100644 index 0000000..451d1b5 --- /dev/null +++ b/digraphs.html @@ -0,0 +1,271 @@ + + + + + + + + + + +Digraphs + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 5.3 Digraphs +

    +
    A digraph, or directed graph, is a visual representation of a relation R on the set A. Every element in set A is shown as a node (vertex). An arrow from the node \(a\) to the node \(b\) represent the pair \((a,b)\) on the relation R.
    +
    Consider the set \(A = \{1,2,3,4\}\text{.}\) Define a relation \(R\) on \(A\) such that \(aRb\) if and only if \(a < b\text{.}\) +
    +
    +
    +
    +
    + + + diff --git a/documentation.html b/documentation.html new file mode 100644 index 0000000..6deceb0 --- /dev/null +++ b/documentation.html @@ -0,0 +1,247 @@ + + + + + + + + + + +Documentation + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 1.7 Documentation +

    +
    Sage can do many more mathematical operations. If you want an idea of what Sage can do, check out the Quick Reference Card
     1 
    wiki.sagemath.org/quickref
    and the Reference Manual
     2 
    doc.sagemath.org/html/en/reference/
    .
    +
    The tutorial
     3 
    doc.sagemath.org/html/en/tutorial/
    is an overview to become familiar with Sage.
    +
    The Sage documentation
     4 
    doc.sagemath.org/html/en/index.html
    can be found at this link. Right now, reading the documentation is optional. We will do our best to get you up and running with Sage with this text.
    +
    +
    + + + diff --git a/equivalence.html b/equivalence.html new file mode 100644 index 0000000..bf30de7 --- /dev/null +++ b/equivalence.html @@ -0,0 +1,358 @@ + + + + + + + + + + +Equivalence + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 5.4 Equivalence +

    +
    A relation is called an equivalence relation if it satisfies three key properties: reflexivity, symmetry, and transitivity. These properties ensure that elements can be grouped into classes of equivalence based on their mutual relations.
    +
      +
    • +
      Reflexive
      +
      \(\displaystyle aRa \quad \forall a \in A\)
      + +
      a relates to a for all elements a in the set A. All the elements relate to themselves.
      + +
      +
    • +
    • +
      Symmetric
      +
      \(\displaystyle \text{If } aRb \text{ then } bRa \quad \forall a, b \in A\)
      + +
      If a relates to b, then b relates to a. The relation is symmetric if the order of the elements does not matter.
      + +
      +
    • +
    • +
      Transitive
      +
      \(\displaystyle \text{If } aRb \text{ and } bRc \text{ then } aRc \quad \forall a, b, c \in A\)
      + +
      If a relates to b and b relates to c, then a relates to c.
      +
    • +
    +
    The class of equivalence for an element a in set A is defined by the set:
    +
    +\begin{equation*} +|a| = \{x \in A \; | \; xRa\} +\end{equation*} +
    +
    This set comprises all elements in A that are related to a through the relation R, illustrating how elements are grouped into equivalence classes.
    +
    Consider set A as defined by the scenario:
    +
    +\begin{equation*} +\text{Let A } = \{x \; | \; x \text{ is a person living in a given building} \} +\end{equation*} +
    +
    +
    In this context, let R be the relation on A described as follows:
    +
    +\begin{equation*} +\text{x R y iff x and y live in the same floor of the building.} +\end{equation*} +
    +
    +
    This relation demonstrates the properties of an equivalence relation:
    +
      +
    • +Reflexive: A person lives in the same floor as themselves.
    • +
    • +Symmetric: If person x lives in the same floor as person y, then person y lives in the same floor as person x.
    • +
    • +Transitive: If person x lives in the same floor as person y and person y lives in the same floor as person z, then person x lives in the same floor as person z.
    • +
    +
    +
    For the class of equivalence, considering person a as an example:
    +
    +\begin{equation*} +| \text{person a} | = \{ x \in A \; | \; x R a \} = \text{all people living on the same floor as person a} +\end{equation*} +
    +
    This definition shows that the class of equivalence for person a includes all individuals residing on the same floor as a. The relation "living on the same floor as" groups the building’s residents into sets, with each set corresponding to a floor, forming an equivalence class.
    +
    +
    +
    + + + diff --git a/frontmatter-2.html b/frontmatter-2.html new file mode 100644 index 0000000..ff0a39d --- /dev/null +++ b/frontmatter-2.html @@ -0,0 +1,247 @@ + + + + + + + + + + +Colophon + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Colophon Colophon +

    +

    Website My Website

     1 
    pretextbook.org

    + +

    This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit CreativeCommons.org

     2 
    creativecommons.org/licenses/by-sa/4.0

    +
    +
    + + + diff --git a/frontmatter.html b/frontmatter.html new file mode 100644 index 0000000..0d21e15 --- /dev/null +++ b/frontmatter.html @@ -0,0 +1,250 @@ + + + + + + + + + + +Front Matter + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    + + + + diff --git a/generated/.web_assets.pkl b/generated/.web_assets.pkl new file mode 100644 index 0000000..e2ecf72 --- /dev/null +++ b/generated/.web_assets.pkl @@ -0,0 +1 @@ +}. \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..a5f0cfb --- /dev/null +++ b/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/intro-relations.html b/intro-relations.html new file mode 100644 index 0000000..4fc6353 --- /dev/null +++ b/intro-relations.html @@ -0,0 +1,330 @@ + + + + + + + + + + +Introduction to Relations + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 5.1 Introduction to Relations +

    +
    +
    A relation \(R\) from set \(A\) into set \(B\) is a subset of the Cartesian product \(A \times B\text{,}\) represented as:
    +
    +\begin{equation*} +R \subseteq A \times B +\end{equation*} +
    +
    +
    Recall, the Cartesian product \(A \times B\) consists of all possible ordered pairs \((a, b)\text{,}\) where \(a \in A\) and \(b \in B\text{.}\) Each pair combines an element from set \(A\) with an element from set \(B\text{.}\) +
    +
    Let’s define two sets, pants and shirts, as examples:
    +
    +
    +\begin{equation*} +\text{pants} = \{p_1, p_2, p_3\} +\end{equation*} +
    +
    +\begin{equation*} +\text{shirts} = \{s_1, s_2, s_3, s_4\} +\end{equation*} +
    +
    +
    +
    Create a relation from pants to shirts based on style, where each pair of pants is matched with a shirt.
    +
    +
    The Cartesian product of pants and shirts includes all possible combinations of pants with shirts.
    +
    +
    This relation of pants to shirts can be represented as a subset of the Cartesian product of pants and shirts.
    +
    +
    +\begin{equation*} +\text{formal_relation} \subseteq \text{pants} \times \text{shirts} +\end{equation*} +
    +
    +\begin{equation*} +\text{athletic_relation} \subseteq \text{pants} \times \text{shirts} +\end{equation*} +
    +
    +
    +
    +
    + + + diff --git a/iteration.html b/iteration.html new file mode 100644 index 0000000..5a2da02 --- /dev/null +++ b/iteration.html @@ -0,0 +1,244 @@ + + + + + + + + + + +Iteration + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    + + + + diff --git a/lunr-pretext-search-index.js b/lunr-pretext-search-index.js new file mode 100644 index 0000000..158f333 --- /dev/null +++ b/lunr-pretext-search-index.js @@ -0,0 +1,455 @@ +var ptx_lunr_search_style = "textbook"; +var ptx_lunr_docs = [ +{ + "id": "frontmatter-2", + "level": "1", + "url": "frontmatter-2.html", + "type": "Colophon", + "number": "", + "title": "Colophon", + "body": " My Website copyright " +}, +{ + "id": "about-sage", + "level": "1", + "url": "about-sage.html", + "type": "Section", + "number": "1.1", + "title": "Intro to Sage", + "body": " Intro to Sage You can run and edit the Sage code directly in the SageMathCells embedded in this webpage. All the cells on the same page share the same memory. Be sure to run the cells in order. If you run the cells on a given page out of order, you may get unexpected results. Notice how Sage builds on Python. Valid Python is also valid Sage. Sage adds many feature that are well suited for mathematical computation. Before we get started with discrete math, let's see how we can use Sage as a calculator. " +}, +{ + "id": "printing", + "level": "1", + "url": "printing.html", + "type": "Section", + "number": "1.2", + "title": "Printing", + "body": " Printing Sometimes we use print() to display output and sometimes we do not. Other times we need to use multiple print statements. It looks like Sage is only showing the value of the last line of code. If we want to print both of these strings we will need two print statements. Did you expect these words to be on the same line? Let's investigate what print() does. We can look up the documentation for a function by using the ? operator at the end of the function name. It turns out print() adds a new line after printing. Lets get the output we want on a single line. We can also display mathematical notation " +}, +{ + "id": "OOP", + "level": "1", + "url": "OOP.html", + "type": "Section", + "number": "1.3", + "title": "Object Oriented Programming", + "body": " Object Oriented Programming What is an object ? Almost everything in Sage and Python for that matter is an object! More specifically an object is an instance of a class . A class provides a template or blueprint for creating objects and defines the attributes (properties) and methods (behaviors) that those objects can have. This might not mean too much right now and it will be more clear as we explore what is known as object-oriented programming. Just know that SageMath has different ways of representing and working with data. We can create an object by typing something into our Sage Worksheet or the cells on this page. Dot notation is a feature in object-oriented programming. Here is an example of dot notation. There are many more examples of this in Sage. Dot notation is used to access attributes and methods of an object. We can also pass in arguments to this method to specify the number of digits we want to round to. Sage supports different ways of accomplishing the same task. " +}, +{ + "id": "OOP-2", + "level": "2", + "url": "OOP.html#OOP-2", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "object class " +}, +{ + "id": "OOP-3", + "level": "2", + "url": "OOP.html#OOP-3", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "attributes methods " +}, +{ + "id": "OOP-4", + "level": "2", + "url": "OOP.html#OOP-4", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "object-oriented " +}, +{ + "id": "OOP-5", + "level": "2", + "url": "OOP.html#OOP-5", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Dot notation " +}, +{ + "id": "data-types", + "level": "1", + "url": "data-types.html", + "type": "Section", + "number": "1.4", + "title": "Data Types", + "body": " Data Types Let's ask sage what type of object this is. Strings : Sequence of characters used for text. You can use single or double quotes. True and False boolean values. Lists : Ordered mutable collections of items within a pair of square brackets [] . If an object is mutable, the value can be changed after it is created. Tuples : Ordered, immutable collections within a pair of parenthesis () . If an object is immutable, the value cannot be changed after it is created. set : sets() with lowercase s are built into Python. Python sets are collections of unique items within a pair of curly braces {} . Set is a built-in Sage class. It is similar to a Python set, with added functionality for mathematical operations. Dictionaries : Collections of key-value pairs. In the following example Sage does not evaluate an approximation of sqrt(2) * log(3) . Sage will retain the symbolic value for accuracy. " +}, +{ + "id": "data-types-2", + "level": "2", + "url": "data-types.html#data-types-2", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "object " +}, +{ + "id": "data-types-3", + "level": "2", + "url": "data-types.html#data-types-3", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Strings " +}, +{ + "id": "data-types-5", + "level": "2", + "url": "data-types.html#data-types-5", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "boolean " +}, +{ + "id": "data-types-7", + "level": "2", + "url": "data-types.html#data-types-7", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Lists " +}, +{ + "id": "data-types-9", + "level": "2", + "url": "data-types.html#data-types-9", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Tuples " +}, +{ + "id": "data-types-11", + "level": "2", + "url": "data-types.html#data-types-11", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "set " +}, +{ + "id": "data-types-13", + "level": "2", + "url": "data-types.html#data-types-13", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Set " +}, +{ + "id": "data-types-15", + "level": "2", + "url": "data-types.html#data-types-15", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Dictionaries " +}, +{ + "id": "iteration", + "level": "1", + "url": "iteration.html", + "type": "Section", + "number": "1.5", + "title": "Iteration", + "body": " Iteration " +}, +{ + "id": "debugging", + "level": "1", + "url": "debugging.html", + "type": "Section", + "number": "1.6", + "title": "Debugging", + "body": " Debugging When you learn how to program you will make many mistakes. This will always be part of the process. Please try your best to get comfortable with making mistakes and experimenting. Over time you will learn to recognize how to correct these mistakes quicker. Reading error messages is an essential element of programming. Sometimes error messages are helpful and descriptive. Other times they will seem confusing and will become more clear over time and with practice. Let's make some mistakes together! Why didn't this print Hello, World! to the screen? Sage told us we have a SyntaxError . In this case we are not too concerned with the meaning of invalid decimal literal . The problem is with how we named our variable. It turns out there are rules about naming identifiers. Rules for naming identifiers in Python: Identifiers cannot start with a digit. Identifiers are case-sensitive. Identifiers can include: letters ( a - z , A - Z ) digits ( 0 - 9 ) underscore character _ Do not use spaces, punctuation or special characters when naming identifiers. Keywords cannot be used as identifiers. Let's use an acceptable identifier to name our variable. Here are some more keywords that cannot be used for variable names False , None , True , and , as , assert , async , await , break , class , continue , def , del , elif , else , except , finally , for , from , global , if , import , in , is , lambda , nonlocal , not , or , pass , raise , return , try , while , with , yield . Here is another error: It looks like we have a NameError . We also know that Hello is not defined. In this case Sage thinks that Hello is a variable because there are no parenthesis around it. " +}, +{ + "id": "documentation", + "level": "1", + "url": "documentation.html", + "type": "Section", + "number": "1.7", + "title": "Documentation", + "body": " Documentation Sage can do many more mathematical operations. If you want an idea of what Sage can do, check out the Quick Reference Card and the Reference Manual . The tutorial is an overview to become familiar with Sage. The Sage documentation can be found at this link. Right now, reading the documentation is optional. We will do our best to get you up and running with Sage with this text. " +}, +{ + "id": "sage-browser", + "level": "1", + "url": "sage-browser.html", + "type": "Section", + "number": "1.8", + "title": "Run Sage in the browser", + "body": " Run Sage in the browser The easiest way to get started is by running SageMath online. However, if you do not have reliable internet, you can also install the software locally on your own computer. Begin your journey with SageMath by following these steps: Navigate to the SageMath website Click on Sage on CoCalc Create a CoCalc account Go to Your Projects on CoCalc and create a new project. Start your new project and create a new worksheet. Choose the SageMath Worksheet option. Enter SageMath code into the worksheet. Try to evaluate a simple expression and use the worksheet like a calculator. Execute the code by clicking Run or using the shortcut Shift + Enter . We'll learn more ways to run code in the next section. Save your worksheet as a PDF for your records. To learn more about SageMath worksheets, refer to the documentation Alternatively, you can run Sage code in a Jupyter Notebook for some additional features. If you are feeling adventurous, you can install Sage and run it locally on your own computer. Keep in mind that a local install will be the most involved way to run Sage code. " +}, +{ + "id": "creating-sets", + "level": "1", + "url": "creating-sets.html", + "type": "Section", + "number": "2.1", + "title": "Creating Sets", + "body": " Creating Sets Sage Math Set We can create a set by inserting a list within a Set() function, with an uppercase S . We create a list with square brackets [] . Notice when we print the set, the elements are ordered and the duplicates are ignored. We can ask Sage to compare two sets to see if they are equal or not. We can use the == operator to compare two values. A single equal sign = and double equal sign == have different meanings. The equality operator == is used to ask Sage if two values are the same. Sage compares the values on each side of the operator and returns the boolean value. The == operator returns True if the sets are equal and False if they are not equal. The assignment operator = is used to assign a value to a variable. The value on the right side of the operator is assigned to the variable on the left side. Since sets remove duplicates, the two sets are equal. If you are familiar with Python, you may have used a Python set with a lower case s . Even though Sage supports Python sets, we will be using Sage Set for the added features. Be sure to define Sets() with an upper case S . Set Builder Notation Instead of explicitly listing the elements of a set, we can use a set builder notation to define a set. The set builder notation is a way to define a set by describing the properties of its elements. Iteration is a way to repeat a block of code multiple times and can be used to automate repetitive tasks. We could have created the same set by typing C = Set([2, 4, 6, 8, 10]) . Imagine if we wanted to create a set of even numbers between 1 and 100. It would be much easier to use iteration. Subsets To list all the subsets included in this set, we can use the Subsets() function to generate all the subsets and then use the Set() function to display the sets of subsets. " +}, +{ + "id": "subsec-Ways-to-create-a-set-5", + "level": "2", + "url": "creating-sets.html#subsec-Ways-to-create-a-set-5", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "equality operator " +}, +{ + "id": "subsec-Ways-to-create-a-set-6", + "level": "2", + "url": "creating-sets.html#subsec-Ways-to-create-a-set-6", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "assignment operator " +}, +{ + "id": "cardinality", + "level": "1", + "url": "cardinality.html", + "type": "Section", + "number": "2.2", + "title": "Cardinality", + "body": " Cardinality To find the cardinality of a set, we use the cardinality() function. Tips! In social networks like Facebook or Twitter, cardinality can represent the number of friends or followers a user has. Understanding the cardinality of social connections can help in personalization, targeted advertising, and studying social influence. Alternatively, we can also use the len() function, built into Python. Instead of returning a Sage Integer , this will return a Python int . In many cases, using Sage classes and functions will provide more functionality. " +}, +{ + "id": "sec-operation-on-sets", + "level": "1", + "url": "sec-operation-on-sets.html", + "type": "Section", + "number": "2.3", + "title": "Operations on Sets", + "body": " Operations on Sets Set Membership Check Sage allows you to easily check whether a certain element belongs to a set. You can use the in operator to check membership, which returns True if the element is in the set and False otherwise. Let's consider . We can check if the number 3 is in set A: Tips! For organizations such as clubs, gyms, or online subscription services, set membership checks can be used to validate if a user is a member or subscriber. This can help control access to facilities or content. We also can check if is a subset of A by using the Subsets function to generate a set S with all the subsets of A. Then we use the in function to check whether B belongs to the subset of A. Union of Sets There are two distinct methods available in Sage for calculating unions. Suppose and . We can use the union() function to calculate . Tips! This operation can be visualized in real-world scenarios such as merging two distinct music playlists into one. In this case, any song that appears in both playlists will only be listed once in the merged playlist. Alternatively, we can also use the | operator to perform the union operation. Intersection of Sets Similar to union, there are two methods of using the intersection function in sage. Suppose and . We can use the intersection() function to calculate . Tips! A practical application of set intersection could be finding common members between two different social media groups. Members who belong to both groups represent the intersection of these groups. Alternatively, we can also use the & operator to perform the intersection operation. Difference of Sets We have two methods to solve for difference as well. Suppose and . We can use the difference() function to calculate the difference between 2 sets. Tips! In a real-life context, this can be seen as identifying items on a restaurant menu (set A) that you have not yet tried (set B), with A - B representing the new dishes to explore. Alternatively, we can also use the - operator to perform the difference operation. Multiple Sets For doing operations involving multiple sets, we can repeat the operations to get our results, let us see an example. Suppose , and . To find the union of all three sets, we will repeat the union() function. Alternatively, we can also repeat the | operator to perform the union operation. Similar operations can also be done using the intersection() and difference() functions as well as their operators. Complement of Sets Assume the universal set, and . We can use the difference() function to find the complement of A. Tips! This is analogous to having a list of all possible ice cream flavors (U) and identifying those flavors you have yet to try (A'). Alternatively, we can also use the - operator as well. Cartesian Product of Sets Suppose and . We can use the cartesian_product() and Set() functions to display the operation . Tips! This concept can be applied in situations like determining all possible combinations of two different sets, such as shirt colors and pants styles in a wardrobe. " +}, +{ + "id": "sec-combinatorics", + "level": "1", + "url": "sec-combinatorics.html", + "type": "Section", + "number": "3.1", + "title": "Combinatorics", + "body": " Combinatorics Factorial Function The factorial of a non-negative integer , denoted by , is the product of all positive integers less than or equal to . In Sage, the factorial() function computes this value, which is essential in permutations and combinations calculations. Tips! Factorials are widely used in probability problems, such as determining the number of possible ways a set of items can be arranged. For example, to compute the factorial of 5: Combinations The combination is an unordered selection of k objects from a set of n objects. Tips! Combinations are useful in scenarios like determining the number of possible committees that can be formed from a larger group. For instance, to calculate the number of ways to choose 3 elements from a set of 5: Another method would be using the binomial() function. Permutations A permutation is an ordered selection of k objects from a set of n objects. Tips! Understanding permutations can help solve problems like scheduling where the order of tasks or events matters. To display the set of permutations with 3 elements, we use the Permutations() function and the use the Set() function for output. We can also specify the elements by: In the code above, we specified the elements to be 2, 3 and 4. " +}, +{ + "id": "sec-logical-operation", + "level": "1", + "url": "sec-logical-operation.html", + "type": "Section", + "number": "4.1", + "title": "Logical Operators", + "body": " Logical Operators In Sage, logical operations such as AND & , OR | , NOT ~ , conditional -> , and biconditional <-> play crucial roles in constructing and evaluating logical expressions. Operator Symbol Description AND & True if both operands are true OR | True if at least one operand is true NOT ~ Negates the truth value of its operand Conditional -> True if the first operand implies the second Biconditional <-> True if both operands are equal Boolean Formula Sage's propcalc.formula() function allows for the creation of Boolean formulas using variables and logical operators. Tips! Logical operations can model decision-making processes in programming, such as determining whether a set of conditions are met before executing a particular block of code. " +}, +{ + "id": "sec-truth-table", + "level": "1", + "url": "sec-truth-table.html", + "type": "Section", + "number": "4.2", + "title": "Truth Tables", + "body": " Truth Tables Truth tables represent the fundamental tool in logic to display the truth values of statements for all possible interpretations. The truthtable() function in Sage generates the truth table for a given logical expression. Tips! Constructing truth tables is a practical method for debugging complex logical conditions in software development, ensuring all scenarios are accounted for. Expanding on the concept of truth tables, we can analyze logical expressions involving three variables. This provides a deeper understanding of the interplay between multiple conditions. The truthtable() function accommodates expressions with any reasonable number of variables. Tips! Truth tables for three variables are particularly useful in the study of digital circuits and Boolean algebra, where each variable represents a different input or condition. " +}, +{ + "id": "sec-tautology", + "level": "1", + "url": "sec-tautology.html", + "type": "Section", + "number": "4.3", + "title": "Tautologies", + "body": " Tautologies Analyzing Logical Equivalences Truth tables are instrumental in determining logical equivalences between two expressions. By comparing their truth tables, we can ascertain if two logical statements are equivalent, meaning they have identical truth values for all possible inputs. Tips! This approach is invaluable in simplifying logical expressions in computer algorithms and understanding proofs in mathematical logic. Tautologies A tautology is a logical statement that is always true. The is_tautology() function checks whether a given logical expression is a tautology. Tips! Understanding tautologies is essential in computer science, particularly in optimizing algorithms and validating logical propositions in software verification. It's also fundamental in mathematical proof strategies, such as proof by contradiction. Tautologies play a key role in deductive reasoning, where they serve as universally valid starting points for logical deductions. They are also instrumental in the design of digital logic circuits, where the goal is to achieve certain logical conditions regardless of the input state. Exploring tautologies with Sage not only strengthens a student's grasp of logical principles but also enhances their ability to apply these concepts in computing and mathematical proof construction. By analyzing various expressions and verifying their status as tautologies, students gain insights into the structure and properties of logical statements. Contradictions In contrast to tautologies, contradictions are statements that are always false. Tips! Analyzing the relationship between tautologies and contradictions can aid in the development of critical thinking skills, important for debugging in programming, constructing mathematical proofs, and designing logical circuits. By studying tautologies alongside contradictions, students can better understand the boundaries of logical expressions and the concept of logical necessity versus impossibility. This knowledge is crucial in fields such as theoretical computer science, philosophy of logic, and mathematical logic. " +}, +{ + "id": "intro-relations", + "level": "1", + "url": "intro-relations.html", + "type": "Section", + "number": "5.1", + "title": "Introduction to Relations", + "body": " Introduction to Relations A relation from set into set is a subset of the Cartesian product , represented as: Recall, the Cartesian product consists of all possible ordered pairs , where and . Each pair combines an element from set with an element from set . Let's define two sets, pants and shirts, as examples: Create a relation from pants to shirts based on style, where each pair of pants is matched with a shirt. The Cartesian product of pants and shirts includes all possible combinations of pants with shirts. This relation of pants to shirts can be represented as a subset of the Cartesian product of pants and shirts. " +}, +{ + "id": "intro-relations-2", + "level": "2", + "url": "intro-relations.html#intro-relations-2", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "relation " +}, +{ + "id": "relations-on-a-set", + "level": "1", + "url": "relations-on-a-set.html", + "type": "Section", + "number": "5.2", + "title": "Relations on a set", + "body": " Relations on a set Let's explore specific kind of relation. When the two sets are identical, we refer to a relation from to as a relation on . Consider the set . Let's define a relation on such that iff ( divides ). The relation can be represented by the set of ordered pairs where the first element divides the second: To understand the pairs in this relation, consider whether divides . Since it does, the pair is included in . However, does not divide , so any pair involving and is excluded. Following this logic, we include pairs where the first element divides the second. " +}, +{ + "id": "relations-on-a-set-2", + "level": "2", + "url": "relations-on-a-set.html#relations-on-a-set-2", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "on " +}, +{ + "id": "digraphs", + "level": "1", + "url": "digraphs.html", + "type": "Section", + "number": "5.3", + "title": "Digraphs", + "body": " Digraphs A digraph, or directed graph, is a visual representation of a relation R on the set A. Every element in set A is shown as a node (vertex). An arrow from the node to the node represent the pair on the relation R. Consider the set . Define a relation on such that if and only if . " +}, +{ + "id": "equivalence", + "level": "1", + "url": "equivalence.html", + "type": "Section", + "number": "5.4", + "title": "Equivalence", + "body": " Equivalence A relation is called an equivalence relation if it satisfies three key properties: reflexivity , symmetry , and transitivity . These properties ensure that elements can be grouped into classes of equivalence based on their mutual relations. Reflexive a relates to a for all elements a in the set A. All the elements relate to themselves. Symmetric If a relates to b, then b relates to a. The relation is symmetric if the order of the elements does not matter. Transitive If a relates to b and b relates to c, then a relates to c. The class of equivalence for an element a in set A is defined by the set: This set comprises all elements in A that are related to a through the relation R, illustrating how elements are grouped into equivalence classes. Consider set A as defined by the scenario: In this context, let R be the relation on A described as follows: This relation demonstrates the properties of an equivalence relation: Reflexive : A person lives in the same floor as themselves. Symmetric : If person x lives in the same floor as person y, then person y lives in the same floor as person x. Transitive : If person x lives in the same floor as person y and person y lives in the same floor as person z, then person x lives in the same floor as person z. For the class of equivalence, considering person a as an example: This definition shows that the class of equivalence for person a includes all individuals residing on the same floor as a. The relation \"living on the same floor as\" groups the building's residents into sets, with each set corresponding to a floor, forming an equivalence class. " +}, +{ + "id": "equivalence-2", + "level": "2", + "url": "equivalence.html#equivalence-2", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "equivalence relation reflexivity symmetry transitivity " +}, +{ + "id": "equivalence-3-1-1", + "level": "2", + "url": "equivalence.html#equivalence-3-1-1", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Reflexive " +}, +{ + "id": "equivalence-3-2-1", + "level": "2", + "url": "equivalence.html#equivalence-3-2-1", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Symmetric " +}, +{ + "id": "equivalence-3-3-1", + "level": "2", + "url": "equivalence.html#equivalence-3-3-1", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Transitive " +}, +{ + "id": "equivalence-4", + "level": "2", + "url": "equivalence.html#equivalence-4", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "class of equivalence " +}, +{ + "id": "equivalence-14", + "level": "2", + "url": "equivalence.html#equivalence-14", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Reflexive Symmetric Transitive " +}, +{ + "id": "partial-order", + "level": "1", + "url": "partial-order.html", + "type": "Section", + "number": "5.5", + "title": "Partial Order", + "body": " Partial Order A Partial Order (PO) satisfies the following properties: Reflexive : a relates to a for all elements a in the set A. All the elements relate to themselves. Antisymmetric : The only case that a relates to be and b relates to a is when a and b are equal. Transitive : if a relates to b and b relates to c, then a relates to c. Example: Let and define as the power set of , denoted . Establish a relation on where if and only if . This relation represents the idea of one set being a subset of another within the power set of . To explore how elements relate within these examples, consider the element in the context of the second example. The set is not related to the empty set, denoted as , because is not a subset of . Similarly, does not relate to because is not a subset of . However, is related to because is indeed a subset of , which we denote as . We can also define a poset by specifying the relation directly. " +}, +{ + "id": "partial-order-3", + "level": "2", + "url": "partial-order.html#partial-order-3", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Reflexive " +}, +{ + "id": "partial-order-4", + "level": "2", + "url": "partial-order.html#partial-order-4", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Antisymmetric " +}, +{ + "id": "partial-order-5", + "level": "2", + "url": "partial-order.html#partial-order-5", + "type": "Paragraph (with a defined term)", + "number": "", + "title": "", + "body": "Transitive " +}, +{ + "id": "sec-functions", + "level": "1", + "url": "sec-functions.html", + "type": "Section", + "number": "6.1", + "title": "Functions", + "body": " Functions A function from a set into a set is a relation from into such that each element of is related to exactly one element of the set . The set is called the domain of the function, and the set is called the codomain. Functions are fundamental in both mathematics and computer science for describing mathematical relationships and implementing computational logic. Tips! Defining functions in Sage is not only useful for mathematical calculations but also for creating complex algorithms, modeling data, and simulating real-world scenarios in various fields of science and engineering. In Sage, functions can be defined in various ways, including direct definition using Sage syntax or by defining Python functions. For example, defining a function to calculate the cube of a number: Alternatively, using Python syntax: Graphical Representations Sage provides powerful tools for visualizing functions, enabling students to explore the graphical representations of mathematical relationships. Graphs can be plotted directly from function definitions, offering insights into function behavior, such as continuity, limits, and extrema. Tips! Utilizing graphical representations of functions can greatly aid in understanding complex concepts in calculus and analysis, such as differentiation and integration, by providing a visual context. For example, to plot the function over the interval : " +}, +{ + "id": "sec-recursion", + "level": "1", + "url": "sec-recursion.html", + "type": "Section", + "number": "6.2", + "title": "Recursion", + "body": " Recursion Recursion is a method where the solution to a problem depends on solutions to smaller instances of the same problem. This approach is extensively used in mathematics and computer science, especially in the computation of binomial coefficients, the evaluation of polynomials, and the generation of sequences. Recursion in Sequences A recursive sequence is defined by one or more base cases and a recursive step that relates each term to its predecessors. The following Python code in Sage illustrates how to solve a recursive sequence using the rsolve() function from the sympy library, which symbolically solves recurrence equations. Here, s is a function representing the sequence. The equation eqn defines the recursive relation . The rsolve() function is then used to find a closed-form solution to this recurrence, given the initial conditions and . Recursion with Binomial Coefficients Binomial coefficients, denoted as , count the number of ways to choose elements from an -element set. They can be defined recursively. Sage can compute binomial coefficients using the binomial(n, k) function. We can also explore the recursive nature of binomials using a Python syntax. This Python function implements the recursive formula , with base cases . Recursion in Polynomials Polynomials can also be generated and manipulated recursively. For instance, the derivative of a polynomial is a lower-degree polynomial that can be calculated recursively. Sage provides tools for polynomial manipulation, including differentiation. In this code, PolynomialRing(QQ, 'x') creates a polynomial ring in the variable with rational number coefficients ( QQ ). The polynomial is defined within this ring. The method .derivative() computes the derivative of , producing a new polynomial representing the derivative. " +}, +{ + "id": "backmatter-2", + "level": "1", + "url": "backmatter-2.html", + "type": "Colophon", + "number": "", + "title": "Colophon", + "body": " This book was authored in PreTeXt . " +} +] + +var ptx_lunr_idx = lunr(function () { + this.ref('id') + this.field('title') + this.field('body') + this.metadataWhitelist = ['position'] + + ptx_lunr_docs.forEach(function (doc) { + this.add(doc) + }, this) +}) diff --git a/partial-order.html b/partial-order.html new file mode 100644 index 0000000..8a57979 --- /dev/null +++ b/partial-order.html @@ -0,0 +1,316 @@ + + + + + + + + + + +Partial Order + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 5.5 Partial Order +

    +
    A Partial Order (PO) \(\prec\) satisfies the following properties:
    +
    +
    +Reflexive: a relates to a for all elements a in the set A. All the elements relate to themselves.
    +
    +\begin{equation*} +aRa \quad \forall a \in A +\end{equation*} +
    +
    +
    +
    +Antisymmetric: The only case that a relates to be and b relates to a is when a and b are equal.
    +
    +\begin{equation*} +\text{If } aRb \text{ and } bRa \text{ then } a = b \quad \forall a, b \in A +\end{equation*} +
    +
    +
    +
    +Transitive: if a relates to b and b relates to c, then a relates to c.
    +
    +\begin{equation*} +\text{If } aRb \text{ and } bRc \text{ then } aRc \quad \forall a, b, c \in A +\end{equation*} +
    +
    +
    +
    +
    +Example: Let \(B = \{0,1\}\) and define \(A\) as the power set of \(B\text{,}\) denoted \(A = \mathcal{P}(B)\text{.}\) Establish a relation \(R\) on \(A\) where \(XRY\) if and only if \(X \subseteq Y\text{.}\) This relation represents the idea of one set being a subset of another within the power set of \(B\text{.}\) +
    +
    To explore how elements relate within these examples, consider the element \(\{1\}\) in the context of the second example. The set \(\{1\}\) is not related to the empty set, denoted as \(\{\}\text{,}\) because \(\{1\}\) is not a subset of \(\{\}\text{.}\) Similarly, \(\{1\}\) does not relate to \(\{0\}\) because \(\{1\}\) is not a subset of \(\{0\}\text{.}\) However, \(\{1\}\) is related to \(\{0,1\}\) because \(\{1\}\) is indeed a subset of \(\{0,1\}\text{,}\) which we denote as \(\{1\} R \{0,1\}\text{.}\) +
    +
    +
    We can also define a poset by specifying the relation directly.
    +
    +
    +
    + + + diff --git a/printing.html b/printing.html new file mode 100644 index 0000000..7901e71 --- /dev/null +++ b/printing.html @@ -0,0 +1,279 @@ + + + + + + + + + + +Printing + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 1.2 Printing +

    +
    +
    Sometimes we use print() to display output and sometimes we do not. Other times we need to use multiple print statements.
    +
    +
    +
    It looks like Sage is only showing the value of the last line of code. If we want to print both of these strings we will need two print statements.
    +
    +
    Did you expect these words to be on the same line? Let’s investigate what print() does. We can look up the documentation for a function by using the ? operator at the end of the function name.
    +
    +
    It turns out print() adds a new line after printing. Lets get the output we want on a single line.
    +
    +
    +
    We can also display mathematical notation
    +
    +
    +
    + + + diff --git a/relations-on-a-set.html b/relations-on-a-set.html new file mode 100644 index 0000000..2a40ede --- /dev/null +++ b/relations-on-a-set.html @@ -0,0 +1,275 @@ + + + + + + + + + + +Relations on a set + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 5.2 Relations on a set +

    +
    Let’s explore specific kind of relation. When the two sets are identical, we refer to a relation from \(A\) to \(A\) as a relation on \(A\text{.}\) +
    +
    +
    Consider the set \(A = \{2,3,4,6,8\}\text{.}\) Let’s define a relation \(R\) on \(A\) such that \(aRb\) iff \(a | b\) (\(a\) divides \(b\)). The relation \(R\) can be represented by the set of ordered pairs where the first element divides the second:
    +
    +\begin{equation*} +R = \{(2,2),(2,4),(2,6),(2,8),(3,3),(3,6),(4,4),(4,8),(6,6),(8,8)\} +\end{equation*} +
    +
    +
    To understand the pairs in this relation, consider whether \(2\) divides \(2\text{.}\) Since it does, the pair \((2,2)\) is included in \(R\text{.}\) However, \(2\) does not divide \(3\text{,}\) so any pair involving \(2\) and \(3\) is excluded. Following this logic, we include pairs where the first element divides the second.
    +
    +
    +
    + + + diff --git a/sage-browser.html b/sage-browser.html new file mode 100644 index 0000000..ae0a013 --- /dev/null +++ b/sage-browser.html @@ -0,0 +1,262 @@ + + + + + + + + + + +Run Sage in the browser + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 1.8 Run Sage in the browser +

    +
    The easiest way to get started is by running SageMath online. However, if you do not have reliable internet, you can also install the software locally on your own computer. Begin your journey with SageMath by following these steps:
    +
      +
    1. Navigate to the SageMath website
       1 
      https://www.sagemath.org/
      +
    2. +
    3. Click on Sage on CoCalc
       2 
      https://cocalc.com/features/sage
      +
    4. +
    5. +Create a CoCalc account
       3 
      https://cocalc.com/auth/sign-up
      +
    6. +
    7. Go to Your Projects
       4 
      https://cocalc.com/projects
      on CoCalc and create a new project.
    8. +
    9. Start your new project and create a new worksheet. Choose the SageMath Worksheet option.
    10. +
    11. Enter SageMath code into the worksheet. Try to evaluate a simple expression and use the worksheet like a calculator. Execute the code by clicking Run or using the shortcut Shift + Enter. We’ll learn more ways to run code in the next section.
    12. +
    13. Save your worksheet as a PDF for your records.
    14. +
    15. To learn more about SageMath worksheets, refer to the documentation
       5 
      https://doc.cocalc.com/sagews.html
      +
    16. +
    17. Alternatively, you can run Sage code in a Jupyter Notebook
       6 
      doc.cocalc.com/jupyter-start.html
      for some additional features.
    18. +
    19. If you are feeling adventurous, you can install Sage
       7 
      doc.sagemath.org/html/en/installation/index.html
      and run it locally on your own computer. Keep in mind that a local install will be the most involved way to run Sage code.
    20. +
    +
    +
    + + + diff --git a/sec-combinatorics.html b/sec-combinatorics.html new file mode 100644 index 0000000..5fbcae3 --- /dev/null +++ b/sec-combinatorics.html @@ -0,0 +1,287 @@ + + + + + + + + + + +Combinatorics + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 3.1 Combinatorics +

    +

    +Subsection 3.1.1 Factorial Function +

    +
    The factorial of a non-negative integer \(n\text{,}\) denoted by \(n!\text{,}\) is the product of all positive integers less than or equal to \(n\text{.}\) In Sage, the factorial() function computes this value, which is essential in permutations and combinations calculations.
    +
    For example, to compute the factorial of 5:
    +

    +Subsection 3.1.2 Combinations +

    +
    The combination \((n, k)\) is an unordered selection of k objects from a set of n objects.
    +
    For instance, to calculate the number of ways to choose 3 elements from a set of 5:
    +
    +
    Another method would be using the binomial() function.
    +

    +Subsection 3.1.3 Permutations +

    +
    A permutation \((n, k)\) is an ordered selection of k objects from a set of n objects.
    +
    To display the set of permutations with 3 elements, we use the Permutations() function and the use the Set() function for output.
    +
    +
    We can also specify the elements by:
    +
    +
    In the code above, we specified the elements to be 2, 3 and 4.
    +
    +
    + + + diff --git a/sec-functions.html b/sec-functions.html new file mode 100644 index 0000000..7e155c1 --- /dev/null +++ b/sec-functions.html @@ -0,0 +1,281 @@ + + + + + + + + + + +Functions + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 6.1 Functions +

    +
    A function from a set \(A\) into a set \(B\) is a relation from \(A\) into \(B\) such that each element of \(A\) is related to exactly one element of the set \(B\text{.}\) The set \(A\) is called the domain of the function, and the set \(B\) is called the codomain. Functions are fundamental in both mathematics and computer science for describing mathematical relationships and implementing computational logic.
    +
    In Sage, functions can be defined in various ways, including direct definition using Sage syntax or by defining Python functions.
    +
    For example, defining a function to calculate the cube of a number:
    +
    +
    Alternatively, using Python syntax:
    +
    +

    +Subsection 6.1.1 Graphical Representations +

    +
    Sage provides powerful tools for visualizing functions, enabling students to explore the graphical representations of mathematical relationships. Graphs can be plotted directly from function definitions, offering insights into function behavior, such as continuity, limits, and extrema.
    +
    For example, to plot the function \(f(x) = x^3\) over the interval \([-2, 2]\text{:}\) +
    +
    +
    +
    + + + diff --git a/sec-logical-operation.html b/sec-logical-operation.html new file mode 100644 index 0000000..6ea6fc9 --- /dev/null +++ b/sec-logical-operation.html @@ -0,0 +1,296 @@ + + + + + + + + + + +Logical Operators + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 4.1 Logical Operators +

    +
    In Sage, logical operations such as AND &, OR |, NOT ~, conditional ->, and biconditional <-> play crucial roles in constructing and evaluating logical expressions.
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OperatorSymbolDescription
    AND&True if both operands are true
    OR|True if at least one operand is true
    NOT~Negates the truth value of its operand
    Conditional->True if the first operand implies the second
    Biconditional<->True if both operands are equal
    +

    +Subsection 4.1.1 Boolean Formula +

    +
    Sage’s propcalc.formula() function allows for the creation of Boolean formulas using variables and logical operators.
    +
    +
    +
    + + + diff --git a/sec-operation-on-sets.html b/sec-operation-on-sets.html new file mode 100644 index 0000000..73fbbdb --- /dev/null +++ b/sec-operation-on-sets.html @@ -0,0 +1,353 @@ + + + + + + + + + + +Operations on Sets + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 2.3 Operations on Sets +

    +

    +Subsection 2.3.1 Set Membership Check +

    +
    Sage allows you to easily check whether a certain element belongs to a set. You can use the in operator to check membership, which returns True if the element is in the set and False otherwise.
    +
    Let’s consider \(A = \{1, 2, 3, 4, 5\}\text{.}\) We can check if the number 3 is in set A:
    +
    +
    We also can check if \(B = \{3, 4, 5, 6\}\) is a subset of A by using the Subsets function to generate a set S with all the subsets of A. Then we use the in function to check whether B belongs to the subset of A.
    +

    +Subsection 2.3.2 Union of Sets +

    +
    There are two distinct methods available in Sage for calculating unions.
    +
    Suppose \(A = \{1, 2, 3, 4, 5\}\) and \(B = \{3, 4, 5, 6\}\text{.}\) We can use the union() function to calculate \(A ∪ B\text{.}\) +
    +
    +
    Alternatively, we can also use the | operator to perform the union operation.
    +

    +Subsection 2.3.3 Intersection of Sets +

    +
    Similar to union, there are two methods of using the intersection function in sage.
    +
    Suppose \(A = \{1, 2, 3, 4, 5\}\) and \(B = \{3, 4, 5, 6\}\text{.}\) We can use the intersection() function to calculate \(A ∩ B\text{.}\) +
    +
    +
    Alternatively, we can also use the & operator to perform the intersection operation.
    +

    +Subsection 2.3.4 Difference of Sets +

    +
    We have two methods to solve for difference as well.
    +
    Suppose \(A = \{1, 2, 3, 4, 5\}\) and \(B = \{3, 4, 5, 6\}\text{.}\) We can use the difference() function to calculate the difference between 2 sets.
    +
    +
    Alternatively, we can also use the - operator to perform the difference operation.
    +

    +Subsection 2.3.5 Multiple Sets +

    +
    For doing operations involving multiple sets, we can repeat the operations to get our results, let us see an example.
    +
    Suppose \(A = \{1, 2, 3, 4, 5\}\text{,}\) \(B = \{3, 4, 5, 6\}\) and \(C = \{5, 6, 7\}\text{.}\) To find the union of all three sets, we will repeat the union() function.
    +
    +
    Alternatively, we can also repeat the | operator to perform the union operation.
    +
    +
    Similar operations can also be done using the intersection() and difference() functions as well as their operators.

    +Subsection 2.3.6 Complement of Sets +

    +
    Assume the universal set, \(U = \{1, 2, 3, 4, 5, 6, 7, 8, 9\}\) and \(A = \{1, 2, 3, 4, 5\}\text{.}\) We can use the difference() function to find the complement of A.
    +
    +
    Alternatively, we can also use the - operator as well.
    +

    +Subsection 2.3.7 Cartesian Product of Sets +

    +
    Suppose \(A = \{1, 2, 3, 4, 5\}\) and \(D = \{x, y\}\text{.}\) We can use the cartesian_product() and Set() functions to display the operation \(A × D\text{.}\) +
    +
    +
    +
    + + + diff --git a/sec-recursion.html b/sec-recursion.html new file mode 100644 index 0000000..3ef8b3b --- /dev/null +++ b/sec-recursion.html @@ -0,0 +1,295 @@ + + + + + + + + + + +Recursion + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 6.2 Recursion +

    +
    Recursion is a method where the solution to a problem depends on solutions to smaller instances of the same problem. This approach is extensively used in mathematics and computer science, especially in the computation of binomial coefficients, the evaluation of polynomials, and the generation of sequences.
    +

    +Subsection 6.2.1 Recursion in Sequences +

    +
    A recursive sequence is defined by one or more base cases and a recursive step that relates each term to its predecessors. The following Python code in Sage illustrates how to solve a recursive sequence using the rsolve() function from the sympy library, which symbolically solves recurrence equations.
    +
    +
    Here, s is a function representing the sequence. The equation eqn defines the recursive relation \(s(n) = s(n-1) + 2\cdot s(n-2)\text{.}\) The rsolve() function is then used to find a closed-form solution to this recurrence, given the initial conditions \(s(0) = 2\) and \(s(1) = 7\text{.}\) +

    +Subsection 6.2.2 Recursion with Binomial Coefficients +

    +
    Binomial coefficients, denoted as \(\binom{n}{k}\text{,}\) count the number of ways to choose \(k\) elements from an \(n\)-element set. They can be defined recursively. Sage can compute binomial coefficients using the binomial(n, k) function.
    +
    +
    We can also explore the recursive nature of binomials using a Python syntax.
    +
    +
    This Python function implements the recursive formula \(\binom{n}{k} = \binom{n-1}{k-1} + \binom{n-1}{k}\text{,}\) with base cases \(\binom{n}{0} = \binom{n}{n} = 1\text{.}\) +

    +Subsection 6.2.3 Recursion in Polynomials +

    +
    Polynomials can also be generated and manipulated recursively. For instance, the derivative of a polynomial is a lower-degree polynomial that can be calculated recursively. Sage provides tools for polynomial manipulation, including differentiation.
    +
    +
    In this code, PolynomialRing(QQ, 'x') creates a polynomial ring in the variable \(x\) with rational number coefficients (QQ). The polynomial \(p = x^3 + 2x^2 + x + 1\) is defined within this ring. The method .derivative() computes the derivative of \(p\text{,}\) producing a new polynomial \(dp\) representing the derivative.
    +
    +
    + + + diff --git a/sec-tautology.html b/sec-tautology.html new file mode 100644 index 0000000..d732c0e --- /dev/null +++ b/sec-tautology.html @@ -0,0 +1,284 @@ + + + + + + + + + + +Tautologies + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 4.3 Tautologies +

    +

    +Subsection 4.3.1 Analyzing Logical Equivalences +

    +
    Truth tables are instrumental in determining logical equivalences between two expressions. By comparing their truth tables, we can ascertain if two logical statements are equivalent, meaning they have identical truth values for all possible inputs.
    +

    +Subsection 4.3.2 Tautologies +

    +
    A tautology is a logical statement that is always true. The is_tautology() function checks whether a given logical expression is a tautology.
    +
    +
    Tautologies play a key role in deductive reasoning, where they serve as universally valid starting points for logical deductions. They are also instrumental in the design of digital logic circuits, where the goal is to achieve certain logical conditions regardless of the input state.
    +
    Exploring tautologies with Sage not only strengthens a student’s grasp of logical principles but also enhances their ability to apply these concepts in computing and mathematical proof construction. By analyzing various expressions and verifying their status as tautologies, students gain insights into the structure and properties of logical statements.

    +Subsection 4.3.3 Contradictions +

    +
    In contrast to tautologies, contradictions are statements that are always false.
    +
    +
    By studying tautologies alongside contradictions, students can better understand the boundaries of logical expressions and the concept of logical necessity versus impossibility. This knowledge is crucial in fields such as theoretical computer science, philosophy of logic, and mathematical logic.
    +
    +
    + + + diff --git a/sec-truth-table.html b/sec-truth-table.html new file mode 100644 index 0000000..d21a4cb --- /dev/null +++ b/sec-truth-table.html @@ -0,0 +1,266 @@ + + + + + + + + + + +Truth Tables + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to main content
    +
    +

    Discrete Math with SageMath: Learn math with open-source software

    + +
    +
    +
    + +

    +Section 4.2 Truth Tables +

    +
    Truth tables represent the fundamental tool in logic to display the truth values of statements for all possible interpretations. The truthtable() function in Sage generates the truth table for a given logical expression.
    +
    +
    Expanding on the concept of truth tables, we can analyze logical expressions involving three variables. This provides a deeper understanding of the interplay between multiple conditions. The truthtable() function accommodates expressions with any reasonable number of variables.
    +
    +
    +
    + + +