Ticket #20055: 20055.diff
File 20055.diff, 148.0 KB (added by , 13 years ago) |
---|
-
wp-includes/js/tinymce/plugins/media/editor_plugin.dev.js
1 /** 2 * editor_plugin_src.js 3 * 4 * Copyright 2009, Moxiecode Systems AB 5 * Released under LGPL License. 6 * 7 * License: http://tinymce.moxiecode.com/license 8 * Contributing: http://tinymce.moxiecode.com/contributing 9 */ 10 11 (function() { 12 var rootAttributes = tinymce.explode('id,name,width,height,style,align,class,hspace,vspace,bgcolor,type'), excludedAttrs = tinymce.makeMap(rootAttributes.join(',')), Node = tinymce.html.Node, 13 mediaTypes, scriptRegExp, JSON = tinymce.util.JSON, mimeTypes; 14 15 // Media types supported by this plugin 16 mediaTypes = [ 17 // Type, clsid:s, mime types, codebase 18 ["Flash", "d27cdb6e-ae6d-11cf-96b8-444553540000", "application/x-shockwave-flash", "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"], 19 ["ShockWave", "166b1bca-3f9c-11cf-8075-444553540000", "application/x-director", "http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0"], 20 ["WindowsMedia", "6bf52a52-394a-11d3-b153-00c04f79faa6,22d6f312-b0f6-11d0-94ab-0080c74c7e95,05589fa1-c356-11ce-bf01-00aa0055595a", "application/x-mplayer2", "http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701"], 21 ["QuickTime", "02bf25d5-8c17-4b23-bc80-d3488abddc6b", "video/quicktime", "http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0"], 22 ["RealMedia", "cfcdaa03-8be4-11cf-b84b-0020afbbccfa", "audio/x-pn-realaudio-plugin", "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"], 23 ["Java", "8ad9c840-044e-11d1-b3e9-00805f499d93", "application/x-java-applet", "http://java.sun.com/products/plugin/autodl/jinstall-1_5_0-windows-i586.cab#Version=1,5,0,0"], 24 ["Silverlight", "dfeaf541-f3e1-4c24-acac-99c30715084a", "application/x-silverlight-2"], 25 ["Iframe"], 26 ["Video"], 27 ["EmbeddedAudio"], 28 ["Audio"] 29 ]; 30 31 function toArray(obj) { 32 var undef, out, i; 33 34 if (obj && !obj.splice) { 35 out = []; 36 37 for (i = 0; true; i++) { 38 if (obj[i]) 39 out[i] = obj[i]; 40 else 41 break; 42 } 43 44 return out; 45 } 46 47 return obj; 48 }; 49 50 tinymce.create('tinymce.plugins.MediaPlugin', { 51 init : function(ed, url) { 52 var self = this, lookup = {}, i, y, item, name; 53 54 function isMediaImg(node) { 55 return node && node.nodeName === 'IMG' && ed.dom.hasClass(node, 'mceItemMedia'); 56 }; 57 58 self.editor = ed; 59 self.url = url; 60 61 // Parse media types into a lookup table 62 scriptRegExp = ''; 63 for (i = 0; i < mediaTypes.length; i++) { 64 name = mediaTypes[i][0]; 65 66 item = { 67 name : name, 68 clsids : tinymce.explode(mediaTypes[i][1] || ''), 69 mimes : tinymce.explode(mediaTypes[i][2] || ''), 70 codebase : mediaTypes[i][3] 71 }; 72 73 for (y = 0; y < item.clsids.length; y++) 74 lookup['clsid:' + item.clsids[y]] = item; 75 76 for (y = 0; y < item.mimes.length; y++) 77 lookup[item.mimes[y]] = item; 78 79 lookup['mceItem' + name] = item; 80 lookup[name.toLowerCase()] = item; 81 82 scriptRegExp += (scriptRegExp ? '|' : '') + name; 83 } 84 85 // Handle the media_types setting 86 tinymce.each(ed.getParam("media_types", 87 "video=mp4,m4v,ogv,webm;" + 88 "silverlight=xap;" + 89 "flash=swf,flv;" + 90 "shockwave=dcr;" + 91 "quicktime=mov,qt,mpg,mpeg;" + 92 "shockwave=dcr;" + 93 "windowsmedia=avi,wmv,wm,asf,asx,wmx,wvx;" + 94 "realmedia=rm,ra,ram;" + 95 "java=jar;" + 96 "audio=mp3,ogg" 97 ).split(';'), function(item) { 98 var i, extensions, type; 99 100 item = item.split(/=/); 101 extensions = tinymce.explode(item[1].toLowerCase()); 102 for (i = 0; i < extensions.length; i++) { 103 type = lookup[item[0].toLowerCase()]; 104 105 if (type) 106 lookup[extensions[i]] = type; 107 } 108 }); 109 110 scriptRegExp = new RegExp('write(' + scriptRegExp + ')\\(([^)]+)\\)'); 111 self.lookup = lookup; 112 113 ed.onPreInit.add(function() { 114 // Allow video elements 115 ed.schema.addValidElements('object[id|style|width|height|classid|codebase|*],param[name|value],embed[id|style|width|height|type|src|*],video[*],audio[*],source[*]'); 116 117 // Convert video elements to image placeholder 118 ed.parser.addNodeFilter('object,embed,video,audio,script,iframe', function(nodes) { 119 var i = nodes.length; 120 121 while (i--) 122 self.objectToImg(nodes[i]); 123 }); 124 125 // Convert image placeholders to video elements 126 ed.serializer.addNodeFilter('img', function(nodes, name, args) { 127 var i = nodes.length, node; 128 129 while (i--) { 130 node = nodes[i]; 131 if ((node.attr('class') || '').indexOf('mceItemMedia') !== -1) 132 self.imgToObject(node, args); 133 } 134 }); 135 }); 136 137 ed.onInit.add(function() { 138 // Display "media" instead of "img" in element path 139 if (ed.theme && ed.theme.onResolveName) { 140 ed.theme.onResolveName.add(function(theme, path_object) { 141 if (path_object.name === 'img' && ed.dom.hasClass(path_object.node, 'mceItemMedia')) 142 path_object.name = 'media'; 143 }); 144 } 145 146 // Add contect menu if it's loaded 147 if (ed && ed.plugins.contextmenu) { 148 ed.plugins.contextmenu.onContextMenu.add(function(plugin, menu, element) { 149 if (element.nodeName === 'IMG' && element.className.indexOf('mceItemMedia') !== -1) 150 menu.add({title : 'media.edit', icon : 'media', cmd : 'mceMedia'}); 151 }); 152 } 153 }); 154 155 // Register commands 156 ed.addCommand('mceMedia', function() { 157 var data, img; 158 159 img = ed.selection.getNode(); 160 if (isMediaImg(img)) { 161 data = ed.dom.getAttrib(img, 'data-mce-json'); 162 if (data) { 163 data = JSON.parse(data); 164 165 // Add some extra properties to the data object 166 tinymce.each(rootAttributes, function(name) { 167 var value = ed.dom.getAttrib(img, name); 168 169 if (value) 170 data[name] = value; 171 }); 172 173 data.type = self.getType(img.className).name.toLowerCase(); 174 } 175 } 176 177 if (!data) { 178 data = { 179 type : 'flash', 180 video: {sources:[]}, 181 params: {} 182 }; 183 } 184 185 ed.windowManager.open({ 186 file : url + '/media.htm', 187 width : 430 + parseInt(ed.getLang('media.delta_width', 0)), 188 height : 500 + parseInt(ed.getLang('media.delta_height', 0)), 189 inline : 1 190 }, { 191 plugin_url : url, 192 data : data 193 }); 194 }); 195 196 // Register buttons 197 ed.addButton('media', {title : 'media.desc', cmd : 'mceMedia'}); 198 199 // Update media selection status 200 ed.onNodeChange.add(function(ed, cm, node) { 201 cm.setActive('media', isMediaImg(node)); 202 }); 203 }, 204 205 convertUrl : function(url, force_absolute) { 206 var self = this, editor = self.editor, settings = editor.settings, 207 urlConverter = settings.url_converter, 208 urlConverterScope = settings.url_converter_scope || self; 209 210 if (!url) 211 return url; 212 213 if (force_absolute) 214 return editor.documentBaseURI.toAbsolute(url); 215 216 return urlConverter.call(urlConverterScope, url, 'src', 'object'); 217 }, 218 219 getInfo : function() { 220 return { 221 longname : 'Media', 222 author : 'Moxiecode Systems AB', 223 authorurl : 'http://tinymce.moxiecode.com', 224 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media', 225 version : tinymce.majorVersion + "." + tinymce.minorVersion 226 }; 227 }, 228 229 /** 230 * Converts the JSON data object to an img node. 231 */ 232 dataToImg : function(data, force_absolute) { 233 var self = this, editor = self.editor, baseUri = editor.documentBaseURI, sources, attrs, img, i; 234 235 data.params.src = self.convertUrl(data.params.src, force_absolute); 236 237 attrs = data.video.attrs; 238 if (attrs) 239 attrs.src = self.convertUrl(attrs.src, force_absolute); 240 241 if (attrs) 242 attrs.poster = self.convertUrl(attrs.poster, force_absolute); 243 244 sources = toArray(data.video.sources); 245 if (sources) { 246 for (i = 0; i < sources.length; i++) 247 sources[i].src = self.convertUrl(sources[i].src, force_absolute); 248 } 249 250 img = self.editor.dom.create('img', { 251 id : data.id, 252 style : data.style, 253 align : data.align, 254 hspace : data.hspace, 255 vspace : data.vspace, 256 src : self.editor.theme.url + '/img/trans.gif', 257 'class' : 'mceItemMedia mceItem' + self.getType(data.type).name, 258 'data-mce-json' : JSON.serialize(data, "'") 259 }); 260 261 img.width = data.width || (data.type == 'audio' ? "300" : "320"); 262 img.height = data.height || (data.type == 'audio' ? "32" : "240"); 263 264 return img; 265 }, 266 267 /** 268 * Converts the JSON data object to a HTML string. 269 */ 270 dataToHtml : function(data, force_absolute) { 271 return this.editor.serializer.serialize(this.dataToImg(data, force_absolute), {forced_root_block : '', force_absolute : force_absolute}); 272 }, 273 274 /** 275 * Converts the JSON data object to a HTML string. 276 */ 277 htmlToData : function(html) { 278 var fragment, img, data; 279 280 data = { 281 type : 'flash', 282 video: {sources:[]}, 283 params: {} 284 }; 285 286 fragment = this.editor.parser.parse(html); 287 img = fragment.getAll('img')[0]; 288 289 if (img) { 290 data = JSON.parse(img.attr('data-mce-json')); 291 data.type = this.getType(img.attr('class')).name.toLowerCase(); 292 293 // Add some extra properties to the data object 294 tinymce.each(rootAttributes, function(name) { 295 var value = img.attr(name); 296 297 if (value) 298 data[name] = value; 299 }); 300 } 301 302 return data; 303 }, 304 305 /** 306 * Get type item by extension, class, clsid or mime type. 307 * 308 * @method getType 309 * @param {String} value Value to get type item by. 310 * @return {Object} Type item object or undefined. 311 */ 312 getType : function(value) { 313 var i, values, typeItem; 314 315 // Find type by checking the classes 316 values = tinymce.explode(value, ' '); 317 for (i = 0; i < values.length; i++) { 318 typeItem = this.lookup[values[i]]; 319 320 if (typeItem) 321 return typeItem; 322 } 323 }, 324 325 /** 326 * Converts a tinymce.html.Node image element to video/object/embed. 327 */ 328 imgToObject : function(node, args) { 329 var self = this, editor = self.editor, video, object, embed, iframe, name, value, data, 330 source, sources, params, param, typeItem, i, item, mp4Source, replacement, 331 posterSrc, style, audio; 332 333 // Adds the flash player 334 function addPlayer(video_src, poster_src) { 335 var baseUri, flashVars, flashVarsOutput, params, flashPlayer; 336 337 flashPlayer = editor.getParam('flash_video_player_url', self.convertUrl(self.url + '/moxieplayer.swf')); 338 if (flashPlayer) { 339 baseUri = editor.documentBaseURI; 340 data.params.src = flashPlayer; 341 342 // Convert the movie url to absolute urls 343 if (editor.getParam('flash_video_player_absvideourl', true)) { 344 video_src = baseUri.toAbsolute(video_src || '', true); 345 poster_src = baseUri.toAbsolute(poster_src || '', true); 346 } 347 348 // Generate flash vars 349 flashVarsOutput = ''; 350 flashVars = editor.getParam('flash_video_player_flashvars', {url : '$url', poster : '$poster'}); 351 tinymce.each(flashVars, function(value, name) { 352 // Replace $url and $poster variables in flashvars value 353 value = value.replace(/\$url/, video_src || ''); 354 value = value.replace(/\$poster/, poster_src || ''); 355 356 if (value.length > 0) 357 flashVarsOutput += (flashVarsOutput ? '&' : '') + name + '=' + escape(value); 358 }); 359 360 if (flashVarsOutput.length) 361 data.params.flashvars = flashVarsOutput; 362 363 params = editor.getParam('flash_video_player_params', { 364 allowfullscreen: true, 365 allowscriptaccess: true 366 }); 367 368 tinymce.each(params, function(value, name) { 369 data.params[name] = "" + value; 370 }); 371 } 372 }; 373 374 data = node.attr('data-mce-json'); 375 if (!data) 376 return; 377 378 data = JSON.parse(data); 379 typeItem = this.getType(node.attr('class')); 380 381 style = node.attr('data-mce-style') 382 if (!style) { 383 style = node.attr('style'); 384 385 if (style) 386 style = editor.dom.serializeStyle(editor.dom.parseStyle(style, 'img')); 387 } 388 389 // Handle iframe 390 if (typeItem.name === 'Iframe') { 391 replacement = new Node('iframe', 1); 392 393 tinymce.each(rootAttributes, function(name) { 394 var value = node.attr(name); 395 396 if (name == 'class' && value) 397 value = value.replace(/mceItem.+ ?/g, ''); 398 399 if (value && value.length > 0) 400 replacement.attr(name, value); 401 }); 402 403 for (name in data.params) 404 replacement.attr(name, data.params[name]); 405 406 replacement.attr({ 407 style: style, 408 src: data.params.src 409 }); 410 411 node.replace(replacement); 412 413 return; 414 } 415 416 // Handle scripts 417 if (this.editor.settings.media_use_script) { 418 replacement = new Node('script', 1).attr('type', 'text/javascript'); 419 420 value = new Node('#text', 3); 421 value.value = 'write' + typeItem.name + '(' + JSON.serialize(tinymce.extend(data.params, { 422 width: node.attr('width'), 423 height: node.attr('height') 424 })) + ');'; 425 426 replacement.append(value); 427 node.replace(replacement); 428 429 return; 430 } 431 432 // Add HTML5 video element 433 if (typeItem.name === 'Video' && data.video.sources[0]) { 434 // Create new object element 435 video = new Node('video', 1).attr(tinymce.extend({ 436 id : node.attr('id'), 437 width: node.attr('width'), 438 height: node.attr('height'), 439 style : style 440 }, data.video.attrs)); 441 442 // Get poster source and use that for flash fallback 443 if (data.video.attrs) 444 posterSrc = data.video.attrs.poster; 445 446 sources = data.video.sources = toArray(data.video.sources); 447 for (i = 0; i < sources.length; i++) { 448 if (/\.mp4$/.test(sources[i].src)) 449 mp4Source = sources[i].src; 450 } 451 452 if (!sources[0].type) { 453 video.attr('src', sources[0].src); 454 sources.splice(0, 1); 455 } 456 457 for (i = 0; i < sources.length; i++) { 458 source = new Node('source', 1).attr(sources[i]); 459 source.shortEnded = true; 460 video.append(source); 461 } 462 463 // Create flash fallback for video if we have a mp4 source 464 if (mp4Source) { 465 addPlayer(mp4Source, posterSrc); 466 typeItem = self.getType('flash'); 467 } else 468 data.params.src = ''; 469 } 470 471 // Add HTML5 audio element 472 if (typeItem.name === 'Audio' && data.video.sources[0]) { 473 // Create new object element 474 audio = new Node('audio', 1).attr(tinymce.extend({ 475 id : node.attr('id'), 476 width: node.attr('width'), 477 height: node.attr('height'), 478 style : style 479 }, data.video.attrs)); 480 481 // Get poster source and use that for flash fallback 482 if (data.video.attrs) 483 posterSrc = data.video.attrs.poster; 484 485 sources = data.video.sources = toArray(data.video.sources); 486 if (!sources[0].type) { 487 audio.attr('src', sources[0].src); 488 sources.splice(0, 1); 489 } 490 491 for (i = 0; i < sources.length; i++) { 492 source = new Node('source', 1).attr(sources[i]); 493 source.shortEnded = true; 494 audio.append(source); 495 } 496 497 data.params.src = ''; 498 } 499 500 if (typeItem.name === 'EmbeddedAudio') { 501 embed = new Node('embed', 1); 502 embed.shortEnded = true; 503 embed.attr({ 504 id: node.attr('id'), 505 width: node.attr('width'), 506 height: node.attr('height'), 507 style : style, 508 type: node.attr('type') 509 }); 510 511 for (name in data.params) 512 embed.attr(name, data.params[name]); 513 514 tinymce.each(rootAttributes, function(name) { 515 if (data[name] && name != 'type') 516 embed.attr(name, data[name]); 517 }); 518 519 data.params.src = ''; 520 } 521 522 // Do we have a params src then we can generate object 523 if (data.params.src) { 524 // Is flv movie add player for it 525 if (/\.flv$/i.test(data.params.src)) 526 addPlayer(data.params.src, ''); 527 528 if (args && args.force_absolute) 529 data.params.src = editor.documentBaseURI.toAbsolute(data.params.src); 530 531 // Create new object element 532 object = new Node('object', 1).attr({ 533 id : node.attr('id'), 534 width: node.attr('width'), 535 height: node.attr('height'), 536 style : style 537 }); 538 539 tinymce.each(rootAttributes, function(name) { 540 var value = data[name]; 541 542 if (name == 'class' && value) 543 value = value.replace(/mceItem.+ ?/g, ''); 544 545 if (value && name != 'type') 546 object.attr(name, value); 547 }); 548 549 // Add params 550 for (name in data.params) { 551 param = new Node('param', 1); 552 param.shortEnded = true; 553 value = data.params[name]; 554 555 // Windows media needs to use url instead of src for the media URL 556 if (name === 'src' && typeItem.name === 'WindowsMedia') 557 name = 'url'; 558 559 param.attr({name: name, value: value}); 560 object.append(param); 561 } 562 563 // Setup add type and classid if strict is disabled 564 if (this.editor.getParam('media_strict', true)) { 565 object.attr({ 566 data: data.params.src, 567 type: typeItem.mimes[0] 568 }); 569 } else { 570 object.attr({ 571 classid: "clsid:" + typeItem.clsids[0], 572 codebase: typeItem.codebase 573 }); 574 575 embed = new Node('embed', 1); 576 embed.shortEnded = true; 577 embed.attr({ 578 id: node.attr('id'), 579 width: node.attr('width'), 580 height: node.attr('height'), 581 style : style, 582 type: typeItem.mimes[0] 583 }); 584 585 for (name in data.params) 586 embed.attr(name, data.params[name]); 587 588 tinymce.each(rootAttributes, function(name) { 589 if (data[name] && name != 'type') 590 embed.attr(name, data[name]); 591 }); 592 593 object.append(embed); 594 } 595 596 // Insert raw HTML 597 if (data.object_html) { 598 value = new Node('#text', 3); 599 value.raw = true; 600 value.value = data.object_html; 601 object.append(value); 602 } 603 604 // Append object to video element if it exists 605 if (video) 606 video.append(object); 607 } 608 609 if (video) { 610 // Insert raw HTML 611 if (data.video_html) { 612 value = new Node('#text', 3); 613 value.raw = true; 614 value.value = data.video_html; 615 video.append(value); 616 } 617 } 618 619 if (audio) { 620 // Insert raw HTML 621 if (data.video_html) { 622 value = new Node('#text', 3); 623 value.raw = true; 624 value.value = data.video_html; 625 audio.append(value); 626 } 627 } 628 629 var n = video || audio || object || embed; 630 if (n) 631 node.replace(n); 632 else 633 node.remove(); 634 }, 635 636 /** 637 * Converts a tinymce.html.Node video/object/embed to an img element. 638 * 639 * The video/object/embed will be converted into an image placeholder with a JSON data attribute like this: 640 * <img class="mceItemMedia mceItemFlash" width="100" height="100" data-mce-json="{..}" /> 641 * 642 * The JSON structure will be like this: 643 * {'params':{'flashvars':'something','quality':'high','src':'someurl'}, 'video':{'sources':[{src: 'someurl', type: 'video/mp4'}]}} 644 */ 645 objectToImg : function(node) { 646 var object, embed, video, iframe, img, name, id, width, height, style, i, html, 647 param, params, source, sources, data, type, lookup = this.lookup, 648 matches, attrs, urlConverter = this.editor.settings.url_converter, 649 urlConverterScope = this.editor.settings.url_converter_scope, 650 hspace, vspace, align, bgcolor; 651 652 function getInnerHTML(node) { 653 return new tinymce.html.Serializer({ 654 inner: true, 655 validate: false 656 }).serialize(node); 657 }; 658 659 function lookupAttribute(o, attr) { 660 return lookup[(o.attr(attr) || '').toLowerCase()]; 661 } 662 663 function lookupExtension(src) { 664 var ext = src.replace(/^.*\.([^.]+)$/, '$1'); 665 return lookup[ext.toLowerCase() || '']; 666 } 667 668 // If node isn't in document 669 if (!node.parent) 670 return; 671 672 // Handle media scripts 673 if (node.name === 'script') { 674 if (node.firstChild) 675 matches = scriptRegExp.exec(node.firstChild.value); 676 677 if (!matches) 678 return; 679 680 type = matches[1]; 681 data = {video : {}, params : JSON.parse(matches[2])}; 682 width = data.params.width; 683 height = data.params.height; 684 } 685 686 // Setup data objects 687 data = data || { 688 video : {}, 689 params : {} 690 }; 691 692 // Setup new image object 693 img = new Node('img', 1); 694 img.attr({ 695 src : this.editor.theme.url + '/img/trans.gif' 696 }); 697 698 // Video element 699 name = node.name; 700 if (name === 'video' || name == 'audio') { 701 video = node; 702 object = node.getAll('object')[0]; 703 embed = node.getAll('embed')[0]; 704 width = video.attr('width'); 705 height = video.attr('height'); 706 id = video.attr('id'); 707 data.video = {attrs : {}, sources : []}; 708 709 // Get all video attributes 710 attrs = data.video.attrs; 711 for (name in video.attributes.map) 712 attrs[name] = video.attributes.map[name]; 713 714 source = node.attr('src'); 715 if (source) 716 data.video.sources.push({src : urlConverter.call(urlConverterScope, source, 'src', node.name)}); 717 718 // Get all sources 719 sources = video.getAll("source"); 720 for (i = 0; i < sources.length; i++) { 721 source = sources[i].remove(); 722 723 data.video.sources.push({ 724 src: urlConverter.call(urlConverterScope, source.attr('src'), 'src', 'source'), 725 type: source.attr('type'), 726 media: source.attr('media') 727 }); 728 } 729 730 // Convert the poster URL 731 if (attrs.poster) 732 attrs.poster = urlConverter.call(urlConverterScope, attrs.poster, 'poster', node.name); 733 } 734 735 // Object element 736 if (node.name === 'object') { 737 object = node; 738 embed = node.getAll('embed')[0]; 739 } 740 741 // Embed element 742 if (node.name === 'embed') 743 embed = node; 744 745 // Iframe element 746 if (node.name === 'iframe') { 747 iframe = node; 748 type = 'Iframe'; 749 } 750 751 if (object) { 752 // Get width/height 753 width = width || object.attr('width'); 754 height = height || object.attr('height'); 755 style = style || object.attr('style'); 756 id = id || object.attr('id'); 757 hspace = hspace || object.attr('hspace'); 758 vspace = vspace || object.attr('vspace'); 759 align = align || object.attr('align'); 760 bgcolor = bgcolor || object.attr('bgcolor'); 761 data.name = object.attr('name'); 762 763 // Get all object params 764 params = object.getAll("param"); 765 for (i = 0; i < params.length; i++) { 766 param = params[i]; 767 name = param.remove().attr('name'); 768 769 if (!excludedAttrs[name]) 770 data.params[name] = param.attr('value'); 771 } 772 773 data.params.src = data.params.src || object.attr('data'); 774 } 775 776 if (embed) { 777 // Get width/height 778 width = width || embed.attr('width'); 779 height = height || embed.attr('height'); 780 style = style || embed.attr('style'); 781 id = id || embed.attr('id'); 782 hspace = hspace || embed.attr('hspace'); 783 vspace = vspace || embed.attr('vspace'); 784 align = align || embed.attr('align'); 785 bgcolor = bgcolor || embed.attr('bgcolor'); 786 787 // Get all embed attributes 788 for (name in embed.attributes.map) { 789 if (!excludedAttrs[name] && !data.params[name]) 790 data.params[name] = embed.attributes.map[name]; 791 } 792 } 793 794 if (iframe) { 795 // Get width/height 796 width = iframe.attr('width'); 797 height = iframe.attr('height'); 798 style = style || iframe.attr('style'); 799 id = iframe.attr('id'); 800 hspace = iframe.attr('hspace'); 801 vspace = iframe.attr('vspace'); 802 align = iframe.attr('align'); 803 bgcolor = iframe.attr('bgcolor'); 804 805 tinymce.each(rootAttributes, function(name) { 806 img.attr(name, iframe.attr(name)); 807 }); 808 809 // Get all iframe attributes 810 for (name in iframe.attributes.map) { 811 if (!excludedAttrs[name] && !data.params[name]) 812 data.params[name] = iframe.attributes.map[name]; 813 } 814 } 815 816 // Use src not movie 817 if (data.params.movie) { 818 data.params.src = data.params.src || data.params.movie; 819 delete data.params.movie; 820 } 821 822 // Convert the URL to relative/absolute depending on configuration 823 if (data.params.src) 824 data.params.src = urlConverter.call(urlConverterScope, data.params.src, 'src', 'object'); 825 826 if (video) { 827 if (node.name === 'video') 828 type = lookup.video.name; 829 else if (node.name === 'audio') 830 type = lookup.audio.name; 831 } 832 833 if (object && !type) 834 type = (lookupAttribute(object, 'clsid') || lookupAttribute(object, 'classid') || lookupAttribute(object, 'type') || {}).name; 835 836 if (embed && !type) 837 type = (lookupAttribute(embed, 'type') || lookupExtension(data.params.src) || {}).name; 838 839 // for embedded audio we preserve the original specified type 840 if (embed && type == 'EmbeddedAudio') { 841 data.params.type = embed.attr('type'); 842 } 843 844 // Replace the video/object/embed element with a placeholder image containing the data 845 node.replace(img); 846 847 // Remove embed 848 if (embed) 849 embed.remove(); 850 851 // Serialize the inner HTML of the object element 852 if (object) { 853 html = getInnerHTML(object.remove()); 854 855 if (html) 856 data.object_html = html; 857 } 858 859 // Serialize the inner HTML of the video element 860 if (video) { 861 html = getInnerHTML(video.remove()); 862 863 if (html) 864 data.video_html = html; 865 } 866 867 data.hspace = hspace; 868 data.vspace = vspace; 869 data.align = align; 870 data.bgcolor = bgcolor; 871 872 // Set width/height of placeholder 873 img.attr({ 874 id : id, 875 'class' : 'mceItemMedia mceItem' + (type || 'Flash'), 876 style : style, 877 width : width || (node.name == 'audio' ? "300" : "320"), 878 height : height || (node.name == 'audio' ? "32" : "240"), 879 hspace : hspace, 880 vspace : vspace, 881 align : align, 882 bgcolor : bgcolor, 883 "data-mce-json" : JSON.serialize(data, "'") 884 }); 885 } 886 }); 887 888 // Register plugin 889 tinymce.PluginManager.add('media', tinymce.plugins.MediaPlugin); 890 })(); -
wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin.js
1 1 2 (function(){tinymce.create("tinymce.plugins.wpEditImage",{init:function(a,c){var d=this,b={};d.url=c;d._createButtons();a.addCommand("WP_EditImage",function(){var i=a.selection.getNode(),g=tinymce.DOM.getViewPort(),h=g.h,e=(720<g.w)?720:g.w,f=a.dom.getAttrib(i,"class");if(f.indexOf("mceItem")!=-1||f.indexOf("wpGallery")!=-1||i.nodeName!="IMG"){return}tb_show("",c+"/editimage.html?ver=321&TB_iframe=true");tinymce.DOM.setStyles("TB_window",{width:(e-50)+"px",height:(h-45)+"px","margin-left":"-"+parseInt(((e-50)/2),10)+"px"});if(!tinymce.isIE6){tinymce.DOM.setStyles("TB_window",{top:"20px",marginTop:"0"})}tinymce.DOM.setStyles("TB_iframeContent",{width:(e-50)+"px",height:(h-75)+"px"});tinymce.DOM.setStyle(["TB_overlay","TB_window","TB_load"],"z-index","999999")});a.onInit.add(function(e){tinymce.dom.Event.add(e.getBody(),"dragstart",function(f){if(!tinymce.isGecko&&f.target.nodeName=="IMG"&&e.dom.getParent(f.target,"dl.wp-caption")){return tinymce.dom.Event.cancel(f)}})});a.onMouseUp.add(function(f,g){if(tinymce.isWebKit||tinymce.isOpera){return}if(b.x&&(g.clientX!=b.x||g.clientY!=b.y)){var h=f.selection.getNode();if("IMG"==h.nodeName){window.setTimeout(function(){var e,i;if(h.width!=b.img_w||h.height!=b.img_h){h.className=h.className.replace(/size-[^ "']+/,"")}if(f.dom.getParent(h,"div.mceTemp")){e=f.dom.getParent(h,"dl.wp-caption");if(e){i=f.dom.getAttrib(h,"width")||h.width;i=parseInt(i,10);f.dom.setStyle(e,"width",10+i);f.execCommand("mceRepaint")}}},100)}}b={}});a.onMouseDown.add(function(f,g){if(g.target&&(g.target.nodeName=="IMG"||(g.target.firstChild&&g.target.firstChild.nodeName=="IMG"))){b={x:g.clientX,y:g.clientY,img_w:g.target.clientWidth,img_h:g.target.clientHeight};if(f.dom.getAttrib(g.target,"class").indexOf("mceItem")==-1){f.plugins.wordpress._showButtons(g.target,"wp_editbtns")}}});a.onKeyPress.add(function(f,j){var k,g,i,h;if(j.keyCode==13){k=f.selection.getNode();g=f.dom.getParent(k,"dl.wp-caption");i=f.dom.getParent(g,"div.mceTemp");if(g&&i){h=f.dom.create("p",{}," ");f.dom.insertAfter(h,i);if(h.firstChild){f.selection.select(h.firstChild)}else{f.selection.select(h)}tinymce.dom.Event.cancel(j);return false}}});a.onBeforeSetContent.add(function(e,f){f.content=d._do_shcode(f.content)});a.onPostProcess.add(function(e,f){if(f.get){f.content=d._get_shcode(f.content)}})},_do_shcode:function(a){return a.replace(/(?:<p>)?\[(?:wp_)?caption([^\]]+)\]([\s\S]+?)\[\/(?:wp_)?caption\](?:<\/p>)?[\s\u00a0]*/g,function(g,d,k){var j,f,e,h,i;d=d.replace(/\\'|\\'|\\'/g,"'").replace(/\\"|\\"/g,""");k=k.replace(/\\'|\\'/g,"'").replace(/\\"/g,""");j=d.match(/id=['"]([^'"]+)/i);f=d.match(/align=['"]([^'"]+)/i);e=d.match(/width=['"]([0-9]+)/);h=d.match(/caption=['"]([^'"]+)/i);j=(j&&j[1])?j[1]:"";f=(f&&f[1])?f[1]:"alignnone";e=(e&&e[1])?e[1]:"";h=(h&&h[1])?h[1]:"";if(!e||!h){return k}i=(f=="aligncenter")?"mceTemp mceIEcenter":"mceTemp";return'<div class="'+i+'" draggable><dl id="'+j+'" class="wp-caption '+f+'" style="width: '+(10+parseInt(e))+'px"><dt class="wp-caption-dt">'+k+'</dt><dd class="wp-caption-dd">'+h+"</dd></dl></div>"})},_get_shcode:function(a){return a.replace(/<div class="mceTemp[^"]*">\s*<dl([^>]+)>\s*<dt[^>]+>([\s\S]+?)<\/dt>\s*<dd[^>]+>(.+?)<\/dd>\s*<\/dl>\s*<\/div>\s*/gi,function(g,d,j,h){var i,f,e;i=d.match(/id=['"]([^'"]+)/i);f=d.match(/class=['"]([^'"]+)/i);e=j.match(/width=['"]([0-9]+)/);i=(i&&i[1])?i[1]:"";f=(f&&f[1])?f[1]:"alignnone";e=(e&&e[1])?e[1]:"";if(!e||!h){return j}f=f.match(/align[^ '"]+/)||"alignnone";h=h.replace(/<\S[^<>]*>/gi,"").replace(/'/g,"'").replace(/"/g,""");return'[caption id="'+i+'" align="'+f+'" width="'+e+'" caption="'+h+'"]'+j+"[/caption]"})},_createButtons:function(){var b=this,a=tinyMCE.activeEditor,d=tinymce.DOM,e,c;d.remove("wp_editbtns");d.add(document.body,"div",{id:"wp_editbtns",style:"display:none;"});e=d.add("wp_editbtns","img",{src:b.url+"/img/image.png",id:"wp_editimgbtn",width:"24",height:"24",title:a.getLang("wpeditimage.edit_img")});tinymce.dom.Event.add(e,"mousedown",function(g){var f=tinyMCE.activeEditor;f.windowManager.bookmark=f.selection.getBookmark("simple");f.execCommand("WP_EditImage")});c=d.add("wp_editbtns","img",{src:b.url+"/img/delete.png",id:"wp_delimgbtn",width:"24",height:"24",title:a.getLang("wpeditimage.del_img")});tinymce.dom.Event.add(c,"mousedown",function(i){var f=tinyMCE.activeEditor,g=f.selection.getNode(),h;if(g.nodeName=="IMG"&&f.dom.getAttrib(g,"class").indexOf("mceItem")==-1){if((h=f.dom.getParent(g,"div"))&&f.dom.hasClass(h,"mceTemp")){f.dom.remove(h)}else{if((h=f.dom.getParent(g,"A"))&&h.childNodes.length==1){f.dom.remove(h)}else{f.dom.remove(g)}}f.execCommand("mceRepaint");return false}})},getInfo:function(){return{longname:"Edit Image",author:"WordPress",authorurl:"http://wordpress.org",infourl:"",version:"1.0"}}});tinymce.PluginManager.add("wpeditimage",tinymce.plugins.wpEditImage)})(); 3 No newline at end of file -
wp-includes/js/tinymce/plugins/fullscreen/editor_plugin.dev.js
1 /** 2 * editor_plugin_src.js 3 * 4 * Copyright 2009, Moxiecode Systems AB 5 * Released under LGPL License. 6 * 7 * License: http://tinymce.moxiecode.com/license 8 * Contributing: http://tinymce.moxiecode.com/contributing 9 */ 10 11 (function() { 12 var DOM = tinymce.DOM; 13 14 tinymce.create('tinymce.plugins.FullScreenPlugin', { 15 init : function(ed, url) { 16 var t = this, s = {}, vp, posCss; 17 18 t.editor = ed; 19 20 // Register commands 21 ed.addCommand('mceFullScreen', function() { 22 var win, de = DOM.doc.documentElement; 23 24 if (ed.getParam('fullscreen_is_enabled')) { 25 if (ed.getParam('fullscreen_new_window')) 26 closeFullscreen(); // Call to close in new window 27 else { 28 DOM.win.setTimeout(function() { 29 tinymce.dom.Event.remove(DOM.win, 'resize', t.resizeFunc); 30 tinyMCE.get(ed.getParam('fullscreen_editor_id')).setContent(ed.getContent()); 31 tinyMCE.remove(ed); 32 DOM.remove('mce_fullscreen_container'); 33 de.style.overflow = ed.getParam('fullscreen_html_overflow'); 34 DOM.setStyle(DOM.doc.body, 'overflow', ed.getParam('fullscreen_overflow')); 35 DOM.win.scrollTo(ed.getParam('fullscreen_scrollx'), ed.getParam('fullscreen_scrolly')); 36 tinyMCE.settings = tinyMCE.oldSettings; // Restore old settings 37 }, 10); 38 } 39 40 return; 41 } 42 43 if (ed.getParam('fullscreen_new_window')) { 44 win = DOM.win.open(url + "/fullscreen.htm", "mceFullScreenPopup", "fullscreen=yes,menubar=no,toolbar=no,scrollbars=no,resizable=yes,left=0,top=0,width=" + screen.availWidth + ",height=" + screen.availHeight); 45 try { 46 win.resizeTo(screen.availWidth, screen.availHeight); 47 } catch (e) { 48 // Ignore 49 } 50 } else { 51 tinyMCE.oldSettings = tinyMCE.settings; // Store old settings 52 s.fullscreen_overflow = DOM.getStyle(DOM.doc.body, 'overflow', 1) || 'auto'; 53 s.fullscreen_html_overflow = DOM.getStyle(de, 'overflow', 1); 54 vp = DOM.getViewPort(); 55 s.fullscreen_scrollx = vp.x; 56 s.fullscreen_scrolly = vp.y; 57 58 // Fixes an Opera bug where the scrollbars doesn't reappear 59 if (tinymce.isOpera && s.fullscreen_overflow == 'visible') 60 s.fullscreen_overflow = 'auto'; 61 62 // Fixes an IE bug where horizontal scrollbars would appear 63 if (tinymce.isIE && s.fullscreen_overflow == 'scroll') 64 s.fullscreen_overflow = 'auto'; 65 66 // Fixes an IE bug where the scrollbars doesn't reappear 67 if (tinymce.isIE && (s.fullscreen_html_overflow == 'visible' || s.fullscreen_html_overflow == 'scroll')) 68 s.fullscreen_html_overflow = 'auto'; 69 70 if (s.fullscreen_overflow == '0px') 71 s.fullscreen_overflow = ''; 72 73 DOM.setStyle(DOM.doc.body, 'overflow', 'hidden'); 74 de.style.overflow = 'hidden'; //Fix for IE6/7 75 vp = DOM.getViewPort(); 76 DOM.win.scrollTo(0, 0); 77 78 if (tinymce.isIE) 79 vp.h -= 1; 80 81 // Use fixed position if it exists 82 if (tinymce.isIE6) 83 posCss = 'absolute;top:' + vp.y; 84 else 85 posCss = 'fixed;top:0'; 86 87 n = DOM.add(DOM.doc.body, 'div', { 88 id : 'mce_fullscreen_container', 89 style : 'position:' + posCss + ';left:0;width:' + vp.w + 'px;height:' + vp.h + 'px;z-index:200000;'}); 90 DOM.add(n, 'div', {id : 'mce_fullscreen'}); 91 92 tinymce.each(ed.settings, function(v, n) { 93 s[n] = v; 94 }); 95 96 s.id = 'mce_fullscreen'; 97 s.width = n.clientWidth; 98 s.height = n.clientHeight - 15; 99 s.fullscreen_is_enabled = true; 100 s.fullscreen_editor_id = ed.id; 101 s.theme_advanced_resizing = false; 102 s.save_onsavecallback = function() { 103 ed.setContent(tinyMCE.get(s.id).getContent()); 104 ed.execCommand('mceSave'); 105 }; 106 107 tinymce.each(ed.getParam('fullscreen_settings'), function(v, k) { 108 s[k] = v; 109 }); 110 111 if (s.theme_advanced_toolbar_location === 'external') 112 s.theme_advanced_toolbar_location = 'top'; 113 114 t.fullscreenEditor = new tinymce.Editor('mce_fullscreen', s); 115 t.fullscreenEditor.onInit.add(function() { 116 t.fullscreenEditor.setContent(ed.getContent()); 117 t.fullscreenEditor.focus(); 118 }); 119 120 t.fullscreenEditor.render(); 121 122 t.fullscreenElement = new tinymce.dom.Element('mce_fullscreen_container'); 123 t.fullscreenElement.update(); 124 //document.body.overflow = 'hidden'; 125 126 t.resizeFunc = tinymce.dom.Event.add(DOM.win, 'resize', function() { 127 var vp = tinymce.DOM.getViewPort(), fed = t.fullscreenEditor, outerSize, innerSize; 128 129 // Get outer/inner size to get a delta size that can be used to calc the new iframe size 130 outerSize = fed.dom.getSize(fed.getContainer().firstChild); 131 innerSize = fed.dom.getSize(fed.getContainer().getElementsByTagName('iframe')[0]); 132 133 fed.theme.resizeTo(vp.w - outerSize.w + innerSize.w, vp.h - outerSize.h + innerSize.h); 134 }); 135 } 136 }); 137 138 // Register buttons 139 ed.addButton('fullscreen', {title : 'fullscreen.desc', cmd : 'mceFullScreen'}); 140 141 ed.onNodeChange.add(function(ed, cm) { 142 cm.setActive('fullscreen', ed.getParam('fullscreen_is_enabled')); 143 }); 144 }, 145 146 getInfo : function() { 147 return { 148 longname : 'Fullscreen', 149 author : 'Moxiecode Systems AB', 150 authorurl : 'http://tinymce.moxiecode.com', 151 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullscreen', 152 version : tinymce.majorVersion + "." + tinymce.minorVersion 153 }; 154 } 155 }); 156 157 // Register plugin 158 tinymce.PluginManager.add('fullscreen', tinymce.plugins.FullScreenPlugin); 159 })(); 160 No newline at end of file -
wp-includes/js/tinymce/plugins/directionality/editor_plugin.dev.js
1 /** 2 * editor_plugin_src.js 3 * 4 * Copyright 2009, Moxiecode Systems AB 5 * Released under LGPL License. 6 * 7 * License: http://tinymce.moxiecode.com/license 8 * Contributing: http://tinymce.moxiecode.com/contributing 9 */ 10 11 (function() { 12 tinymce.create('tinymce.plugins.Directionality', { 13 init : function(ed, url) { 14 var t = this; 15 16 t.editor = ed; 17 18 ed.addCommand('mceDirectionLTR', function() { 19 var e = ed.dom.getParent(ed.selection.getNode(), ed.dom.isBlock); 20 21 if (e) { 22 if (ed.dom.getAttrib(e, "dir") != "ltr") 23 ed.dom.setAttrib(e, "dir", "ltr"); 24 else 25 ed.dom.setAttrib(e, "dir", ""); 26 } 27 28 ed.nodeChanged(); 29 }); 30 31 ed.addCommand('mceDirectionRTL', function() { 32 var e = ed.dom.getParent(ed.selection.getNode(), ed.dom.isBlock); 33 34 if (e) { 35 if (ed.dom.getAttrib(e, "dir") != "rtl") 36 ed.dom.setAttrib(e, "dir", "rtl"); 37 else 38 ed.dom.setAttrib(e, "dir", ""); 39 } 40 41 ed.nodeChanged(); 42 }); 43 44 ed.addButton('ltr', {title : 'directionality.ltr_desc', cmd : 'mceDirectionLTR'}); 45 ed.addButton('rtl', {title : 'directionality.rtl_desc', cmd : 'mceDirectionRTL'}); 46 47 ed.onNodeChange.add(t._nodeChange, t); 48 }, 49 50 getInfo : function() { 51 return { 52 longname : 'Directionality', 53 author : 'Moxiecode Systems AB', 54 authorurl : 'http://tinymce.moxiecode.com', 55 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/directionality', 56 version : tinymce.majorVersion + "." + tinymce.minorVersion 57 }; 58 }, 59 60 // Private methods 61 62 _nodeChange : function(ed, cm, n) { 63 var dom = ed.dom, dir; 64 65 n = dom.getParent(n, dom.isBlock); 66 if (!n) { 67 cm.setDisabled('ltr', 1); 68 cm.setDisabled('rtl', 1); 69 return; 70 } 71 72 dir = dom.getAttrib(n, 'dir'); 73 cm.setActive('ltr', dir == "ltr"); 74 cm.setDisabled('ltr', 0); 75 cm.setActive('rtl', dir == "rtl"); 76 cm.setDisabled('rtl', 0); 77 } 78 }); 79 80 // Register plugin 81 tinymce.PluginManager.add('directionality', tinymce.plugins.Directionality); 82 })(); 83 No newline at end of file -
wp-includes/js/tinymce/plugins/spellchecker/editor_plugin.dev.js
1 /** 2 * editor_plugin_src.js 3 * 4 * Copyright 2009, Moxiecode Systems AB 5 * Released under LGPL License. 6 * 7 * License: http://tinymce.moxiecode.com/license 8 * Contributing: http://tinymce.moxiecode.com/contributing 9 */ 10 11 (function() { 12 var JSONRequest = tinymce.util.JSONRequest, each = tinymce.each, DOM = tinymce.DOM; 13 14 tinymce.create('tinymce.plugins.SpellcheckerPlugin', { 15 getInfo : function() { 16 return { 17 longname : 'Spellchecker', 18 author : 'Moxiecode Systems AB', 19 authorurl : 'http://tinymce.moxiecode.com', 20 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker', 21 version : tinymce.majorVersion + "." + tinymce.minorVersion 22 }; 23 }, 24 25 init : function(ed, url) { 26 var t = this, cm; 27 28 t.url = url; 29 t.editor = ed; 30 t.rpcUrl = ed.getParam("spellchecker_rpc_url", "{backend}"); 31 32 if (t.rpcUrl == '{backend}') { 33 // Sniff if the browser supports native spellchecking (Don't know of a better way) 34 if (tinymce.isIE) 35 return; 36 37 t.hasSupport = true; 38 39 // Disable the context menu when spellchecking is active 40 ed.onContextMenu.addToTop(function(ed, e) { 41 if (t.active) 42 return false; 43 }); 44 } 45 46 // Register commands 47 ed.addCommand('mceSpellCheck', function() { 48 if (t.rpcUrl == '{backend}') { 49 // Enable/disable native spellchecker 50 t.editor.getBody().spellcheck = t.active = !t.active; 51 return; 52 } 53 54 if (!t.active) { 55 ed.setProgressState(1); 56 t._sendRPC('checkWords', [t.selectedLang, t._getWords()], function(r) { 57 if (r.length > 0) { 58 t.active = 1; 59 t._markWords(r); 60 ed.setProgressState(0); 61 ed.nodeChanged(); 62 } else { 63 ed.setProgressState(0); 64 65 if (ed.getParam('spellchecker_report_no_misspellings', true)) 66 ed.windowManager.alert('spellchecker.no_mpell'); 67 } 68 }); 69 } else 70 t._done(); 71 }); 72 73 if (ed.settings.content_css !== false) 74 ed.contentCSS.push(url + '/css/content.css'); 75 76 ed.onClick.add(t._showMenu, t); 77 ed.onContextMenu.add(t._showMenu, t); 78 ed.onBeforeGetContent.add(function() { 79 if (t.active) 80 t._removeWords(); 81 }); 82 83 ed.onNodeChange.add(function(ed, cm) { 84 cm.setActive('spellchecker', t.active); 85 }); 86 87 ed.onSetContent.add(function() { 88 t._done(); 89 }); 90 91 ed.onBeforeGetContent.add(function() { 92 t._done(); 93 }); 94 95 ed.onBeforeExecCommand.add(function(ed, cmd) { 96 if (cmd == 'mceFullScreen') 97 t._done(); 98 }); 99 100 // Find selected language 101 t.languages = {}; 102 each(ed.getParam('spellchecker_languages', '+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv', 'hash'), function(v, k) { 103 if (k.indexOf('+') === 0) { 104 k = k.substring(1); 105 t.selectedLang = v; 106 } 107 108 t.languages[k] = v; 109 }); 110 }, 111 112 createControl : function(n, cm) { 113 var t = this, c, ed = t.editor; 114 115 if (n == 'spellchecker') { 116 // Use basic button if we use the native spellchecker 117 if (t.rpcUrl == '{backend}') { 118 // Create simple toggle button if we have native support 119 if (t.hasSupport) 120 c = cm.createButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t}); 121 122 return c; 123 } 124 125 c = cm.createSplitButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t}); 126 127 c.onRenderMenu.add(function(c, m) { 128 m.add({title : 'spellchecker.langs', 'class' : 'mceMenuItemTitle'}).setDisabled(1); 129 each(t.languages, function(v, k) { 130 var o = {icon : 1}, mi; 131 132 o.onclick = function() { 133 if (v == t.selectedLang) { 134 return; 135 } 136 mi.setSelected(1); 137 t.selectedItem.setSelected(0); 138 t.selectedItem = mi; 139 t.selectedLang = v; 140 }; 141 142 o.title = k; 143 mi = m.add(o); 144 mi.setSelected(v == t.selectedLang); 145 146 if (v == t.selectedLang) 147 t.selectedItem = mi; 148 }) 149 }); 150 151 return c; 152 } 153 }, 154 155 // Internal functions 156 157 _walk : function(n, f) { 158 var d = this.editor.getDoc(), w; 159 160 if (d.createTreeWalker) { 161 w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false); 162 163 while ((n = w.nextNode()) != null) 164 f.call(this, n); 165 } else 166 tinymce.walk(n, f, 'childNodes'); 167 }, 168 169 _getSeparators : function() { 170 var re = '', i, str = this.editor.getParam('spellchecker_word_separator_chars', '\\s!"#$%&()*+,-./:;<=>?@[\]^_{|}§©«®±¶·¸»¼½¾¿×÷¤\u201d\u201c'); 171 172 // Build word separator regexp 173 for (i=0; i<str.length; i++) 174 re += '\\' + str.charAt(i); 175 176 return re; 177 }, 178 179 _getWords : function() { 180 var ed = this.editor, wl = [], tx = '', lo = {}, rawWords = []; 181 182 // Get area text 183 this._walk(ed.getBody(), function(n) { 184 if (n.nodeType == 3) 185 tx += n.nodeValue + ' '; 186 }); 187 188 // split the text up into individual words 189 if (ed.getParam('spellchecker_word_pattern')) { 190 // look for words that match the pattern 191 rawWords = tx.match('(' + ed.getParam('spellchecker_word_pattern') + ')', 'gi'); 192 } else { 193 // Split words by separator 194 tx = tx.replace(new RegExp('([0-9]|[' + this._getSeparators() + '])', 'g'), ' '); 195 tx = tinymce.trim(tx.replace(/(\s+)/g, ' ')); 196 rawWords = tx.split(' '); 197 } 198 199 // Build word array and remove duplicates 200 each(rawWords, function(v) { 201 if (!lo[v]) { 202 wl.push(v); 203 lo[v] = 1; 204 } 205 }); 206 207 return wl; 208 }, 209 210 _removeWords : function(w) { 211 var ed = this.editor, dom = ed.dom, se = ed.selection, b = se.getBookmark(); 212 213 each(dom.select('span').reverse(), function(n) { 214 if (n && (dom.hasClass(n, 'mceItemHiddenSpellWord') || dom.hasClass(n, 'mceItemHidden'))) { 215 if (!w || dom.decode(n.innerHTML) == w) 216 dom.remove(n, 1); 217 } 218 }); 219 220 se.moveToBookmark(b); 221 }, 222 223 _markWords : function(wl) { 224 var ed = this.editor, dom = ed.dom, doc = ed.getDoc(), se = ed.selection, b = se.getBookmark(), nl = [], 225 w = wl.join('|'), re = this._getSeparators(), rx = new RegExp('(^|[' + re + '])(' + w + ')(?=[' + re + ']|$)', 'g'); 226 227 // Collect all text nodes 228 this._walk(ed.getBody(), function(n) { 229 if (n.nodeType == 3) { 230 nl.push(n); 231 } 232 }); 233 234 // Wrap incorrect words in spans 235 each(nl, function(n) { 236 var node, elem, txt, pos, v = n.nodeValue; 237 238 if (rx.test(v)) { 239 // Encode the content 240 v = dom.encode(v); 241 // Create container element 242 elem = dom.create('span', {'class' : 'mceItemHidden'}); 243 244 // Following code fixes IE issues by creating text nodes 245 // using DOM methods instead of innerHTML. 246 // Bug #3124: <PRE> elements content is broken after spellchecking. 247 // Bug #1408: Preceding whitespace characters are removed 248 // @TODO: I'm not sure that both are still issues on IE9. 249 if (tinymce.isIE) { 250 // Enclose mispelled words with temporal tag 251 v = v.replace(rx, '$1<mcespell>$2</mcespell>'); 252 // Loop over the content finding mispelled words 253 while ((pos = v.indexOf('<mcespell>')) != -1) { 254 // Add text node for the content before the word 255 txt = v.substring(0, pos); 256 if (txt.length) { 257 node = doc.createTextNode(dom.decode(txt)); 258 elem.appendChild(node); 259 } 260 v = v.substring(pos+10); 261 pos = v.indexOf('</mcespell>'); 262 txt = v.substring(0, pos); 263 v = v.substring(pos+11); 264 // Add span element for the word 265 elem.appendChild(dom.create('span', {'class' : 'mceItemHiddenSpellWord'}, txt)); 266 } 267 // Add text node for the rest of the content 268 if (v.length) { 269 node = doc.createTextNode(dom.decode(v)); 270 elem.appendChild(node); 271 } 272 } else { 273 // Other browsers preserve whitespace characters on innerHTML usage 274 elem.innerHTML = v.replace(rx, '$1<span class="mceItemHiddenSpellWord">$2</span>'); 275 } 276 277 // Finally, replace the node with the container 278 dom.replace(elem, n); 279 } 280 }); 281 282 se.moveToBookmark(b); 283 }, 284 285 _showMenu : function(ed, e) { 286 var t = this, ed = t.editor, m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin()), wordSpan = e.target; 287 288 e = 0; // Fixes IE memory leak 289 290 if (!m) { 291 m = ed.controlManager.createDropMenu('spellcheckermenu', {'class' : 'mceNoIcons'}); 292 t._menu = m; 293 } 294 295 if (dom.hasClass(wordSpan, 'mceItemHiddenSpellWord')) { 296 m.removeAll(); 297 m.add({title : 'spellchecker.wait', 'class' : 'mceMenuItemTitle'}).setDisabled(1); 298 299 t._sendRPC('getSuggestions', [t.selectedLang, dom.decode(wordSpan.innerHTML)], function(r) { 300 var ignoreRpc; 301 302 m.removeAll(); 303 304 if (r.length > 0) { 305 m.add({title : 'spellchecker.sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1); 306 each(r, function(v) { 307 m.add({title : v, onclick : function() { 308 dom.replace(ed.getDoc().createTextNode(v), wordSpan); 309 t._checkDone(); 310 }}); 311 }); 312 313 m.addSeparator(); 314 } else 315 m.add({title : 'spellchecker.no_sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1); 316 317 if (ed.getParam('show_ignore_words', true)) { 318 ignoreRpc = t.editor.getParam("spellchecker_enable_ignore_rpc", ''); 319 m.add({ 320 title : 'spellchecker.ignore_word', 321 onclick : function() { 322 var word = wordSpan.innerHTML; 323 324 dom.remove(wordSpan, 1); 325 t._checkDone(); 326 327 // tell the server if we need to 328 if (ignoreRpc) { 329 ed.setProgressState(1); 330 t._sendRPC('ignoreWord', [t.selectedLang, word], function(r) { 331 ed.setProgressState(0); 332 }); 333 } 334 } 335 }); 336 337 m.add({ 338 title : 'spellchecker.ignore_words', 339 onclick : function() { 340 var word = wordSpan.innerHTML; 341 342 t._removeWords(dom.decode(word)); 343 t._checkDone(); 344 345 // tell the server if we need to 346 if (ignoreRpc) { 347 ed.setProgressState(1); 348 t._sendRPC('ignoreWords', [t.selectedLang, word], function(r) { 349 ed.setProgressState(0); 350 }); 351 } 352 } 353 }); 354 } 355 356 if (t.editor.getParam("spellchecker_enable_learn_rpc")) { 357 m.add({ 358 title : 'spellchecker.learn_word', 359 onclick : function() { 360 var word = wordSpan.innerHTML; 361 362 dom.remove(wordSpan, 1); 363 t._checkDone(); 364 365 ed.setProgressState(1); 366 t._sendRPC('learnWord', [t.selectedLang, word], function(r) { 367 ed.setProgressState(0); 368 }); 369 } 370 }); 371 } 372 373 m.update(); 374 }); 375 376 p1 = DOM.getPos(ed.getContentAreaContainer()); 377 m.settings.offset_x = p1.x; 378 m.settings.offset_y = p1.y; 379 380 ed.selection.select(wordSpan); 381 p1 = dom.getPos(wordSpan); 382 m.showMenu(p1.x, p1.y + wordSpan.offsetHeight - vp.y); 383 384 return tinymce.dom.Event.cancel(e); 385 } else 386 m.hideMenu(); 387 }, 388 389 _checkDone : function() { 390 var t = this, ed = t.editor, dom = ed.dom, o; 391 392 each(dom.select('span'), function(n) { 393 if (n && dom.hasClass(n, 'mceItemHiddenSpellWord')) { 394 o = true; 395 return false; 396 } 397 }); 398 399 if (!o) 400 t._done(); 401 }, 402 403 _done : function() { 404 var t = this, la = t.active; 405 406 if (t.active) { 407 t.active = 0; 408 t._removeWords(); 409 410 if (t._menu) 411 t._menu.hideMenu(); 412 413 if (la) 414 t.editor.nodeChanged(); 415 } 416 }, 417 418 _sendRPC : function(m, p, cb) { 419 var t = this; 420 421 JSONRequest.sendRPC({ 422 url : t.rpcUrl, 423 method : m, 424 params : p, 425 success : cb, 426 error : function(e, x) { 427 t.editor.setProgressState(0); 428 t.editor.windowManager.alert(e.errstr || ('Error response: ' + x.responseText)); 429 } 430 }); 431 } 432 }); 433 434 // Register plugin 435 tinymce.PluginManager.add('spellchecker', tinymce.plugins.SpellcheckerPlugin); 436 })(); -
wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin.dev.js
1 /** 2 * editor_plugin_src.js 3 * 4 * Copyright 2009, Moxiecode Systems AB 5 * Released under LGPL License. 6 * 7 * License: http://tinymce.moxiecode.com/license 8 * Contributing: http://tinymce.moxiecode.com/contributing 9 */ 10 11 (function() { 12 var DOM = tinymce.DOM, Element = tinymce.dom.Element, Event = tinymce.dom.Event, each = tinymce.each, is = tinymce.is; 13 14 tinymce.create('tinymce.plugins.InlinePopups', { 15 init : function(ed, url) { 16 // Replace window manager 17 ed.onBeforeRenderUI.add(function() { 18 ed.windowManager = new tinymce.InlineWindowManager(ed); 19 DOM.loadCSS(url + '/skins/' + (ed.settings.inlinepopups_skin || 'clearlooks2') + "/window.css"); 20 }); 21 }, 22 23 getInfo : function() { 24 return { 25 longname : 'InlinePopups', 26 author : 'Moxiecode Systems AB', 27 authorurl : 'http://tinymce.moxiecode.com', 28 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups', 29 version : tinymce.majorVersion + "." + tinymce.minorVersion 30 }; 31 } 32 }); 33 34 tinymce.create('tinymce.InlineWindowManager:tinymce.WindowManager', { 35 InlineWindowManager : function(ed) { 36 var t = this; 37 38 t.parent(ed); 39 t.zIndex = 300000; 40 t.count = 0; 41 t.windows = {}; 42 }, 43 44 open : function(f, p) { 45 var t = this, id, opt = '', ed = t.editor, dw = 0, dh = 0, vp, po, mdf, clf, we, w, u, parentWindow; 46 47 f = f || {}; 48 p = p || {}; 49 50 // Run native windows 51 if (!f.inline) 52 return t.parent(f, p); 53 54 parentWindow = t._frontWindow(); 55 if (parentWindow && DOM.get(parentWindow.id + '_ifr')) { 56 parentWindow.focussedElement = DOM.get(parentWindow.id + '_ifr').contentWindow.document.activeElement; 57 } 58 59 // Only store selection if the type is a normal window 60 if (!f.type) 61 t.bookmark = ed.selection.getBookmark(1); 62 63 id = DOM.uniqueId(); 64 vp = DOM.getViewPort(); 65 f.width = parseInt(f.width || 320); 66 f.height = parseInt(f.height || 240) + (tinymce.isIE ? 8 : 0); 67 f.min_width = parseInt(f.min_width || 150); 68 f.min_height = parseInt(f.min_height || 100); 69 f.max_width = parseInt(f.max_width || 2000); 70 f.max_height = parseInt(f.max_height || 2000); 71 f.left = f.left || Math.round(Math.max(vp.x, vp.x + (vp.w / 2.0) - (f.width / 2.0))); 72 f.top = f.top || Math.round(Math.max(vp.y, vp.y + (vp.h / 2.0) - (f.height / 2.0))); 73 f.movable = f.resizable = true; 74 p.mce_width = f.width; 75 p.mce_height = f.height; 76 p.mce_inline = true; 77 p.mce_window_id = id; 78 p.mce_auto_focus = f.auto_focus; 79 80 // Transpose 81 // po = DOM.getPos(ed.getContainer()); 82 // f.left -= po.x; 83 // f.top -= po.y; 84 85 t.features = f; 86 t.params = p; 87 t.onOpen.dispatch(t, f, p); 88 89 if (f.type) { 90 opt += ' mceModal'; 91 92 if (f.type) 93 opt += ' mce' + f.type.substring(0, 1).toUpperCase() + f.type.substring(1); 94 95 f.resizable = false; 96 } 97 98 if (f.statusbar) 99 opt += ' mceStatusbar'; 100 101 if (f.resizable) 102 opt += ' mceResizable'; 103 104 if (f.minimizable) 105 opt += ' mceMinimizable'; 106 107 if (f.maximizable) 108 opt += ' mceMaximizable'; 109 110 if (f.movable) 111 opt += ' mceMovable'; 112 113 // Create DOM objects 114 t._addAll(DOM.doc.body, 115 ['div', {id : id, role : 'dialog', 'aria-labelledby': f.type ? id + '_content' : id + '_title', 'class' : (ed.settings.inlinepopups_skin || 'clearlooks2') + (tinymce.isIE && window.getSelection ? ' ie9' : ''), style : 'width:100px;height:100px'}, 116 ['div', {id : id + '_wrapper', 'class' : 'mceWrapper' + opt}, 117 ['div', {id : id + '_top', 'class' : 'mceTop'}, 118 ['div', {'class' : 'mceLeft'}], 119 ['div', {'class' : 'mceCenter'}], 120 ['div', {'class' : 'mceRight'}], 121 ['span', {id : id + '_title'}, f.title || ''] 122 ], 123 124 ['div', {id : id + '_middle', 'class' : 'mceMiddle'}, 125 ['div', {id : id + '_left', 'class' : 'mceLeft', tabindex : '0'}], 126 ['span', {id : id + '_content'}], 127 ['div', {id : id + '_right', 'class' : 'mceRight', tabindex : '0'}] 128 ], 129 130 ['div', {id : id + '_bottom', 'class' : 'mceBottom'}, 131 ['div', {'class' : 'mceLeft'}], 132 ['div', {'class' : 'mceCenter'}], 133 ['div', {'class' : 'mceRight'}], 134 ['span', {id : id + '_status'}, 'Content'] 135 ], 136 137 ['a', {'class' : 'mceMove', tabindex : '-1', href : 'javascript:;'}], 138 ['a', {'class' : 'mceMin', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], 139 ['a', {'class' : 'mceMax', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], 140 ['a', {'class' : 'mceMed', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], 141 ['a', {'class' : 'mceClose', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], 142 ['a', {id : id + '_resize_n', 'class' : 'mceResize mceResizeN', tabindex : '-1', href : 'javascript:;'}], 143 ['a', {id : id + '_resize_s', 'class' : 'mceResize mceResizeS', tabindex : '-1', href : 'javascript:;'}], 144 ['a', {id : id + '_resize_w', 'class' : 'mceResize mceResizeW', tabindex : '-1', href : 'javascript:;'}], 145 ['a', {id : id + '_resize_e', 'class' : 'mceResize mceResizeE', tabindex : '-1', href : 'javascript:;'}], 146 ['a', {id : id + '_resize_nw', 'class' : 'mceResize mceResizeNW', tabindex : '-1', href : 'javascript:;'}], 147 ['a', {id : id + '_resize_ne', 'class' : 'mceResize mceResizeNE', tabindex : '-1', href : 'javascript:;'}], 148 ['a', {id : id + '_resize_sw', 'class' : 'mceResize mceResizeSW', tabindex : '-1', href : 'javascript:;'}], 149 ['a', {id : id + '_resize_se', 'class' : 'mceResize mceResizeSE', tabindex : '-1', href : 'javascript:;'}] 150 ] 151 ] 152 ); 153 154 DOM.setStyles(id, {top : -10000, left : -10000}); 155 156 // Fix gecko rendering bug, where the editors iframe messed with window contents 157 if (tinymce.isGecko) 158 DOM.setStyle(id, 'overflow', 'auto'); 159 160 // Measure borders 161 if (!f.type) { 162 dw += DOM.get(id + '_left').clientWidth; 163 dw += DOM.get(id + '_right').clientWidth; 164 dh += DOM.get(id + '_top').clientHeight; 165 dh += DOM.get(id + '_bottom').clientHeight; 166 } 167 168 // Resize window 169 DOM.setStyles(id, {top : f.top, left : f.left, width : f.width + dw, height : f.height + dh}); 170 171 u = f.url || f.file; 172 if (u) { 173 if (tinymce.relaxedDomain) 174 u += (u.indexOf('?') == -1 ? '?' : '&') + 'mce_rdomain=' + tinymce.relaxedDomain; 175 176 u = tinymce._addVer(u); 177 } 178 179 if (!f.type) { 180 DOM.add(id + '_content', 'iframe', {id : id + '_ifr', src : 'javascript:""', frameBorder : 0, style : 'border:0;width:10px;height:10px'}); 181 DOM.setStyles(id + '_ifr', {width : f.width, height : f.height}); 182 DOM.setAttrib(id + '_ifr', 'src', u); 183 } else { 184 DOM.add(id + '_wrapper', 'a', {id : id + '_ok', 'class' : 'mceButton mceOk', href : 'javascript:;', onmousedown : 'return false;'}, 'Ok'); 185 186 if (f.type == 'confirm') 187 DOM.add(id + '_wrapper', 'a', {'class' : 'mceButton mceCancel', href : 'javascript:;', onmousedown : 'return false;'}, 'Cancel'); 188 189 DOM.add(id + '_middle', 'div', {'class' : 'mceIcon'}); 190 DOM.setHTML(id + '_content', f.content.replace('\n', '<br />')); 191 192 Event.add(id, 'keyup', function(evt) { 193 var VK_ESCAPE = 27; 194 if (evt.keyCode === VK_ESCAPE) { 195 f.button_func(false); 196 return Event.cancel(evt); 197 } 198 }); 199 200 Event.add(id, 'keydown', function(evt) { 201 var cancelButton, VK_TAB = 9; 202 if (evt.keyCode === VK_TAB) { 203 cancelButton = DOM.select('a.mceCancel', id + '_wrapper')[0]; 204 if (cancelButton && cancelButton !== evt.target) { 205 cancelButton.focus(); 206 } else { 207 DOM.get(id + '_ok').focus(); 208 } 209 return Event.cancel(evt); 210 } 211 }); 212 } 213 214 // Register events 215 mdf = Event.add(id, 'mousedown', function(e) { 216 var n = e.target, w, vp; 217 218 w = t.windows[id]; 219 t.focus(id); 220 221 if (n.nodeName == 'A' || n.nodeName == 'a') { 222 if (n.className == 'mceClose') { 223 t.close(null, id); 224 return Event.cancel(e); 225 } else if (n.className == 'mceMax') { 226 w.oldPos = w.element.getXY(); 227 w.oldSize = w.element.getSize(); 228 229 vp = DOM.getViewPort(); 230 231 // Reduce viewport size to avoid scrollbars 232 vp.w -= 2; 233 vp.h -= 2; 234 235 w.element.moveTo(vp.x, vp.y); 236 w.element.resizeTo(vp.w, vp.h); 237 DOM.setStyles(id + '_ifr', {width : vp.w - w.deltaWidth, height : vp.h - w.deltaHeight}); 238 DOM.addClass(id + '_wrapper', 'mceMaximized'); 239 } else if (n.className == 'mceMed') { 240 // Reset to old size 241 w.element.moveTo(w.oldPos.x, w.oldPos.y); 242 w.element.resizeTo(w.oldSize.w, w.oldSize.h); 243 w.iframeElement.resizeTo(w.oldSize.w - w.deltaWidth, w.oldSize.h - w.deltaHeight); 244 245 DOM.removeClass(id + '_wrapper', 'mceMaximized'); 246 } else if (n.className == 'mceMove') 247 return t._startDrag(id, e, n.className); 248 else if (DOM.hasClass(n, 'mceResize')) 249 return t._startDrag(id, e, n.className.substring(13)); 250 } 251 }); 252 253 clf = Event.add(id, 'click', function(e) { 254 var n = e.target; 255 256 t.focus(id); 257 258 if (n.nodeName == 'A' || n.nodeName == 'a') { 259 switch (n.className) { 260 case 'mceClose': 261 t.close(null, id); 262 return Event.cancel(e); 263 264 case 'mceButton mceOk': 265 case 'mceButton mceCancel': 266 f.button_func(n.className == 'mceButton mceOk'); 267 return Event.cancel(e); 268 } 269 } 270 }); 271 272 // Make sure the tab order loops within the dialog. 273 Event.add([id + '_left', id + '_right'], 'focus', function(evt) { 274 var iframe = DOM.get(id + '_ifr'); 275 if (iframe) { 276 var body = iframe.contentWindow.document.body; 277 var focusable = DOM.select(':input:enabled,*[tabindex=0]', body); 278 if (evt.target.id === (id + '_left')) { 279 focusable[focusable.length - 1].focus(); 280 } else { 281 focusable[0].focus(); 282 } 283 } else { 284 DOM.get(id + '_ok').focus(); 285 } 286 }); 287 288 // Add window 289 w = t.windows[id] = { 290 id : id, 291 mousedown_func : mdf, 292 click_func : clf, 293 element : new Element(id, {blocker : 1, container : ed.getContainer()}), 294 iframeElement : new Element(id + '_ifr'), 295 features : f, 296 deltaWidth : dw, 297 deltaHeight : dh 298 }; 299 300 w.iframeElement.on('focus', function() { 301 t.focus(id); 302 }); 303 304 // Setup blocker 305 if (t.count == 0 && t.editor.getParam('dialog_type', 'modal') == 'modal') { 306 DOM.add(DOM.doc.body, 'div', { 307 id : 'mceModalBlocker', 308 'class' : (t.editor.settings.inlinepopups_skin || 'clearlooks2') + '_modalBlocker', 309 style : {zIndex : t.zIndex - 1} 310 }); 311 312 DOM.show('mceModalBlocker'); // Reduces flicker in IE 313 DOM.setAttrib(DOM.doc.body, 'aria-hidden', 'true'); 314 } else 315 DOM.setStyle('mceModalBlocker', 'z-index', t.zIndex - 1); 316 317 if (tinymce.isIE6 || /Firefox\/2\./.test(navigator.userAgent) || (tinymce.isIE && !DOM.boxModel)) 318 DOM.setStyles('mceModalBlocker', {position : 'absolute', left : vp.x, top : vp.y, width : vp.w - 2, height : vp.h - 2}); 319 320 DOM.setAttrib(id, 'aria-hidden', 'false'); 321 t.focus(id); 322 t._fixIELayout(id, 1); 323 324 // Focus ok button 325 if (DOM.get(id + '_ok')) 326 DOM.get(id + '_ok').focus(); 327 t.count++; 328 329 return w; 330 }, 331 332 focus : function(id) { 333 var t = this, w; 334 335 if (w = t.windows[id]) { 336 w.zIndex = this.zIndex++; 337 w.element.setStyle('zIndex', w.zIndex); 338 w.element.update(); 339 340 id = id + '_wrapper'; 341 DOM.removeClass(t.lastId, 'mceFocus'); 342 DOM.addClass(id, 'mceFocus'); 343 t.lastId = id; 344 345 if (w.focussedElement) { 346 w.focussedElement.focus(); 347 } else if (DOM.get(id + '_ok')) { 348 DOM.get(w.id + '_ok').focus(); 349 } else if (DOM.get(w.id + '_ifr')) { 350 DOM.get(w.id + '_ifr').focus(); 351 } 352 } 353 }, 354 355 _addAll : function(te, ne) { 356 var i, n, t = this, dom = tinymce.DOM; 357 358 if (is(ne, 'string')) 359 te.appendChild(dom.doc.createTextNode(ne)); 360 else if (ne.length) { 361 te = te.appendChild(dom.create(ne[0], ne[1])); 362 363 for (i=2; i<ne.length; i++) 364 t._addAll(te, ne[i]); 365 } 366 }, 367 368 _startDrag : function(id, se, ac) { 369 var t = this, mu, mm, d = DOM.doc, eb, w = t.windows[id], we = w.element, sp = we.getXY(), p, sz, ph, cp, vp, sx, sy, sex, sey, dx, dy, dw, dh; 370 371 // Get positons and sizes 372 // cp = DOM.getPos(t.editor.getContainer()); 373 cp = {x : 0, y : 0}; 374 vp = DOM.getViewPort(); 375 376 // Reduce viewport size to avoid scrollbars while dragging 377 vp.w -= 2; 378 vp.h -= 2; 379 380 sex = se.screenX; 381 sey = se.screenY; 382 dx = dy = dw = dh = 0; 383 384 // Handle mouse up 385 mu = Event.add(d, 'mouseup', function(e) { 386 Event.remove(d, 'mouseup', mu); 387 Event.remove(d, 'mousemove', mm); 388 389 if (eb) 390 eb.remove(); 391 392 we.moveBy(dx, dy); 393 we.resizeBy(dw, dh); 394 sz = we.getSize(); 395 DOM.setStyles(id + '_ifr', {width : sz.w - w.deltaWidth, height : sz.h - w.deltaHeight}); 396 t._fixIELayout(id, 1); 397 398 return Event.cancel(e); 399 }); 400 401 if (ac != 'Move') 402 startMove(); 403 404 function startMove() { 405 if (eb) 406 return; 407 408 t._fixIELayout(id, 0); 409 410 // Setup event blocker 411 DOM.add(d.body, 'div', { 412 id : 'mceEventBlocker', 413 'class' : 'mceEventBlocker ' + (t.editor.settings.inlinepopups_skin || 'clearlooks2'), 414 style : {zIndex : t.zIndex + 1} 415 }); 416 417 if (tinymce.isIE6 || (tinymce.isIE && !DOM.boxModel)) 418 DOM.setStyles('mceEventBlocker', {position : 'absolute', left : vp.x, top : vp.y, width : vp.w - 2, height : vp.h - 2}); 419 420 eb = new Element('mceEventBlocker'); 421 eb.update(); 422 423 // Setup placeholder 424 p = we.getXY(); 425 sz = we.getSize(); 426 sx = cp.x + p.x - vp.x; 427 sy = cp.y + p.y - vp.y; 428 DOM.add(eb.get(), 'div', {id : 'mcePlaceHolder', 'class' : 'mcePlaceHolder', style : {left : sx, top : sy, width : sz.w, height : sz.h}}); 429 ph = new Element('mcePlaceHolder'); 430 }; 431 432 // Handle mouse move/drag 433 mm = Event.add(d, 'mousemove', function(e) { 434 var x, y, v; 435 436 startMove(); 437 438 x = e.screenX - sex; 439 y = e.screenY - sey; 440 441 switch (ac) { 442 case 'ResizeW': 443 dx = x; 444 dw = 0 - x; 445 break; 446 447 case 'ResizeE': 448 dw = x; 449 break; 450 451 case 'ResizeN': 452 case 'ResizeNW': 453 case 'ResizeNE': 454 if (ac == "ResizeNW") { 455 dx = x; 456 dw = 0 - x; 457 } else if (ac == "ResizeNE") 458 dw = x; 459 460 dy = y; 461 dh = 0 - y; 462 break; 463 464 case 'ResizeS': 465 case 'ResizeSW': 466 case 'ResizeSE': 467 if (ac == "ResizeSW") { 468 dx = x; 469 dw = 0 - x; 470 } else if (ac == "ResizeSE") 471 dw = x; 472 473 dh = y; 474 break; 475 476 case 'mceMove': 477 dx = x; 478 dy = y; 479 break; 480 } 481 482 // Boundary check 483 if (dw < (v = w.features.min_width - sz.w)) { 484 if (dx !== 0) 485 dx += dw - v; 486 487 dw = v; 488 } 489 490 if (dh < (v = w.features.min_height - sz.h)) { 491 if (dy !== 0) 492 dy += dh - v; 493 494 dh = v; 495 } 496 497 dw = Math.min(dw, w.features.max_width - sz.w); 498 dh = Math.min(dh, w.features.max_height - sz.h); 499 dx = Math.max(dx, vp.x - (sx + vp.x)); 500 dy = Math.max(dy, vp.y - (sy + vp.y)); 501 dx = Math.min(dx, (vp.w + vp.x) - (sx + sz.w + vp.x)); 502 dy = Math.min(dy, (vp.h + vp.y) - (sy + sz.h + vp.y)); 503 504 // Move if needed 505 if (dx + dy !== 0) { 506 if (sx + dx < 0) 507 dx = 0; 508 509 if (sy + dy < 0) 510 dy = 0; 511 512 ph.moveTo(sx + dx, sy + dy); 513 } 514 515 // Resize if needed 516 if (dw + dh !== 0) 517 ph.resizeTo(sz.w + dw, sz.h + dh); 518 519 return Event.cancel(e); 520 }); 521 522 return Event.cancel(se); 523 }, 524 525 resizeBy : function(dw, dh, id) { 526 var w = this.windows[id]; 527 528 if (w) { 529 w.element.resizeBy(dw, dh); 530 w.iframeElement.resizeBy(dw, dh); 531 } 532 }, 533 534 close : function(win, id) { 535 var t = this, w, d = DOM.doc, fw, id; 536 537 id = t._findId(id || win); 538 539 // Probably not inline 540 if (!t.windows[id]) { 541 t.parent(win); 542 return; 543 } 544 545 t.count--; 546 547 if (t.count == 0) { 548 DOM.remove('mceModalBlocker'); 549 DOM.setAttrib(DOM.doc.body, 'aria-hidden', 'false'); 550 t.editor.focus(); 551 } 552 553 if (w = t.windows[id]) { 554 t.onClose.dispatch(t); 555 Event.remove(d, 'mousedown', w.mousedownFunc); 556 Event.remove(d, 'click', w.clickFunc); 557 Event.clear(id); 558 Event.clear(id + '_ifr'); 559 560 DOM.setAttrib(id + '_ifr', 'src', 'javascript:""'); // Prevent leak 561 w.element.remove(); 562 delete t.windows[id]; 563 564 fw = t._frontWindow(); 565 566 if (fw) 567 t.focus(fw.id); 568 } 569 }, 570 571 // Find front most window 572 _frontWindow : function() { 573 var fw, ix = 0; 574 // Find front most window and focus that 575 each (this.windows, function(w) { 576 if (w.zIndex > ix) { 577 fw = w; 578 ix = w.zIndex; 579 } 580 }); 581 return fw; 582 }, 583 584 setTitle : function(w, ti) { 585 var e; 586 587 w = this._findId(w); 588 589 if (e = DOM.get(w + '_title')) 590 e.innerHTML = DOM.encode(ti); 591 }, 592 593 alert : function(txt, cb, s) { 594 var t = this, w; 595 596 w = t.open({ 597 title : t, 598 type : 'alert', 599 button_func : function(s) { 600 if (cb) 601 cb.call(s || t, s); 602 603 t.close(null, w.id); 604 }, 605 content : DOM.encode(t.editor.getLang(txt, txt)), 606 inline : 1, 607 width : 400, 608 height : 130 609 }); 610 }, 611 612 confirm : function(txt, cb, s) { 613 var t = this, w; 614 615 w = t.open({ 616 title : t, 617 type : 'confirm', 618 button_func : function(s) { 619 if (cb) 620 cb.call(s || t, s); 621 622 t.close(null, w.id); 623 }, 624 content : DOM.encode(t.editor.getLang(txt, txt)), 625 inline : 1, 626 width : 400, 627 height : 130 628 }); 629 }, 630 631 // Internal functions 632 633 _findId : function(w) { 634 var t = this; 635 636 if (typeof(w) == 'string') 637 return w; 638 639 each(t.windows, function(wo) { 640 var ifr = DOM.get(wo.id + '_ifr'); 641 642 if (ifr && w == ifr.contentWindow) { 643 w = wo.id; 644 return false; 645 } 646 }); 647 648 return w; 649 }, 650 651 _fixIELayout : function(id, s) { 652 var w, img; 653 654 if (!tinymce.isIE6) 655 return; 656 657 // Fixes the bug where hover flickers and does odd things in IE6 658 each(['n','s','w','e','nw','ne','sw','se'], function(v) { 659 var e = DOM.get(id + '_resize_' + v); 660 661 DOM.setStyles(e, { 662 width : s ? e.clientWidth : '', 663 height : s ? e.clientHeight : '', 664 cursor : DOM.getStyle(e, 'cursor', 1) 665 }); 666 667 DOM.setStyle(id + "_bottom", 'bottom', '-1px'); 668 669 e = 0; 670 }); 671 672 // Fixes graphics glitch 673 if (w = this.windows[id]) { 674 // Fixes rendering bug after resize 675 w.element.hide(); 676 w.element.show(); 677 678 // Forced a repaint of the window 679 //DOM.get(id).style.filter = ''; 680 681 // IE has a bug where images used in CSS won't get loaded 682 // sometimes when the cache in the browser is disabled 683 // This fix tries to solve it by loading the images using the image object 684 each(DOM.select('div,a', id), function(e, i) { 685 if (e.currentStyle.backgroundImage != 'none') { 686 img = new Image(); 687 img.src = e.currentStyle.backgroundImage.replace(/url\(\"(.+)\"\)/, '$1'); 688 } 689 }); 690 691 DOM.get(id).style.filter = ''; 692 } 693 } 694 }); 695 696 // Register plugin 697 tinymce.PluginManager.add('inlinepopups', tinymce.plugins.InlinePopups); 698 })(); 699 -
wp-includes/js/tinymce/plugins/tabfocus/editor_plugin.dev.js
1 /** 2 * editor_plugin_src.js 3 * 4 * Copyright 2009, Moxiecode Systems AB 5 * Released under LGPL License. 6 * 7 * License: http://tinymce.moxiecode.com/license 8 * Contributing: http://tinymce.moxiecode.com/contributing 9 */ 10 11 (function() { 12 var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, explode = tinymce.explode; 13 14 tinymce.create('tinymce.plugins.TabFocusPlugin', { 15 init : function(ed, url) { 16 function tabCancel(ed, e) { 17 if (e.keyCode === 9) 18 return Event.cancel(e); 19 } 20 21 function tabHandler(ed, e) { 22 var x, i, f, el, v; 23 24 function find(d) { 25 el = DOM.select(':input:enabled,*[tabindex]'); 26 27 function canSelectRecursive(e) { 28 return e.nodeName==="BODY" || (e.type != 'hidden' && 29 !(e.style.display == "none") && 30 !(e.style.visibility == "hidden") && canSelectRecursive(e.parentNode)); 31 } 32 function canSelectInOldIe(el) { 33 return el.attributes["tabIndex"].specified || el.nodeName == "INPUT" || el.nodeName == "TEXTAREA"; 34 } 35 function isOldIe() { 36 return tinymce.isIE6 || tinymce.isIE7; 37 } 38 function canSelect(el) { 39 return ((!isOldIe() || canSelectInOldIe(el))) && el.getAttribute("tabindex") != '-1' && canSelectRecursive(el); 40 } 41 42 each(el, function(e, i) { 43 if (e.id == ed.id) { 44 x = i; 45 return false; 46 } 47 }); 48 if (d > 0) { 49 for (i = x + 1; i < el.length; i++) { 50 if (canSelect(el[i])) 51 return el[i]; 52 } 53 } else { 54 for (i = x - 1; i >= 0; i--) { 55 if (canSelect(el[i])) 56 return el[i]; 57 } 58 } 59 60 return null; 61 } 62 63 if (e.keyCode === 9) { 64 v = explode(ed.getParam('tab_focus', ed.getParam('tabfocus_elements', ':prev,:next'))); 65 66 if (v.length == 1) { 67 v[1] = v[0]; 68 v[0] = ':prev'; 69 } 70 71 // Find element to focus 72 if (e.shiftKey) { 73 if (v[0] == ':prev') 74 el = find(-1); 75 else 76 el = DOM.get(v[0]); 77 } else { 78 if (v[1] == ':next') 79 el = find(1); 80 else 81 el = DOM.get(v[1]); 82 } 83 84 if (el) { 85 if (el.id && (ed = tinymce.get(el.id || el.name))) 86 ed.focus(); 87 else 88 window.setTimeout(function() { 89 if (!tinymce.isWebKit) 90 window.focus(); 91 el.focus(); 92 }, 10); 93 94 return Event.cancel(e); 95 } 96 } 97 } 98 99 ed.onKeyUp.add(tabCancel); 100 101 if (tinymce.isGecko) { 102 ed.onKeyPress.add(tabHandler); 103 ed.onKeyDown.add(tabCancel); 104 } else 105 ed.onKeyDown.add(tabHandler); 106 107 }, 108 109 getInfo : function() { 110 return { 111 longname : 'Tabfocus', 112 author : 'Moxiecode Systems AB', 113 authorurl : 'http://tinymce.moxiecode.com', 114 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/tabfocus', 115 version : tinymce.majorVersion + "." + tinymce.minorVersion 116 }; 117 } 118 }); 119 120 // Register plugin 121 tinymce.PluginManager.add('tabfocus', tinymce.plugins.TabFocusPlugin); 122 })(); -
wp-includes/js/tinymce/plugins/paste/editor_plugin.dev.js
1 /** 2 * editor_plugin_src.js 3 * 4 * Copyright 2009, Moxiecode Systems AB 5 * Released under LGPL License. 6 * 7 * License: http://tinymce.moxiecode.com/license 8 * Contributing: http://tinymce.moxiecode.com/contributing 9 */ 10 11 (function() { 12 var each = tinymce.each, 13 defs = { 14 paste_auto_cleanup_on_paste : true, 15 paste_enable_default_filters : true, 16 paste_block_drop : false, 17 paste_retain_style_properties : "none", 18 paste_strip_class_attributes : "mso", 19 paste_remove_spans : false, 20 paste_remove_styles : false, 21 paste_remove_styles_if_webkit : true, 22 paste_convert_middot_lists : true, 23 paste_convert_headers_to_strong : false, 24 paste_dialog_width : "450", 25 paste_dialog_height : "400", 26 paste_text_use_dialog : false, 27 paste_text_sticky : false, 28 paste_text_sticky_default : false, 29 paste_text_notifyalways : false, 30 paste_text_linebreaktype : "combined", 31 paste_text_replacements : [ 32 [/\u2026/g, "..."], 33 [/[\x93\x94\u201c\u201d]/g, '"'], 34 [/[\x60\x91\x92\u2018\u2019]/g, "'"] 35 ] 36 }; 37 38 function getParam(ed, name) { 39 return ed.getParam(name, defs[name]); 40 } 41 42 tinymce.create('tinymce.plugins.PastePlugin', { 43 init : function(ed, url) { 44 var t = this; 45 46 t.editor = ed; 47 t.url = url; 48 49 // Setup plugin events 50 t.onPreProcess = new tinymce.util.Dispatcher(t); 51 t.onPostProcess = new tinymce.util.Dispatcher(t); 52 53 // Register default handlers 54 t.onPreProcess.add(t._preProcess); 55 t.onPostProcess.add(t._postProcess); 56 57 // Register optional preprocess handler 58 t.onPreProcess.add(function(pl, o) { 59 ed.execCallback('paste_preprocess', pl, o); 60 }); 61 62 // Register optional postprocess 63 t.onPostProcess.add(function(pl, o) { 64 ed.execCallback('paste_postprocess', pl, o); 65 }); 66 67 ed.onKeyDown.addToTop(function(ed, e) { 68 // Block ctrl+v from adding an undo level since the default logic in tinymce.Editor will add that 69 if (((tinymce.isMac ? e.metaKey : e.ctrlKey) && e.keyCode == 86) || (e.shiftKey && e.keyCode == 45)) 70 return false; // Stop other listeners 71 }); 72 73 // Initialize plain text flag 74 ed.pasteAsPlainText = getParam(ed, 'paste_text_sticky_default'); 75 76 // This function executes the process handlers and inserts the contents 77 // force_rich overrides plain text mode set by user, important for pasting with execCommand 78 function process(o, force_rich) { 79 var dom = ed.dom, rng; 80 81 // Execute pre process handlers 82 t.onPreProcess.dispatch(t, o); 83 84 // Create DOM structure 85 o.node = dom.create('div', 0, o.content); 86 87 // If pasting inside the same element and the contents is only one block 88 // remove the block and keep the text since Firefox will copy parts of pre and h1-h6 as a pre element 89 if (tinymce.isGecko) { 90 rng = ed.selection.getRng(true); 91 if (rng.startContainer == rng.endContainer && rng.startContainer.nodeType == 3) { 92 // Is only one block node and it doesn't contain word stuff 93 if (o.node.childNodes.length === 1 && /^(p|h[1-6]|pre)$/i.test(o.node.firstChild.nodeName) && o.content.indexOf('__MCE_ITEM__') === -1) 94 dom.remove(o.node.firstChild, true); 95 } 96 } 97 98 // Execute post process handlers 99 t.onPostProcess.dispatch(t, o); 100 101 // Serialize content 102 o.content = ed.serializer.serialize(o.node, {getInner : 1, forced_root_block : ''}); 103 104 // Plain text option active? 105 if ((!force_rich) && (ed.pasteAsPlainText)) { 106 t._insertPlainText(o.content); 107 108 if (!getParam(ed, "paste_text_sticky")) { 109 ed.pasteAsPlainText = false; 110 ed.controlManager.setActive("pastetext", false); 111 } 112 } else { 113 t._insert(o.content); 114 } 115 } 116 117 // Add command for external usage 118 ed.addCommand('mceInsertClipboardContent', function(u, o) { 119 process(o, true); 120 }); 121 122 if (!getParam(ed, "paste_text_use_dialog")) { 123 ed.addCommand('mcePasteText', function(u, v) { 124 var cookie = tinymce.util.Cookie; 125 126 ed.pasteAsPlainText = !ed.pasteAsPlainText; 127 ed.controlManager.setActive('pastetext', ed.pasteAsPlainText); 128 129 if ((ed.pasteAsPlainText) && (!cookie.get("tinymcePasteText"))) { 130 if (getParam(ed, "paste_text_sticky")) { 131 ed.windowManager.alert(ed.translate('paste.plaintext_mode_sticky')); 132 } else { 133 ed.windowManager.alert(ed.translate('paste.plaintext_mode')); 134 } 135 136 if (!getParam(ed, "paste_text_notifyalways")) { 137 cookie.set("tinymcePasteText", "1", new Date(new Date().getFullYear() + 1, 12, 31)) 138 } 139 } 140 }); 141 } 142 143 ed.addButton('pastetext', {title: 'paste.paste_text_desc', cmd: 'mcePasteText'}); 144 ed.addButton('selectall', {title: 'paste.selectall_desc', cmd: 'selectall'}); 145 146 // This function grabs the contents from the clipboard by adding a 147 // hidden div and placing the caret inside it and after the browser paste 148 // is done it grabs that contents and processes that 149 function grabContent(e) { 150 var n, or, rng, oldRng, sel = ed.selection, dom = ed.dom, body = ed.getBody(), posY, textContent; 151 152 // Check if browser supports direct plaintext access 153 if (e.clipboardData || dom.doc.dataTransfer) { 154 textContent = (e.clipboardData || dom.doc.dataTransfer).getData('Text'); 155 156 if (ed.pasteAsPlainText) { 157 e.preventDefault(); 158 process({content : dom.encode(textContent).replace(/\r?\n/g, '<br />')}); 159 return; 160 } 161 } 162 163 if (dom.get('_mcePaste')) 164 return; 165 166 // Create container to paste into 167 n = dom.add(body, 'div', {id : '_mcePaste', 'class' : 'mcePaste', 'data-mce-bogus' : '1'}, '\uFEFF\uFEFF'); 168 169 // If contentEditable mode we need to find out the position of the closest element 170 if (body != ed.getDoc().body) 171 posY = dom.getPos(ed.selection.getStart(), body).y; 172 else 173 posY = body.scrollTop + dom.getViewPort(ed.getWin()).y; 174 175 // Styles needs to be applied after the element is added to the document since WebKit will otherwise remove all styles 176 // If also needs to be in view on IE or the paste would fail 177 dom.setStyles(n, { 178 position : 'absolute', 179 left : tinymce.isGecko ? -40 : 0, // Need to move it out of site on Gecko since it will othewise display a ghost resize rect for the div 180 top : posY - 25, 181 width : 1, 182 height : 1, 183 overflow : 'hidden' 184 }); 185 186 if (tinymce.isIE) { 187 // Store away the old range 188 oldRng = sel.getRng(); 189 190 // Select the container 191 rng = dom.doc.body.createTextRange(); 192 rng.moveToElementText(n); 193 rng.execCommand('Paste'); 194 195 // Remove container 196 dom.remove(n); 197 198 // Check if the contents was changed, if it wasn't then clipboard extraction failed probably due 199 // to IE security settings so we pass the junk though better than nothing right 200 if (n.innerHTML === '\uFEFF\uFEFF') { 201 ed.execCommand('mcePasteWord'); 202 e.preventDefault(); 203 return; 204 } 205 206 // Restore the old range and clear the contents before pasting 207 sel.setRng(oldRng); 208 sel.setContent(''); 209 210 // For some odd reason we need to detach the the mceInsertContent call from the paste event 211 // It's like IE has a reference to the parent element that you paste in and the selection gets messed up 212 // when it tries to restore the selection 213 setTimeout(function() { 214 // Process contents 215 process({content : n.innerHTML}); 216 }, 0); 217 218 // Block the real paste event 219 return tinymce.dom.Event.cancel(e); 220 } else { 221 function block(e) { 222 e.preventDefault(); 223 }; 224 225 // Block mousedown and click to prevent selection change 226 dom.bind(ed.getDoc(), 'mousedown', block); 227 dom.bind(ed.getDoc(), 'keydown', block); 228 229 or = ed.selection.getRng(); 230 231 // Move select contents inside DIV 232 n = n.firstChild; 233 rng = ed.getDoc().createRange(); 234 rng.setStart(n, 0); 235 rng.setEnd(n, 2); 236 sel.setRng(rng); 237 238 // Wait a while and grab the pasted contents 239 window.setTimeout(function() { 240 var h = '', nl; 241 242 // Paste divs duplicated in paste divs seems to happen when you paste plain text so lets first look for that broken behavior in WebKit 243 if (!dom.select('div.mcePaste > div.mcePaste').length) { 244 nl = dom.select('div.mcePaste'); 245 246 // WebKit will split the div into multiple ones so this will loop through then all and join them to get the whole HTML string 247 each(nl, function(n) { 248 var child = n.firstChild; 249 250 // WebKit inserts a DIV container with lots of odd styles 251 if (child && child.nodeName == 'DIV' && child.style.marginTop && child.style.backgroundColor) { 252 dom.remove(child, 1); 253 } 254 255 // Remove apply style spans 256 each(dom.select('span.Apple-style-span', n), function(n) { 257 dom.remove(n, 1); 258 }); 259 260 // Remove bogus br elements 261 each(dom.select('br[data-mce-bogus]', n), function(n) { 262 dom.remove(n); 263 }); 264 265 // WebKit will make a copy of the DIV for each line of plain text pasted and insert them into the DIV 266 if (n.parentNode.className != 'mcePaste') 267 h += n.innerHTML; 268 }); 269 } else { 270 // Found WebKit weirdness so force the content into paragraphs this seems to happen when you paste plain text from Nodepad etc 271 // So this logic will replace double enter with paragraphs and single enter with br so it kind of looks the same 272 h = '<p>' + dom.encode(textContent).replace(/\r?\n\r?\n/g, '</p><p>').replace(/\r?\n/g, '<br />') + '</p>'; 273 } 274 275 // Remove the nodes 276 each(dom.select('div.mcePaste'), function(n) { 277 dom.remove(n); 278 }); 279 280 // Restore the old selection 281 if (or) 282 sel.setRng(or); 283 284 process({content : h}); 285 286 // Unblock events ones we got the contents 287 dom.unbind(ed.getDoc(), 'mousedown', block); 288 dom.unbind(ed.getDoc(), 'keydown', block); 289 }, 0); 290 } 291 } 292 293 // Check if we should use the new auto process method 294 if (getParam(ed, "paste_auto_cleanup_on_paste")) { 295 // Is it's Opera or older FF use key handler 296 if (tinymce.isOpera || /Firefox\/2/.test(navigator.userAgent)) { 297 ed.onKeyDown.addToTop(function(ed, e) { 298 if (((tinymce.isMac ? e.metaKey : e.ctrlKey) && e.keyCode == 86) || (e.shiftKey && e.keyCode == 45)) 299 grabContent(e); 300 }); 301 } else { 302 // Grab contents on paste event on Gecko and WebKit 303 ed.onPaste.addToTop(function(ed, e) { 304 return grabContent(e); 305 }); 306 } 307 } 308 309 ed.onInit.add(function() { 310 ed.controlManager.setActive("pastetext", ed.pasteAsPlainText); 311 312 // Block all drag/drop events 313 if (getParam(ed, "paste_block_drop")) { 314 ed.dom.bind(ed.getBody(), ['dragend', 'dragover', 'draggesture', 'dragdrop', 'drop', 'drag'], function(e) { 315 e.preventDefault(); 316 e.stopPropagation(); 317 318 return false; 319 }); 320 } 321 }); 322 323 // Add legacy support 324 t._legacySupport(); 325 }, 326 327 getInfo : function() { 328 return { 329 longname : 'Paste text/word', 330 author : 'Moxiecode Systems AB', 331 authorurl : 'http://tinymce.moxiecode.com', 332 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste', 333 version : tinymce.majorVersion + "." + tinymce.minorVersion 334 }; 335 }, 336 337 _preProcess : function(pl, o) { 338 var ed = this.editor, 339 h = o.content, 340 grep = tinymce.grep, 341 explode = tinymce.explode, 342 trim = tinymce.trim, 343 len, stripClass; 344 345 //console.log('Before preprocess:' + o.content); 346 347 function process(items) { 348 each(items, function(v) { 349 // Remove or replace 350 if (v.constructor == RegExp) 351 h = h.replace(v, ''); 352 else 353 h = h.replace(v[0], v[1]); 354 }); 355 } 356 357 if (ed.settings.paste_enable_default_filters == false) { 358 return; 359 } 360 361 // IE9 adds BRs before/after block elements when contents is pasted from word or for example another browser 362 if (tinymce.isIE && document.documentMode >= 9) { 363 // IE9 adds BRs before/after block elements when contents is pasted from word or for example another browser 364 process([[/(?:<br> [\s\r\n]+|<br>)*(<\/?(h[1-6r]|p|div|address|pre|form|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|blockquote|center|dl|dt|dd|dir|fieldset)[^>]*>)(?:<br> [\s\r\n]+|<br>)*/g, '$1']]); 365 366 // IE9 also adds an extra BR element for each soft-linefeed and it also adds a BR for each word wrap break 367 process([ 368 [/<br><br>/g, '<BR><BR>'], // Replace multiple BR elements with uppercase BR to keep them intact 369 [/<br>/g, ' '], // Replace single br elements with space since they are word wrap BR:s 370 [/<BR><BR>/g, '<br>'] // Replace back the double brs but into a single BR 371 ]); 372 } 373 374 // Detect Word content and process it more aggressive 375 if (/class="?Mso|style="[^"]*\bmso-|w:WordDocument/i.test(h) || o.wordContent) { 376 o.wordContent = true; // Mark the pasted contents as word specific content 377 //console.log('Word contents detected.'); 378 379 // Process away some basic content 380 process([ 381 /^\s*( )+/gi, // entities at the start of contents 382 /( |<br[^>]*>)+\s*$/gi // entities at the end of contents 383 ]); 384 385 if (getParam(ed, "paste_convert_headers_to_strong")) { 386 h = h.replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>"); 387 } 388 389 if (getParam(ed, "paste_convert_middot_lists")) { 390 process([ 391 [/<!--\[if !supportLists\]-->/gi, '$&__MCE_ITEM__'], // Convert supportLists to a list item marker 392 [/(<span[^>]+(?:mso-list:|:\s*symbol)[^>]+>)/gi, '$1__MCE_ITEM__'], // Convert mso-list and symbol spans to item markers 393 [/(<p[^>]+(?:MsoListParagraph)[^>]+>)/gi, '$1__MCE_ITEM__'] // Convert mso-list and symbol paragraphs to item markers (FF) 394 ]); 395 } 396 397 process([ 398 // Word comments like conditional comments etc 399 /<!--[\s\S]+?-->/gi, 400 401 // Remove comments, scripts (e.g., msoShowComment), XML tag, VML content, MS Office namespaced tags, and a few other tags 402 /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi, 403 404 // Convert <s> into <strike> for line-though 405 [/<(\/?)s>/gi, "<$1strike>"], 406 407 // Replace nsbp entites to char since it's easier to handle 408 [/ /gi, "\u00a0"] 409 ]); 410 411 // Remove bad attributes, with or without quotes, ensuring that attribute text is really inside a tag. 412 // If JavaScript had a RegExp look-behind, we could have integrated this with the last process() array and got rid of the loop. But alas, it does not, so we cannot. 413 do { 414 len = h.length; 415 h = h.replace(/(<[a-z][^>]*\s)(?:id|name|language|type|on\w+|\w+:\w+)=(?:"[^"]*"|\w+)\s?/gi, "$1"); 416 } while (len != h.length); 417 418 // Remove all spans if no styles is to be retained 419 if (getParam(ed, "paste_retain_style_properties").replace(/^none$/i, "").length == 0) { 420 h = h.replace(/<\/?span[^>]*>/gi, ""); 421 } else { 422 // We're keeping styles, so at least clean them up. 423 // CSS Reference: http://msdn.microsoft.com/en-us/library/aa155477.aspx 424 425 process([ 426 // Convert <span style="mso-spacerun:yes">___</span> to string of alternating breaking/non-breaking spaces of same length 427 [/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi, 428 function(str, spaces) { 429 return (spaces.length > 0)? spaces.replace(/./, " ").slice(Math.floor(spaces.length/2)).split("").join("\u00a0") : ""; 430 } 431 ], 432 433 // Examine all styles: delete junk, transform some, and keep the rest 434 [/(<[a-z][^>]*)\sstyle="([^"]*)"/gi, 435 function(str, tag, style) { 436 var n = [], 437 i = 0, 438 s = explode(trim(style).replace(/"/gi, "'"), ";"); 439 440 // Examine each style definition within the tag's style attribute 441 each(s, function(v) { 442 var name, value, 443 parts = explode(v, ":"); 444 445 function ensureUnits(v) { 446 return v + ((v !== "0") && (/\d$/.test(v)))? "px" : ""; 447 } 448 449 if (parts.length == 2) { 450 name = parts[0].toLowerCase(); 451 value = parts[1].toLowerCase(); 452 453 // Translate certain MS Office styles into their CSS equivalents 454 switch (name) { 455 case "mso-padding-alt": 456 case "mso-padding-top-alt": 457 case "mso-padding-right-alt": 458 case "mso-padding-bottom-alt": 459 case "mso-padding-left-alt": 460 case "mso-margin-alt": 461 case "mso-margin-top-alt": 462 case "mso-margin-right-alt": 463 case "mso-margin-bottom-alt": 464 case "mso-margin-left-alt": 465 case "mso-table-layout-alt": 466 case "mso-height": 467 case "mso-width": 468 case "mso-vertical-align-alt": 469 n[i++] = name.replace(/^mso-|-alt$/g, "") + ":" + ensureUnits(value); 470 return; 471 472 case "horiz-align": 473 n[i++] = "text-align:" + value; 474 return; 475 476 case "vert-align": 477 n[i++] = "vertical-align:" + value; 478 return; 479 480 case "font-color": 481 case "mso-foreground": 482 n[i++] = "color:" + value; 483 return; 484 485 case "mso-background": 486 case "mso-highlight": 487 n[i++] = "background:" + value; 488 return; 489 490 case "mso-default-height": 491 n[i++] = "min-height:" + ensureUnits(value); 492 return; 493 494 case "mso-default-width": 495 n[i++] = "min-width:" + ensureUnits(value); 496 return; 497 498 case "mso-padding-between-alt": 499 n[i++] = "border-collapse:separate;border-spacing:" + ensureUnits(value); 500 return; 501 502 case "text-line-through": 503 if ((value == "single") || (value == "double")) { 504 n[i++] = "text-decoration:line-through"; 505 } 506 return; 507 508 case "mso-zero-height": 509 if (value == "yes") { 510 n[i++] = "display:none"; 511 } 512 return; 513 } 514 515 // Eliminate all MS Office style definitions that have no CSS equivalent by examining the first characters in the name 516 if (/^(mso|column|font-emph|lang|layout|line-break|list-image|nav|panose|punct|row|ruby|sep|size|src|tab-|table-border|text-(?!align|decor|indent|trans)|top-bar|version|vnd|word-break)/.test(name)) { 517 return; 518 } 519 520 // If it reached this point, it must be a valid CSS style 521 n[i++] = name + ":" + parts[1]; // Lower-case name, but keep value case 522 } 523 }); 524 525 // If style attribute contained any valid styles the re-write it; otherwise delete style attribute. 526 if (i > 0) { 527 return tag + ' style="' + n.join(';') + '"'; 528 } else { 529 return tag; 530 } 531 } 532 ] 533 ]); 534 } 535 } 536 537 // Replace headers with <strong> 538 if (getParam(ed, "paste_convert_headers_to_strong")) { 539 process([ 540 [/<h[1-6][^>]*>/gi, "<p><strong>"], 541 [/<\/h[1-6][^>]*>/gi, "</strong></p>"] 542 ]); 543 } 544 545 process([ 546 // Copy paste from Java like Open Office will produce this junk on FF 547 [/Version:[\d.]+\nStartHTML:\d+\nEndHTML:\d+\nStartFragment:\d+\nEndFragment:\d+/gi, ''] 548 ]); 549 550 // Class attribute options are: leave all as-is ("none"), remove all ("all"), or remove only those starting with mso ("mso"). 551 // Note:- paste_strip_class_attributes: "none", verify_css_classes: true is also a good variation. 552 stripClass = getParam(ed, "paste_strip_class_attributes"); 553 554 if (stripClass !== "none") { 555 function removeClasses(match, g1) { 556 if (stripClass === "all") 557 return ''; 558 559 var cls = grep(explode(g1.replace(/^(["'])(.*)\1$/, "$2"), " "), 560 function(v) { 561 return (/^(?!mso)/i.test(v)); 562 } 563 ); 564 565 return cls.length ? ' class="' + cls.join(" ") + '"' : ''; 566 }; 567 568 h = h.replace(/ class="([^"]+)"/gi, removeClasses); 569 h = h.replace(/ class=([\-\w]+)/gi, removeClasses); 570 } 571 572 // Remove spans option 573 if (getParam(ed, "paste_remove_spans")) { 574 h = h.replace(/<\/?span[^>]*>/gi, ""); 575 } 576 577 //console.log('After preprocess:' + h); 578 579 o.content = h; 580 }, 581 582 /** 583 * Various post process items. 584 */ 585 _postProcess : function(pl, o) { 586 var t = this, ed = t.editor, dom = ed.dom, styleProps; 587 588 if (ed.settings.paste_enable_default_filters == false) { 589 return; 590 } 591 592 if (o.wordContent) { 593 // Remove named anchors or TOC links 594 each(dom.select('a', o.node), function(a) { 595 if (!a.href || a.href.indexOf('#_Toc') != -1) 596 dom.remove(a, 1); 597 }); 598 599 if (getParam(ed, "paste_convert_middot_lists")) { 600 t._convertLists(pl, o); 601 } 602 603 // Process styles 604 styleProps = getParam(ed, "paste_retain_style_properties"); // retained properties 605 606 // Process only if a string was specified and not equal to "all" or "*" 607 if ((tinymce.is(styleProps, "string")) && (styleProps !== "all") && (styleProps !== "*")) { 608 styleProps = tinymce.explode(styleProps.replace(/^none$/i, "")); 609 610 // Retains some style properties 611 each(dom.select('*', o.node), function(el) { 612 var newStyle = {}, npc = 0, i, sp, sv; 613 614 // Store a subset of the existing styles 615 if (styleProps) { 616 for (i = 0; i < styleProps.length; i++) { 617 sp = styleProps[i]; 618 sv = dom.getStyle(el, sp); 619 620 if (sv) { 621 newStyle[sp] = sv; 622 npc++; 623 } 624 } 625 } 626 627 // Remove all of the existing styles 628 dom.setAttrib(el, 'style', ''); 629 630 if (styleProps && npc > 0) 631 dom.setStyles(el, newStyle); // Add back the stored subset of styles 632 else // Remove empty span tags that do not have class attributes 633 if (el.nodeName == 'SPAN' && !el.className) 634 dom.remove(el, true); 635 }); 636 } 637 } 638 639 // Remove all style information or only specifically on WebKit to avoid the style bug on that browser 640 if (getParam(ed, "paste_remove_styles") || (getParam(ed, "paste_remove_styles_if_webkit") && tinymce.isWebKit)) { 641 each(dom.select('*[style]', o.node), function(el) { 642 el.removeAttribute('style'); 643 el.removeAttribute('data-mce-style'); 644 }); 645 } else { 646 if (tinymce.isWebKit) { 647 // We need to compress the styles on WebKit since if you paste <img border="0" /> it will become <img border="0" style="... lots of junk ..." /> 648 // Removing the mce_style that contains the real value will force the Serializer engine to compress the styles 649 each(dom.select('*', o.node), function(el) { 650 el.removeAttribute('data-mce-style'); 651 }); 652 } 653 } 654 }, 655 656 /** 657 * Converts the most common bullet and number formats in Office into a real semantic UL/LI list. 658 */ 659 _convertLists : function(pl, o) { 660 var dom = pl.editor.dom, listElm, li, lastMargin = -1, margin, levels = [], lastType, html; 661 662 // Convert middot lists into real semantic lists 663 each(dom.select('p', o.node), function(p) { 664 var sib, val = '', type, html, idx, parents; 665 666 // Get text node value at beginning of paragraph 667 for (sib = p.firstChild; sib && sib.nodeType == 3; sib = sib.nextSibling) 668 val += sib.nodeValue; 669 670 val = p.innerHTML.replace(/<\/?\w+[^>]*>/gi, '').replace(/ /g, '\u00a0'); 671 672 // Detect unordered lists look for bullets 673 if (/^(__MCE_ITEM__)+[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*\u00a0*/.test(val)) 674 type = 'ul'; 675 676 // Detect ordered lists 1., a. or ixv. 677 if (/^__MCE_ITEM__\s*\w+\.\s*\u00a0+/.test(val)) 678 type = 'ol'; 679 680 // Check if node value matches the list pattern: o 681 if (type) { 682 margin = parseFloat(p.style.marginLeft || 0); 683 684 if (margin > lastMargin) 685 levels.push(margin); 686 687 if (!listElm || type != lastType) { 688 listElm = dom.create(type); 689 dom.insertAfter(listElm, p); 690 } else { 691 // Nested list element 692 if (margin > lastMargin) { 693 listElm = li.appendChild(dom.create(type)); 694 } else if (margin < lastMargin) { 695 // Find parent level based on margin value 696 idx = tinymce.inArray(levels, margin); 697 parents = dom.getParents(listElm.parentNode, type); 698 listElm = parents[parents.length - 1 - idx] || listElm; 699 } 700 } 701 702 // Remove middot or number spans if they exists 703 each(dom.select('span', p), function(span) { 704 var html = span.innerHTML.replace(/<\/?\w+[^>]*>/gi, ''); 705 706 // Remove span with the middot or the number 707 if (type == 'ul' && /^__MCE_ITEM__[\u2022\u00b7\u00a7\u00d8o\u25CF]/.test(html)) 708 dom.remove(span); 709 else if (/^__MCE_ITEM__[\s\S]*\w+\.( |\u00a0)*\s*/.test(html)) 710 dom.remove(span); 711 }); 712 713 html = p.innerHTML; 714 715 // Remove middot/list items 716 if (type == 'ul') 717 html = p.innerHTML.replace(/__MCE_ITEM__/g, '').replace(/^[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*( |\u00a0)+\s*/, ''); 718 else 719 html = p.innerHTML.replace(/__MCE_ITEM__/g, '').replace(/^\s*\w+\.( |\u00a0)+\s*/, ''); 720 721 // Create li and add paragraph data into the new li 722 li = listElm.appendChild(dom.create('li', 0, html)); 723 dom.remove(p); 724 725 lastMargin = margin; 726 lastType = type; 727 } else 728 listElm = lastMargin = 0; // End list element 729 }); 730 731 // Remove any left over makers 732 html = o.node.innerHTML; 733 if (html.indexOf('__MCE_ITEM__') != -1) 734 o.node.innerHTML = html.replace(/__MCE_ITEM__/g, ''); 735 }, 736 737 /** 738 * Inserts the specified contents at the caret position. 739 */ 740 _insert : function(h, skip_undo) { 741 var ed = this.editor, r = ed.selection.getRng(); 742 743 // First delete the contents seems to work better on WebKit when the selection spans multiple list items or multiple table cells. 744 if (!ed.selection.isCollapsed() && r.startContainer != r.endContainer) 745 ed.getDoc().execCommand('Delete', false, null); 746 747 ed.execCommand('mceInsertContent', false, h, {skip_undo : skip_undo}); 748 }, 749 750 /** 751 * Instead of the old plain text method which tried to re-create a paste operation, the 752 * new approach adds a plain text mode toggle switch that changes the behavior of paste. 753 * This function is passed the same input that the regular paste plugin produces. 754 * It performs additional scrubbing and produces (and inserts) the plain text. 755 * This approach leverages all of the great existing functionality in the paste 756 * plugin, and requires minimal changes to add the new functionality. 757 * Speednet - June 2009 758 */ 759 _insertPlainText : function(content) { 760 var ed = this.editor, 761 linebr = getParam(ed, "paste_text_linebreaktype"), 762 rl = getParam(ed, "paste_text_replacements"), 763 is = tinymce.is; 764 765 function process(items) { 766 each(items, function(v) { 767 if (v.constructor == RegExp) 768 content = content.replace(v, ""); 769 else 770 content = content.replace(v[0], v[1]); 771 }); 772 }; 773 774 if ((typeof(content) === "string") && (content.length > 0)) { 775 // If HTML content with line-breaking tags, then remove all cr/lf chars because only tags will break a line 776 if (/<(?:p|br|h[1-6]|ul|ol|dl|table|t[rdh]|div|blockquote|fieldset|pre|address|center)[^>]*>/i.test(content)) { 777 process([ 778 /[\n\r]+/g 779 ]); 780 } else { 781 // Otherwise just get rid of carriage returns (only need linefeeds) 782 process([ 783 /\r+/g 784 ]); 785 } 786 787 process([ 788 [/<\/(?:p|h[1-6]|ul|ol|dl|table|div|blockquote|fieldset|pre|address|center)>/gi, "\n\n"], // Block tags get a blank line after them 789 [/<br[^>]*>|<\/tr>/gi, "\n"], // Single linebreak for <br /> tags and table rows 790 [/<\/t[dh]>\s*<t[dh][^>]*>/gi, "\t"], // Table cells get tabs betweem them 791 /<[a-z!\/?][^>]*>/gi, // Delete all remaining tags 792 [/ /gi, " "], // Convert non-break spaces to regular spaces (remember, *plain text*) 793 [/(?:(?!\n)\s)*(\n+)(?:(?!\n)\s)*/gi, "$1"],// Cool little RegExp deletes whitespace around linebreak chars. 794 [/\n{3,}/g, "\n\n"] // Max. 2 consecutive linebreaks 795 ]); 796 797 content = ed.dom.decode(tinymce.html.Entities.encodeRaw(content)); 798 799 // Perform default or custom replacements 800 if (is(rl, "array")) { 801 process(rl); 802 } else if (is(rl, "string")) { 803 process(new RegExp(rl, "gi")); 804 } 805 806 // Treat paragraphs as specified in the config 807 if (linebr == "none") { 808 // Convert all line breaks to space 809 process([ 810 [/\n+/g, " "] 811 ]); 812 } else if (linebr == "br") { 813 // Convert all line breaks to <br /> 814 process([ 815 [/\n/g, "<br />"] 816 ]); 817 } else if (linebr == "p") { 818 // Convert all line breaks to <p>...</p> 819 process([ 820 [/\n+/g, "</p><p>"], 821 [/^(.*<\/p>)(<p>)$/, '<p>$1'] 822 ]); 823 } else { 824 // defaults to "combined" 825 // Convert single line breaks to <br /> and double line breaks to <p>...</p> 826 process([ 827 [/\n\n/g, "</p><p>"], 828 [/^(.*<\/p>)(<p>)$/, '<p>$1'], 829 [/\n/g, "<br />"] 830 ]); 831 } 832 833 ed.execCommand('mceInsertContent', false, content); 834 } 835 }, 836 837 /** 838 * This method will open the old style paste dialogs. Some users might want the old behavior but still use the new cleanup engine. 839 */ 840 _legacySupport : function() { 841 var t = this, ed = t.editor; 842 843 // Register command(s) for backwards compatibility 844 ed.addCommand("mcePasteWord", function() { 845 ed.windowManager.open({ 846 file: t.url + "/pasteword.htm", 847 width: parseInt(getParam(ed, "paste_dialog_width")), 848 height: parseInt(getParam(ed, "paste_dialog_height")), 849 inline: 1 850 }); 851 }); 852 853 if (getParam(ed, "paste_text_use_dialog")) { 854 ed.addCommand("mcePasteText", function() { 855 ed.windowManager.open({ 856 file : t.url + "/pastetext.htm", 857 width: parseInt(getParam(ed, "paste_dialog_width")), 858 height: parseInt(getParam(ed, "paste_dialog_height")), 859 inline : 1 860 }); 861 }); 862 } 863 864 // Register button for backwards compatibility 865 ed.addButton("pasteword", {title : "paste.paste_word_desc", cmd : "mcePasteWord"}); 866 } 867 }); 868 869 // Register plugin 870 tinymce.PluginManager.add("paste", tinymce.plugins.PastePlugin); 871 })(); -
wp-includes/js/tinymce/themes/advanced/editor_template.dev.js
1 /** 2 * editor_template_src.js 3 * 4 * Copyright 2009, Moxiecode Systems AB 5 * Released under LGPL License. 6 * 7 * License: http://tinymce.moxiecode.com/license 8 * Contributing: http://tinymce.moxiecode.com/contributing 9 */ 10 11 (function(tinymce) { 12 var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, each = tinymce.each, Cookie = tinymce.util.Cookie, lastExtID, explode = tinymce.explode; 13 14 // Tell it to load theme specific language pack(s) 15 tinymce.ThemeManager.requireLangPack('advanced'); 16 17 tinymce.create('tinymce.themes.AdvancedTheme', { 18 sizes : [8, 10, 12, 14, 18, 24, 36], 19 20 // Control name lookup, format: title, command 21 controls : { 22 bold : ['bold_desc', 'Bold'], 23 italic : ['italic_desc', 'Italic'], 24 underline : ['underline_desc', 'Underline'], 25 strikethrough : ['striketrough_desc', 'Strikethrough'], 26 justifyleft : ['justifyleft_desc', 'JustifyLeft'], 27 justifycenter : ['justifycenter_desc', 'JustifyCenter'], 28 justifyright : ['justifyright_desc', 'JustifyRight'], 29 justifyfull : ['justifyfull_desc', 'JustifyFull'], 30 bullist : ['bullist_desc', 'InsertUnorderedList'], 31 numlist : ['numlist_desc', 'InsertOrderedList'], 32 outdent : ['outdent_desc', 'Outdent'], 33 indent : ['indent_desc', 'Indent'], 34 cut : ['cut_desc', 'Cut'], 35 copy : ['copy_desc', 'Copy'], 36 paste : ['paste_desc', 'Paste'], 37 undo : ['undo_desc', 'Undo'], 38 redo : ['redo_desc', 'Redo'], 39 link : ['link_desc', 'mceLink'], 40 unlink : ['unlink_desc', 'unlink'], 41 image : ['image_desc', 'mceImage'], 42 cleanup : ['cleanup_desc', 'mceCleanup'], 43 help : ['help_desc', 'mceHelp'], 44 code : ['code_desc', 'mceCodeEditor'], 45 hr : ['hr_desc', 'InsertHorizontalRule'], 46 removeformat : ['removeformat_desc', 'RemoveFormat'], 47 sub : ['sub_desc', 'subscript'], 48 sup : ['sup_desc', 'superscript'], 49 forecolor : ['forecolor_desc', 'ForeColor'], 50 forecolorpicker : ['forecolor_desc', 'mceForeColor'], 51 backcolor : ['backcolor_desc', 'HiliteColor'], 52 backcolorpicker : ['backcolor_desc', 'mceBackColor'], 53 charmap : ['charmap_desc', 'mceCharMap'], 54 visualaid : ['visualaid_desc', 'mceToggleVisualAid'], 55 anchor : ['anchor_desc', 'mceInsertAnchor'], 56 newdocument : ['newdocument_desc', 'mceNewDocument'], 57 blockquote : ['blockquote_desc', 'mceBlockQuote'] 58 }, 59 60 stateControls : ['bold', 'italic', 'underline', 'strikethrough', 'bullist', 'numlist', 'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', 'sub', 'sup', 'blockquote'], 61 62 init : function(ed, url) { 63 var t = this, s, v, o; 64 65 t.editor = ed; 66 t.url = url; 67 t.onResolveName = new tinymce.util.Dispatcher(this); 68 69 ed.forcedHighContrastMode = ed.settings.detect_highcontrast && t._isHighContrast(); 70 ed.settings.skin = ed.forcedHighContrastMode ? 'highcontrast' : ed.settings.skin; 71 72 // Default settings 73 t.settings = s = extend({ 74 theme_advanced_path : true, 75 theme_advanced_toolbar_location : 'bottom', 76 theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect", 77 theme_advanced_buttons2 : "bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code", 78 theme_advanced_buttons3 : "hr,removeformat,visualaid,|,sub,sup,|,charmap", 79 theme_advanced_blockformats : "p,address,pre,h1,h2,h3,h4,h5,h6", 80 theme_advanced_toolbar_align : "center", 81 theme_advanced_fonts : "Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats", 82 theme_advanced_more_colors : 1, 83 theme_advanced_row_height : 23, 84 theme_advanced_resize_horizontal : 1, 85 theme_advanced_resizing_use_cookie : 1, 86 theme_advanced_font_sizes : "1,2,3,4,5,6,7", 87 theme_advanced_font_selector : "span", 88 theme_advanced_show_current_color: 0, 89 readonly : ed.settings.readonly 90 }, ed.settings); 91 92 // Setup default font_size_style_values 93 if (!s.font_size_style_values) 94 s.font_size_style_values = "8pt,10pt,12pt,14pt,18pt,24pt,36pt"; 95 96 if (tinymce.is(s.theme_advanced_font_sizes, 'string')) { 97 s.font_size_style_values = tinymce.explode(s.font_size_style_values); 98 s.font_size_classes = tinymce.explode(s.font_size_classes || ''); 99 100 // Parse string value 101 o = {}; 102 ed.settings.theme_advanced_font_sizes = s.theme_advanced_font_sizes; 103 each(ed.getParam('theme_advanced_font_sizes', '', 'hash'), function(v, k) { 104 var cl; 105 106 if (k == v && v >= 1 && v <= 7) { 107 k = v + ' (' + t.sizes[v - 1] + 'pt)'; 108 cl = s.font_size_classes[v - 1]; 109 v = s.font_size_style_values[v - 1] || (t.sizes[v - 1] + 'pt'); 110 } 111 112 if (/^\s*\./.test(v)) 113 cl = v.replace(/\./g, ''); 114 115 o[k] = cl ? {'class' : cl} : {fontSize : v}; 116 }); 117 118 s.theme_advanced_font_sizes = o; 119 } 120 121 if ((v = s.theme_advanced_path_location) && v != 'none') 122 s.theme_advanced_statusbar_location = s.theme_advanced_path_location; 123 124 if (s.theme_advanced_statusbar_location == 'none') 125 s.theme_advanced_statusbar_location = 0; 126 127 if (ed.settings.content_css !== false) 128 ed.contentCSS.push(ed.baseURI.toAbsolute(url + "/skins/" + ed.settings.skin + "/content.css")); 129 130 // Init editor 131 ed.onInit.add(function() { 132 if (!ed.settings.readonly) { 133 ed.onNodeChange.add(t._nodeChanged, t); 134 ed.onKeyUp.add(t._updateUndoStatus, t); 135 ed.onMouseUp.add(t._updateUndoStatus, t); 136 ed.dom.bind(ed.dom.getRoot(), 'dragend', function() { 137 t._updateUndoStatus(ed); 138 }); 139 } 140 }); 141 142 ed.onSetProgressState.add(function(ed, b, ti) { 143 var co, id = ed.id, tb; 144 145 if (b) { 146 t.progressTimer = setTimeout(function() { 147 co = ed.getContainer(); 148 co = co.insertBefore(DOM.create('DIV', {style : 'position:relative'}), co.firstChild); 149 tb = DOM.get(ed.id + '_tbl'); 150 151 DOM.add(co, 'div', {id : id + '_blocker', 'class' : 'mceBlocker', style : {width : tb.clientWidth + 2, height : tb.clientHeight + 2}}); 152 DOM.add(co, 'div', {id : id + '_progress', 'class' : 'mceProgress', style : {left : tb.clientWidth / 2, top : tb.clientHeight / 2}}); 153 }, ti || 0); 154 } else { 155 DOM.remove(id + '_blocker'); 156 DOM.remove(id + '_progress'); 157 clearTimeout(t.progressTimer); 158 } 159 }); 160 161 DOM.loadCSS(s.editor_css ? ed.documentBaseURI.toAbsolute(s.editor_css) : url + "/skins/" + ed.settings.skin + "/ui.css"); 162 163 if (s.skin_variant) 164 DOM.loadCSS(url + "/skins/" + ed.settings.skin + "/ui_" + s.skin_variant + ".css"); 165 }, 166 167 _isHighContrast : function() { 168 var actualColor, div = DOM.add(DOM.getRoot(), 'div', {'style': 'background-color: rgb(171,239,86);'}); 169 170 actualColor = (DOM.getStyle(div, 'background-color', true) + '').toLowerCase().replace(/ /g, ''); 171 DOM.remove(div); 172 173 return actualColor != 'rgb(171,239,86)' && actualColor != '#abef56'; 174 }, 175 176 createControl : function(n, cf) { 177 var cd, c; 178 179 if (c = cf.createControl(n)) 180 return c; 181 182 switch (n) { 183 case "styleselect": 184 return this._createStyleSelect(); 185 186 case "formatselect": 187 return this._createBlockFormats(); 188 189 case "fontselect": 190 return this._createFontSelect(); 191 192 case "fontsizeselect": 193 return this._createFontSizeSelect(); 194 195 case "forecolor": 196 return this._createForeColorMenu(); 197 198 case "backcolor": 199 return this._createBackColorMenu(); 200 } 201 202 if ((cd = this.controls[n])) 203 return cf.createButton(n, {title : "advanced." + cd[0], cmd : cd[1], ui : cd[2], value : cd[3]}); 204 }, 205 206 execCommand : function(cmd, ui, val) { 207 var f = this['_' + cmd]; 208 209 if (f) { 210 f.call(this, ui, val); 211 return true; 212 } 213 214 return false; 215 }, 216 217 _importClasses : function(e) { 218 var ed = this.editor, ctrl = ed.controlManager.get('styleselect'); 219 220 if (ctrl.getLength() == 0) { 221 each(ed.dom.getClasses(), function(o, idx) { 222 var name = 'style_' + idx; 223 224 ed.formatter.register(name, { 225 inline : 'span', 226 attributes : {'class' : o['class']}, 227 selector : '*' 228 }); 229 230 ctrl.add(o['class'], name); 231 }); 232 } 233 }, 234 235 _createStyleSelect : function(n) { 236 var t = this, ed = t.editor, ctrlMan = ed.controlManager, ctrl; 237 238 // Setup style select box 239 ctrl = ctrlMan.createListBox('styleselect', { 240 title : 'advanced.style_select', 241 onselect : function(name) { 242 var matches, formatNames = []; 243 244 each(ctrl.items, function(item) { 245 formatNames.push(item.value); 246 }); 247 248 ed.focus(); 249 ed.undoManager.add(); 250 251 // Toggle off the current format 252 matches = ed.formatter.matchAll(formatNames); 253 if (!name || matches[0] == name) { 254 if (matches[0]) 255 ed.formatter.remove(matches[0]); 256 } else 257 ed.formatter.apply(name); 258 259 ed.undoManager.add(); 260 ed.nodeChanged(); 261 262 return false; // No auto select 263 } 264 }); 265 266 // Handle specified format 267 ed.onInit.add(function() { 268 var counter = 0, formats = ed.getParam('style_formats'); 269 270 if (formats) { 271 each(formats, function(fmt) { 272 var name, keys = 0; 273 274 each(fmt, function() {keys++;}); 275 276 if (keys > 1) { 277 name = fmt.name = fmt.name || 'style_' + (counter++); 278 ed.formatter.register(name, fmt); 279 ctrl.add(fmt.title, name); 280 } else 281 ctrl.add(fmt.title); 282 }); 283 } else { 284 each(ed.getParam('theme_advanced_styles', '', 'hash'), function(val, key) { 285 var name; 286 287 if (val) { 288 name = 'style_' + (counter++); 289 290 ed.formatter.register(name, { 291 inline : 'span', 292 classes : val, 293 selector : '*' 294 }); 295 296 ctrl.add(t.editor.translate(key), name); 297 } 298 }); 299 } 300 }); 301 302 // Auto import classes if the ctrl box is empty 303 if (ctrl.getLength() == 0) { 304 ctrl.onPostRender.add(function(ed, n) { 305 if (!ctrl.NativeListBox) { 306 Event.add(n.id + '_text', 'focus', t._importClasses, t); 307 Event.add(n.id + '_text', 'mousedown', t._importClasses, t); 308 Event.add(n.id + '_open', 'focus', t._importClasses, t); 309 Event.add(n.id + '_open', 'mousedown', t._importClasses, t); 310 } else 311 Event.add(n.id, 'focus', t._importClasses, t); 312 }); 313 } 314 315 return ctrl; 316 }, 317 318 _createFontSelect : function() { 319 var c, t = this, ed = t.editor; 320 321 c = ed.controlManager.createListBox('fontselect', { 322 title : 'advanced.fontdefault', 323 onselect : function(v) { 324 var cur = c.items[c.selectedIndex]; 325 326 if (!v && cur) { 327 ed.execCommand('FontName', false, cur.value); 328 return; 329 } 330 331 ed.execCommand('FontName', false, v); 332 333 // Fake selection, execCommand will fire a nodeChange and update the selection 334 c.select(function(sv) { 335 return v == sv; 336 }); 337 338 if (cur && cur.value == v) { 339 c.select(null); 340 } 341 342 return false; // No auto select 343 } 344 }); 345 346 if (c) { 347 each(ed.getParam('theme_advanced_fonts', t.settings.theme_advanced_fonts, 'hash'), function(v, k) { 348 c.add(ed.translate(k), v, {style : v.indexOf('dings') == -1 ? 'font-family:' + v : ''}); 349 }); 350 } 351 352 return c; 353 }, 354 355 _createFontSizeSelect : function() { 356 var t = this, ed = t.editor, c, i = 0, cl = []; 357 358 c = ed.controlManager.createListBox('fontsizeselect', {title : 'advanced.font_size', onselect : function(v) { 359 var cur = c.items[c.selectedIndex]; 360 361 if (!v && cur) { 362 cur = cur.value; 363 364 if (cur['class']) { 365 ed.formatter.toggle('fontsize_class', {value : cur['class']}); 366 ed.undoManager.add(); 367 ed.nodeChanged(); 368 } else { 369 ed.execCommand('FontSize', false, cur.fontSize); 370 } 371 372 return; 373 } 374 375 if (v['class']) { 376 ed.focus(); 377 ed.undoManager.add(); 378 ed.formatter.toggle('fontsize_class', {value : v['class']}); 379 ed.undoManager.add(); 380 ed.nodeChanged(); 381 } else 382 ed.execCommand('FontSize', false, v.fontSize); 383 384 // Fake selection, execCommand will fire a nodeChange and update the selection 385 c.select(function(sv) { 386 return v == sv; 387 }); 388 389 if (cur && (cur.value.fontSize == v.fontSize || cur.value['class'] && cur.value['class'] == v['class'])) { 390 c.select(null); 391 } 392 393 return false; // No auto select 394 }}); 395 396 if (c) { 397 each(t.settings.theme_advanced_font_sizes, function(v, k) { 398 var fz = v.fontSize; 399 400 if (fz >= 1 && fz <= 7) 401 fz = t.sizes[parseInt(fz) - 1] + 'pt'; 402 403 c.add(k, v, {'style' : 'font-size:' + fz, 'class' : 'mceFontSize' + (i++) + (' ' + (v['class'] || ''))}); 404 }); 405 } 406 407 return c; 408 }, 409 410 _createBlockFormats : function() { 411 var c, fmts = { 412 p : 'advanced.paragraph', 413 address : 'advanced.address', 414 pre : 'advanced.pre', 415 h1 : 'advanced.h1', 416 h2 : 'advanced.h2', 417 h3 : 'advanced.h3', 418 h4 : 'advanced.h4', 419 h5 : 'advanced.h5', 420 h6 : 'advanced.h6', 421 div : 'advanced.div', 422 blockquote : 'advanced.blockquote', 423 code : 'advanced.code', 424 dt : 'advanced.dt', 425 dd : 'advanced.dd', 426 samp : 'advanced.samp' 427 }, t = this; 428 429 c = t.editor.controlManager.createListBox('formatselect', {title : 'advanced.block', onselect : function(v) { 430 t.editor.execCommand('FormatBlock', false, v); 431 return false; 432 }}); 433 434 if (c) { 435 each(t.editor.getParam('theme_advanced_blockformats', t.settings.theme_advanced_blockformats, 'hash'), function(v, k) { 436 c.add(t.editor.translate(k != v ? k : fmts[v]), v, {'class' : 'mce_formatPreview mce_' + v}); 437 }); 438 } 439 440 return c; 441 }, 442 443 _createForeColorMenu : function() { 444 var c, t = this, s = t.settings, o = {}, v; 445 446 if (s.theme_advanced_more_colors) { 447 o.more_colors_func = function() { 448 t._mceColorPicker(0, { 449 color : c.value, 450 func : function(co) { 451 c.setColor(co); 452 } 453 }); 454 }; 455 } 456 457 if (v = s.theme_advanced_text_colors) 458 o.colors = v; 459 460 if (s.theme_advanced_default_foreground_color) 461 o.default_color = s.theme_advanced_default_foreground_color; 462 463 o.title = 'advanced.forecolor_desc'; 464 o.cmd = 'ForeColor'; 465 o.scope = this; 466 467 c = t.editor.controlManager.createColorSplitButton('forecolor', o); 468 469 return c; 470 }, 471 472 _createBackColorMenu : function() { 473 var c, t = this, s = t.settings, o = {}, v; 474 475 if (s.theme_advanced_more_colors) { 476 o.more_colors_func = function() { 477 t._mceColorPicker(0, { 478 color : c.value, 479 func : function(co) { 480 c.setColor(co); 481 } 482 }); 483 }; 484 } 485 486 if (v = s.theme_advanced_background_colors) 487 o.colors = v; 488 489 if (s.theme_advanced_default_background_color) 490 o.default_color = s.theme_advanced_default_background_color; 491 492 o.title = 'advanced.backcolor_desc'; 493 o.cmd = 'HiliteColor'; 494 o.scope = this; 495 496 c = t.editor.controlManager.createColorSplitButton('backcolor', o); 497 498 return c; 499 }, 500 501 renderUI : function(o) { 502 var n, ic, tb, t = this, ed = t.editor, s = t.settings, sc, p, nl; 503 504 if (ed.settings) { 505 ed.settings.aria_label = s.aria_label + ed.getLang('advanced.help_shortcut'); 506 } 507 508 // TODO: ACC Should have an aria-describedby attribute which is user-configurable to describe what this field is actually for. 509 // Maybe actually inherit it from the original textara? 510 n = p = DOM.create('span', {role : 'application', 'aria-labelledby' : ed.id + '_voice', id : ed.id + '_parent', 'class' : 'mceEditor ' + ed.settings.skin + 'Skin' + (s.skin_variant ? ' ' + ed.settings.skin + 'Skin' + t._ufirst(s.skin_variant) : '')}); 511 DOM.add(n, 'span', {'class': 'mceVoiceLabel', 'style': 'display:none;', id: ed.id + '_voice'}, s.aria_label); 512 513 if (!DOM.boxModel) 514 n = DOM.add(n, 'div', {'class' : 'mceOldBoxModel'}); 515 516 n = sc = DOM.add(n, 'table', {role : "presentation", id : ed.id + '_tbl', 'class' : 'mceLayout', cellSpacing : 0, cellPadding : 0}); 517 n = tb = DOM.add(n, 'tbody'); 518 519 switch ((s.theme_advanced_layout_manager || '').toLowerCase()) { 520 case "rowlayout": 521 ic = t._rowLayout(s, tb, o); 522 break; 523 524 case "customlayout": 525 ic = ed.execCallback("theme_advanced_custom_layout", s, tb, o, p); 526 break; 527 528 default: 529 ic = t._simpleLayout(s, tb, o, p); 530 } 531 532 n = o.targetNode; 533 534 // Add classes to first and last TRs 535 nl = sc.rows; 536 DOM.addClass(nl[0], 'mceFirst'); 537 DOM.addClass(nl[nl.length - 1], 'mceLast'); 538 539 // Add classes to first and last TDs 540 each(DOM.select('tr', tb), function(n) { 541 DOM.addClass(n.firstChild, 'mceFirst'); 542 DOM.addClass(n.childNodes[n.childNodes.length - 1], 'mceLast'); 543 }); 544 545 if (DOM.get(s.theme_advanced_toolbar_container)) 546 DOM.get(s.theme_advanced_toolbar_container).appendChild(p); 547 else 548 DOM.insertAfter(p, n); 549 550 Event.add(ed.id + '_path_row', 'click', function(e) { 551 e = e.target; 552 553 if (e.nodeName == 'A') { 554 t._sel(e.className.replace(/^.*mcePath_([0-9]+).*$/, '$1')); 555 556 return Event.cancel(e); 557 } 558 }); 559 /* 560 if (DOM.get(ed.id + '_path_row')) { 561 Event.add(ed.id + '_tbl', 'mouseover', function(e) { 562 var re; 563 564 e = e.target; 565 566 if (e.nodeName == 'SPAN' && DOM.hasClass(e.parentNode, 'mceButton')) { 567 re = DOM.get(ed.id + '_path_row'); 568 t.lastPath = re.innerHTML; 569 DOM.setHTML(re, e.parentNode.title); 570 } 571 }); 572 573 Event.add(ed.id + '_tbl', 'mouseout', function(e) { 574 if (t.lastPath) { 575 DOM.setHTML(ed.id + '_path_row', t.lastPath); 576 t.lastPath = 0; 577 } 578 }); 579 } 580 */ 581 582 if (!ed.getParam('accessibility_focus')) 583 Event.add(DOM.add(p, 'a', {href : '#'}, '<!-- IE -->'), 'focus', function() {tinyMCE.get(ed.id).focus();}); 584 585 if (s.theme_advanced_toolbar_location == 'external') 586 o.deltaHeight = 0; 587 588 t.deltaHeight = o.deltaHeight; 589 o.targetNode = null; 590 591 ed.onKeyDown.add(function(ed, evt) { 592 var DOM_VK_F10 = 121, DOM_VK_F11 = 122; 593 594 if (evt.altKey) { 595 if (evt.keyCode === DOM_VK_F10) { 596 // Make sure focus is given to toolbar in Safari. 597 // We can't do this in IE as it prevents giving focus to toolbar when editor is in a frame 598 if (tinymce.isWebKit) { 599 window.focus(); 600 } 601 t.toolbarGroup.focus(); 602 return Event.cancel(evt); 603 } else if (evt.keyCode === DOM_VK_F11) { 604 DOM.get(ed.id + '_path_row').focus(); 605 return Event.cancel(evt); 606 } 607 } 608 }); 609 610 // alt+0 is the UK recommended shortcut for accessing the list of access controls. 611 ed.addShortcut('alt+0', '', 'mceShortcuts', t); 612 613 return { 614 iframeContainer : ic, 615 editorContainer : ed.id + '_parent', 616 sizeContainer : sc, 617 deltaHeight : o.deltaHeight 618 }; 619 }, 620 621 getInfo : function() { 622 return { 623 longname : 'Advanced theme', 624 author : 'Moxiecode Systems AB', 625 authorurl : 'http://tinymce.moxiecode.com', 626 version : tinymce.majorVersion + "." + tinymce.minorVersion 627 } 628 }, 629 630 resizeBy : function(dw, dh) { 631 var e = DOM.get(this.editor.id + '_ifr'); 632 633 this.resizeTo(e.clientWidth + dw, e.clientHeight + dh); 634 }, 635 636 resizeTo : function(w, h, store) { 637 var ed = this.editor, s = this.settings, e = DOM.get(ed.id + '_tbl'), ifr = DOM.get(ed.id + '_ifr'); 638 639 // Boundery fix box 640 w = Math.max(s.theme_advanced_resizing_min_width || 100, w); 641 h = Math.max(s.theme_advanced_resizing_min_height || 100, h); 642 w = Math.min(s.theme_advanced_resizing_max_width || 0xFFFF, w); 643 h = Math.min(s.theme_advanced_resizing_max_height || 0xFFFF, h); 644 645 // Resize iframe and container 646 DOM.setStyle(e, 'height', ''); 647 DOM.setStyle(ifr, 'height', h); 648 649 if (s.theme_advanced_resize_horizontal) { 650 DOM.setStyle(e, 'width', ''); 651 DOM.setStyle(ifr, 'width', w); 652 653 // Make sure that the size is never smaller than the over all ui 654 if (w < e.clientWidth) { 655 w = e.clientWidth; 656 DOM.setStyle(ifr, 'width', e.clientWidth); 657 } 658 } 659 660 // Store away the size 661 if (store && s.theme_advanced_resizing_use_cookie) { 662 Cookie.setHash("TinyMCE_" + ed.id + "_size", { 663 cw : w, 664 ch : h 665 }); 666 } 667 }, 668 669 destroy : function() { 670 var id = this.editor.id; 671 672 Event.clear(id + '_resize'); 673 Event.clear(id + '_path_row'); 674 Event.clear(id + '_external_close'); 675 }, 676 677 // Internal functions 678 679 _simpleLayout : function(s, tb, o, p) { 680 var t = this, ed = t.editor, lo = s.theme_advanced_toolbar_location, sl = s.theme_advanced_statusbar_location, n, ic, etb, c; 681 682 if (s.readonly) { 683 n = DOM.add(tb, 'tr'); 684 n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); 685 return ic; 686 } 687 688 // Create toolbar container at top 689 if (lo == 'top') 690 t._addToolbars(tb, o); 691 692 // Create external toolbar 693 if (lo == 'external') { 694 n = c = DOM.create('div', {style : 'position:relative'}); 695 n = DOM.add(n, 'div', {id : ed.id + '_external', 'class' : 'mceExternalToolbar'}); 696 DOM.add(n, 'a', {id : ed.id + '_external_close', href : 'javascript:;', 'class' : 'mceExternalClose'}); 697 n = DOM.add(n, 'table', {id : ed.id + '_tblext', cellSpacing : 0, cellPadding : 0}); 698 etb = DOM.add(n, 'tbody'); 699 700 if (p.firstChild.className == 'mceOldBoxModel') 701 p.firstChild.appendChild(c); 702 else 703 p.insertBefore(c, p.firstChild); 704 705 t._addToolbars(etb, o); 706 707 ed.onMouseUp.add(function() { 708 var e = DOM.get(ed.id + '_external'); 709 DOM.show(e); 710 711 DOM.hide(lastExtID); 712 713 var f = Event.add(ed.id + '_external_close', 'click', function() { 714 DOM.hide(ed.id + '_external'); 715 Event.remove(ed.id + '_external_close', 'click', f); 716 }); 717 718 DOM.show(e); 719 DOM.setStyle(e, 'top', 0 - DOM.getRect(ed.id + '_tblext').h - 1); 720 721 // Fixes IE rendering bug 722 DOM.hide(e); 723 DOM.show(e); 724 e.style.filter = ''; 725 726 lastExtID = ed.id + '_external'; 727 728 e = null; 729 }); 730 } 731 732 if (sl == 'top') 733 t._addStatusBar(tb, o); 734 735 // Create iframe container 736 if (!s.theme_advanced_toolbar_container) { 737 n = DOM.add(tb, 'tr'); 738 n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); 739 } 740 741 // Create toolbar container at bottom 742 if (lo == 'bottom') 743 t._addToolbars(tb, o); 744 745 if (sl == 'bottom') 746 t._addStatusBar(tb, o); 747 748 return ic; 749 }, 750 751 _rowLayout : function(s, tb, o) { 752 var t = this, ed = t.editor, dc, da, cf = ed.controlManager, n, ic, to, a; 753 754 dc = s.theme_advanced_containers_default_class || ''; 755 da = s.theme_advanced_containers_default_align || 'center'; 756 757 each(explode(s.theme_advanced_containers || ''), function(c, i) { 758 var v = s['theme_advanced_container_' + c] || ''; 759 760 switch (c.toLowerCase()) { 761 case 'mceeditor': 762 n = DOM.add(tb, 'tr'); 763 n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); 764 break; 765 766 case 'mceelementpath': 767 t._addStatusBar(tb, o); 768 break; 769 770 default: 771 a = (s['theme_advanced_container_' + c + '_align'] || da).toLowerCase(); 772 a = 'mce' + t._ufirst(a); 773 774 n = DOM.add(DOM.add(tb, 'tr'), 'td', { 775 'class' : 'mceToolbar ' + (s['theme_advanced_container_' + c + '_class'] || dc) + ' ' + a || da 776 }); 777 778 to = cf.createToolbar("toolbar" + i); 779 t._addControls(v, to); 780 DOM.setHTML(n, to.renderHTML()); 781 o.deltaHeight -= s.theme_advanced_row_height; 782 } 783 }); 784 785 return ic; 786 }, 787 788 _addControls : function(v, tb) { 789 var t = this, s = t.settings, di, cf = t.editor.controlManager; 790 791 if (s.theme_advanced_disable && !t._disabled) { 792 di = {}; 793 794 each(explode(s.theme_advanced_disable), function(v) { 795 di[v] = 1; 796 }); 797 798 t._disabled = di; 799 } else 800 di = t._disabled; 801 802 each(explode(v), function(n) { 803 var c; 804 805 if (di && di[n]) 806 return; 807 808 // Compatiblity with 2.x 809 if (n == 'tablecontrols') { 810 each(["table","|","row_props","cell_props","|","row_before","row_after","delete_row","|","col_before","col_after","delete_col","|","split_cells","merge_cells"], function(n) { 811 n = t.createControl(n, cf); 812 813 if (n) 814 tb.add(n); 815 }); 816 817 return; 818 } 819 820 c = t.createControl(n, cf); 821 822 if (c) 823 tb.add(c); 824 }); 825 }, 826 827 _addToolbars : function(c, o) { 828 var t = this, i, tb, ed = t.editor, s = t.settings, v, cf = ed.controlManager, di, n, h = [], a, toolbarGroup; 829 830 toolbarGroup = cf.createToolbarGroup('toolbargroup', { 831 'name': ed.getLang('advanced.toolbar'), 832 'tab_focus_toolbar':ed.getParam('theme_advanced_tab_focus_toolbar') 833 }); 834 835 t.toolbarGroup = toolbarGroup; 836 837 a = s.theme_advanced_toolbar_align.toLowerCase(); 838 a = 'mce' + t._ufirst(a); 839 840 n = DOM.add(DOM.add(c, 'tr', {role: 'presentation'}), 'td', {'class' : 'mceToolbar ' + a, "role":"presentation"}); 841 842 // Create toolbar and add the controls 843 for (i=1; (v = s['theme_advanced_buttons' + i]); i++) { 844 tb = cf.createToolbar("toolbar" + i, {'class' : 'mceToolbarRow' + i}); 845 846 if (s['theme_advanced_buttons' + i + '_add']) 847 v += ',' + s['theme_advanced_buttons' + i + '_add']; 848 849 if (s['theme_advanced_buttons' + i + '_add_before']) 850 v = s['theme_advanced_buttons' + i + '_add_before'] + ',' + v; 851 852 t._addControls(v, tb); 853 toolbarGroup.add(tb); 854 855 o.deltaHeight -= s.theme_advanced_row_height; 856 } 857 h.push(toolbarGroup.renderHTML()); 858 h.push(DOM.createHTML('a', {href : '#', accesskey : 'z', title : ed.getLang("advanced.toolbar_focus"), onfocus : 'tinyMCE.getInstanceById(\'' + ed.id + '\').focus();'}, '<!-- IE -->')); 859 DOM.setHTML(n, h.join('')); 860 }, 861 862 _addStatusBar : function(tb, o) { 863 var n, t = this, ed = t.editor, s = t.settings, r, mf, me, td; 864 865 n = DOM.add(tb, 'tr'); 866 n = td = DOM.add(n, 'td', {'class' : 'mceStatusbar'}); 867 n = DOM.add(n, 'div', {id : ed.id + '_path_row', 'role': 'group', 'aria-labelledby': ed.id + '_path_voice'}); 868 if (s.theme_advanced_path) { 869 DOM.add(n, 'span', {id: ed.id + '_path_voice'}, ed.translate('advanced.path')); 870 DOM.add(n, 'span', {}, ': '); 871 } else { 872 DOM.add(n, 'span', {}, ' '); 873 } 874 875 876 if (s.theme_advanced_resizing) { 877 DOM.add(td, 'a', {id : ed.id + '_resize', href : 'javascript:;', onclick : "return false;", 'class' : 'mceResize', tabIndex:"-1"}); 878 879 if (s.theme_advanced_resizing_use_cookie) { 880 ed.onPostRender.add(function() { 881 var o = Cookie.getHash("TinyMCE_" + ed.id + "_size"), c = DOM.get(ed.id + '_tbl'); 882 883 if (!o) 884 return; 885 886 t.resizeTo(o.cw, o.ch); 887 }); 888 } 889 890 ed.onPostRender.add(function() { 891 Event.add(ed.id + '_resize', 'click', function(e) { 892 e.preventDefault(); 893 }); 894 895 Event.add(ed.id + '_resize', 'mousedown', function(e) { 896 var mouseMoveHandler1, mouseMoveHandler2, 897 mouseUpHandler1, mouseUpHandler2, 898 startX, startY, startWidth, startHeight, width, height, ifrElm; 899 900 function resizeOnMove(e) { 901 e.preventDefault(); 902 903 width = startWidth + (e.screenX - startX); 904 height = startHeight + (e.screenY - startY); 905 906 t.resizeTo(width, height); 907 }; 908 909 function endResize(e) { 910 // Stop listening 911 Event.remove(DOM.doc, 'mousemove', mouseMoveHandler1); 912 Event.remove(ed.getDoc(), 'mousemove', mouseMoveHandler2); 913 Event.remove(DOM.doc, 'mouseup', mouseUpHandler1); 914 Event.remove(ed.getDoc(), 'mouseup', mouseUpHandler2); 915 916 width = startWidth + (e.screenX - startX); 917 height = startHeight + (e.screenY - startY); 918 t.resizeTo(width, height, true); 919 }; 920 921 e.preventDefault(); 922 923 // Get the current rect size 924 startX = e.screenX; 925 startY = e.screenY; 926 ifrElm = DOM.get(t.editor.id + '_ifr'); 927 startWidth = width = ifrElm.clientWidth; 928 startHeight = height = ifrElm.clientHeight; 929 930 // Register envent handlers 931 mouseMoveHandler1 = Event.add(DOM.doc, 'mousemove', resizeOnMove); 932 mouseMoveHandler2 = Event.add(ed.getDoc(), 'mousemove', resizeOnMove); 933 mouseUpHandler1 = Event.add(DOM.doc, 'mouseup', endResize); 934 mouseUpHandler2 = Event.add(ed.getDoc(), 'mouseup', endResize); 935 }); 936 }); 937 } 938 939 o.deltaHeight -= 21; 940 n = tb = null; 941 }, 942 943 _updateUndoStatus : function(ed) { 944 var cm = ed.controlManager, um = ed.undoManager; 945 946 cm.setDisabled('undo', !um.hasUndo() && !um.typing); 947 cm.setDisabled('redo', !um.hasRedo()); 948 }, 949 950 _nodeChanged : function(ed, cm, n, co, ob) { 951 var t = this, p, de = 0, v, c, s = t.settings, cl, fz, fn, fc, bc, formatNames, matches; 952 953 tinymce.each(t.stateControls, function(c) { 954 cm.setActive(c, ed.queryCommandState(t.controls[c][1])); 955 }); 956 957 function getParent(name) { 958 var i, parents = ob.parents, func = name; 959 960 if (typeof(name) == 'string') { 961 func = function(node) { 962 return node.nodeName == name; 963 }; 964 } 965 966 for (i = 0; i < parents.length; i++) { 967 if (func(parents[i])) 968 return parents[i]; 969 } 970 }; 971 972 cm.setActive('visualaid', ed.hasVisual); 973 t._updateUndoStatus(ed); 974 cm.setDisabled('outdent', !ed.queryCommandState('Outdent')); 975 976 p = getParent('A'); 977 if (c = cm.get('link')) { 978 if (!p || !p.name) { 979 c.setDisabled(!p && co); 980 c.setActive(!!p); 981 } 982 } 983 984 if (c = cm.get('unlink')) { 985 c.setDisabled(!p && co); 986 c.setActive(!!p && !p.name); 987 } 988 989 if (c = cm.get('anchor')) { 990 c.setActive(!co && !!p && p.name); 991 } 992 993 p = getParent('IMG'); 994 if (c = cm.get('image')) 995 c.setActive(!co && !!p && n.className.indexOf('mceItem') == -1); 996 997 if (c = cm.get('styleselect')) { 998 t._importClasses(); 999 1000 formatNames = []; 1001 each(c.items, function(item) { 1002 formatNames.push(item.value); 1003 }); 1004 1005 matches = ed.formatter.matchAll(formatNames); 1006 c.select(matches[0]); 1007 } 1008 1009 if (c = cm.get('formatselect')) { 1010 p = getParent(DOM.isBlock); 1011 1012 if (p) 1013 c.select(p.nodeName.toLowerCase()); 1014 } 1015 1016 // Find out current fontSize, fontFamily and fontClass 1017 getParent(function(n) { 1018 if (n.nodeName === 'SPAN') { 1019 if (!cl && n.className) 1020 cl = n.className; 1021 } 1022 1023 if (ed.dom.is(n, s.theme_advanced_font_selector)) { 1024 if (!fz && n.style.fontSize) 1025 fz = n.style.fontSize; 1026 1027 if (!fn && n.style.fontFamily) 1028 fn = n.style.fontFamily.replace(/[\"\']+/g, '').replace(/^([^,]+).*/, '$1').toLowerCase(); 1029 1030 if (!fc && n.style.color) 1031 fc = n.style.color; 1032 1033 if (!bc && n.style.backgroundColor) 1034 bc = n.style.backgroundColor; 1035 } 1036 1037 return false; 1038 }); 1039 1040 if (c = cm.get('fontselect')) { 1041 c.select(function(v) { 1042 return v.replace(/^([^,]+).*/, '$1').toLowerCase() == fn; 1043 }); 1044 } 1045 1046 // Select font size 1047 if (c = cm.get('fontsizeselect')) { 1048 // Use computed style 1049 if (s.theme_advanced_runtime_fontsize && !fz && !cl) 1050 fz = ed.dom.getStyle(n, 'fontSize', true); 1051 1052 c.select(function(v) { 1053 if (v.fontSize && v.fontSize === fz) 1054 return true; 1055 1056 if (v['class'] && v['class'] === cl) 1057 return true; 1058 }); 1059 } 1060 1061 if (s.theme_advanced_show_current_color) { 1062 function updateColor(controlId, color) { 1063 if (c = cm.get(controlId)) { 1064 if (!color) 1065 color = c.settings.default_color; 1066 if (color !== c.value) { 1067 c.displayColor(color); 1068 } 1069 } 1070 } 1071 updateColor('forecolor', fc); 1072 updateColor('backcolor', bc); 1073 } 1074 1075 if (s.theme_advanced_show_current_color) { 1076 function updateColor(controlId, color) { 1077 if (c = cm.get(controlId)) { 1078 if (!color) 1079 color = c.settings.default_color; 1080 if (color !== c.value) { 1081 c.displayColor(color); 1082 } 1083 } 1084 }; 1085 1086 updateColor('forecolor', fc); 1087 updateColor('backcolor', bc); 1088 } 1089 1090 if (s.theme_advanced_path && s.theme_advanced_statusbar_location) { 1091 p = DOM.get(ed.id + '_path') || DOM.add(ed.id + '_path_row', 'span', {id : ed.id + '_path'}); 1092 1093 if (t.statusKeyboardNavigation) { 1094 t.statusKeyboardNavigation.destroy(); 1095 t.statusKeyboardNavigation = null; 1096 } 1097 1098 DOM.setHTML(p, ''); 1099 1100 getParent(function(n) { 1101 var na = n.nodeName.toLowerCase(), u, pi, ti = ''; 1102 1103 // Ignore non element and bogus/hidden elements 1104 if (n.nodeType != 1 || na === 'br' || n.getAttribute('data-mce-bogus') || DOM.hasClass(n, 'mceItemHidden') || DOM.hasClass(n, 'mceItemRemoved')) 1105 return; 1106 1107 // Handle prefix 1108 if (tinymce.isIE && n.scopeName !== 'HTML') 1109 na = n.scopeName + ':' + na; 1110 1111 // Remove internal prefix 1112 na = na.replace(/mce\:/g, ''); 1113 1114 // Handle node name 1115 switch (na) { 1116 case 'b': 1117 na = 'strong'; 1118 break; 1119 1120 case 'i': 1121 na = 'em'; 1122 break; 1123 1124 case 'img': 1125 if (v = DOM.getAttrib(n, 'src')) 1126 ti += 'src: ' + v + ' '; 1127 1128 break; 1129 1130 case 'a': 1131 if (v = DOM.getAttrib(n, 'name')) { 1132 ti += 'name: ' + v + ' '; 1133 na += '#' + v; 1134 } 1135 1136 if (v = DOM.getAttrib(n, 'href')) 1137 ti += 'href: ' + v + ' '; 1138 1139 break; 1140 1141 case 'font': 1142 if (v = DOM.getAttrib(n, 'face')) 1143 ti += 'font: ' + v + ' '; 1144 1145 if (v = DOM.getAttrib(n, 'size')) 1146 ti += 'size: ' + v + ' '; 1147 1148 if (v = DOM.getAttrib(n, 'color')) 1149 ti += 'color: ' + v + ' '; 1150 1151 break; 1152 1153 case 'span': 1154 if (v = DOM.getAttrib(n, 'style')) 1155 ti += 'style: ' + v + ' '; 1156 1157 break; 1158 } 1159 1160 if (v = DOM.getAttrib(n, 'id')) 1161 ti += 'id: ' + v + ' '; 1162 1163 if (v = n.className) { 1164 v = v.replace(/\b\s*(webkit|mce|Apple-)\w+\s*\b/g, '') 1165 1166 if (v) { 1167 ti += 'class: ' + v + ' '; 1168 1169 if (DOM.isBlock(n) || na == 'img' || na == 'span') 1170 na += '.' + v; 1171 } 1172 } 1173 1174 na = na.replace(/(html:)/g, ''); 1175 na = {name : na, node : n, title : ti}; 1176 t.onResolveName.dispatch(t, na); 1177 ti = na.title; 1178 na = na.name; 1179 1180 //u = "javascript:tinymce.EditorManager.get('" + ed.id + "').theme._sel('" + (de++) + "');"; 1181 pi = DOM.create('a', {'href' : "javascript:;", role: 'button', onmousedown : "return false;", title : ti, 'class' : 'mcePath_' + (de++)}, na); 1182 1183 if (p.hasChildNodes()) { 1184 p.insertBefore(DOM.create('span', {'aria-hidden': 'true'}, '\u00a0\u00bb '), p.firstChild); 1185 p.insertBefore(pi, p.firstChild); 1186 } else 1187 p.appendChild(pi); 1188 }, ed.getBody()); 1189 1190 if (DOM.select('a', p).length > 0) { 1191 t.statusKeyboardNavigation = new tinymce.ui.KeyboardNavigation({ 1192 root: ed.id + "_path_row", 1193 items: DOM.select('a', p), 1194 excludeFromTabOrder: true, 1195 onCancel: function() { 1196 ed.focus(); 1197 } 1198 }, DOM); 1199 } 1200 } 1201 }, 1202 1203 // Commands gets called by execCommand 1204 1205 _sel : function(v) { 1206 this.editor.execCommand('mceSelectNodeDepth', false, v); 1207 }, 1208 1209 _mceInsertAnchor : function(ui, v) { 1210 var ed = this.editor; 1211 1212 ed.windowManager.open({ 1213 url : this.url + '/anchor.htm', 1214 width : 320 + parseInt(ed.getLang('advanced.anchor_delta_width', 0)), 1215 height : 90 + parseInt(ed.getLang('advanced.anchor_delta_height', 0)), 1216 inline : true 1217 }, { 1218 theme_url : this.url 1219 }); 1220 }, 1221 1222 _mceCharMap : function() { 1223 var ed = this.editor; 1224 1225 ed.windowManager.open({ 1226 url : this.url + '/charmap.htm', 1227 width : 550 + parseInt(ed.getLang('advanced.charmap_delta_width', 0)), 1228 height : 265 + parseInt(ed.getLang('advanced.charmap_delta_height', 0)), 1229 inline : true 1230 }, { 1231 theme_url : this.url 1232 }); 1233 }, 1234 1235 _mceHelp : function() { 1236 var ed = this.editor; 1237 1238 ed.windowManager.open({ 1239 url : this.url + '/about.htm', 1240 width : 480, 1241 height : 380, 1242 inline : true 1243 }, { 1244 theme_url : this.url 1245 }); 1246 }, 1247 1248 _mceShortcuts : function() { 1249 var ed = this.editor; 1250 ed.windowManager.open({ 1251 url: this.url + '/shortcuts.htm', 1252 width: 480, 1253 height: 380, 1254 inline: true 1255 }, { 1256 theme_url: this.url 1257 }); 1258 }, 1259 1260 _mceColorPicker : function(u, v) { 1261 var ed = this.editor; 1262 1263 v = v || {}; 1264 1265 ed.windowManager.open({ 1266 url : this.url + '/color_picker.htm', 1267 width : 375 + parseInt(ed.getLang('advanced.colorpicker_delta_width', 0)), 1268 height : 250 + parseInt(ed.getLang('advanced.colorpicker_delta_height', 0)), 1269 close_previous : false, 1270 inline : true 1271 }, { 1272 input_color : v.color, 1273 func : v.func, 1274 theme_url : this.url 1275 }); 1276 }, 1277 1278 _mceCodeEditor : function(ui, val) { 1279 var ed = this.editor; 1280 1281 ed.windowManager.open({ 1282 url : this.url + '/source_editor.htm', 1283 width : parseInt(ed.getParam("theme_advanced_source_editor_width", 720)), 1284 height : parseInt(ed.getParam("theme_advanced_source_editor_height", 580)), 1285 inline : true, 1286 resizable : true, 1287 maximizable : true 1288 }, { 1289 theme_url : this.url 1290 }); 1291 }, 1292 1293 _mceImage : function(ui, val) { 1294 var ed = this.editor; 1295 1296 // Internal image object like a flash placeholder 1297 if (ed.dom.getAttrib(ed.selection.getNode(), 'class').indexOf('mceItem') != -1) 1298 return; 1299 1300 ed.windowManager.open({ 1301 url : this.url + '/image.htm', 1302 width : 355 + parseInt(ed.getLang('advanced.image_delta_width', 0)), 1303 height : 275 + parseInt(ed.getLang('advanced.image_delta_height', 0)), 1304 inline : true 1305 }, { 1306 theme_url : this.url 1307 }); 1308 }, 1309 1310 _mceLink : function(ui, val) { 1311 var ed = this.editor; 1312 1313 ed.windowManager.open({ 1314 url : this.url + '/link.htm', 1315 width : 310 + parseInt(ed.getLang('advanced.link_delta_width', 0)), 1316 height : 200 + parseInt(ed.getLang('advanced.link_delta_height', 0)), 1317 inline : true 1318 }, { 1319 theme_url : this.url 1320 }); 1321 }, 1322 1323 _mceNewDocument : function() { 1324 var ed = this.editor; 1325 1326 ed.windowManager.confirm('advanced.newdocument', function(s) { 1327 if (s) 1328 ed.execCommand('mceSetContent', false, ''); 1329 }); 1330 }, 1331 1332 _mceForeColor : function() { 1333 var t = this; 1334 1335 this._mceColorPicker(0, { 1336 color: t.fgColor, 1337 func : function(co) { 1338 t.fgColor = co; 1339 t.editor.execCommand('ForeColor', false, co); 1340 } 1341 }); 1342 }, 1343 1344 _mceBackColor : function() { 1345 var t = this; 1346 1347 this._mceColorPicker(0, { 1348 color: t.bgColor, 1349 func : function(co) { 1350 t.bgColor = co; 1351 t.editor.execCommand('HiliteColor', false, co); 1352 } 1353 }); 1354 }, 1355 1356 _ufirst : function(s) { 1357 return s.substring(0, 1).toUpperCase() + s.substring(1); 1358 } 1359 }); 1360 1361 tinymce.ThemeManager.add('advanced', tinymce.themes.AdvancedTheme); 1362 }(tinymce)); -
wp-includes/class-wp-editor.php
523 523 <script type="text/javascript"> 524 524 tinyMCEPreInit = { 525 525 base : "<?php echo self::$baseurl; ?>", 526 suffix : "",526 suffix : '<?php echo ( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) ? '.dev' : ''; ?>', 527 527 query : "<?php echo $version; ?>", 528 528 mceInit : <?php echo $mceInit; ?>, 529 529 qtInit : <?php echo $qtInit; ?>,