3.12. 3 テキスト→ビジュアル切り替え

 wp-admin/js/editor.js を改造する場合の、テキスト→ビジュアル切り替え用 JavaScript コードです。

コード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
// content reform for visual editor
//   text to visual
function hk_editor_html2tmce( content ) {
    var pre_tags1, pre_tags2, line_break, code_names, code_types;
    // 1st common reform
    content = hk_editor_reform_1st( content );
    // empty content
    if ( content.length == 0 ) {
        return '<p>&nbsp;</p>';
    }
    // escape PRE tag
    pre_tags1 = new Array();
    pre_tags2 = new Array();
    line_break = false;
    content = hk_editor_escape_pre( content, pre_tags1, pre_tags2, line_break );
    // remove \n
    content = content.replace( /\n/g, '' );
    // short code check
    code_names = new Array();
    code_types = new Array();
    content = hk_short_code_check( content, code_names, code_types );
    // 2nd common reform
    content = hk_editor_reform_2nd( content, code_names, code_types );
    // insert input area around table
    content = content.replace( /^<table( [^>]*>|>)/i, '<p>&nbsp;</p><table$1' );
    content = content.replace( /<\/table><table( [^>]*>|>)/ig, '</table><p>&nbsp;</p><table$1' );
    content = content.replace( /<\/table>$/ig, '</table><p>&nbsp;</p>' );
    // put back PRE tag
    content = hk_editor_put_back_pre( content, pre_tags1, pre_tags2 );
    // trim
    content = content.trim();
    if ( content.length == 0 ) {
        content = '<p>&nbsp;</p>';
    }
    return content;
}

// 1st Common Reform
function hk_editor_reform_1st( content ) {
    // remove tab
    content = content.replace( /\t/g, '' );
    // change characters
    content = content.replace( /\u00A0/g, ' ' );
    content = content.replace( /\r\n|\r/g, '\n' );
    // remove unnecessary space: before and after tag
    content = content.replace( / *(<[^>]*>) */g, '$1' );
    // remove unnecessary p-tag
    content = content.replace( /<p>&nbsp;<\/p>/ig, '' );
    content = content.replace( /<p><\/p>/ig,       '' );
    content = content.replace( /<p>\n<\/p>/ig,     '' );
    // trim
    content = content.trim();
    return content;
}

// 2nd Common Reform
function hk_editor_reform_2nd( content, code_names, code_types ) {
    var allblocks, pattern_b, re_str_b, blocks, i, pattern00, pattern3, re_str3, j_max, j, sub_blocks, sub_max,
        content_parts, pattern, re_str;
    allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)';
    // if top character is not '<', p-tag wrap.
    if ( content.indexOf( '<' ) != 0 ) {
        // split by block tag
        pattern_b = '(<' + allblocks + '(?: [^>]*>|>))';
        re_str_b = new RegExp( pattern_b, 'ig' );
        blocks = content.split( re_str_b );
        // blocks[0] <block-tag>
        // wrap blocks[0] with p-tag
        blocks[0] = '<p>' + blocks[0] + '</p>';
        content = blocks.join( '' );
    }
    // shortcode_unautop
    if ( code_names.length != 0 ) {
        for ( i in code_names ) {
            code_name = code_names[i];
            code_type = code_types[code_name];
            pattern00 = hk_short_code_pattern( code_name, code_type );
            // split by short code
            pattern3 = '(' + pattern00 + ')(?!\\])';
            re_str3 = new RegExp( pattern3, 'ig' );
            blocks = content.split( re_str3 );
            j_max = blocks.length - 2;
            for ( j=0; j<j_max; j+=2 ) {
                // blocks[j] [shortcode] blocks[j+2]
                // split blocks[j] by block-tag
                pattern_b = '(<' + allblocks + '(?: [^>]*>|>))';
                re_str_b = new RegExp( pattern_b, 'ig' );
                sub_blocks = blocks[ j ].split( re_str_b );
                sub_max = sub_blocks.length;
                // if no block tag, 'continue'.
                if ( sub_max == 1 ) {
                    continue;
                }
                // <block-tag> sub_blocks[sub_max-1] [shortcode]
                // if block-tag is not p-tag, 'continue'.
                if ( sub_blocks[ sub_max-2 ].match( /<p( [^>]*>|>)/i ) == null ) {
                    continue;
                }
                // <p> sub_blocks[sub_max-1] [shortcode]
                // if </p> exists in sub_blocks[sub_max-1], 'continue'.
                if ( sub_blocks[ sub_max-1 ].indexOf( '</p>' ) != -1 ) {
                    continue;
                }
                // <p> xxxxx [shortcode] yyyyy </p>
                // insert </p> and <p>
                // -> <p> xxxxx </p> [shortcode] <p> yyyyy </p>
                blocks[ j ]  += '</p>';
                blocks[ j+2 ] = '<p>' + blocks[ j+2 ];
            }
            content = blocks.join( '' );
            // delete <p></p>
            content = content.replace( /<p(?: [^>]*>|>)((?:<br [^>]*>)+)<\/p>/ig, '$1' );
            content = content.replace( /<p( [^>]*>|>)<\/p>/ig, '' );
        }
    }
    // delete p-tag inside table
    if ( content.indexOf( '</td>' ) != -1 ) {
        // split by </td>
        content_parts = content.split( '</td>' );
        content = '';
        for ( i in content_parts ) {
            // split by <td
            pattern = '(<td(?: [^>]*>|>))';
            re_str = new RegExp( pattern, 'ig' );
            blocks = content_parts[ i ].split( re_str );
            // if no td tag, 'continue'.
            if ( blocks.length == 1 ) {
                content += content_parts[ i ];
                continue;
            }
            // string after td-tag
            // delete p-tag
            blocks[ 2 ] = blocks[ 2 ].replace( /<p(?: [^>]*>|>)/ig, '' );
            // delete </p> at the end of string
            blocks[ 2 ] = blocks[ 2 ].replace( /<\/p>$/i, '' );
            // replace </p> with <br />
            blocks[ 2 ] = blocks[ 2 ].replace( /<\/p>/ig, '<br />' );
            // add string
            content += blocks[ 0 ] + blocks[ 1 ] + blocks[ 2 ] + '</td>';
        }
    }
    // p-tag indent ( \u3000 : ZENKAKU space )
    content = content.replace( /<p>\u3000/ig,  '<p>' );
    content = content.replace( /<p>/ig,        '<p>\u3000' );
    content = content.replace( /<p>\u3000</ig, '<p><' );
    content = content.replace( /<p><\/p>/ig,   '' );
    return content;
}

// escape PRE tag
function hk_editor_escape_pre( content, pre_tags1, pre_tags2, line_break ) {
    var content_parts, pre_i, i, pattern, re_str, blocks, pre_block, pre_name;
    // </pre> check
    if ( content.indexOf( '</pre>' ) == -1 ) {
        return content;
    }
    // split by </pre>
    content_parts = content.split( '</pre>' );
    // initialize
    content = '';
    pre_i = 0;
    for ( i in content_parts ) {
        // split by <pre
        pattern = '(<pre(?: [^>]*>|>))';
        re_str = new RegExp( pattern, 'ig' );
        blocks = content_parts[ i ].split( re_str );
        // if no pre tag, 'continue'.
        if ( blocks.length == 1 ) {
            content += content_parts[ i ];
            continue;
        }
        // blocks[0] <pre> blocks[2]
        // string : before <pre>
        content += blocks[ 0 ];
        // string : after <pre>
        // trim \n
        blocks[ 2 ] = blocks[ 2 ].replace( /^\n+/, '' );
        blocks[ 2 ] = blocks[ 2 ].replace( /\n+$/, '' );
        // string : <pre> and after
        if ( line_break ) {
            pre_block = blocks[ 1 ] + '\n' + blocks[ 2 ] + '\n</pre>';
        }
        else {
            pre_block = blocks[ 1 ] + blocks[ 2 ] + '</pre>';
        }
        // data save
        pre_name = '<pre hk-pre-tag-' + pre_i + '></pre>';
        pre_tags1[ pre_i ] = pre_name;
        pre_tags2[ pre_i ] = pre_block;
        content += pre_name;
        pre_i++;
    }
    return content;
}

// put back PRE tag
function hk_editor_put_back_pre( content, pre_tags1, pre_tags2 ) {
    var pre_i, i;
    pre_i = pre_tags1.length;
    if ( pre_i != 0 ) {
        for ( i=0; i<pre_i; i++ ) {
            content = content.replace( pre_tags1[ i ], pre_tags2[ i ] );
        }
    }
    return content;
}

// Short Code Check
function hk_short_code_check( content, code_names, code_types ) {
    var i, code_name, self, re_str1, encl, re_str2, type, pattern00, pattern01, re_str01, pattern02, re_str02,
        pattern03, re_str03, pattern04, re_str04;
    for ( i in hk_short_codes ) {
        code_name = hk_short_codes[i];
        self = hk_short_code_pattern( code_name, 'self' );
        re_str1 = new RegExp( self, 'i' );
        // if shortcode does not exist, 'continue'.
        if ( content.match( re_str1 ) == null ) {
            continue;
        }
        encl = hk_short_code_pattern( code_name, 'encl' );
        re_str2 = new RegExp( encl, 'i' );
        // enclosing shortcodes
        if ( content.match( re_str2 ) ) {
            type = 'encl';
            pattern00 = encl;
        }
        // self-closing shortcodes
        else {
            type = 'self';
            pattern00 = self;
        }
        // correct pseudo-shortcode
        pattern01 = '(\\[' + pattern00 + ')(?!\\])';
        re_str01 = new RegExp( pattern01, 'ig' );
        content = content.replace( re_str01, '$1\]' );
        pattern02 = '(' + pattern00 + '\\])';
        re_str02 = new RegExp( pattern02, 'ig' );
        content = content.replace( re_str02, '\[$1' );
        pattern03 = '\\[(\\[' + pattern00 + '\\])';
        re_str03 = new RegExp( pattern03, 'ig' );
        content = content.replace( re_str03, '$1' );
        // register shortcode
        pattern04 = '(?:[^\\[]|^)' + pattern00 + '(?:[^\\]]|$)';
        re_str04 = new RegExp( pattern04, 'i' );
        if ( content.match( re_str04 ) ) {
            code_names.push( code_name );
            code_types[ code_name ] = type;
        }
    }
    return content;
}

// Short Code pattern
function hk_short_code_pattern( code_name, code_type ) {
    var self, encl;
    self = '\\[' + code_name + '[^\\]]*\\]';
    encl = self + '[^\\[]*[\\[]+\\/' + code_name + '\\]';
    if ( code_type == 'self' ) {
        return self;
    }
    return encl;
}

説明

 9行目:コンテンツが空の場合の初期値です。文頭の字下げ用です。
 15行目:PREタグを退避。Script も必要があれば退避した方が良いでしょう。
 17行目:改行を削除。ビジュアルエディターで改行が空白に変わるため削除します。
 21行目:shortcode の有無をチェックします。
 24~27行目:表の周りに文字入力スペースを作ります。
 29行目:PREタグ復元。
 43行目:u00A0 はユニコードの空白文字コードの一つ。
 61~71行目:先頭がタグでない場合、pタグでラップします。
 72~115行目:ショートコードのpタグラップ解除。
 116~141行目:表内部のpタグ削除。
 142~146行目:字下げ。u3000 はユニコードの全角スペースです。
 150~194行目:PREタグ退避。
 196~206行目:PREタグ復元。
 208~251行目:ショートコードの有無をチェック。
 253~262行目:ショートコード用正規表現パターン作成。

 このプログラムをお使いになる場合は、お使いになる方の自己責任でお願いします。

更新日:2015/11/22
掲載日:2015/11/22