WordPress.org

Make WordPress Core

Ticket #20055: 20055.diff

File 20055.diff, 148.0 KB (added by ericlewis, 8 years ago)

packaged .dev.js non-WP plugin files from TinyMCE source; also themes/advanced/editor_template.dev.js added ternary declaration of suffix of tinyMCEPreInit depending on SCRIPT_DEBUG constant.

  • 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
    12(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",{},"&nbsp;");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(/\\'|\\&#39;|\\&#039;/g,"&#39;").replace(/\\"|\\&quot;/g,"&quot;");k=k.replace(/\\&#39;|\\&#039;/g,"&#39;").replace(/\\&quot;/g,"&quot;");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,"&#39;").replace(/"/g,"&quot;");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>&nbsp;[\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>&nbsp;[\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*(&nbsp;)+/gi,                              // &nbsp; entities at the start of contents
     382                                        /(&nbsp;|<br[^>]*>)+\s*$/gi             // &nbsp; 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                                        [/&nbsp;/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(/&quot;/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(/&nbsp;/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&nbsp;&nbsp;
     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+\.(&nbsp;|\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*(&nbsp;|\u00a0)+\s*/, '');
     718                                        else
     719                                                html = p.innerHTML.replace(/__MCE_ITEM__/g, '').replace(/^\s*\w+\.(&nbsp;|\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                                        [/&nbsp;/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', {}, '&#160;');
     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