[ Index ] |
|
Code source de TinyMCE 2.1.0 |
1 /** 2 * $Id: editor_plugin_src.js 162 2007-01-03 16:16:52Z spocke $ 3 * 4 * @author Moxiecode 5 * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved. 6 */ 7 8 tinyMCE.importPluginLanguagePack('template'); 9 10 var TinyMCE_TemplatePlugin = { 11 getInfo : function() { 12 return { 13 longname : 'Template plugin', 14 author : 'Moxiecode Systems AB', 15 authorurl : 'http://www.moxiecode.com', 16 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/template', 17 version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion 18 }; 19 }, 20 21 initInstance : function(inst) { 22 var cdate, mdate, content, x = 0, key, value, rvals, ds = inst.getData('template'); 23 24 // ensure the required elements and sttributes are added 25 //inst.cleanup.addRuleStr('*[' + TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR + '],div[title,tsrc]'); 26 27 //setup template content functions 28 // creation date and modified date classes 29 cdate = tinyMCE.getParam("template_cdate_classes", '').split(/\s+/); 30 mdate = tinyMCE.getParam("template_mdate_classes", '').split(/\s+/); 31 32 // classes that specify where selected content should go 33 content = tinyMCE.getParam("template_selected_content_classes", '').split(/\s+/); 34 35 for (x = 0; x < cdate.length; x++) 36 TinyMCE_TemplatePlugin.functions[cdate[x]] = TinyMCE_TemplatePlugin.functions['cdate']; 37 38 for (x = 0; x < mdate.length; x++) 39 TinyMCE_TemplatePlugin.functions[mdate[x]] = TinyMCE_TemplatePlugin.functions['mdate']; 40 41 for (x = 0; x < content.length; x++) 42 TinyMCE_TemplatePlugin.functions[content[x]] = TinyMCE_TemplatePlugin.functions['selectedContent']; 43 44 // special template functions for replacing template content 45 rvals = tinyMCE.getParam("template_replace_values", false); 46 for (key in rvals) { 47 value = rvals[key]; 48 49 if (typeof value == "function") 50 TinyMCE_TemplatePlugin.functions[key] = value; 51 else 52 TinyMCE_TemplatePlugin.functions[key] = TinyMCE_TemplatePlugin.functions['generateReplacer'](value); 53 } 54 55 // Setup replace_items 56 rvals = tinyMCE.getParam("template_replace_values", false); 57 ds.replace_items = {}; 58 59 for (key in rvals) 60 ds.replace_items[key] = rvals[key]; 61 62 inst.addShortcut('ctrl', 't', 'lang_template_desc', 'mceTemplate'); 63 64 // Setup data storage 65 ds.currentAction = "insert"; 66 ds.currentTmplNode = null; 67 }, 68 69 getControlHTML : function(cn) { 70 switch (cn) { 71 case "template": 72 return tinyMCE.getButtonHTML(cn, 'lang_template_desc', '{$pluginurl}/images/template.gif', 'mceTemplate', true); 73 } 74 75 return ""; 76 }, 77 78 execCommand : function(editor_id, element, command, user_interface, value) { 79 var nodeArray, current, newTmpl, x, inst = tinyMCE.getInstanceById(editor_id), ds = inst.getData('template'), telm; 80 81 switch (command) { 82 case "mceTemplate": 83 if (user_interface) { 84 // called from toolbar button - show the popup 85 tinyMCE.openWindow({ 86 file : '../../plugins/template/template.htm', // Relative to theme 87 width : tinyMCE.getParam('template_popup_width', 750), 88 height : tinyMCE.getParam('template_popup_height', 600) 89 }, {editor_id : editor_id, resizable : "yes", scrollbars : "no", pluginObj : TinyMCE_TemplatePlugin}); 90 } else { 91 // internal command do the template stuff 92 93 // get the returned HTML string from the pop-up and appened it to a DIV element 94 telm = TinyMCE_TemplatePlugin._convertToNode(value.body); 95 96 // Find template body 97 nodeArray = tinyMCE.selectElements(telm, 'div', function(n) { 98 return tinyMCE.hasCSSClass(n, TinyMCE_TemplatePlugin.TMPL); 99 }); 100 101 telm = nodeArray.length > 0 ? nodeArray[0] : null; 102 nodeArray = []; 103 104 if (ds.currentAction == "insert") { 105 //insert new template after applying all the template content functions 106 107 // Is it a template or snippet 108 if (telm) { 109 tinyMCE.execCommand('mceBeginUndoLevel'); 110 ds.currentAction = "insert-new"; 111 TinyMCE_TemplatePlugin._insertTemplate(editor_id, telm, value.title, value.tsrc, true); 112 ds.currentAction == "insert"; 113 tinyMCE.execCommand('mceEndUndoLevel'); 114 tinyMCE.execInstanceCommand(editor_id, 'mceCleanup', false); 115 } else 116 tinyMCE.execCommand('mceInsertContent', false, this._replaceValues(value.body)); 117 } else { 118 // First collect the selected template in the editor 119 nodeArray = TinyMCE_TemplatePlugin._collectTemplateElements(ds.currentTmplNode); 120 current = []; 121 newTmpl = []; 122 tinyMCE.getNodeTree(telm, newTmpl); 123 124 for (x=0; x<nodeArray.length; x++) 125 tinyMCE.getNodeTree(nodeArray[x], current); 126 127 /** 128 * inner function used in the loop below. 129 * compares the supplied HTML element to the new template to: 130 * - find a match with the new template and copy the element's content over 131 * - find no match and indicate content will be lost 132 */ 133 var _test = function(elm) { 134 var replaced = true; 135 136 if (elm.className) { 137 var names = elm.className.split(/\s+/), c, n; 138 139 for (c = 0; c<names.length; c++) { 140 if (names[c].match(/^mce/i)) 141 continue; // ignore all internal class names 142 143 for (n=0; n<newTmpl.length; n++){ 144 replaced = false; 145 146 if (newTmpl[n].className && newTmpl[n].className.match(new RegExp(names[c], "gi"))) { 147 newTmpl[n].innerHTML = elm.innerHTML; 148 //if(tinyMCE.getAttrib(elm,TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR,"") != "") { 149 // tinyMCE.setAttrib(newTmpl[n], TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR, tinyMCE.getAttrib(elm,TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR)); 150 //} 151 replaced = true; 152 break; 153 } 154 155 } 156 } 157 } 158 159 return replaced; 160 }; 161 162 // comparison loop - first mis-match alerts user for confirmation. 163 var cont = true; 164 var asked = false; 165 166 for (x = 0; x < current.length; x++) { 167 if(!_test(current[x])) { 168 cont = (asked || confirm("The new template has less elements than the currently selected content.\nIf you proceed you will loose content.\nAre you sure you want to proceed?", "Proceed?")); 169 asked = true; 170 171 if (!cont) 172 break; 173 } 174 }; 175 176 // apply replacement if allowed to 177 if (cont) { 178 tinyMCE.execCommand('mceBeginUndoLevel'); 179 TinyMCE_TemplatePlugin._replaceTemplateContent(current[0], editor_id, telm, value.title, value.tsrc); 180 tinyMCE.execCommand('mceEndUndoLevel'); 181 tinyMCE.execInstanceCommand(editor_id, 'mceCleanup', false); 182 } 183 } 184 185 tinyMCE.triggerNodeChange(true); 186 } 187 188 return true; 189 } 190 191 return false; 192 }, 193 194 handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) { 195 var inst = tinyMCE.getInstanceById(editor_id), ds = inst.getData('template'); 196 197 if (tinyMCE.hasCSSClass(node, TinyMCE_TemplatePlugin.TMPL_ELEMENT) || tinyMCE.hasCSSClass(node.parentNode, TinyMCE_TemplatePlugin.TMPL_ELEMENT)) { 198 tinyMCE.switchClass(editor_id + '_template', 'mceButtonSelected'); 199 ds.currentAction = "update"; 200 ds.currentTmplNode = node; 201 202 return true; 203 } 204 205 ds.currentAction = "insert"; 206 ds.currentTmplNode = null; 207 tinyMCE.switchClass(editor_id + '_template', 'mceButtonNormal'); 208 209 return false; 210 }, 211 212 cleanup : function(type, content, inst) { 213 var nodes = []; 214 215 switch (type) { 216 case "get_from_editor": 217 // replace the opening wrapper div tag with a HTML comment 218 content = content.replace( 219 new RegExp('<div class="' + TinyMCE_TemplatePlugin.TMPL + '">', 'gi'), 220 '<!-- ' + TinyMCE_TemplatePlugin.TMPL_BEGINS + ' -->' 221 ); 222 223 // delete any empty template wrappers 224 content = content.replace( 225 new RegExp('<div class="' + TinyMCE_TemplatePlugin.TMPL + '">(\s| | )?(<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' -->|\s)?</div>', 'gi'), 226 '' 227 ); 228 229 // replace the closing wrapper tag 230 content = content.replace( 231 new RegExp('<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' --></div>', 'gi'), 232 '<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' -->' 233 ); 234 235 break; 236 237 case "insert_to_editor": 238 // replace HTML comment with DIV wrapper 239 content = content.replace( 240 new RegExp('<!-- ' + TinyMCE_TemplatePlugin.TMPL_BEGINS + ' -->', 'gi'), 241 '<div class="' + TinyMCE_TemplatePlugin.TMPL + '">' 242 ); 243 244 content = content.replace( 245 new RegExp('<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' -->', 'gi'), 246 '<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' --></div>' 247 ); 248 249 break; 250 251 case "get_from_editor_dom": 252 // apply template content replacement functions 253 nodes = tinyMCE.selectNodes(content, function(n) { 254 return tinyMCE.hasCSSClass(n, TinyMCE_TemplatePlugin.TMPL_ELEMENT); 255 } 256 ); 257 258 TinyMCE_TemplatePlugin._applyFunctions(nodes, type); 259 260 break; 261 262 case "insert_to_editor_dom": 263 // apply template content replacement functions 264 nodes = tinyMCE.selectNodes(content, function(n) { 265 return tinyMCE.hasCSSClass(n, TinyMCE_TemplatePlugin.TMPL_ELEMENT); 266 } 267 ); 268 269 TinyMCE_TemplatePlugin._applyFunctions(nodes, type); 270 271 break; 272 } 273 274 return content; 275 }, 276 277 // Private plugin internal methods 278 279 /** 280 * Creates a HTML DIV element and sets the innerHTML to equal the temlate innerHTML so that the template can be manipulated as DOM nodes. 281 * 282 * @param {string} Template innerHTML 283 * @return a HTML Element 284 * @type HTMLElement 285 */ 286 _convertToNode : function(html) { 287 var elm = document.createElement('div'); 288 289 elm.innerHTML = html; 290 291 return elm; 292 }, 293 294 /** 295 * pass an array of template html elements and they will have the template class name added and any template functions applied 296 * 297 * @param {array} template HTML elements 298 * @return array of template HTML elements 299 * @type array 300 */ 301 _prepareTemplateContent : function(elms) { 302 var x, n, nodes = []; 303 304 if (!elms) 305 return {}; 306 307 if (!elms.length) 308 elms = [elms]; 309 310 for (x = 0; x<elms.length; x++) 311 tinyMCE.getNodeTree(elms[x], nodes, 1); 312 313 for (n = 0; n<nodes.length; n++) { 314 tinyMCE.addCSSClass(nodes[n], TinyMCE_TemplatePlugin.TMPL_ELEMENT); 315 TinyMCE_TemplatePlugin._applyFunctions(nodes[n], TinyMCE_TemplatePlugin.TMPL_TEMPLATE_EVENT); 316 } 317 318 return elms; 319 }, 320 321 _replaceValues : function(s) { 322 var t = this, ds = tinyMCE.selectedInstance.getData('template'); 323 324 return s.replace(/\{\$([^\}]+)\}/g, function(a, b) { 325 var it = ds.replace_items[b]; 326 327 if (it) { 328 // Only supports text for now 329 if (typeof(it) != 'function') 330 return it; 331 } 332 333 return b; 334 }); 335 }, 336 337 /** 338 * Applies any special functions to the template elements 339 * 340 * @param {array} template HTML elements 341 * @return array of template HTML elements 342 * @type array 343 */ 344 _applyFunctions : function(elms, editor_event) { 345 var x, elm, names, c, f; 346 347 if (!elms) 348 return {}; 349 350 if (!elms.length) 351 elms = [elms]; 352 353 for(x = 0; x < elms.length; x++) { 354 elm = elms[x]; 355 356 if (elm.className){ 357 names = elm.className.split(/\s+/); 358 359 for (c = 0; c < names.length; c++){ 360 if (names[c] == TinyMCE_TemplatePlugin.TMPL_ELEMENT) 361 continue; 362 363 f = (TinyMCE_TemplatePlugin.functions[names[c]] ? TinyMCE_TemplatePlugin.functions[names[c]] : TinyMCE_TemplatePlugin.functions['blank']); 364 f(elm, editor_event); 365 } 366 } 367 } 368 369 return elms; 370 }, 371 372 /** 373 * Given one node reference this function will collect all the nodes of the template to which it belongs. 374 * It does this by finding the parent template wrapper DIV and returning all child nodes. 375 * 376 * @param {HTMLElement} a HTMLElement which is part of a template 377 * @return array of template HTML elements 378 * @type array 379 */ 380 _collectTemplateElements : function(node) { 381 var nodeArray = [], p; 382 383 p = tinyMCE.getParentElement(node, 'DIV', function(n) { 384 return tinyMCE.hasCSSClass(n, TinyMCE_TemplatePlugin.TMPL); 385 }); 386 387 if (p) 388 tinyMCE.getNodeTree(p, nodeArray); 389 390 return nodeArray; 391 }, 392 393 /** 394 * Simply calls TinyMCE_TemplatePlugin._deleteTemplateContent and then TinyMCE_TemplatePlugin._insertTemplate 395 * 396 * @param {HTMLElement} currently selected template node in editor 397 * @param {string} id of editor instance 398 * @param {HTMLElement} template contents as a HTMLElement (the parent DIV wrapper) 399 * @param {string} title of template (unused as yet) 400 * @param {string} source URI of the template file (unused as yet) 401 * @return array of template HTML elements 402 * @type array 403 */ 404 _replaceTemplateContent : function(currentNode, editor_id, newTemplate, title, tsrc) { 405 TinyMCE_TemplatePlugin._deleteTemplateContent(currentNode); 406 TinyMCE_TemplatePlugin._insertTemplate(editor_id, newTemplate, title, tsrc, false); 407 }, 408 409 /** 410 * Deletes a template from the editor content 411 * Finds the parent DIV wrapper and deletes it and all children 412 * @param {HTMLElement} currently selected template node in editor 413 */ 414 _deleteTemplateContent : function(node) { 415 var p = tinyMCE.getParentElement(node, 'DIV', function(n) { 416 return tinyMCE.hasCSSClass(n, TinyMCE_TemplatePlugin.TMPL); 417 }); 418 419 if (p) 420 p.parentNode.removeChild(p, true); 421 }, 422 423 /** 424 * Inserts a template into the specified editor 425 * 426 * @param {string} id of editor instance 427 * @param {HTMLElement} template contents as a HTMLElement (the parent DIV wrapper) 428 * @param {string} title of template (unused as yet) 429 * @param {string} source URI of the template file (unused as yet) 430 */ 431 _insertTemplate : function(editor_id, elm, title, tsrc, incComments) { 432 var html; 433 434 TinyMCE_TemplatePlugin._prepareTemplateContent(elm); 435 436 html = '<div class="' + TinyMCE_TemplatePlugin.TMPL + '">'; 437 html += elm.innerHTML; 438 html += '<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' --></div>'; 439 440 tinyMCE.execInstanceCommand(editor_id, 'mceInsertContent', false, html); 441 }, 442 443 /** 444 * template functions - functions for modifying template content 445 */ 446 functions : { 447 blank : function(elm, editor_event) {}, 448 449 cdate : function(elm, editor_event) { 450 var d, dsrc; 451 452 if (editor_event != TinyMCE_TemplatePlugin.TMPL_TEMPLATE_EVENT) 453 return; 454 455 d = new Date(); 456 // find out if the creation date was previously stored 457 dsrc = elm.innerHTML.match(new RegExp("<!-- " + TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR + ":(.*) -->", "gi")); 458 459 if (dsrc) 460 d = new Date(RegExp.$1); 461 462 elm.innerHTML = TinyMCE_TemplatePlugin._getDateTime(d, tinyMCE.getParam("template_cdate_format", tinyMCE.getLang("lang_template_def_date_format"))); 463 //now we have to store the date value in a format easily read again, in case a future template change changes the date format... 464 elm.innerHTML += "<!-- " + TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR + ":" + d.toUTCString() + " -->"; 465 }, 466 467 mdate : function(elm, editor_event) { 468 var d = new Date(); 469 elm.innerHTML = TinyMCE_TemplatePlugin._getDateTime(d, tinyMCE.getParam("template_mdate_format", tinyMCE.getLang("lang_template_def_date_format"))); 470 }, 471 472 /** 473 * This will insert the currently selected editor content into the template element. 474 * It only does this if the template inserted is a new one and if the element does not have the special class. 475 * The special class name prevents this from happening more than once. 476 */ 477 selectedContent : function(elm, editor_event) { 478 var ds = tinyMCE.selectedInstance.getData('template'); 479 480 if (editor_event != TinyMCE_TemplatePlugin.TMPL_TEMPLATE_EVENT) 481 return; 482 483 if (ds.currentAction == "insert-new" && !tinyMCE.hasCSSClass(elm, TinyMCE_TemplatePlugin.TMPL_SEL_HTML_DONE)) { 484 elm.innerHTML = tinyMCE.selectedInstance.selection.getSelectedHTML(); 485 tinyMCE.addCSSClass(elm, TinyMCE_TemplatePlugin.TMPL_SEL_HTML_DONE); 486 } 487 }, 488 489 /** 490 * When the plugin is initialised this generates the functions that insert configured strings into template elements. 491 */ 492 generateReplacer : function(s) { 493 return function(elm, editor_event) {elm.innerHTML = "" + s;}; 494 } 495 }, 496 497 /** 498 * formats a date according to the format string - straight from the 'insert date/time' plugin 499 * 500 * @param {Date} date object 501 * @param {string} format string 502 * @return formatted date 503 * @type string 504 */ 505 _getDateTime : function(d,fmt) { 506 if (!fmt) 507 return ""; 508 509 function addZeros(value, len) { 510 var i; 511 512 value = "" + value; 513 514 if (value.length < len) { 515 for (i=0; i<(len-value.length); i++) 516 value = "0" + value; 517 } 518 519 return value; 520 } 521 522 fmt = fmt.replace("%D", "%m/%d/%y"); 523 fmt = fmt.replace("%r", "%I:%M:%S %p"); 524 fmt = fmt.replace("%Y", "" + d.getFullYear()); 525 fmt = fmt.replace("%y", "" + d.getYear()); 526 fmt = fmt.replace("%m", addZeros(d.getMonth()+1, 2)); 527 fmt = fmt.replace("%d", addZeros(d.getDate(), 2)); 528 fmt = fmt.replace("%H", "" + addZeros(d.getHours(), 2)); 529 fmt = fmt.replace("%M", "" + addZeros(d.getMinutes(), 2)); 530 fmt = fmt.replace("%S", "" + addZeros(d.getSeconds(), 2)); 531 fmt = fmt.replace("%I", "" + ((d.getHours() + 11) % 12 + 1)); 532 fmt = fmt.replace("%p", "" + (d.getHours() < 12 ? "AM" : "PM")); 533 fmt = fmt.replace("%B", "" + tinyMCE.getLang("lang_template_months_long")[d.getMonth()]); 534 fmt = fmt.replace("%b", "" + tinyMCE.getLang("lang_template_months_short")[d.getMonth()]); 535 fmt = fmt.replace("%A", "" + tinyMCE.getLang("lang_template_day_long")[d.getDay()]); 536 fmt = fmt.replace("%a", "" + tinyMCE.getLang("lang_template_day_short")[d.getDay()]); 537 fmt = fmt.replace("%%", "%"); 538 539 return fmt; 540 }, 541 542 TMPL_ELEMENT : 'mceTmplElm', 543 TMPL : 'mceTmpl', 544 TMPL_BEGINS : 'mceTmplBegins', 545 TMPL_SEL_HTML_DONE : 'mceSelHTMLDone', 546 TMPL_ENDS : 'mceTmplEnds', 547 TMPL_DATE_SRC_ATTR : 'mcetmpldtesrc', 548 TMPL_TEMPLATE_EVENT : 'prepare_template' 549 }; 550 551 tinyMCE.addPlugin("template", TinyMCE_TemplatePlugin);
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 15:23:03 2007 | par Balluche grâce à PHPXref 0.7 |