1. 1 : import { MelHtml } from "../../html/JsHtml/MelHtml.js";
  2. 2 : import { MaterialSymbolHtml } from "../../html/html_icon.js";
  3. 3 : import { MelObject } from "../../mel_object.js";
  4. 4 :
  5. 5 : function find_parent(node, cond) {
  6. 6 : while ((!cond(node)) || node[0].nodeName === 'BODY') {
  7. 7 : node = node.parent();
  8. 8 : }
  9. 9 :
  10. 10 : return node[0].nodeName === 'BODY' ? false : node;
  11. 11 : }
  12. 12 :
  13. 13 : function string_rgb_to_hex(rgb){
  14. 14 : if (rgb.includes('(')) {
  15. 15 : rgb = rgb.split('(');
  16. 16 : rgb = rgb[1].replace(')', '');
  17. 17 : rgb = rgb.split(',');
  18. 18 :
  19. 19 : let hex = '#';
  20. 20 :
  21. 21 : for (const iterator of rgb) {
  22. 22 : hex += componentToHex(+iterator);
  23. 23 : }
  24. 24 :
  25. 25 : rgb = hex;
  26. 26 : }
  27. 27 :
  28. 28 : return rgb;
  29. 29 : }
  30. 30 :
  31. 31 : MelHtml.extend('button_note', function (attribs = {}) {
  32. 32 : return this.button(attribs)
  33. 33 : .addClass(MaterialSymbolHtml.get_class_fill_on_hover())
  34. 34 : .addClass('bckg')
  35. 35 : .addClass('true')
  36. 36 : .css({
  37. 37 : border:'none!important',
  38. 38 : 'border-radius':'0px!important',
  39. 39 : transition:'none'
  40. 40 : })
  41. 41 : .attr('onmouseenter', function (e) {
  42. 42 : e = $(e.currentTarget);
  43. 43 :
  44. 44 : let parent = find_parent(e, (x) => x.hasClass('mel-note'));
  45. 45 :
  46. 46 : if (!parent) throw new Error('Unable to found parent !');
  47. 47 :
  48. 48 : const note_color = string_rgb_to_hex(parent.attr('data-textcolor'));
  49. 49 :
  50. 50 : console.log('color', note_color, parent.attr('data-textcolor'));
  51. 51 :
  52. 52 : const bckg_color = string_rgb_to_hex(e.css('background-color'));
  53. 53 : const color = mel_metapage.Functions.colors.kMel_extractRGB(note_color);
  54. 54 : const background = mel_metapage.Functions.colors.kMel_extractRGB(bckg_color);
  55. 55 :
  56. 56 : console.log('ratio', mel_metapage.Functions.colors.kMel_CompareLuminance(color, background), color, background);
  57. 57 :
  58. 58 : if (!mel_metapage.Functions.colors.kMel_LuminanceRatioAAA(color, background)) {
  59. 59 : e.css('color', invertColor(note_color, true));
  60. 60 : }
  61. 61 :
  62. 62 : })
  63. 63 : .attr('onmouseleave', function (e) {
  64. 64 : e = $(e.currentTarget);
  65. 65 : let parent = find_parent(e, (x) => x.hasClass('mel-note'));
  66. 66 :
  67. 67 : if (!parent) throw new Error('Unable to found parent !');
  68. 68 :
  69. 69 : const note_color = string_rgb_to_hex(parent.attr('data-textcolor'));
  70. 70 :
  71. 71 : e.css('color', note_color);
  72. 72 : });
  73. 73 : });
  74. 74 :
  75. 75 : /**
  76. 76 : * Plugin qui contient la localization pour rcmail.gettext
  77. 77 : */
  78. 78 : const plugin_text = 'mel_metapage';
  79. 79 :
  80. 80 : /**
  81. 81 : * Couleur d'arrière plan de base
  82. 82 : */
  83. 83 : const base_color = "#E6B905";
  84. 84 : /**
  85. 85 : * Couleur du texte de base
  86. 86 : */
  87. 87 : const base_text_color = "#000000";
  88. 88 : /**
  89. 89 : * Id par défaut lorsqu'il n'y a pas de notes
  90. 90 : */
  91. 91 : export const default_note_uid = 'create';
  92. 92 :
  93. 93 : /**
  94. 94 : * Change une valeur en hexadécimal
  95. 95 : * @param {number} c Valeur décimale
  96. 96 : * @returns Valeur hexadécimal
  97. 97 : */
  98. 98 : function componentToHex(c) {
  99. 99 : var hex = c.toString(16);
  100. 100 : return hex.length == 1 ? "0" + hex : hex;
  101. 101 : }
  102. 102 :
  103. 103 : /**
  104. 104 : * Récupère la valeur hexadécimal d'un rgb.
  105. 105 : * @param {number} r Valeur rouge
  106. 106 : * @param {number} g Valeur vert
  107. 107 : * @param {number} b Valeur bleu
  108. 108 : * @returns Hexadécimal
  109. 109 : */
  110. 110 : function rgbToHex(r, g, b) {
  111. 111 : return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
  112. 112 : }
  113. 113 :
  114. 114 : function padZero(str, len) {
  115. 115 : len = len || 2;
  116. 116 : var zeros = new Array(len).join('0');
  117. 117 : return (zeros + str).slice(-len);
  118. 118 : }
  119. 119 :
  120. 120 : function invertColor(hex, bw) {
  121. 121 : if (hex.indexOf('#') === 0) {
  122. 122 : hex = hex.slice(1);
  123. 123 : }
  124. 124 : // convert 3-digit hex to 6-digits.
  125. 125 : if (hex.length === 3) {
  126. 126 : hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
  127. 127 : }
  128. 128 : if (hex.length !== 6) {
  129. 129 : throw new Error('Invalid HEX color.');
  130. 130 : }
  131. 131 : var r = parseInt(hex.slice(0, 2), 16),
  132. 132 : g = parseInt(hex.slice(2, 4), 16),
  133. 133 : b = parseInt(hex.slice(4, 6), 16);
  134. 134 : if (bw) {
  135. 135 : // https://stackoverflow.com/a/3943023/112731
  136. 136 : return (r * 0.299 + g * 0.587 + b * 0.114) > 186
  137. 137 : ? '#000000'
  138. 138 : : '#FFFFFF';
  139. 139 : }
  140. 140 : // invert color components
  141. 141 : r = (255 - r).toString(16);
  142. 142 : g = (255 - g).toString(16);
  143. 143 : b = (255 - b).toString(16);
  144. 144 : // pad each with zeros and return
  145. 145 : return "#" + padZero(r) + padZero(g) + padZero(b);
  146. 146 : }
  147. 147 :
  148. 148 : /**
  149. 149 : * Représentation et fonctions utile d'une note
  150. 150 : */
  151. 151 : export class Sticker
  152. 152 : {
  153. 153 : /**
  154. 154 : *
  155. 155 : * @param {string} uid Id de la note
  156. 156 : * @param {number} order Ordre de la note
  157. 157 : * @param {string} title Titre de la note
  158. 158 : * @param {string} text Contenu de la note
  159. 159 : * @param {string} color Couleur de la note
  160. 160 : * @param {string} text_color Couleur du texte de la note
  161. 161 : */
  162. 162 : constructor(uid, order, title, text, color = base_color, text_color = base_text_color, tak = false)
  163. 163 : {
  164. 164 : this.uid = uid;
  165. 165 : this.order = +(order);
  166. 166 : this.title = title;
  167. 167 : this.text = text;
  168. 168 : this.color = color;
  169. 169 : this.textcolor = text_color;
  170. 170 : this.pin = tak;
  171. 171 :
  172. 172 : if (typeof this.pin === 'string') this.pin = this.pin === 'true';
  173. 173 : }
  174. 174 :
  175. 175 : /**
  176. 176 : * Convertit la classe en html
  177. 177 : * @returns html
  178. 178 : */
  179. 179 : html(hidden = false)
  180. 180 : {
  181. 181 : const generate_style = () => {
  182. 182 : let html = `background-color:${this.color};color:${this.textcolor};`;
  183. 183 :
  184. 184 : if (hidden) html += 'display:none;';
  185. 185 :
  186. 186 : return html;
  187. 187 : };
  188. 188 :
  189. 189 : const html_js = MelHtml.start
  190. 190 : .div({class:"mel-note", style:generate_style(), id:`note-${this.uid}`}).attrs(this.get_datas())
  191. 191 : .div({class:"note-header"})
  192. 192 : .table()
  193. 193 : .tr()
  194. 194 : .td()
  195. 195 : .button_note(this._generate_buttons_attributes('takb', 'Afficher sur le Bnum', {})).css('border-radius', '5px 0 0 0!important')
  196. 196 : .icon('push_pin').end()
  197. 197 : .sr()
  198. 198 : .text('Afficher sur le Bnum - Affiche la note en avant plan sur le bureau numérique. Cela permet d\'avoir toujours la note en visu.')
  199. 199 : .end('sr')
  200. 200 : .end('epingler')
  201. 201 : .end('td')
  202. 202 : .td().css('width', '100%')
  203. 203 : .input_text({class:'change mel-focus', title: 'Titre de la note', 'aria-describedby': this.uid, value: this.title}).css({width: '100%', 'background-color': this.color, 'color': this.textcolor})
  204. 204 : .end('td 100%')
  205. 205 : .td()
  206. 206 : .button_note(this._generate_buttons_attributes('pb', rcmail.gettext('settings', plugin_text), {}))
  207. 207 : .icon('more_horiz').end()
  208. 208 : .sr()
  209. 209 : .text(`${plugin_text}.settings`)
  210. 210 : .end('sr')
  211. 211 : .end('paramètres')
  212. 212 : .end('td')
  213. 213 : .td()
  214. 214 : .button_note(this._generate_buttons_attributes('db danger', rcmail.gettext('delete'), {})).css('border-radius', '0 5px 0 0!important')
  215. 215 : .icon('delete_forever').end()
  216. 216 : .sr()
  217. 217 : .text('delete')
  218. 218 : .end('sr')
  219. 219 : .end('Supprimer')
  220. 220 : .end('td')
  221. 221 : .end('tr')
  222. 222 : .end('table')
  223. 223 : .end('div')
  224. 224 : .div({class:'note-header-params'}).css('display', 'none')
  225. 225 : .input_color(`title="${rcmail.gettext('change_background_color', plugin_text)}" aria-describedby="${this.uid}" class="change bcgcolor" value="${this.color === base_color ? this.color : rgbToHex(...Enumerable.from(this.color.replace('!important', '').replace('rgb', "").replace('a', '').replace('(', '').replace(')', '').split(',')).select(x => parseInt(x)).toArray())}"`).removeClass('form-control').removeClass('input-mel')
  226. 226 : .input_color(`title="${rcmail.gettext('change_text_color', plugin_text)}" aria-describedby="${this.uid}" class="change txtcolor" value="${this.textcolor === base_text_color ? this.textcolor : rgbToHex(...Enumerable.from(this.textcolor.replace('rgb', "").replace('a', '').replace('(', '').replace(')', '').split(',')).select(x => parseInt(x)).toArray())}"`).removeClass('form-control').removeClass('input-mel')
  227. 227 : .button_note(this._generate_buttons_attributes('bb', rcmail.gettext('quit_settings', plugin_text), {})).css('float', 'right').css('border-radius', '0 5px 0 0!important')
  228. 228 : .icon('arrow_back').end()
  229. 229 : .sr()
  230. 230 : .text(`${plugin_text}.quit_settings`)
  231. 231 : .end('sr')
  232. 232 : .end('retour')
  233. 233 : .button_note(this._generate_buttons_attributes('downb', rcmail.gettext('move', plugin_text), {})).css('float', 'right')
  234. 234 : .icon('drag_pan').end()
  235. 235 : .sr()
  236. 236 : .text(`${plugin_text}.move`)
  237. 237 : .end('sr')
  238. 238 : .end('Déplacer')
  239. 239 : .button_note(this._generate_buttons_attributes('rsb', 'Réinitialiser la taille de la note', {})).css('float', 'right')
  240. 240 : .icon('fullscreen_exit').end()
  241. 241 : .sr()
  242. 242 : .text('Réinitialiser la taille de la note')
  243. 243 : .end('sr')
  244. 244 : .end('Taille')
  245. 245 : .end('params')
  246. 246 : .div({class:'note-body'})
  247. 247 : .textarea({rows:5, title:'Ecrivez vos notes dans ce champ', class:'change', style:`width:100%;background-color:${this.color};color:${this.textcolor};${(!!this.height ? `height:${this.height}px;` : '')}`})
  248. 248 : .text(this.text)
  249. 249 : .end()
  250. 250 : .end()
  251. 251 : .end()
  252. 252 : ;
  253. 253 :
  254. 254 : return html_js.generate();
  255. 255 : }
  256. 256 :
  257. 257 : _generate_buttons_attributes(button_class, title, {additionnal_style = ''}){
  258. 258 : return {
  259. 259 : title,
  260. 260 : 'aria-describedby':this.uid,
  261. 261 : class:`${MaterialSymbolHtml.get_class_fill_on_hover()} mel-button no-button-margin bckg true ${button_class}`,
  262. 262 : style:`color:${this.textcolor};${additionnal_style}`
  263. 263 : };
  264. 264 : }
  265. 265 :
  266. 266 : /**
  267. 267 : * Récupère l'élément lié à la note
  268. 268 : * @returns Jquery
  269. 269 : */
  270. 270 : get_html()
  271. 271 : {
  272. 272 : return $(`.mel-note#note-${this.uid}`);
  273. 273 : }
  274. 274 :
  275. 275 : /**
  276. 276 : * Défini le bon comportement de la note.
  277. 277 : * @returns Chaînage
  278. 278 : */
  279. 279 : set_handlers()
  280. 280 : {
  281. 281 : let $element = this.get_html();
  282. 282 :
  283. 283 : $element.on('mousedown', () => {
  284. 284 : this._tmp_height = $element.find('textarea').height();
  285. 285 : })
  286. 286 : .on('mouseup', () => {
  287. 287 : const th = $element.find('textarea').height();
  288. 288 : if (th !== this._tmp_height)
  289. 289 : {
  290. 290 : this.post_height_updated(th);
  291. 291 : }
  292. 292 :
  293. 293 : delete this._tmp_height;
  294. 294 : });
  295. 295 :
  296. 296 : $element.find('button.rsb').click(() => {
  297. 297 : $element.find('textarea').css('height', '');
  298. 298 : if (this.uid !== default_note_uid) this.post_height_updated(-1);
  299. 299 : });
  300. 300 :
  301. 301 : //Handler pour le bouton créer
  302. 302 : $element.find("button.nb").click(async () => {
  303. 303 :
  304. 304 : if (rcmail.busy === true) return;
  305. 305 :
  306. 306 : rcmail.set_busy(true, "loading");
  307. 307 : $element.find(".change").addClass("disabled").attr("disabled", "disabled");
  308. 308 : //$element.find("textarea").addClass("disabled").attr("disabled", "disabled");
  309. 309 :
  310. 310 : if (this.uid === default_note_uid) await this.post_add();
  311. 311 :
  312. 312 : let sticker = Sticker.fromHtml(this.uid);
  313. 313 : sticker.text = "";
  314. 314 : sticker.title = "";
  315. 315 : await sticker.post_add();
  316. 316 :
  317. 317 : rcmail.set_busy(false);
  318. 318 : $element.find(".change").removeClass("disabled").removeAttr("disabled");
  319. 319 : //$element.find("textarea").removeClass("disabled").removeAttr("disabled");
  320. 320 : rcmail.clear_messages();
  321. 321 : rcmail.display_message(rcmail.gettext('note_created_success', plugin_text), "confirmation");
  322. 322 : });
  323. 323 :
  324. 324 : if (this.pin) $element.find('.takb').find('.material-symbols-outlined').css('font-variation-settings', "'FILL' 1");
  325. 325 :
  326. 326 : $element.find('.takb').click(async () => {
  327. 327 : let $item = this.uid.includes('pin-') ? Sticker.fromHtml(this.uid.replace('pin-', '')).get_html() : [];
  328. 328 :
  329. 329 : this.pin = !this.pin;
  330. 330 : rcmail.env.mel_metapages_notes[this.uid.replace('pin-', '')].pin = this.pin;
  331. 331 :
  332. 332 : if (this.pin)
  333. 333 : {
  334. 334 : $element.find('.takb').find('.material-symbols-outlined').css('font-variation-settings', "'FILL' 1");
  335. 335 : if ($item.length > 0) $item.find('.takb').find('.material-symbols-outlined').css('font-variation-settings', "'FILL' 1");
  336. 336 : }
  337. 337 : else {
  338. 338 : $element.find('.takb').find('.material-symbols-outlined').css('font-variation-settings', '');
  339. 339 : if ($item.length > 0) $item.find('.takb').find('.material-symbols-outlined').css('font-variation-settings', '');
  340. 340 : }
  341. 341 :
  342. 342 : await this.post('pin', {
  343. 343 : _uid:this.uid.replace('pin-', ''),
  344. 344 : _pin:this.pin
  345. 345 : });
  346. 346 :
  347. 347 : Sticker.helper.trigger_event('notes.apps.tak', this);
  348. 348 :
  349. 349 : })
  350. 350 :
  351. 351 : $element.find('button.eye').click((e) => {
  352. 352 : e = $(e.currentTarget);
  353. 353 : if (!e.hasClass('crossed'))
  354. 354 : {
  355. 355 : $('.mel-note').css('display', 'none');
  356. 356 : $element.css('display', '');
  357. 357 : $('.mm-shortcuts.apps .square_div').css('display', 'none');
  358. 358 : $('.shortcut-notes').css('display', '').css('max-width', '100%').css('width', '100%').css('margin','0 20%');
  359. 359 : $('.fullscreen-item-flex').css('display', 'block');
  360. 360 : $('.nb').addClass('disabled').attr('disabled', 'disabled');
  361. 361 : $('.downb').css('display', 'none');
  362. 362 : $('.upb').css('display', 'none');
  363. 363 : e.addClass('crossed').find(`.material-symbols-outlined`).html('visibility_off');
  364. 364 : this.get_html().addClass('eye-focus');
  365. 365 : }
  366. 366 : else {
  367. 367 : $('.mel-note').css('display', '');
  368. 368 : $('.mm-shortcuts.apps .square_div').css('display', '');
  369. 369 : $('.shortcut-notes').css('display', '').css('max-width', '').css('width', '').css('margin', '');
  370. 370 : $('.fullscreen-item-flex').css('display', 'flex');
  371. 371 : $('.nb').removeClass('disabled').removeAttr('disabled');
  372. 372 : $('.downb').css('display', '');
  373. 373 : $('.upb').css('display', '');
  374. 374 : e.removeClass('crossed').find(`.material-symbols-outlined`).html('visibility');//.find('.icon-mel-eye-crossed').addClass('icon-mel-eye').removeClass('icon-mel-eye-crossed');
  375. 375 : this.get_html().removeClass('eye-focus');
  376. 376 : }
  377. 377 :
  378. 378 :
  379. 379 : });
  380. 380 :
  381. 381 : //Handler pour le bouton paramètre
  382. 382 : $element.find("button.pb").click(() => {
  383. 383 : $element.css("width", $element.width() + "px");
  384. 384 : $element.find(".note-header").css("display", "none");
  385. 385 : $element.find(".note-header-params").css("display", "");
  386. 386 : })
  387. 387 :
  388. 388 : //Handler pour le bouton retour
  389. 389 : $element.find("button.bb").click(() => {
  390. 390 : $element.find(".note-header").css("display", "");
  391. 391 : $element.find(".note-header-params").css("display", "none");
  392. 392 : $element.css("width", '');
  393. 393 : })
  394. 394 :
  395. 395 : //Handler pour le bouton supprimer
  396. 396 : $element.find("button.db").click(async () => {
  397. 397 :
  398. 398 : if (rcmail.busy === true) return;
  399. 399 :
  400. 400 : if (this.uid === default_note_uid)
  401. 401 : {
  402. 402 : rcmail.display_message(rcmail.gettext('note_reinit_success', plugin_text), "confirmation");
  403. 403 : return;
  404. 404 : }
  405. 405 :
  406. 406 : rcmail.set_busy(true, "loading");
  407. 407 : $element.find(".change").addClass("disabled").attr("disabled", "disabled");
  408. 408 : //$element.find("textarea").addClass("disabled").attr("disabled", "disabled");
  409. 409 :
  410. 410 : await this.post_delete();
  411. 411 :
  412. 412 : rcmail.set_busy(false);
  413. 413 : $element.find(".change").removeClass("disabled").removeAttr("disabled");
  414. 414 : //$element.find("textarea").removeClass("disabled").removeAttr("disabled");
  415. 415 : rcmail.clear_messages();
  416. 416 : rcmail.display_message(rcmail.gettext('note_deleted_success', plugin_text), "confirmation");
  417. 417 : });
  418. 418 :
  419. 419 : //Handler pour les modifications
  420. 420 : $element.find(".change").on('change', async () => {
  421. 421 :
  422. 422 : const isCreate = this.uid === default_note_uid;
  423. 423 : if (isCreate)
  424. 424 : {
  425. 425 : if (rcmail.busy === true) return;
  426. 426 :
  427. 427 : rcmail.set_busy(true, "loading");
  428. 428 : $element.find(".change").addClass("disabled").attr("disabled", "disabled");
  429. 429 : }
  430. 430 :
  431. 431 : $element.css("color", $element.find("input.txtcolor").val());//bcgcolor
  432. 432 : $element.css("background-color", $element.find("input.bcgcolor").val());
  433. 433 :
  434. 434 : $element.find(".note-header input")
  435. 435 : .css("color", $element.find("input.txtcolor").val())
  436. 436 : .css("background-color", $element.find("input.bcgcolor").val());
  437. 437 :
  438. 438 : $element.find("textarea")
  439. 439 : .css("color", $element.find("input.txtcolor").val())
  440. 440 : .css("background-color", $element.find("input.bcgcolor").val());
  441. 441 :
  442. 442 : $element.find("button").css("color", $element.find("input.txtcolor").val());
  443. 443 :
  444. 444 : this.title = $element.find(".note-header input").val();
  445. 445 : this.text = $element.find("textarea").val();
  446. 446 : this.color = $element.css("background-color");
  447. 447 : this.textcolor = $element.css("color");
  448. 448 :
  449. 449 : $element.attr('data-textcolor', this.textcolor);
  450. 450 :
  451. 451 : await this.post_update();
  452. 452 :
  453. 453 : if (isCreate)
  454. 454 : {
  455. 455 : rcmail.set_busy(false);
  456. 456 : $element.find(".change").removeClass("disabled").removeAttr("disabled");
  457. 457 : rcmail.clear_messages();
  458. 458 : rcmail.display_message(rcmail.gettext('note_created_success', plugin_text), "confirmation");
  459. 459 : }
  460. 460 : else {
  461. 461 : Sticker.helper.rcmail().display_message('Note sauvegardée avec succès !', 'confirmation');
  462. 462 : }
  463. 463 : });
  464. 464 :
  465. 465 : let $down = $element.find('.downb');
  466. 466 :
  467. 467 : //Handler pour le bouton "descendre"
  468. 468 : if ($down.length > 0)
  469. 469 : {
  470. 470 : $down.attr('draggable', true)[0].addEventListener("dragstart", (ev) => {
  471. 471 : if (!!Sticker.lock) {
  472. 472 : ev.preventDefault();
  473. 473 : rcmail.display_message('Une action est déjà en cours !');
  474. 474 : return;
  475. 475 : }
  476. 476 : ev.dataTransfer.dropEffect = "move";
  477. 477 :
  478. 478 : var img = new Image();
  479. 479 : img.src = window.location.origin + window.location.pathname + 'plugins/mel_metapage/skins/sticker.png';
  480. 480 : ev.dataTransfer.setDragImage(img, 10, 10);
  481. 481 :
  482. 482 : ev.dataTransfer.setData("text/plain", this.uid);
  483. 483 : //console.log('drag&drop', ev);
  484. 484 : });
  485. 485 :
  486. 486 : $down[0].addEventListener("dragend", (ev) => {
  487. 487 : $('.mel-note.dragover').removeClass('dragover')
  488. 488 : .removeClass('dragover-right')
  489. 489 : .removeClass('dragover-left');
  490. 490 : });
  491. 491 : }
  492. 492 :
  493. 493 : // //Handler pour le bouton "monter"
  494. 494 : // if (hasUp)
  495. 495 : // {
  496. 496 : // $element.find('.upb').click(async () => {
  497. 497 : // if (rcmail.busy === true) return;
  498. 498 :
  499. 499 : // rcmail.set_busy(true, "loading");
  500. 500 : // $(".shortcut-notes .change").addClass("disabled").attr("disabled", "disabled");
  501. 501 : // //$element.find("textarea").addClass("disabled").attr("disabled", "disabled");
  502. 502 : // await this.post_move_up(Sticker.findByOrder(this.order - 1).uid);
  503. 503 :
  504. 504 : // rcmail.set_busy(false);
  505. 505 : // $(".shortcut-notes .change").removeClass("disabled").removeAttr("disabled");
  506. 506 : // //$element.find("textarea").removeClass("disabled").removeAttr("disabled");
  507. 507 : // rcmail.clear_messages();
  508. 508 : // rcmail.display_message(rcmail.gettext('note_move_success', plugin_text), "confirmation");
  509. 509 : // });
  510. 510 : // }
  511. 511 : // else $element.find('.upb').addClass("disabled").attr("disabled", "disabled");
  512. 512 :
  513. 513 : // $element[0].addEventListener("dragstart", (ev) => {
  514. 514 : // if (!!Sticker.lock) {
  515. 515 : // ev.preventDefault();
  516. 516 : // rcmail.display_message('Une action est déjà en cours !');
  517. 517 : // return;
  518. 518 : // }
  519. 519 : // ev.dataTransfer.dropEffect = "move";
  520. 520 : // ev.dataTransfer.setData("text/plain", this.uid);
  521. 521 : // console.log('drag&drop', ev);
  522. 522 : // });
  523. 523 :
  524. 524 : // $element.on('drop', (ev) => {
  525. 525 : // ev.dataTransfer.dropEffect = "move";
  526. 526 : // console.log('drop', ev);
  527. 527 : // });
  528. 528 :
  529. 529 : // $element.on('dragover', (ev) => {
  530. 530 : // console.log('dragover', ev);
  531. 531 : // });
  532. 532 :
  533. 533 : return this;
  534. 534 : }
  535. 535 :
  536. 536 : /**
  537. 537 : * Affiche sous forme de string certaines données pour le html
  538. 538 : * @returns id & data-order
  539. 539 : */
  540. 540 : get_datas(){
  541. 541 : return {
  542. 542 : id:`note-${this.uid}`,
  543. 543 : 'data-textcolor': this.textcolor,
  544. 544 : 'data-order': this.order,
  545. 545 : 'data-pin': this.pin
  546. 546 : }
  547. 547 : }
  548. 548 :
  549. 549 : /**
  550. 550 : * Créer une note
  551. 551 : * @returns Ajax
  552. 552 : */
  553. 553 : post_add()
  554. 554 : {
  555. 555 : return this.post("add", {_raw:this})
  556. 556 : }
  557. 557 :
  558. 558 : async drop(uid, new_order) {
  559. 559 : await this.post('drag_move', {_uid:uid, _order:new_order});
  560. 560 : }
  561. 561 :
  562. 562 : /**
  563. 563 : * Change l'ordre de la note par rapport à une autre note
  564. 564 : * @param {string} uid Id de la note
  565. 565 : * @param {number} order Nouvel ordre de la note
  566. 566 : * @param {Sticker} other Autre note
  567. 567 : */
  568. 568 : async _post_move(uid, order, other)
  569. 569 : {
  570. 570 : //On change l'ordre de la note
  571. 571 : await this.post("move", {_uid:uid, _order:order});
  572. 572 : //puis de l'autre note
  573. 573 : await other.post("move", {_uid:other.uid, _order:other.order});
  574. 574 : //Puis on récupère tout pour éviter les bugs
  575. 575 : await this.post("get");/*.done((e) => {
  576. 576 :
  577. 577 : rcmail.env.mel_metapages_notes = JSON.parse(e);
  578. 578 :
  579. 579 : if (Enumerable.from(rcmail.env.mel_metapages_notes).count() === 0)
  580. 580 : {
  581. 581 : rcmail.env.mel_metapages_notes = {
  582. 582 : "create":new Sticker("create", 0, "", "")
  583. 583 : };
  584. 584 : }
  585. 585 :
  586. 586 : // const html = this.html();
  587. 587 : // other = Sticker.fromHtml(other.uid);
  588. 588 : // const other_html = other.html();
  589. 589 : // let $other = other.get_html();
  590. 590 : // let $this = this.get_html();
  591. 591 : // $this[0].outerHTML = other_html;
  592. 592 : // $other[0].outerHTML = html;
  593. 593 : // other.set_handlers();
  594. 594 : // this.set_handlers();
  595. 595 :
  596. 596 : this.trigger_event('notes.apps.updated', rcmail.env.mel_metapages_notes);
  597. 597 : });*/
  598. 598 : }
  599. 599 :
  600. 600 : /**
  601. 601 : * Descend la note
  602. 602 : * @param {string} $uid Id de l'autre note
  603. 603 : * @returns Ajax
  604. 604 : */
  605. 605 : post_move_down($uid)
  606. 606 : {
  607. 607 : this.order += 1;
  608. 608 : let other = Sticker.fromHtml($uid);
  609. 609 : other.order -= 1;
  610. 610 : return this._post_move(this.uid, this.order, other);
  611. 611 : }
  612. 612 : /**
  613. 613 : * Monte la note
  614. 614 : * @param {string} $uid Id de l'autre note
  615. 615 : * @returns Ajax
  616. 616 : */
  617. 617 : post_move_up($uid)
  618. 618 : {
  619. 619 : this.order -= 1;
  620. 620 : let other = Sticker.fromHtml($uid);
  621. 621 : other.order += 1;
  622. 622 : return this._post_move(this.uid, this.order, other);
  623. 623 : }
  624. 624 :
  625. 625 : /**
  626. 626 : * Supprime la note
  627. 627 : * @returns {Promise<any>|null} Ajax
  628. 628 : */
  629. 629 : async post_delete()
  630. 630 : {
  631. 631 : if (this.uid === default_note_uid) return;
  632. 632 :
  633. 633 : if (this.get_html().find('.icon-mel-eye-crossed').length > 0)
  634. 634 : {
  635. 635 : this.get_html().find('.eye').click();
  636. 636 : }
  637. 637 :
  638. 638 : await this.post('pin', {
  639. 639 : _uid:this.uid,
  640. 640 : _pin:false
  641. 641 : });
  642. 642 :
  643. 643 : this.pin = false;
  644. 644 :
  645. 645 : Sticker.helper.trigger_event('notes.apps.tak', this);
  646. 646 :
  647. 647 : return await this.post('del', {_uid:this.uid});
  648. 648 : }
  649. 649 :
  650. 650 : post_height_updated(newHeight)
  651. 651 : {
  652. 652 : if (this.uid === default_note_uid) return;
  653. 653 :
  654. 654 : return this.post('update_height', {
  655. 655 : _uid:this.uid,
  656. 656 : _height:newHeight
  657. 657 : });
  658. 658 : }
  659. 659 :
  660. 660 : /**
  661. 661 : * @async Met à jours la note
  662. 662 : */
  663. 663 : async post_update()
  664. 664 : {
  665. 665 : if (this.uid === default_note_uid) {
  666. 666 : await this.post_add();
  667. 667 : }
  668. 668 : else {
  669. 669 : await this.post('update', {
  670. 670 : _uid:this.uid,
  671. 671 : _raw:this
  672. 672 : }, true, false);
  673. 673 : rcmail.env.mel_metapages_notes[this.uid.replace('pin-', '')].text = this.text;
  674. 674 : //Sticker.helper.trigger_event('notes.apps.updated', rcmail.env.mel_metapages_notes)
  675. 675 : }
  676. 676 : }
  677. 677 :
  678. 678 : /**
  679. 679 : * Effectue une action sur le serveur
  680. 680 : * @param {string} action Nom de l'action
  681. 681 : * @param {JSON} params Paramètres de l'action
  682. 682 : * @param {boolean} doAction Si faux, la fonction de réussite ne sera pas appelé
  683. 683 : * @returns {Promise<any>} Appel ajax
  684. 684 : */
  685. 685 : async post(action, params = {}, doAction = true, lock = true)
  686. 686 : {
  687. 687 : //const on_eye = this.get_html().find('.icon-mel-eye-crossed').length > 0;
  688. 688 : if (lock && !!Sticker.lock) {
  689. 689 : rcmail.display_message('Une action est déjà en cours !');
  690. 690 : return;
  691. 691 : }
  692. 692 :
  693. 693 : if (lock) Sticker.lock = rcmail.set_busy(true, 'loading');
  694. 694 : params["_a"] = action;
  695. 695 :
  696. 696 : const pin = !!params["_uid"] && (params["_uid"].includes('pin-') || this.uid.includes('pin-'));
  697. 697 :
  698. 698 : if (!!params["_uid"] && params["_uid"].includes('pin-')) params["_uid"] = params["_uid"].replace('pin-', '');
  699. 699 :
  700. 700 : if (action === 'pin') {
  701. 701 : Sticker.helper.trigger_event('notes.apps.start-pin', true);
  702. 702 : }
  703. 703 :
  704. 704 : await Sticker.helper.http_internal_post({
  705. 705 : params,
  706. 706 : task:"mel_metapage",
  707. 707 : action:'notes',
  708. 708 : on_success:(datas) => {
  709. 709 : if (datas !== "break" && doAction)
  710. 710 : {
  711. 711 : rcmail.env.mel_metapages_notes = JSON.parse(datas);
  712. 712 :
  713. 713 : if (Enumerable.from(rcmail.env.mel_metapages_notes).count() === 0)
  714. 714 : {
  715. 715 : rcmail.env.mel_metapages_notes = {};
  716. 716 : rcmail.env.mel_metapages_notes[default_note_uid] = new Sticker("create", 0, "", "");
  717. 717 : }
  718. 718 :
  719. 719 : Sticker.helper.trigger_event('notes.apps.updated', rcmail.env.mel_metapages_notes)
  720. 720 :
  721. 721 : if (action !== 'get' && action !== 'add') Sticker.helper.rcmail().display_message('Note sauvegardée avec succès !', 'confirmation');
  722. 722 : }
  723. 723 : else {
  724. 724 : rcmail.env.mel_metapages_notes[this.uid.replace('pin-', '')].text = this.text;
  725. 725 : rcmail.env.mel_metapages_notes[this.uid.replace('pin-', '')].title = this.title;
  726. 726 :
  727. 727 : if (pin) {
  728. 728 : Sticker.helper.trigger_event('notes.apps.updated', rcmail.env.mel_metapages_notes);
  729. 729 : }
  730. 730 : else {
  731. 731 : for (const key in this) {
  732. 732 : if (Object.hasOwnProperty.call(this, key)) {
  733. 733 : const element = this[key];
  734. 734 : rcmail.env.mel_metapages_notes[this.uid][key] = element;
  735. 735 : }
  736. 736 : }
  737. 737 : Sticker.helper.trigger_event('notes.apps.updated.breaked', rcmail.env.mel_metapages_notes)
  738. 738 : }
  739. 739 : }
  740. 740 :
  741. 741 :
  742. 742 : }
  743. 743 : });
  744. 744 :
  745. 745 : if (lock) {
  746. 746 : rcmail.set_busy(false, 'loading', Sticker.lock);
  747. 747 : Sticker.lock = null;
  748. 748 : }
  749. 749 : }
  750. 750 :
  751. 751 : /**
  752. 752 : * Créer une note à partir d'une autre note
  753. 753 : * @param {Sticker} element Sticker ou objet ayant les même props.
  754. 754 : * @returns Nouvelle note
  755. 755 : */
  756. 756 : static from(element)
  757. 757 : {
  758. 758 : let s = new Sticker(element.uid, element.order, element.title, element.text, element.color, element.textcolor, (element.pin ?? false));
  759. 759 :
  760. 760 : if (!!element.height) s.height = element.height;
  761. 761 :
  762. 762 : return s;
  763. 763 : }
  764. 764 :
  765. 765 : /**
  766. 766 : * Créer une note depuis les données d'un block html
  767. 767 : * @param {string} uid Id de la div
  768. 768 : * @returns Nouvelle note
  769. 769 : */
  770. 770 : static fromHtml(uid)
  771. 771 : {
  772. 772 : let $element = $(`.mel-note#note-${uid}`);
  773. 773 : return new Sticker(uid, $element.data("order"), $element.find("input").val(), $element.find("textarea").val(), $element.css("background-color"), $element.css("color"), $element.data("pin"));
  774. 774 : }
  775. 775 :
  776. 776 : /**
  777. 777 : * Récupère une note via son ordre
  778. 778 : * @param {number} order Ordre de la note cherchée
  779. 779 : * @returns Nouvelle note
  780. 780 : */
  781. 781 : static findByOrder(order)
  782. 782 : {
  783. 783 : let id = $(`.mel-note[data-order=${order}]`).attr("id");
  784. 784 : return Sticker.fromHtml(id === undefined ? undefined : id.replace('note-', ''));
  785. 785 : }
  786. 786 :
  787. 787 : static async new() {
  788. 788 : await new Sticker("", -1, "", "").post_add()
  789. 789 : }
  790. 790 :
  791. 791 :
  792. 792 : }
  793. 793 :
  794. 794 : let helper = null;
  795. 795 : let timeout = null;
  796. 796 : Object.defineProperties(Sticker, {
  797. 797 : helper: {
  798. 798 : get: () => {
  799. 799 :
  800. 800 : if (!helper) helper = MelObject.Empty();
  801. 801 :
  802. 802 : if (!!timeout) clearTimeout(timeout);
  803. 803 :
  804. 804 : timeout = setTimeout(() => {
  805. 805 : helper = null;
  806. 806 : timeout = null;
  807. 807 : }, 5000);
  808. 808 :
  809. 809 : return helper;
  810. 810 : },
  811. 811 : configurable: true
  812. 812 : },
  813. 813 : });