add discourse-details plugin

This commit is contained in:
Régis Hanol
2015-11-30 11:32:01 +01:00
parent 08ae5f89bd
commit f36ba0b5bf
10 changed files with 216 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
(function(document, $) {
// cf. http://mths.be/details
var hasNativeSupport = (function(doc) {
var fake, el = doc.createElement("details");
// fail-fast
if (!("open" in el)) { return false; }
// figure out a root node
var root = doc.body || (function() {
var de = doc.documentElement;
fake = true;
return de.insertBefore(doc.createElement("body"), de.firstElementChild || de.firstChild);
})();
// setup test element
el.innerHTML = "<summary>a</summary>b";
el.style.display = "block";
// add test element to the root node
root.appendChild(el);
// can we open it?
var diff = el.offsetHeight;
el.open = true;
diff = diff !== el.offsetHeight;
// cleanup
root.removeChild(el);
if (fake) { root.parentNode.removeChild(root); }
// return the result
return diff;
})(document);
function toggleOpen($details) {
$details.toggleClass("open");
}
$.fn.details = function() {
if (hasNativeSupport) { return this; }
return this.each(function() {
var $details = $(this),
$firstSummary = $("summary", $details).first();
$firstSummary.prop("tabIndex", 0);
$firstSummary.on("keydown", function(event) {
if (event.keyCode === 32 /* SPACE */ || event.keyCode === 13 /* ENTER */) {
toggleOpen($details);
return false;
}
});
$firstSummary.on("click", function() {
$firstSummary.focus();
toggleOpen($details);
});
});
};
})(document, jQuery);

View File

@@ -0,0 +1,26 @@
(function() {
function insertDetails(_, summary, details) {
return "<details><summary>" + summary + "</summary>" + details + "</details>";
}
// replace all [details] BBCode with HTML 5.1 equivalent
function replaceDetails(text) {
text = text || "";
while (text !== (text = text.replace(/\[details=([^\]]+)\]((?:(?!\[details=[^\]]+\]|\[\/details\])[\S\s])*)\[\/details\]/ig, insertDetails)));
// add new lines to make sure we *always* have a <p> element after </summary> and around </details>
// otherwise we can't hide the content since we can't target text nodes via CSS
return text.replace(/<\/summary>/ig, "</summary>\n\n")
.replace(/<\/details>/ig, "\n\n</details>\n\n");
}
Discourse.Dialect.addPreProcessor(function(text) {
if (Discourse.SiteSettings.details_enabled) {
text = replaceDetails(text);
}
return text;
});
})();

View File

@@ -0,0 +1,10 @@
import { decorateCooked } from "discourse/lib/plugin-api";
export default {
name: "apply-details",
initialize(container) {
decorateCooked(container, $elem => $("details", $elem).details());
}
};

View File

@@ -0,0 +1,38 @@
details {
position: relative;
}
details > *,
details .lightbox-wrapper {
display: none;
}
summary:first-of-type {
cursor: pointer;
display: block;
}
summary:before {
content: '\25BA';
margin-right: .25em;
}
details[open] > summary:before,
details.open > summary:before {
content: '\25BC';
}
details[open] > summary:first-of-type ~ *,
details.open > summary:first-of-type ~ * {
display: block;
}
/* hide native indicator */
summary::-webkit-details-marker {
display: none;
}
/* FF: hide div generated by lazyYT plugin */
details .lazyYT-container {
display: none;
}