Advertisement
circlejourney

THBlog 0.3

Jul 31st, 2023
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.42 KB | None | 0 0
  1. // ==UserScript==
  2. // @name THBlog
  3. // @namespace https://circlejourney.net/
  4. // @version 0.3
  5. // @description Blog theme formatter for Toyhouse
  6. // @author Circlejourney
  7. // @match https://toyhou.se/~bulletins/*
  8. // @icon https://circlejourney.net/resources/images/favicon.png
  9. // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
  10. // @require https://code.jquery.com/jquery-3.7.0.min.js
  11. // @grant GM_getValue
  12. // @grant GM_setValue
  13. // @grant GM.getValue
  14. // @grant GM.setValue
  15. // @license MIT
  16. // ==/UserScript==
  17.  
  18.  
  19. (function() {
  20. 'use strict';
  21. let isGenerated = false;
  22. const defaultTemplate = `<div class="card" style="overflow: hidden; {Wrapper_CustomCSS}">
  23. <div class="mb-0 rounded text-center" style="border-bottom-right-radius: 0; border-bottom-left-radius: 0; overflow:hidden; background-image:url({Header_BG}); background-size:{Header_BGSize}; background-position:{Header_BGPosition};">
  24. <div style="background:{HeaderOverlay_BG}; {HeaderOverlay_CustomCSS}">
  25. <div id="post-title" class="display-4" style="{Title_CustomCSS}">{Title}</div>
  26. <div id="post-mood" style="{Mood_CustomCSS}">{Mood}</div>
  27. </div>
  28. </div>
  29. <div class="card-block" id="post-body" style="{Body_CustomCSS}">
  30. {Body}
  31. </div>
  32. <div class="card-footer" id="post-tags" style="{Tags_CustomCSS}">
  33. {Tags}
  34. </div>
  35. </div>`;
  36. const css = `#THBlog {
  37. }
  38. #THBlog * {
  39. font-family: -apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;
  40. }
  41.  
  42. #THBlog_wrapper {
  43. display: flex;
  44. flex-wrap: wrap;
  45. }
  46.  
  47. #THBlog .config_header {
  48. font-weight: normal;
  49. text-transform: uppercase;
  50. flex-basis: 100%;
  51. }
  52.  
  53. #THBlog .section_header_holder {
  54. flex-basis: 50%;
  55. box-sizing: border-box;
  56. padding: 0.5rem;
  57. }
  58.  
  59. #THBlog .section_header_holder#how-to {
  60. flex-basis: 100%;
  61. }
  62.  
  63. #THBlog .section_header_holder#THBlog_section_2 {
  64. flex-basis: 100%;
  65. }
  66.  
  67. #THBlog_section_2 textarea {
  68. font-size: 9pt;
  69. height: 10em;
  70. width: 100%;
  71. font-family: monospace;
  72. }
  73.  
  74. #THBlog .section_header {
  75. margin-bottom: 0.5rem;
  76. font-weight: 300;
  77. text-transform: uppercase;
  78. border-radius: .25rem;
  79. background-color: var(--color-dark);
  80. }
  81.  
  82. #THBlog .section_desc {
  83. margin-bottom: 0.5rem;
  84. font-size: 10pt;
  85. border-radius: .25rem;
  86. background-color: var(--color-light);
  87. }
  88.  
  89. input {
  90. border-radius: .25rem;
  91. }
  92.  
  93. #THBlog .field_label {
  94. font-size: 10pt;
  95. }
  96.  
  97. #THBlog_buttons_holder {
  98. flex-basis: 100%;
  99. }`;
  100.  
  101. let frame = document.createElement('div');
  102. document.body.appendChild(frame);
  103.  
  104. const configObject = {
  105. 'id': 'THBlog',
  106. 'css': css,
  107. 'title': "Customise Blog Theme",
  108. 'frame': frame,
  109.  
  110. 'fields':
  111. {
  112. 'DefaultTitle': {
  113. 'label': "Placeholder title",
  114. "type": "text",
  115. "default": "New post",
  116. "section": ["Placeholder text"]
  117. },
  118. 'DefaultMood': {
  119. 'label': "Placeholder mood",
  120. "type": "text",
  121. "default": "Mood: It's a mystery",
  122. },
  123. 'DefaultBody': {
  124. 'label': "Placeholder post content",
  125. "type": "text",
  126. "default": "Write your post here."
  127. },
  128. 'DefaultTags': {
  129. 'label': "No tag placeholder text",
  130. "type": "text",
  131. "default": "No tags found",
  132. },
  133. 'Wrapper_CustomCSS':
  134. {
  135. 'label': 'Wrapper custom CSS',
  136. 'type': 'text',
  137. 'section': ['CSS customisations']
  138. },
  139. 'Header_BG':
  140. {
  141. 'label': 'Header background image',
  142. 'type': 'text',
  143. 'default': 'https://f2.toyhou.se/file/f2-toyhou-se/images/60724018_5JIbTcQVHT9nJA1.jpg'
  144. },
  145. 'Header_BGSize': {
  146. 'label': 'Header background size',
  147. 'type': 'text',
  148. 'default': 'cover'
  149. },
  150. 'Header_BGPosition': {
  151. 'label': 'Header background position',
  152. 'type': 'text',
  153. 'default': 'center'
  154. },
  155. 'HeaderOverlay_BG': {
  156. 'label': 'Header overlay colour',
  157. 'type': 'text',
  158. 'default': 'rgba(40,40,40,0.7)'
  159. },
  160. 'HeaderOverlay_CustomCSS': {
  161. 'label': 'Header custom CSS',
  162. 'type': 'text',
  163. 'default': 'padding:50px; color: white;'
  164. },
  165. 'Title_CustomCSS': {
  166. 'label': 'Title custom CSS',
  167. 'type': 'text',
  168. 'default': '',
  169. },
  170. 'Mood_CustomCSS': {
  171. 'label': 'Mood custom CSS',
  172. 'type': 'text',
  173. 'default': 'opacity: 0.6;',
  174. },
  175. 'Body_CustomCSS': {
  176. 'label': 'Body custom CSS',
  177. 'type': 'text',
  178. 'default': '',
  179. },
  180. 'Tags_CustomCSS': {
  181. 'label': 'Tags custom CSS',
  182. 'type': 'text',
  183. 'default': 'opacity: 0.6',
  184. },
  185. "Template": {
  186. "label": "",
  187. "type": "textarea",
  188. "default": defaultTemplate,
  189. "section": ["Template", "This part can be ignored, but it is included for those who want more control over their blog theme template. When you click \"Apply theme\", parts of this template are replaced with the contents of the h1, h2, and pre elements at the top of the source text: {Title} replaced with h1, {Mood} replaced with h2, {Tags} replaced with pre. {Body} is replaced with everything else after these template elements."]
  190. }
  191. },
  192.  
  193. "events": {
  194. "save": function() {
  195. this.close();
  196. if(isGenerated) {
  197. revert();
  198. generate();
  199. }
  200. },
  201. "open": function() {
  202. $("#THBlog_header").after("<div class='section_header_holder' id='how-to'><p class='section_desc center'>How-to: In WYSIWYG mode, write your source text with a Heading 1 element at the top (the post title), followed by a Heading 2 element (the post mood), and then a Code element (the post tags). Everything after that will be assumed to be the post body. When you click \"Apply theme\", the post will be formatted automatically. All template parts are optional, and if not included in the source text, will be substituted with the placeholder text that you have set.</p></div>");
  203. $("#THBlog_section_2").before( $("#THBlog_buttons_holder") );
  204. }
  205. }
  206. };
  207.  
  208. const config = new GM_config(configObject);
  209.  
  210. function generate(){
  211. let wasWYS = localStorage.froalaEnabled == 1;
  212. if(wasWYS) $(".wysiwyg-toggler")[0].click(); // Turn off WYSIWYG
  213.  
  214. const HTMLCapture = $(".wysiwyg").val().match(/\s*(?:<h1>([\S\s]*)<\/h1>)?\s*(?:<h2>([\S\s]*)<\/h2>)?\s*(?:<pre>([\S\s]*)<\/pre>)?\s*(.*)/);
  215.  
  216. const unformatted = HTMLCapture.slice(1);
  217. const title = unformatted[0] || config.get("DefaultTitle");
  218. const mood = unformatted[1] || config.get("DefaultMood");
  219. const tags = unformatted[2] ? unformatted[2].replace(/\s#/g, "&emsp;#") : config.get("DefaultTags");
  220. const body = unformatted[3] || config.get("DefaultBody");
  221.  
  222. let replaceDictionary = {
  223. "Title": title,
  224. "Mood": mood,
  225. "Body": body,
  226. "Tags": tags,
  227. ...Object.fromEntries(
  228. Object.keys(config.fields).map( (k)=>[k, config.get(k)] )
  229. )
  230. };
  231. console.log(body, tags);
  232.  
  233. let post = config.get("Template");
  234. for(const [k,v] of Object.entries(replaceDictionary)) {
  235. post = v ? post.replace(`{${k}}`, v) : post;
  236. }
  237.  
  238. $(".wysiwyg").val( post );
  239. const titleField = $(".profile-create-character-basics input[type='text']");
  240. if(!$(titleField).val() || $(titleField).val() !== title && confirm("Update title field?")) {
  241. const titleArr = title.split("");
  242. const newtitle = titleArr.reduce((a, c)=> (a+c).length >= 50 ? a : ((a+c).length >= 47 ? a+"..." : a+c));
  243. $(titleField).val(newtitle);
  244. }
  245.  
  246. $("#gen-button").text("Revert to source").off("click").click(revert);
  247. $(".wysiwyg-toggler")[0].click(); // Turn WYSIWYG on on success
  248. isGenerated = true;
  249. }
  250.  
  251. function revert() {
  252. const wasWYS = localStorage.froalaEnabled==1;
  253. if(wasWYS) $(".wysiwyg-toggler")[0].click(); // Turn WYSIWYG off
  254. if($(".wysiwyg").val().indexOf('id="post-title"') === -1) {
  255. if(wasWYS) $(".wysiwyg-toggler")[0].click(); // Turn WYSIWYG back on
  256. return false;
  257. }
  258.  
  259. const domParser = new DOMParser();
  260. const postDOM = domParser.parseFromString($(".wysiwyg").val(), "text/html");
  261. const uglyTags = $(postDOM).find("#post-tags").html() == config.get("DefaultTags") ? "" : $(postDOM).find("#post-tags").html().trim().replace(/&emsp;/g, " ");
  262. const uglyTitle = $(postDOM).find("#post-title").html() == config.get("DefaultTitle") ? "" : $(postDOM).find("#post-title").html().trim();
  263. const uglyMood = $(postDOM).find("#post-mood").html() == config.get("DefaultMood") ? "" : $(postDOM).find("#post-mood").html().trim();
  264. const uglyPost = $(postDOM).find("#post-body").html() == config.get("DefaultBody") ? "" : $(postDOM).find("#post-body").html().trim();
  265.  
  266. const post = (uglyTitle ? "<h1>"+uglyTitle+"</h1>" : "")
  267. + (uglyMood ? "<h2>"+uglyMood+"</h2>" : "")
  268. + (uglyTags ? "<pre>"+uglyTags+"</pre>" : "")
  269. + uglyPost;
  270.  
  271. $(".wysiwyg").val( post );
  272.  
  273. $("#gen-button").text("Apply theme").off("click").click(generate);
  274. if(wasWYS) $(".wysiwyg-toggler")[0].click(); // Turn WYSIWYG back on
  275. isGenerated = false;
  276. }
  277. $(document).ready( function() {
  278. isGenerated = $(".wysiwyg").val().indexOf('id="post-title"') !== -1
  279. const wasWYS = localStorage.froalaEnabled==1;
  280. if(wasWYS) $(".wysiwyg-toggler")[0].click(); // Turn WYSIWYG off
  281.  
  282. const genButton = $("<a class='btn btn-primary mr-1' href='#' id='gen-button' onclick='event.preventDefault()'></a>").click(
  283. isGenerated ? revert : generate
  284. ).text(
  285. isGenerated ? "Revert to source" : "Apply theme"
  286. );
  287. const settingsBar = $('<div class="card mb-3"></div>').append(
  288. $('<div class="card-block bg-faded"></div>').append(genButton).append(
  289. $("<a class='btn btn-primary mr-1' href='#' onclick='event.preventDefault()'>Customise Blog Theme</a>")
  290. .click(function(){config.open()})
  291. )
  292. );
  293. $( $(".profile-create-character-basics")[2] ).before(settingsBar);
  294. $(".wysiwyg-toggler")[0].click(); // Turn WYSIWYG back on
  295. });
  296. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement