Skip to content

Commit ea6958f

Browse files
authored
Merge pull request #2841 from limonspb/marked
Presets: support Marked description layout
2 parents a8a9ac6 + 35d7cb6 commit ea6958f

File tree

9 files changed

+82
-10
lines changed

9 files changed

+82
-10
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"@panter/vue-i18next": "^0.15.2",
5555
"bluebird": "^3.7.2",
5656
"djv": "^2.1.4",
57+
"dompurify": "^2.3.6",
5758
"i18next": "^19.0.0",
5859
"i18next-xhr-backend": "^3.2.2",
5960
"inflection": "^1.12.0",

src/js/gui.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,6 @@ GuiControl.prototype.saveToTextFileDialog = function(textToSave, suggestedFileNa
500500
});
501501
};
502502

503-
504503
GuiControl.prototype._saveToTextFileDialogFileSelected = function(entry, textToSave, resolve, reject) {
505504
checkChromeRuntimeError();
506505

@@ -533,7 +532,6 @@ GuiControl.prototype._saveToTextFileDialogFileSelected = function(entry, textToS
533532
});
534533
};
535534

536-
537535
GuiControl.prototype.readTextFileDialog = function(extension) {
538536
const accepts = [{ description: `${extension.toUpperCase()} files`, extensions: [extension] }];
539537

@@ -560,7 +558,6 @@ GuiControl.prototype.readTextFileDialog = function(extension) {
560558
});
561559
};
562560

563-
564561
GuiControl.prototype.escapeHtml = function(unsafe) {
565562
return unsafe
566563
.replace(/&/g, "&")
@@ -570,5 +567,11 @@ GuiControl.prototype.escapeHtml = function(unsafe) {
570567
.replace(/'/g, "'");
571568
};
572569

570+
GuiControl.prototype.addLinksTargetBlank = function(element) {
571+
element.find('a').each(function() {
572+
$(this).attr('target', '_blank');
573+
});
574+
};
575+
573576
// initialize object into GUI variable
574577
window.GUI = new GuiControl();

src/js/tabs/firmware_flasher.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,9 @@ firmware_flasher.initialize = function (callback) {
8484

8585
let formattedNotes = summary.notes.replace(/#(\d+)/g, '[#$1](https://github.com/betaflight/betaflight/pull/$1)');
8686
formattedNotes = marked.parse(formattedNotes);
87+
formattedNotes = DOMPurify.sanitize(formattedNotes);
8788
$('div.release_info .notes').html(formattedNotes);
88-
$('div.release_info .notes').find('a').each(function() {
89-
$(this).attr('target', '_blank');
90-
});
89+
GUI.addLinksTargetBlank($('div.release_info .notes'));
9190

9291
if (self.releases) {
9392
$('div.release_info').slideDown();

src/main.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
<!-- CORDOVA_INCLUDE js/cordova_startup.js -->
6060
<script type="text/javascript" src="./node_modules/lru_map/lru.js"></script>
6161
<script type="text/javascript" src="./node_modules/marked/marked.min.js"></script>
62+
<script type="text/javascript" src="./node_modules/dompurify/dist/purify.min.js"></script>
6263
<script type="text/javascript" src="./node_modules/universal-ga/lib/analytics.min.js"></script>
6364
<script type="text/javascript" src="./node_modules/short-unique-id/dist/short-unique-id.min.js"></script>
6465
<script type="text/javascript" src="./node_modules/object-hash/dist/object_hash.js"></script>

src/tabs/presets/DetailedDialog/PresetsDetailedDialog.css

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,39 @@
4141
user-select: text;
4242
}
4343

44+
#presets_detailed_dialog_html_description {
45+
white-space: normal;
46+
}
47+
48+
#presets_detailed_dialog_html_description h1, h2 {
49+
padding-top: 10px;
50+
padding-bottom: 3px;
51+
}
52+
53+
#presets_detailed_dialog_html_description h3 {
54+
padding-top: 5px;
55+
padding-bottom: 0px;
56+
}
57+
58+
#presets_detailed_dialog_html_description h4, h5, h6 {
59+
padding-top: 0px;
60+
padding-bottom: 0px;
61+
}
62+
63+
#presets_detailed_dialog_html_description ul, ol {
64+
padding-left: 25px;
65+
}
66+
67+
#presets_detailed_dialog_html_description ul li {
68+
padding-left: 12px;
69+
list-style-type: disclosure-closed;
70+
}
71+
72+
#presets_detailed_dialog_html_description ol li {
73+
padding-left: 12px;
74+
list-style-type: decimal;
75+
}
76+
4477
#presets_detailed_dialog_properties {
4578
height: 360px;
4679
}

src/tabs/presets/DetailedDialog/PresetsDetailedDialog.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<select multiple="multiple" id="presets_options_select"></select>
88
</div>
99
<div class="presets_detailed_dialog_text" id="presets_detailed_dialog_text_description"></div>
10+
<div class="presets_detailed_dialog_text" id="presets_detailed_dialog_html_description"></div>
1011
<div class="presets_detailed_dialog_text" id="presets_detailed_dialog_text_cli"></div>
1112
</div>
1213
<div id = "presets_detailed_dialog_loading" class="data-loading"></div>

src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class PresetsDetailedDialog {
77
this._finalDialogYesNoSettings = {};
88
this._onPresetPickedCallback = onPresetPickedCallback;
99
this._openPromiseResolve = undefined;
10+
this._isDescriptionHtml = false;
1011
}
1112

1213
load() {
@@ -57,7 +58,7 @@ class PresetsDetailedDialog {
5758
}
5859

5960
_loadPresetUi() {
60-
this._domDescription.text(this._preset.description?.join("\n"));
61+
this._loadDescription();
6162

6263
this._domGitHubLink.attr("href", this._presetsRepo.getPresetOnlineLink(this._preset));
6364

@@ -76,6 +77,24 @@ class PresetsDetailedDialog {
7677
this._showCliText(false);
7778
}
7879

80+
_loadDescription() {
81+
let text = this._preset.description?.join("\n");
82+
83+
switch(this._preset.parser) {
84+
case "MARKED":
85+
this._isDescriptionHtml = true;
86+
text = marked.parse(text);
87+
text = DOMPurify.sanitize(text);
88+
this._domDescriptionHtml.html(text);
89+
GUI.addLinksTargetBlank(this._domDescriptionHtml);
90+
break;
91+
default:
92+
this._isDescriptionHtml = false;
93+
this._domDescriptionText.text(text);
94+
break;
95+
}
96+
}
97+
7998
_updateFinalCliText() {
8099
this._domCliText.text(this._getFinalCliText().join("\n"));
81100
}
@@ -107,7 +126,8 @@ class PresetsDetailedDialog {
107126
this._domError = $('#presets_detailed_dialog_error');
108127
this._domProperties = $('#presets_detailed_dialog_properties');
109128
this._titlePanel = $('.preset_detailed_dialog_title_panel');
110-
this._domDescription = $('#presets_detailed_dialog_text_description');
129+
this._domDescriptionText = $('#presets_detailed_dialog_text_description');
130+
this._domDescriptionHtml = $('#presets_detailed_dialog_html_description');
111131
this._domCliText = $('#presets_detailed_dialog_text_cli');
112132
this._domGitHubLink = this._domDialog.find('#presets_open_online');
113133
this._domDiscussionLink = this._domDialog.find('#presets_open_discussion');
@@ -118,7 +138,8 @@ class PresetsDetailedDialog {
118138
}
119139

120140
_showCliText(value) {
121-
this._domDescription.toggle(!value);
141+
this._domDescriptionText.toggle(!value && !this._isDescriptionHtml);
142+
this._domDescriptionHtml.toggle(!value && this._isDescriptionHtml);
122143
this._domCliText.toggle(value);
123144
this._domButtonCliShow.toggle(!value);
124145
this._domButtonCliHide.toggle(value);

src/tabs/presets/PresetsRepoIndexed/PresetParser.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class PresetParser {
66
}
77

88
readPresetProperties(preset, strings) {
9-
const propertiesToRead = ["description", "discussion", "warning", "disclaimer", "include_warning", "include_disclaimer", "discussion", "force_options_review"];
9+
const propertiesToRead = ["description", "discussion", "warning", "disclaimer", "include_warning", "include_disclaimer", "discussion", "force_options_review", "parser"];
1010
const propertiesMetadata = {};
1111
preset.options = [];
1212

@@ -113,11 +113,19 @@ class PresetParser {
113113
case this._settings.MetadataTypes.BOOLEAN:
114114
this._processBooleanProperty(preset, line, propertyName);
115115
break;
116+
case this._settings.MetadataTypes.PARSER:
117+
this._processParserProperty(preset, line, propertyName);
118+
break;
116119
default:
117120
this.console.err(`Parcing preset: unknown property type '${this._settings.presetsFileMetadata[property].type}' for the property '${propertyName}'`);
118121
}
119122
}
120123

124+
_processParserProperty(preset, line, propertyName)
125+
{
126+
preset[propertyName] = line;
127+
}
128+
121129
_processBooleanProperty(preset, line, propertyName) {
122130
const trueValues = ["true", "yes"];
123131

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2630,6 +2630,11 @@ domain-browser@^1.2.0:
26302630
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
26312631
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
26322632

2633+
dompurify@^2.3.6:
2634+
version "2.3.6"
2635+
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.6.tgz#2e019d7d7617aacac07cbbe3d88ae3ad354cf875"
2636+
integrity sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg==
2637+
26332638
dot-prop@^4.1.0:
26342639
version "4.2.1"
26352640
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4"

0 commit comments

Comments
 (0)