summaryrefslogtreecommitdiff
path: root/skins/common/edit.js
blob: f986c854b05161d88046074d08a73a7ec805a92d (plain)
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
window.currentFocused = undefined;

// this function adds a toolbar button to the mwEditButtons list
window.addButton = function( imageFile, speedTip, tagOpen, tagClose, sampleText, imageId ) {
	// Don't generate buttons for browsers which don't fully
	// support it.
	mwEditButtons.push({
		'imageId': imageId,
		'imageFile': imageFile,
		'speedTip': speedTip,
		'tagOpen': tagOpen,
		'tagClose': tagClose,
		'sampleText': sampleText
	});
};

// this function adds one toolbar button from a mwEditButtons/mwCustomEditButtons item
window.mwInsertEditButton = function( parent, item ) {
	var image = document.createElement( 'img' );
	image.width = 23;
	image.height = 22;
	image.className = 'mw-toolbar-editbutton';
	if ( item.imageId ) {
		image.id = item.imageId;
	}
	image.src = item.imageFile;
	image.border = 0;
	image.alt = item.speedTip;
	image.title = item.speedTip;
	image.style.cursor = 'pointer';
	image.onclick = function() {
		insertTags( item.tagOpen, item.tagClose, item.sampleText );
		// click tracking
		if ( ( typeof $ != 'undefined' )  && ( typeof $.trackAction != 'undefined' ) ) {
			$.trackAction( 'oldedit.' + item.speedTip.replace(/ /g, "-") );
		}
		return false;
	};

	parent.appendChild( image );
	return true;
};

// this function generates the actual toolbar buttons with localized text
// we use it to avoid creating the toolbar where javascript is not enabled
window.mwSetupToolbar = function() {
	var toolbar = document.getElementById( 'toolbar' );
	if ( !toolbar ) {
		return false;
	}

	// Don't generate buttons for browsers which don't fully
	// support it.
	// but don't assume wpTextbox1 is always here
	var textboxes = document.getElementsByTagName( 'textarea' );
	if ( !textboxes.length ) {
		// No toolbar if we can't find any textarea
		return false;
	}
	// Only check for selection capability if the textarea is visible - errors will occur otherwise - just because
	// the textarea is not visible, doesn't mean we shouldn't build out the toolbar though - it might have been replaced
	// with some other kind of control
	if ( textboxes[0].style.display != 'none' ) {
		if ( !( document.selection && document.selection.createRange )
			&& textboxes[0].selectionStart === null ) {
			return false;
		}
	}
	for ( var i = 0; i < mwEditButtons.length; i++ ) {
		mwInsertEditButton( toolbar, mwEditButtons[i] );
	}
	for ( var i = 0; i < mwCustomEditButtons.length; i++ ) {
		mwInsertEditButton( toolbar, mwCustomEditButtons[i] );
	}
	return true;
};

// apply tagOpen/tagClose to selection in textarea,
// use sampleText instead of selection if there is none
window.insertTags = function( tagOpen, tagClose, sampleText ) {
	if ( typeof $ != 'undefined' && typeof $.fn.textSelection != 'undefined' && currentFocused &&
			( currentFocused.nodeName.toLowerCase() == 'iframe' || currentFocused.id == 'wpTextbox1' ) ) {
		$( '#wpTextbox1' ).textSelection(
			'encapsulateSelection', { 'pre': tagOpen, 'peri': sampleText, 'post': tagClose }
		);
		return;
	}
	var txtarea;
	if ( document.editform ) {
		txtarea = currentFocused;
	} else {
		// some alternate form? take the first one we can find
		var areas = document.getElementsByTagName( 'textarea' );
		txtarea = areas[0];
	}
	var selText, isSample = false;

	if ( document.selection  && document.selection.createRange ) { // IE/Opera
		// save window scroll position
		if ( document.documentElement && document.documentElement.scrollTop ) {
			var winScroll = document.documentElement.scrollTop
		} else if ( document.body ) {
			var winScroll = document.body.scrollTop;
		}
		// get current selection
		txtarea.focus();
		var range = document.selection.createRange();
		selText = range.text;
		// insert tags
		checkSelectedText();
		range.text = tagOpen + selText + tagClose;
		// mark sample text as selected
		if ( isSample && range.moveStart ) {
			if ( window.opera ) {
				tagClose = tagClose.replace(/\n/g,'');
			}
			range.moveStart('character', - tagClose.length - selText.length);
			range.moveEnd('character', - tagClose.length);
		}
		range.select();
		// restore window scroll position
		if ( document.documentElement && document.documentElement.scrollTop ) {
			document.documentElement.scrollTop = winScroll;
		} else if ( document.body ) {
			document.body.scrollTop = winScroll;
		}

	} else if ( txtarea.selectionStart || txtarea.selectionStart == '0' ) { // Mozilla
		// save textarea scroll position
		var textScroll = txtarea.scrollTop;
		// get current selection
		txtarea.focus();
		var startPos = txtarea.selectionStart;
		var endPos = txtarea.selectionEnd;
		selText = txtarea.value.substring( startPos, endPos );
		// insert tags
		checkSelectedText();
		txtarea.value = txtarea.value.substring(0, startPos)
			+ tagOpen + selText + tagClose
			+ txtarea.value.substring(endPos, txtarea.value.length);
		// set new selection
		if ( isSample ) {
			txtarea.selectionStart = startPos + tagOpen.length;
			txtarea.selectionEnd = startPos + tagOpen.length + selText.length;
		} else {
			txtarea.selectionStart = startPos + tagOpen.length + selText.length + tagClose.length;
			txtarea.selectionEnd = txtarea.selectionStart;
		}
		// restore textarea scroll position
		txtarea.scrollTop = textScroll;
	}

	function checkSelectedText() {
		if ( !selText ) {
			selText = sampleText;
			isSample = true;
		} else if ( selText.charAt(selText.length - 1) == ' ' ) { // exclude ending space char
			selText = selText.substring(0, selText.length - 1);
			tagClose += ' ';
		}
	}

};

/**
 * Restore the edit box scroll state following a preview operation,
 * and set up a form submission handler to remember this state
 */
window.scrollEditBox = function() {
	var editBox = document.getElementById( 'wpTextbox1' );
	var scrollTop = document.getElementById( 'wpScrolltop' );
	var editForm = document.getElementById( 'editform' );
	if( editForm && editBox && scrollTop ) {
		if( scrollTop.value ) {
			editBox.scrollTop = scrollTop.value;
		}
		addHandler( editForm, 'submit', function() {
			scrollTop.value = editBox.scrollTop;
		} );
	}
};
hookEvent( 'load', scrollEditBox );
hookEvent( 'load', mwSetupToolbar );
hookEvent( 'load', function() {
	currentFocused = document.getElementById( 'wpTextbox1' );
	// http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
	// focus does not bubble normally, but using a trick we can do event delegation
	// on the focus event on all text inputs to make the toolbox usable on all of them
	var editForm = document.getElementById( 'editform' );
	if ( !editForm ) {
		return;
	}
	function onfocus( e ) {
		var elm = e.target || e.srcElement;
		if ( !elm ) {
			return;
		}
		var tagName = elm.tagName.toLowerCase();
		var type = elm.type || '';
		if ( tagName !== 'textarea' && tagName !== 'input' ) {
			return;
		}
		if ( tagName === 'input' && type.toLowerCase() !== 'text' ) {
			return;
		}

		currentFocused = elm;
	}

	if ( editForm.addEventListener ) {
		// Gecko, WebKit, Opera, etc... (all standards compliant browsers)
		editForm.addEventListener( 'focus', onfocus, true ); // This MUST be true to work
	} else if ( editForm.attachEvent ) {
		// IE needs a specific trick here since it doesn't support the standard
		editForm.attachEvent( 'onfocusin', function() { onfocus( event ); } );
	}
	
	// HACK: make currentFocused work with the usability iframe
	// With proper focus detection support (HTML 5!) this'll be much cleaner
	if ( typeof $ != 'undefined' ) {
		var iframe = $( '.wikiEditor-ui-text iframe' );
		if ( iframe.length > 0 ) {
			$( iframe.get( 0 ).contentWindow.document )
				.add( iframe.get( 0 ).contentWindow.document.body ) // for IE
				.focus( function() { currentFocused = iframe.get( 0 ); } );
		}
	}

	editForm
} );