posit-dev / py-htmltools

Tools for HTML generation and output
MIT License
19 stars 4 forks source link

Deduplicate dependencies for `HTMLTextDocument` #72

Closed wch closed 11 months ago

wch commented 11 months ago

In HTML generated by Quarto, the raw HTML can contain repeated entries of HTML dependencies, like this:

<div class="form-group shiny-input-container html-fill-item html-fill-container">
  <label class="control-label" id="start_capital2-label" for="start_capital2">Initial investment</label><input class="js-range-slider" id="start_capital2" data-skin="shiny" data-min="100000.0" data-max="10000000.0" data-from="2000000.0" data-step="99000.0" data-grid="false" data-grid-snap="false" data-prettify-separator="," data-prettify-enabled="true" data-prefix="$" data-keyboard="true" data-data-type="number">
</div><script type="application/json" data-html-dependency="">{"name": "ionrangeslider", "version": "2.3.1", "source": {"package": "shiny", "subdir": "www/shared/ionrangeslider/"}, "script": [{"src": "js/ion.rangeSlider.min.js"}], "stylesheet": [], "meta": [], "all_files": false, "head": null}</script>
<script type="application/json" data-html-dependency="">{"name": "preset-shiny-ionrangeslider", "version": "1.7.5.9001", "source": {"package": "shiny", "subdir": "www/shared/ionrangeslider/"}, "script": [], "stylesheet": [{"href": "css/ion.rangeSlider.css", "rel": "stylesheet"}], "meta": [], "all_files": false, "head": null}</script>
<script type="application/json" data-html-dependency="">{"name": "strftime", "version": "0.9.2", "source": {"package": "shiny", "subdir": "www/shared/strftime/"}, "script": [{"src": "strftime-min.js"}], "stylesheet": [], "meta": [], "all_files": false, "head": null}</script>
</div>
<div class="cell-output cell-output-display html-fill-item html-fill-container" data-execution_count="3">
<div class="form-group shiny-input-container html-fill-item html-fill-container">
  <label class="control-label" id="return_mean2-label" for="return_mean2">Average annual investment return</label><input class="js-range-slider" id="return_mean2" data-skin="shiny" data-min="0" data-max="30" data-from="5" data-step="0.5" data-grid="false" data-grid-snap="false" data-prettify-separator="," data-prettify-enabled="true" data-postfix="%" data-keyboard="true" data-data-type="number">
</div><script type="application/json" data-html-dependency="">{"name": "ionrangeslider", "version": "2.3.1", "source": {"package": "shiny", "subdir": "www/shared/ionrangeslider/"}, "script": [{"src": "js/ion.rangeSlider.min.js"}], "stylesheet": [], "meta": [], "all_files": false, "head": null}</script>
<script type="application/json" data-html-dependency="">{"name": "preset-shiny-ionrangeslider", "version": "1.7.5.9001", "source": {"package": "shiny", "subdir": "www/shared/ionrangeslider/"}, "script": [], "stylesheet": [{"href": "css/ion.rangeSlider.css", "rel": "stylesheet"}], "meta": [], "all_files": false, "head": null}</script>
<script type="application/json" data-html-dependency="">{"name": "strftime", "version": "0.9.2", "source": {"package": "shiny", "subdir": "www/shared/strftime/"}, "script": [{"src": "strftime-min.js"}], "stylesheet": [], "meta": [], "all_files": false, "head": null}</script>
</div>
<div class="cell-output cell-output-display html-fill-item html-fill-container" data-execution_count="3">
<div class="form-group shiny-input-container html-fill-item html-fill-container">
  <label class="control-label" id="inflation_mean2-label" for="inflation_mean2">Average annual inflation</label><input class="js-range-slider" id="inflation_mean2" data-skin="shiny" data-min="0" data-max="20" data-from="2.5" data-step="0.5" data-grid="false" data-grid-snap="false" data-prettify-separator="," data-prettify-enabled="true" data-postfix="%" data-keyboard="true" data-data-type="number">
</div><script type="application/json" data-html-dependency="">{"name": "ionrangeslider", "version": "2.3.1", "source": {"package": "shiny", "subdir": "www/shared/ionrangeslider/"}, "script": [{"src": "js/ion.rangeSlider.min.js"}], "stylesheet": [], "meta": [], "all_files": false, "head": null}</script>
<script type="application/json" data-html-dependency="">{"name": "preset-shiny-ionrangeslider", "version": "1.7.5.9001", "source": {"package": "shiny", "subdir": "www/shared/ionrangeslider/"}, "script": [], "stylesheet": [{"href": "css/ion.rangeSlider.css", "rel": "stylesheet"}], "meta": [], "all_files": false, "head": null}</script>
<script type="application/json" data-html-dependency="">{"name": "strftime", "version": "0.9.2", "source": {"package": "shiny", "subdir": "www/shared/strftime/"}, "script": [{"src": "strftime-min.js"}], "stylesheet": [], "meta": [], "all_files": false, "head": null}</script>
</div>

The resulting <head> can then contain repeated entries like this:

<script src="lib/ionrangeslider-2.3.1/js/ion.rangeSlider.min.js"></script>
<link href="lib/preset-shiny-ionrangeslider-1.7.5.9001/css/ion.rangeSlider.css" rel="stylesheet"/>
<script src="lib/strftime-0.9.2/strftime-min.js"></script>
<script src="lib/ionrangeslider-2.3.1/js/ion.rangeSlider.min.js"></script>
<link href="lib/preset-shiny-ionrangeslider-1.7.5.9001/css/ion.rangeSlider.css" rel="stylesheet"/>
<script src="lib/strftime-0.9.2/strftime-min.js"></script>
<script src="lib/ionrangeslider-2.3.1/js/ion.rangeSlider.min.js"></script>
<link href="lib/preset-shiny-ionrangeslider-1.7.5.9001/css/ion.rangeSlider.css" rel="stylesheet"/>
<script src="lib/strftime-0.9.2/strftime-min.js"></script>

This PR makes it so HTMLTextDocument deduplicates these dependencies, and also removes the <script type="application/json" data-html-dependency=""> tags from the HTML.