root/branches/release-38/mt-static/js/archetype_editor.js @ 2295

Revision 2295, 12.7 kB (checked in by auno, 19 months ago)

Fixed the URL path automatically changed for IE again. BugzID:69810

Line 
1/*
2# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
3# This program is distributed under the terms of the
4# GNU General Public License, version 2.
5#
6# $Id$
7*/
8
9App.singletonConstructor =
10MT.App = new Class( MT.App, {
11
12    initEditor: function() {
13        if ( this.constructor.Editor && DOM.getElement( "editor-content" ) ) {
14           
15            var mode = DOM.getElement( "convert_breaks" );
16            DOM.addEventListener( mode, "change", this.getIndirectEventListener( "setTextareaMode" ) );
17       
18            /* special case */
19            window.cur_text_format = mode.value;
20       
21            this.editorMode = ( mode.value == "richtext" ) ? "iframe" : "textarea";
22           
23            this.editor = this.addComponent( new MT.App.Editor( "editor-content", this.editorMode ) );
24            this.editor.textarea.setTextMode( mode.value );
25       
26            this.editorInput = {
27                content: DOM.getElement( "editor-input-content" ),
28                extended: DOM.getElement( "editor-input-extended" )
29            };
30       
31            if ( this.editorInput.content.value )
32                this.editor.setHTML( this.editorInput.content.value );
33        }
34    }
35
36} );
37
38
39MT.App.Editor = new Class( Editor, {
40   
41
42    setChanged: function() {
43        this.changed = true;
44        log('changed');
45        app.setDirty();
46    }
47
48
49} );
50   
51   
52MT.App.Editor.Toolbar = new Class( Editor.Toolbar, {
53       
54
55    eventClick: function( event ) {
56        var command = this.getMouseEventCommand( event );
57        if ( !command )
58            return event.stop();
59
60        switch( command ) {
61
62            case "insertEmail":
63                var link = this.editor.getSelectedLink();
64                if ( link ) 
65                    this.editEmail( link );
66                else 
67                    this.createEmailLink();
68                break;
69
70            case "openDialog":
71                app.openDialog( event.commandElement.getAttribute( "mt:dialog-params" ) );
72                break;
73
74            case "openFlyout":
75                var name = event.commandElement.getAttribute( "mt:flyout" );
76                var el = DOM.getElement( name );
77                if ( !defined( el ) )
78                    return;
79
80                app.closeFlyouts( event.target );
81
82                DOM.removeClassName( el, "hidden" );
83                app.targetElement = event.target;
84                app.applyAutolayouts( el );
85                app.targetElement = null;
86
87                app.openFlyouts.add( name );
88
89                break;
90
91            default:
92                return arguments.callee.applySuper( this, arguments );
93       
94        }
95
96        return event.stop();
97    },
98   
99   
100    editEmail: function( linkElement ) {
101        this.createEmailLink( linkElement.href, true, linkElement );
102    },
103
104
105    mailtoRegexp: /^mailto:/i,
106
107    createEmailLink: function( url, textSelected, anchor ) {
108        var linkedText = "";
109        if( !textSelected )
110            textSelected = this.editor.isTextSelected();
111        if( !url )
112            url = "";
113
114        url = url.replace( this.mailtoRegexp, "" );
115
116        url = prompt( Editor.strings.enterEmailAddress, url );
117        if( !url )
118            return false;
119        if( !textSelected ) 
120            linkedText = prompt( Editor.strings.enterTextToLinkTo, "" ); 
121
122        this.insertLink( { url: "mailto:" + url, linkedText: linkedText, anchor: anchor } );
123    }
124
125
126} );
127
128
129MT.App.Editor.Textarea = new Class( Editor.Textarea, {
130
131    currentTextMode: "_DEFAULT_",
132   
133
134    setTextMode: function( mode ) {
135        var editorContent = DOM.getElement( "editor-content" );
136        DOM.removeClassName( editorContent, /^editor-textmode-.*/ );
137        if ( this[ mode + "Command" ] )
138            DOM.addClassName( editorContent, "editor-textmode-" + mode.replace( /_/g, "-" ) );
139        this.currentTextMode = mode;
140    },
141
142
143    execCommand: function( command, userInterface, argument ) {
144        if ( this.currentTextMode && this[ this.currentTextMode + "Command" ] ) {
145            log('executeing command: ' + command + ' in mode: '+this.currentTextMode );
146            this[ this.currentTextMode + "Command" ].apply( this, arguments );
147            return;
148        }
149
150        var text = this.getSelectedText();
151        if ( !defined( text ) )
152            text = '';
153        switch ( command ) {
154           
155            case "fontSizeSmaller":
156                this.setSelection( "<small>" + text + "</small>" );
157                break;
158
159            case "fontSizeLarger":
160                this.setSelection( "<big>" + text + "</big>" );
161                break;
162   
163            default:
164                arguments.callee.applySuper( this, arguments );
165                break;       
166        }
167    },
168   
169
170
171    "markdown_with_smartypantsCommand": function() {
172        this.markdownCommand.apply( this, arguments );
173    },
174
175
176    markdownCommand: function( command, userInterface, argument ) {
177        var text = this.getSelectedText();
178        if ( !defined( text ) )
179            text = '';
180        switch ( command ) {
181           
182            case "bold":
183                this.setSelection( "**" + text + "**" );
184                break;
185
186            case "italic":
187                this.setSelection( "*" + text + "*" );
188                break;
189
190            case "createLink":
191                this.setSelection( "[" + text + "](" + argument + ")" );
192                break;
193           
194            case "indent":
195                var list = text.split( /\r?\n/ );
196                for ( var i = 0; i < list.length; i++ )
197                    list[ i ] = "> " + list[ i ];
198                this.setSelection( list.join( "\n" ) );
199                break;
200           
201            case "insertUnorderedList":
202            case "insertOrderedList":
203                var list = text.split( /\r?\n/ );
204                var ordered = ( command == "insertOrderedList" ) ? true : false;
205                for ( var i = 0; i < list.length; i++ )
206                    list[ i ] = " " + ( ordered ? ( ( i + 1 ) + ". " ) : "-" ) + " " + list[ i ];
207                this.setSelection( "\n" + list.join( "\n" ) + "\n" );
208                break;
209        }
210    },
211
212
213    "textile_2Command": function( command, userInterface, argument ) {
214        var text = this.getSelectedText();
215        if ( !defined( text ) )
216            text = '';
217        switch ( command ) {
218           
219            case "bold":
220                this.setSelection( "**" + text + "**" );
221                break;
222
223            case "italic":
224                this.setSelection( "_" + text + "_" );
225                break;
226
227            case "strikethrough":
228                this.setSelection( "-" + text + "-" );
229                break;
230           
231            case "createLink":
232                this.setSelection( '"' + text + '":' + argument );
233                break;
234           
235            case "indent":
236                this.setSelection( "bq. " + text );
237                break;
238           
239            case "underline":
240                this.setSelection( "<u>" + text + "</u>" );
241                break;
242           
243            case "insertUnorderedList":
244            case "insertOrderedList":
245                var list = text.split( /\r?\n/ );
246                var ordered = ( command == "insertOrderedList" ) ? true : false;
247                for ( var i = 0; i < list.length; i++ )
248                    list[ i ] = ( ordered ? "#" : "*" ) + " " + list[ i ];
249                this.setSelection( "\n" + list.join( "\n" ) + "\n" );
250                break;
251
252            case "justifyLeft":
253                this.setSelection( "p< " + text );
254                break;
255
256            case "justifyCenter":
257                this.setSelection( "p= " + text );
258                break;
259
260            case "justifyRight":
261                this.setSelection( "p> " + text );
262                break;
263           
264            case "fontSizeSmaller":
265                this.setSelection( "<small>" + text + "</small>" );
266                break;
267
268            case "fontSizeLarger":
269                this.setSelection( "<big>" + text + "</big>" );
270                break;
271        }
272    }
273
274} );
275
276
277
278MT.App.Editor.Iframe = new Class( Editor.Iframe, {
279
280
281    initObject: function() {
282        arguments.callee.applySuper( this, arguments );
283        this.isWebKit = navigator.userAgent.toLowerCase().match(/webkit/);
284    },
285   
286   
287    eventFocusIn: function( event ) {
288       this.eventFocus( event );
289    },
290
291
292    eventFocus: function( event ) {
293        if ( this.editor.mode == "textarea" )
294            this.editor.focus();
295    },
296
297
298    eventClick: function( event ) {
299        /* for safari */
300        if ( this.isWebKit && event.target.nodeName == "A" )
301            return event.stop();
302        return arguments.callee.applySuper( this, arguments );
303    },
304   
305   
306    eventKeyPress: function( event ) {
307        /* safari forward delete */
308        if ( this.isWebKit && event.keyCode == 63272 )
309            return event.stop();
310    },
311   
312   
313    eventKeyDown: function( event ) {
314        /* safari forward delete */
315        if ( this.isWebKit && event.keyCode == 46 ) {
316            this.document.execCommand( "forwardDelete", false, true );
317            return false;
318        }
319    },
320
321    eventKeyUp: function( event ) {
322        /* safari always makes this event. ignore for language input method */
323        if ( this.isWebKit ) {
324            return false;
325        }
326    },
327
328    extendedExecCommand: function( command, userInterface, argument ) {
329        switch( command ) {
330
331            case "fontSizeSmaller":     
332                this.changeFontSizeOfSelection( false );
333                break;
334
335            case "fontSizeLarger":
336                this.changeFontSizeOfSelection( true );
337                break;
338           
339            default:
340                return arguments.callee.applySuper( this, arguments );
341       
342        }
343    },
344
345
346    mutateFontSize: function( element, bigger ) {
347        // Basic settings:
348        var goSmaller = 0.8;
349        var goBigger = 1.25;
350        var biggest = Math.pow( goBigger, 3 );
351        var smallest = Math.pow( goSmaller, 3);
352        var defaultSize = bigger ? goBigger + "em" : goSmaller + "em";
353
354        // Initial detection, rejection, adjusting:
355        var fontSize = element.style.fontSize.match( /([\d\.]+)(%|em|$)/ );
356        if( fontSize == null || isNaN( fontSize[ 1 ] ) ) // "px" sizes are rejected.
357            return defaultSize; // A browser problem or bad user data would lead to "NaN" fontSize.
358       
359        var size;
360        if( fontSize[ 2 ] == "%" )
361            size = fontSize[ 1 ] / 100; // Convert to "em" units.
362        else if( fontSize[ 2 ] == "em" || fontSize[ 2 ] == "" )
363            size = fontSize[ 1 ];
364       
365        // Mutation:
366        var factor = bigger ? goBigger : goSmaller;
367        size = size * factor;
368       
369        if( size > biggest ) 
370            size = biggest;
371        else if( size < smallest ) 
372            size = smallest;
373
374        return size + "em";                           
375    },
376
377   
378    changeFontSizeOfSelection: function( bigger ) {
379        var bogus = "-editor-proxy";
380        this.document.execCommand( "fontName", false, bogus );
381        var elements = this.document.getElementsByTagName( "font" );
382        for( var i = 0; i < elements.length; i++ ) {
383            var element = elements[ i ];
384            if( element.face == bogus ) {
385                element.removeAttribute( "face" );
386                element.style.fontSize = this.mutateFontSize( element, bigger );
387            }
388        }
389    },
390
391
392    getHTML: function() {
393        var html = this.document.body.innerHTML;
394
395        // cleanup innerHTML garbage browser regurgitates
396        // #1 - lowercase tag names (open and closing tags)
397        html = html.replace(/<\/?[A-Z0-9]+[\s>]/g, function (m) {
398            return m.toLowerCase();
399        });
400
401        // #2 - lowercase attribute names
402        html = html.replace(/(<[\w\d]+\s+)([^>]+)>/g, function (x, m1, m2) {
403            return m1 + m2.replace(/\b([\w\d:-]+)\s*=\s*(?:'([^']*?)'|"([^"]*?)"|(\S+))/g, function (x, m1, m2, m3, m4) {
404                if ( !m2 ) m2 = ''; // for ie
405                if ( !m3 ) m3 = ''; // for ie
406                if ( !m4 ) m4 = ''; // for ie
407                return m1.toLowerCase() + '="' + m2 + m3 + m4 + '"';
408            }) + ">";
409        });
410
411        // #3 - close singlet tags for img, br, input, param, hr
412        html = html.replace(/<(br|img|input|param)([^>]+)?([^\/])?>/g, "<$1$2$3 />");
413
414        // #4 - get absolute path and delete from converted URL
415        this.document.body.innerHTML = '<a href="dummy.html"></a>';
416        var path = this.document.body.innerHTML;
417        path = path.toLowerCase();
418        path = path.replace(/<a href="(.*)dummy.html"><\/a>/, "$1");
419        var regex = new RegExp(path, "g");
420        html = html.replace(regex, "");
421        this.document.body.innerHTML = html;
422        return html;
423    }
424} );
Note: See TracBrowser for help on using the browser.