🏠 Home 

TildaMustDie

Tilda must die. For real.


Install this script?
  1. // ==UserScript==
  2. // @name TildaMustDie
  3. // @namespace TildaMustDie
  4. // @version 1.3
  5. // @description Tilda must die. For real.
  6. // @author @sanyabeast
  7. // @match https://tilda.cc/*
  8. // @match https://tilda.cc/**/*
  9. // @match https://tilda.ws/*
  10. // @match https://tilda.ws/**/*
  11. // @match https://*.tilda.ws/*
  12. // @match https://*.*.tilda.ws/**/*
  13. // @match http://tilda.cc/*
  14. // @match http://tilda.cc/**/*
  15. // @match http://tilda.ws/*
  16. // @match http://tilda.ws/**/*
  17. // @match http://*.tilda.ws/*
  18. // @match http://*.*.tilda.ws/**/*
  19. // @grant none
  20. // ==/UserScript==
  21. (async function() {
  22. 'use strict';
  23. await append_script("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js");
  24. // some vars
  25. let help_text = `
  26. Hi! This I am TildaMustDie and I am going to help u to work with this so-called tool with less pain.
  27. [editor] | CTRL+SHIFT+H: Show this help alert
  28. [editor] | CTRL+S: Save project
  29. [editor] | CTRL+P: Publish project
  30. [editor] | CTRL+SHIFT+P: Save and publish project
  31. [editor] | CTRL+MouseWheel: Normal zooming as at good editors
  32. [editor] | CTRL+PLUS: Normal zooming (without page-zooming)
  33. [editor] | CTRL+Minus: Normal zooming (without page-zooming)
  34. [any] | Middle Mouse Key: Normal panning as at good editors
  35. [any] | Alt+Mousemove: Quick info about hovered element
  36. [page_editor]: DoubleClick on Code block to edit.
  37. [page_editor]: CTRL+S when code editor is open to save
  38. `;
  39. let state = {
  40. is_publishing: false,
  41. is_saving: false,
  42. is_help_box_shown: false,
  43. message_hiding_timeout_id: null,
  44. scroll_el: null,
  45. is_editor: window.location.href.indexOf('tilda.cc/zero') > -1,
  46. is_page_editor: window.location.href.indexOf('tilda.cc/page') > -1,
  47. is_r###lt: window.location.href.indexOf('tilda.ws') > -1,
  48. prev_mousedown_time: -1,
  49. dblclick_time: 300
  50. }
  51. console.log(`is_editor: ${state.is_editor} | is_page_editor: ${state.is_page_editor} | is_r###lt: ${state.is_r###lt}`)
  52. let mouse_events_target = state.is_page_editor?document.body:window
  53. let html_el = x_find("html");
  54. let non_passive = { passive: false };
  55. let middle_mouse_mouse_key_data = { pointer_x: 0, pointer_y: 0, pressed: false, last_el: null };
  56. // messaging setup
  57. let message_box = x_parse_html(`<div id='sb_message_box' class='sb_message_box' style='position:fixed;z-index:99999;bottom:0;right:0;background: black;color:white;height:32px;display:flex;align-items:center;justify-content:center;padding:0 24px;opacity:0.7;'><p style='margin:0;font-family:monospace;'></p></div>`);
  58. let help_box = x_parse_html(`<div id='sb_help_box' class='sb_help_box' style='z-index:9999;position:fixed;z-index:99999;top:0;left:0;background: black;color:white;height:auto;white-space:pre-wrap;display:flex;align-items:center;justify-content:center;padding:24px 24px;opacity:0.7;'><p style='margin:0;font-family:monospace;'></p></div>`);
  59. let frame_box = x_parse_html(`<div id="sb_frame_box" style="pointer-events:none;position:fixed;top:0;left:0;border:2px dotted red;display:flex;z-index:9999;"></div>`)
  60. message_box.style.zIndex = "none";
  61. help_box.style.display = "none";
  62. frame_box.style.display = "none"
  63. document.body.appendChild(message_box);
  64. document.body.appendChild(help_box);
  65. document.body.appendChild(frame_box);
  66. // disabling mousewheel based zooming
  67. console.log("%cHi! I am going to make Tilda (piece of shit) a little bit less shitfull", "color: red");
  68. window.addEventListener("mousewheel", (evt)=>{
  69. if (evt.ctrlKey && state.is_editor){
  70. console.log("Preventing default page-zooming (yeah Tilda`s shitmakers we don`t need it)");
  71. evt.preventDefault();
  72. evt.deltaY>0?window.tn_zoomOut():window.tn_zoomIn();
  73. }
  74. }, non_passive)
  75. // disabling ctrl-key based zooming
  76. window.addEventListener("keydown", (evt)=>{
  77. if (evt.ctrlKey){
  78. console.log(`Keydown: ${evt.keyCode}`);
  79. switch(evt.keyCode){
  80. case 83: //s save
  81. if (state.is_editor){
  82. evt.preventDefault();
  83. x_t_save();
  84. } else if (state.is_page_editor){
  85. let code_save_btn = x_find("button.tbtn-primary");
  86. if (code_save_btn){
  87. evt.preventDefault();
  88. x_fire_event(code_save_btn, "click");
  89. }
  90. }
  91. break;
  92. case 82: //r reload
  93. evt.preventDefault();
  94. if (state.is_editor) {
  95. console.log("reloading with clearing cache");
  96. window.location.reload();
  97. } else if (state.is_r###lt) {
  98. window.location.reload(true);
  99. } else {
  100. window.location.reload();
  101. }
  102. break;
  103. case 80: //p publish
  104. if (state.is_editor){
  105. evt.preventDefault();
  106. if (evt.shiftKey){
  107. console.log(1111);
  108. x_t_save();
  109. setTimeout(a=>x_t_publish(), 1000);
  110. } else {
  111. x_t_publish();
  112. }
  113. } else if (state.is_page_editor){
  114. evt.preventDefault();
  115. x_t_publish();
  116. }
  117. break;
  118. case 72: //h - help
  119. if (evt.shiftKey){
  120. evt.preventDefault();
  121. alert(help_text);
  122. }
  123. break;
  124. case 85: //u - find element
  125. if (evt.shiftKey){
  126. evt.preventDefault();
  127. let selector = prompt('Please enter valid CSS-Selector e.g #blabla or .class_a.class_b etc');
  128. let element = x_find(selector);
  129. if (element){
  130. x_s_show_help_box(element)
  131. } else {
  132. alert(`Element matching this selector "${selector}" was not found on the page`);
  133. }
  134. }
  135. break;
  136. }
  137. } else if (evt.altKey){
  138. evt.preventDefault();
  139. x_s_show_help_box(middle_mouse_mouse_key_data.last_el);
  140. }
  141. }, non_passive)
  142. window.addEventListener("keyup", (evt)=>{
  143. if (state.is_help_box_shown){
  144. x_s_hide_help_box();
  145. }
  146. }, non_passive)
  147. // disable default middle-key scrolling and enabling god-blessed scrolling by @sanyabeast
  148. mouse_events_target.addEventListener("mousedown", (evt)=>{
  149. middle_mouse_mouse_key_data.pointer_x = evt.screenX;
  150. middle_mouse_mouse_key_data.pointer_y = evt.screenY;
  151. if (evt.which === 2){
  152. evt.preventDefault();
  153. //middle_mouse_mouse_key_data.scroll_el = _.throttle(scroll_el, 1000/10)
  154. middle_mouse_mouse_key_data.scroll_el = x_s_scroll_el
  155. middle_mouse_mouse_key_data.pressed = true;
  156. }
  157. if (evt.which===1){
  158. let now = +new Date();
  159. if (now - state.prev_mousedown_time < state.dblclick_time){
  160. x_s_ondblclick(evt);
  161. }
  162. state.prev_mousedown_time = now;
  163. }
  164. }, non_passive);
  165. window.addEventListener("mousemove", (evt)=>{
  166. let x = evt.screenX;
  167. let y = evt.screenY;
  168. let dx = middle_mouse_mouse_key_data.pointer_x - x;
  169. let dy = middle_mouse_mouse_key_data.pointer_y - y;
  170. middle_mouse_mouse_key_data.pointer_x = x;
  171. middle_mouse_mouse_key_data.pointer_y = y;
  172. middle_mouse_mouse_key_data.last_el = evt.target
  173. if (evt.which === 2){
  174. evt.preventDefault();
  175. if (middle_mouse_mouse_key_data.pressed) {
  176. middle_mouse_mouse_key_data.scroll_el(html_el, dx, dy);
  177. }
  178. }
  179. }, non_passive )
  180. window.addEventListener("mouseup", (evt)=>{ if (evt.which === 2){ evt.preventDefault(); middle_mouse_mouse_key_data.pressed = false; } }, non_passive);
  181. // ####ing tilda tools
  182. function x_t_get_page_id(){ return (new URLSearchParams(window.location.search)).get('pageid') }
  183. function x_t_save(){
  184. if (state.is_saving){
  185. return
  186. }
  187. state.is_saving = true
  188. x_s_show_message('saving...', 2);
  189. let btn = x_find(".tn-save-btn");
  190. x_fire_event(btn, "click");
  191. state.is_saving = false
  192. }
  193. function x_t_publish(){
  194. if ( state.is_publishing){
  195. return true;
  196. }
  197. state.is_publishing = true
  198. let pageid = x_t_get_page_id();
  199. let iframe_url = `https://tilda.cc/page/?pageid=${pageid}`
  200. x_s_show_message(`publishing: ${iframe_url}`, 10);
  201. let iframe = x_parse_html(`
  202. <iframe sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
  203. src="${iframe_url}"
  204. style="z-index: 9999;border: 2px solid black; width:600px; height:600px; position: absolute; top: 16px; left: 16px; display: none;"></iframe>
  205. `);
  206. document.body.appendChild(iframe);
  207. console.dir(iframe);
  208. x_s_wait_async(a=>typeof iframe.contentWindow.pagePublish==="function", 10, ()=>{
  209. iframe.contentWindow.pagePublish();
  210. x_s_show_message('PUBLISHED', 4);
  211. setTimeout((a)=>{
  212. iframe.remove();
  213. state.is_publishing = false
  214. }, 2000);
  215. }, ()=>{
  216. x_s_show_message('NOT PUBLISHED:(', 4);
  217. iframe.remove();
  218. state.is_publishing = false
  219. })
  220. }
  221. //service tools
  222. function x_s_ondblclick(evt){
  223. if (state.is_page_editor && evt.target.tagName === "PRE") {
  224. let record_el = evt.target.closest(".record")
  225. let edit_btn = record_el.querySelector(".tp-record-edit-icons-left__three .tp-record-edit-icons-left__item");
  226. x_fire_event(edit_btn, "click");
  227. }
  228. }
  229. function x_s_get_element_brief(el, rect){
  230. let r###lt = ""
  231. let styles = window.getComputedStyle(el);
  232. let id = el.getAttribute('id');
  233. let classes = el.getAttribute('class');
  234. rect = rect || el.getBoundingClientRect();
  235. return [
  236. `ID: ${id}`,
  237. `DATA-ELEM-ID: ${el.getAttribute('data-elem-id')}`,
  238. `CLASSES: ${classes}`,
  239. `Z-INDEX: ${el.style.zIndex||styles.zIndex}`,
  240. `LEFT/TOP: ${Math.ceil(rect.x)}px/${Math.ceil(rect.y)}px`,
  241. `RIGHT/BOTTOM: ${Math.ceil(rect.right)}px/${Math.ceil(rect.bottom)}px`,
  242. `WIDTH/HEIGHT: ${Math.ceil(rect.width)}px/${Math.ceil(rect.height)}px`,
  243. ].join('\n')
  244. }
  245. function x_s_show_help_box(last_el){
  246. if (!last_el){
  247. return;
  248. }
  249. state.is_help_box_shown = true;
  250. let mx = middle_mouse_mouse_key_data.pointer_x;
  251. let my = middle_mouse_mouse_key_data.pointer_y;
  252. let rect = last_el.getBoundingClientRect();
  253. frame_box.style.transform = `translate(${rect.x}px, ${rect.y}px)`;
  254. frame_box.style.width = `${rect.width}px`;
  255. frame_box.style.height = `${rect.height}px`;
  256. help_box.style.display = "flex"
  257. frame_box.style.display = "flex"
  258. help_box.children[0].innerHTML = x_s_get_element_brief(last_el, rect);
  259. help_box.style.transform = `translate(${mx}px, ${my}px)`;
  260. }
  261. function x_s_hide_help_box(){
  262. console.log('hide');
  263. help_box.style.display = "none";
  264. frame_box.style.display = "none";
  265. state.is_help_box_shown = false;
  266. }
  267. function x_s_scroll_el(el, dx, dy){
  268. //console.log(dx, dy)
  269. el.scrollLeft = el.scrollLeft + dx;
  270. el.scrollTop = el.scrollTop + dy;
  271. }
  272. function x_s_show_greetings(){
  273. x_s_show_message(`Wuzzup! I am TildaMustDie! Need help? Press CTRL+SHIFT+H`, 4);
  274. }
  275. function x_s_wait_async(check, max_timeout, on_complete, on_error){
  276. max_timeout = max_timeout || 1;
  277. let start_date = +new Date();
  278. let end_date = start_date + (max_timeout*1000);
  279. let is_successfull = false;
  280. let interval_id = setInterval(()=>{
  281. if (+new Date() < end_date){
  282. if(check()){
  283. on_complete();
  284. is_successfull = true;
  285. clearInterval(interval_id);
  286. }
  287. } else {
  288. clearInterval(interval_id);
  289. if (!is_successfull){ on_error && on_error(); }
  290. }
  291. }, 1000/5);
  292. }
  293. function x_s_show_message(message, timeout){
  294. timeout = timeout || 3;
  295. clearTimeout(state.message_hiding_timeout_id);
  296. message_box.children[0].innerHTML = message;
  297. message_box.style.display = "flex";
  298. state.message_hiding_timeout_id = setTimeout(()=>{
  299. message_box.style.display = "none";
  300. }, timeout*1000)
  301. }
  302. //page tools
  303. async function append_script(url) {
  304. let head = document.getElementsByTagName('head')[0];
  305. let theScript = document.createElement('script');
  306. theScript.type = 'text/javascript';
  307. theScript.src = url;
  308. head.appendChild(theScript);
  309. }
  310. function x_parse_html(html){ let div = document.createElement('div'); div.innerHTML = html; return div.children[0]; }
  311. function x_create_iframe(){};
  312. function x_fire_event(el, etype){ let evt_o = document.createEvent('Events');evt_o.initEvent(etype, true, false);el.dispatchEvent(evt_o); }
  313. function x_find(selector){ return document.querySelector(selector) }
  314. function x_find_all(selector){ return document.querySelector(selector) }
  315. function x_check_all_elements(checker, root_el, r###lt){
  316. r###lt = r###lt || [];
  317. root_el = root_el || document.body;
  318. if (checker(root_el)){ r###lt.push(root_el); }
  319. _.forEach(root_el.children, (child_el, index)=>{
  320. x_check_all_elements(checker, child_el, r###lt);
  321. })
  322. return r###lt;
  323. }
  324. function x_find_scrollable_elements(root_el, r###lt) { return x_check_all_elements((el)=>{ return el.scrollTop>0||el.scrollLeft>0}, root_el, r###lt) }
  325. window.html_el = html_el
  326. //
  327. window.x_s_wait_async = x_s_wait_async;
  328. window.x_s_show_message = x_s_show_message;
  329. // adding everythin to global
  330. window.x_t_get_page_id = x_t_get_page_id;
  331. //
  332. window.x_check_all_elements = x_check_all_elements;
  333. window.x_find_scrollable_elements = x_find_scrollable_elements;
  334. window.x_fire_event = x_fire_event;
  335. window.x_find = x_find;
  336. window.x_find_all = x_find_all;
  337. window.x_find_all = x_find_all;
  338. x_s_show_greetings()
  339. })();