mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 09:36:19 -05:00
add discourse-details plugin
This commit is contained in:
parent
08ae5f89bd
commit
f36ba0b5bf
10 changed files with 216 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -47,6 +47,7 @@ log/
|
||||||
!/plugins/emoji/
|
!/plugins/emoji/
|
||||||
!/plugins/lazyYT/
|
!/plugins/lazyYT/
|
||||||
!/plugins/poll/
|
!/plugins/poll/
|
||||||
|
!/plugins/discourse-details/
|
||||||
/plugins/*/auto_generated/
|
/plugins/*/auto_generated/
|
||||||
|
|
||||||
/spec/fixtures/plugins/my_plugin/auto_generated
|
/spec/fixtures/plugins/my_plugin/auto_generated
|
||||||
|
|
22
plugins/discourse-details/LICENSE
Normal file
22
plugins/discourse-details/LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Discourse
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
27
plugins/discourse-details/README.md
Normal file
27
plugins/discourse-details/README.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
### discourse-details
|
||||||
|
|
||||||
|
HTML 5.1 `<details>` polyfill for [Discourse](https://www.discourse.org).
|
||||||
|
|
||||||
|
NOTE: Does not work on IE9.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
In your posts, surround text with `[details=your summary]` ... `[/details]`.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
I watched the murder mystery on TV last night. [details=Who did it?]The butler did it[/details].
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Follow our [Install a Plugin](https://meta.discourse.org/t/install-a-plugin/19157) howto, using
|
||||||
|
`git clone https://github.com/discourse/discourse-details.git` as the plugin command.
|
||||||
|
|
||||||
|
## Issues
|
||||||
|
|
||||||
|
If you have issues or suggestions for the plugin, please bring them up on [Discourse Meta](https://meta.discourse.org).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
58
plugins/discourse-details/assets/javascripts/details.js
Normal file
58
plugins/discourse-details/assets/javascripts/details.js
Normal 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);
|
|
@ -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;
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { decorateCooked } from "discourse/lib/plugin-api";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "apply-details",
|
||||||
|
|
||||||
|
initialize(container) {
|
||||||
|
decorateCooked(container, $elem => $("details", $elem).details());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
38
plugins/discourse-details/assets/stylesheets/details.scss
Normal file
38
plugins/discourse-details/assets/stylesheets/details.scss
Normal 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;
|
||||||
|
}
|
3
plugins/discourse-details/config/locales/server.en.yml
Normal file
3
plugins/discourse-details/config/locales/server.en.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
en:
|
||||||
|
site_settings:
|
||||||
|
details_enabled: "Enable the details plugin. If you change this, you must rebake all posts with: \"rake posts:rebake\"."
|
4
plugins/discourse-details/config/settings.yml
Normal file
4
plugins/discourse-details/config/settings.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
plugins:
|
||||||
|
details_enabled:
|
||||||
|
default: true
|
||||||
|
client: true
|
27
plugins/discourse-details/plugin.rb
Normal file
27
plugins/discourse-details/plugin.rb
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# name: discourse-details
|
||||||
|
# about: HTML5.1 Details polyfill for Discourse
|
||||||
|
# version: 0.3
|
||||||
|
# authors: Régis Hanol
|
||||||
|
# url: https://github.com/discourse/discourse/tree/master/plugins/discourse-details
|
||||||
|
|
||||||
|
enabled_site_setting :details_enabled
|
||||||
|
|
||||||
|
register_asset "javascripts/details.js"
|
||||||
|
register_asset "javascripts/details_dialect.js", :server_side
|
||||||
|
|
||||||
|
register_asset "stylesheets/details.scss"
|
||||||
|
|
||||||
|
after_initialize do
|
||||||
|
|
||||||
|
# replace all details with their summary in emails
|
||||||
|
Email::Styles.register_plugin_style do |fragment|
|
||||||
|
if SiteSetting.details_enabled
|
||||||
|
fragment.css("details").each do |details|
|
||||||
|
summary = details.css("summary")[0]
|
||||||
|
summary.name = "p"
|
||||||
|
details.replace(summary)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in a new issue