comparison sites/all/modules/insert/insert.js @ 0:ff03f76ab3fe

initial version
author danieleb <danielebarchiesi@me.com>
date Wed, 21 Aug 2013 18:51:11 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:ff03f76ab3fe
1 /**
2 * @file
3 * JavaScript to activate "Insert" buttons on file and image fields.
4 */
5
6 (function ($) {
7
8 /**
9 * Behavior to add "Insert" buttons.
10 */
11 Drupal.behaviors.insert = {};
12 Drupal.behaviors.insert.attach = function(context) {
13 if (typeof(insertTextarea) == 'undefined') {
14 insertTextarea = $('#edit-body textarea.text-full').get(0) || false;
15 }
16
17 // Keep track of the last active textarea (if not using WYSIWYG).
18 $('textarea:not([name$="[data][title]"]):not(.insert-processed)', context).addClass('insert-processed').focus(insertSetActive).blur(insertRemoveActive);
19
20 // Add the click handler to the insert button.
21 $('.insert-button:not(.insert-processed)', context).addClass('insert-processed').click(insert);
22
23 function insertSetActive() {
24 insertTextarea = this;
25 this.insertHasFocus = true;
26 }
27
28 function insertRemoveActive() {
29 if (insertTextarea == this) {
30 var thisTextarea = this;
31 setTimeout(function() {
32 thisTextarea.insertHasFocus = false;
33 }, 1000);
34 }
35 }
36
37 function insert() {
38 var widgetType = $(this).attr('rel');
39 var settings = Drupal.settings.insert.widgets[widgetType];
40 var wrapper = $(this).parents(settings.wrapper).filter(':first').get(0);
41 var style = $('.insert-style', wrapper).val();
42 var content = $('input.insert-template[name$="[' + style + ']"]', wrapper).val();
43 var filename = $('input.insert-filename', wrapper).val();
44 var options = {
45 widgetType: widgetType,
46 filename: filename,
47 style: style,
48 fields: {}
49 };
50
51 // Update replacements.
52 for (var fieldName in settings.fields) {
53 var fieldValue = $(settings.fields[fieldName], wrapper).val();
54 if (fieldValue) {
55 fieldValue = fieldValue
56 .replace(/&/g, '&amp;')
57 .replace(/"/g, '&quot;')
58 .replace(/'/g, '&#39;')
59 .replace(/</g, '&lt;')
60 .replace(/>/g, '&gt;');
61 }
62 options['fields'][fieldName] = fieldValue;
63 if (fieldValue) {
64 var fieldRegExp = new RegExp('__' + fieldName + '(_or_filename)?__', 'g');
65 content = content.replace(fieldRegExp, fieldValue);
66 }
67 else {
68 var fieldRegExp = new RegExp('__' + fieldName + '_or_filename__', 'g');
69 content = content.replace(fieldRegExp, filename);
70 }
71 }
72
73 // File name replacement.
74 var fieldRegExp = new RegExp('__filename__', 'g');
75 content = content.replace(fieldRegExp, filename);
76
77 // Check for a maximum dimension and scale down the width if necessary.
78 // This is intended for use with Image Resize Filter.
79 var widthMatches = content.match(/width[ ]*=[ ]*"(\d*)"/i);
80 var heightMatches = content.match(/height[ ]*=[ ]*"(\d*)"/i);
81 if (settings.maxWidth && widthMatches && parseInt(widthMatches[1]) > settings.maxWidth) {
82 var insertRatio = settings.maxWidth / widthMatches[1];
83 var width = settings.maxWidth;
84 content = content.replace(/width[ ]*=[ ]*"?(\d*)"?/i, 'width="' + width + '"');
85
86 if (heightMatches) {
87 var height = Math.round(heightMatches[1] * insertRatio);
88 content = content.replace(/height[ ]*=[ ]*"?(\d*)"?/i, 'height="' + height + '"');
89 }
90 }
91
92 // Allow other modules to perform replacements.
93 options['content'] = content;
94 $.event.trigger('insertIntoActiveEditor', [options]);
95 content = options['content'];
96
97 // Cleanup unused replacements.
98 content = content.replace(/"__([a-z0-9_]+)__"/g, '""');
99
100 // Cleanup empty attributes (other than alt).
101 content = content.replace(/([a-z]+)[ ]*=[ ]*""/g, function(match, tagName) {
102 return (tagName === 'alt') ? match : '';
103 });
104
105 // Insert the text.
106 Drupal.insert.insertIntoActiveEditor(content);
107 }
108 };
109
110 // General Insert API functions.
111 Drupal.insert = {
112 /**
113 * Insert content into the current (or last active) editor on the page. This
114 * should work with most WYSIWYGs as well as plain textareas.
115 *
116 * @param content
117 */
118 insertIntoActiveEditor: function(content) {
119 var editorElement;
120
121 // Always work in normal text areas that currently have focus.
122 if (insertTextarea && insertTextarea.insertHasFocus) {
123 editorElement = insertTextarea;
124 Drupal.insert.insertAtCursor(insertTextarea, content);
125 }
126 // Direct tinyMCE support.
127 else if (typeof(tinyMCE) != 'undefined' && tinyMCE.activeEditor) {
128 editorElement = document.getElementById(tinyMCE.activeEditor.editorId);
129 Drupal.insert.activateTabPane(editorElement);
130 tinyMCE.activeEditor.execCommand('mceInsertContent', false, content);
131 }
132 // WYSIWYG support, should work in all editors if available.
133 else if (Drupal.wysiwyg && Drupal.wysiwyg.activeId) {
134 editorElement = document.getElementById(Drupal.wysiwyg.activeId);
135 Drupal.insert.activateTabPane(editorElement);
136 Drupal.wysiwyg.instances[Drupal.wysiwyg.activeId].insert(content)
137 }
138 // FCKeditor module support.
139 else if (typeof(FCKeditorAPI) != 'undefined' && typeof(fckActiveId) != 'undefined') {
140 editorElement = document.getElementById(fckActiveId);
141 Drupal.insert.activateTabPane(editorElement);
142 FCKeditorAPI.Instances[fckActiveId].InsertHtml(content);
143 }
144 // Direct FCKeditor support (only body field supported).
145 else if (typeof(FCKeditorAPI) != 'undefined') {
146 // Try inserting into the body.
147 if (FCKeditorAPI.Instances[insertTextarea.id]) {
148 editorElement = insertTextarea;
149 Drupal.insert.activateTabPane(editorElement);
150 FCKeditorAPI.Instances[insertTextarea.id].InsertHtml(content);
151 }
152 // Try inserting into the first instance we find (may occur with very
153 // old versions of FCKeditor).
154 else {
155 for (var n in FCKeditorAPI.Instances) {
156 editorElement = document.getElementById(n);
157 Drupal.insert.activateTabPane(editorElement);
158 FCKeditorAPI.Instances[n].InsertHtml(content);
159 break;
160 }
161 }
162 }
163 // CKeditor module support.
164 else if (typeof(CKEDITOR) != 'undefined' && typeof(Drupal.ckeditorActiveId) != 'undefined') {
165 editorElement = document.getElementById(Drupal.ckeditorActiveId);
166 Drupal.insert.activateTabPane(editorElement);
167 CKEDITOR.instances[Drupal.ckeditorActiveId].insertHtml(content);
168 }
169 // Direct CKeditor support (only body field supported).
170 else if (typeof(CKEDITOR) != 'undefined' && CKEDITOR.instances[insertTextarea.id]) {
171 editorElement = insertTextarea;
172 Drupal.insert.activateTabPane(editorElement);
173 CKEDITOR.instances[insertTextarea.id].insertHtml(content);
174 }
175 else if (insertTextarea) {
176 editorElement = insertTextarea;
177 Drupal.insert.activateTabPane(editorElement);
178 Drupal.insert.insertAtCursor(insertTextarea, content);
179 }
180
181 if (editorElement) {
182 Drupal.insert.contentWarning(editorElement, content);
183 }
184
185 return false;
186 },
187
188 /**
189 * Check for vertical tabs and activate the pane containing the editor.
190 *
191 * @param editor
192 * The DOM object of the editor that will be checked.
193 */
194 activateTabPane: function(editor) {
195 var $pane = $(editor).parents('.vertical-tabs-pane:first');
196 var $panes = $pane.parent('.vertical-tabs-panes');
197 var $tabs = $panes.parents('.vertical-tabs:first').find('ul.vertical-tabs-list:first li a');
198 if ($pane.size() && $pane.is(':hidden') && $panes.size() && $tabs.size()) {
199 var index = $panes.children().index($pane);
200 $tabs.eq(index).click();
201 }
202 },
203
204 /**
205 * Warn users when attempting to insert an image into an unsupported field.
206 *
207 * This function is only a 90% use-case, as it doesn't support when the filter
208 * tip are hidden, themed, or when only one format is available. However it
209 * should fail silently in these situations.
210 */
211 contentWarning: function(editorElement, content) {
212 if (!content.match(/<img /)) return;
213
214 var $wrapper = $(editorElement).parents('div.text-format-wrapper:first');
215 if (!$wrapper.length) return;
216
217 $wrapper.find('.filter-guidelines-item:visible li').each(function(index, element) {
218 var expression = new RegExp(Drupal.t('Allowed HTML tags'));
219 if (expression.exec(element.textContent) && !element.textContent.match(/<img>/)) {
220 alert(Drupal.t("The selected text format will not allow it to display images. The text format will need to be changed for this image to display properly when saved."));
221 }
222 });
223 },
224
225 /**
226 * Insert content into a textarea at the current cursor position.
227 *
228 * @param editor
229 * The DOM object of the textarea that will receive the text.
230 * @param content
231 * The string to be inserted.
232 */
233 insertAtCursor: function(editor, content) {
234 // Record the current scroll position.
235 var scroll = editor.scrollTop;
236
237 // IE support.
238 if (document.selection) {
239 editor.focus();
240 sel = document.selection.createRange();
241 sel.text = content;
242 }
243
244 // Mozilla/Firefox/Netscape 7+ support.
245 else if (editor.selectionStart || editor.selectionStart == '0') {
246 var startPos = editor.selectionStart;
247 var endPos = editor.selectionEnd;
248 editor.value = editor.value.substring(0, startPos) + content + editor.value.substring(endPos, editor.value.length);
249 }
250
251 // Fallback, just add to the end of the content.
252 else {
253 editor.value += content;
254 }
255
256 // Ensure the textarea does not unexpectedly scroll.
257 editor.scrollTop = scroll;
258 }
259 };
260
261 })(jQuery);