liquid_feedback_frontend

view static/wysihtml/wysihtml.toolbar.js @ 1800:b87997219042

Updated spanish translation
author bsw
date Thu Oct 21 15:22:29 2021 +0200 (2021-10-21)
parents 32cc544d5a5b
children
line source
1 /**
2 * Toolbar Dialog
3 *
4 * @param {Element} link The toolbar link which causes the dialog to show up
5 * @param {Element} container The dialog container
6 *
7 * @example
8 * <!-- Toolbar link -->
9 * <a data-wysihtml-command="insertImage">insert an image</a>
10 *
11 * <!-- Dialog -->
12 * <div data-wysihtml-dialog="insertImage" style="display: none;">
13 * <label>
14 * URL: <input data-wysihtml-dialog-field="src" value="http://">
15 * </label>
16 * <label>
17 * Alternative text: <input data-wysihtml-dialog-field="alt" value="">
18 * </label>
19 * </div>
20 *
21 * <script>
22 * var dialog = new wysihtml.toolbar.Dialog(
23 * document.querySelector("[data-wysihtml-command='insertImage']"),
24 * document.querySelector("[data-wysihtml-dialog='insertImage']")
25 * );
26 * dialog.observe("save", function(attributes) {
27 * // do something
28 * });
29 * </script>
30 */
31 (function(wysihtml) {
32 var dom = wysihtml.dom,
33 CLASS_NAME_OPENED = "wysihtml-command-dialog-opened",
34 SELECTOR_FORM_ELEMENTS = "input, select, textarea",
35 SELECTOR_FIELDS = "[data-wysihtml-dialog-field]",
36 ATTRIBUTE_FIELDS = "data-wysihtml-dialog-field";
39 wysihtml.toolbar.Dialog = wysihtml.lang.Dispatcher.extend(
40 /** @scope wysihtml.toolbar.Dialog.prototype */ {
41 constructor: function(link, container) {
42 this.link = link;
43 this.container = container;
44 },
46 _observe: function() {
47 if (this._observed) {
48 return;
49 }
51 var that = this,
52 callbackWrapper = function(event) {
53 var attributes = that._serialize();
54 that.fire("save", attributes);
55 that.hide();
56 event.preventDefault();
57 event.stopPropagation();
58 };
60 dom.observe(that.link, "click", function() {
61 if (dom.hasClass(that.link, CLASS_NAME_OPENED)) {
62 setTimeout(function() { that.hide(); }, 0);
63 }
64 });
66 dom.observe(this.container, "keydown", function(event) {
67 var keyCode = event.keyCode;
68 if (keyCode === wysihtml.ENTER_KEY) {
69 callbackWrapper(event);
70 }
71 if (keyCode === wysihtml.ESCAPE_KEY) {
72 that.cancel();
73 }
74 });
76 dom.delegate(this.container, "[data-wysihtml-dialog-action=save]", "click", callbackWrapper);
78 dom.delegate(this.container, "[data-wysihtml-dialog-action=cancel]", "click", function(event) {
79 that.cancel();
80 event.preventDefault();
81 event.stopPropagation();
82 });
84 this._observed = true;
85 },
87 /**
88 * Grabs all fields in the dialog and puts them in key=>value style in an object which
89 * then gets returned
90 */
91 _serialize: function() {
92 var data = {},
93 fields = this.container.querySelectorAll(SELECTOR_FIELDS),
94 length = fields.length,
95 i = 0;
97 for (; i<length; i++) {
98 data[fields[i].getAttribute(ATTRIBUTE_FIELDS)] = fields[i].value;
99 }
100 return data;
101 },
103 /**
104 * Takes the attributes of the "elementToChange"
105 * and inserts them in their corresponding dialog input fields
106 *
107 * Assume the "elementToChange" looks like this:
108 * <a href="http://www.google.com" target="_blank">foo</a>
109 *
110 * and we have the following dialog:
111 * <input type="text" data-wysihtml-dialog-field="href" value="">
112 * <input type="text" data-wysihtml-dialog-field="target" value="">
113 *
114 * after calling _interpolate() the dialog will look like this
115 * <input type="text" data-wysihtml-dialog-field="href" value="http://www.google.com">
116 * <input type="text" data-wysihtml-dialog-field="target" value="_blank">
117 *
118 * Basically it adopted the attribute values into the corresponding input fields
119 *
120 */
121 _interpolate: function(avoidHiddenFields) {
122 var field,
123 fieldName,
124 newValue,
125 focusedElement = document.querySelector(":focus"),
126 fields = this.container.querySelectorAll(SELECTOR_FIELDS),
127 length = fields.length,
128 i = 0;
129 for (; i<length; i++) {
130 field = fields[i];
132 // Never change elements where the user is currently typing in
133 if (field === focusedElement) {
134 continue;
135 }
137 // Don't update hidden fields
138 // See https://github.com/xing/wysihtml5/pull/14
139 if (avoidHiddenFields && field.type === "hidden") {
140 continue;
141 }
143 fieldName = field.getAttribute(ATTRIBUTE_FIELDS);
144 newValue = (this.elementToChange && typeof(this.elementToChange) !== 'boolean') ? (this.elementToChange.getAttribute(fieldName) || "") : field.defaultValue;
145 field.value = newValue;
146 }
147 },
149 update: function (elementToChange) {
150 this.elementToChange = elementToChange ? elementToChange : this.elementToChange;
151 this._interpolate();
152 },
154 /**
155 * Show the dialog element
156 */
157 show: function(elementToChange) {
158 var firstField = this.container.querySelector(SELECTOR_FORM_ELEMENTS);
160 this._observe();
161 this.update(elementToChange);
163 dom.addClass(this.link, CLASS_NAME_OPENED);
164 this.container.style.display = "";
165 this.isOpen = true;
166 this.fire("show");
168 if (firstField && !elementToChange) {
169 try {
170 firstField.focus();
171 } catch(e) {}
172 }
173 },
175 /**
176 * Hide the dialog element
177 */
178 _hide: function(focus) {
179 this.elementToChange = null;
180 dom.removeClass(this.link, CLASS_NAME_OPENED);
181 this.container.style.display = "none";
182 this.isOpen = false;
183 },
185 hide: function() {
186 this._hide();
187 this.fire("hide");
188 },
190 cancel: function() {
191 this._hide();
192 this.fire("cancel");
193 }
194 });
195 })(wysihtml); //jshint ignore:line
197 (function(wysihtml) {
198 var dom = wysihtml.dom,
199 SELECTOR_FIELDS = "[data-wysihtml-dialog-field]",
200 ATTRIBUTE_FIELDS = "data-wysihtml-dialog-field";
202 wysihtml.toolbar.Dialog_bgColorStyle = wysihtml.toolbar.Dialog.extend({
203 multiselect: true,
205 _serialize: function() {
206 var data = {},
207 fields = this.container.querySelectorAll(SELECTOR_FIELDS),
208 length = fields.length,
209 i = 0;
211 for (; i<length; i++) {
212 data[fields[i].getAttribute(ATTRIBUTE_FIELDS)] = fields[i].value;
213 }
214 return data;
215 },
217 _interpolate: function(avoidHiddenFields) {
218 var field,
219 fieldName,
220 newValue,
221 focusedElement = document.querySelector(":focus"),
222 fields = this.container.querySelectorAll(SELECTOR_FIELDS),
223 length = fields.length,
224 i = 0,
225 firstElement = (this.elementToChange) ? ((wysihtml.lang.object(this.elementToChange).isArray()) ? this.elementToChange[0] : this.elementToChange) : null,
226 colorStr = (firstElement) ? firstElement.getAttribute('style') : null,
227 color = (colorStr) ? wysihtml.quirks.styleParser.parseColor(colorStr, "background-color") : null;
229 for (; i<length; i++) {
230 field = fields[i];
231 // Never change elements where the user is currently typing in
232 if (field === focusedElement) {
233 continue;
234 }
235 // Don't update hidden fields3
236 if (avoidHiddenFields && field.type === "hidden") {
237 continue;
238 }
239 if (field.getAttribute(ATTRIBUTE_FIELDS) === "color") {
240 if (color) {
241 if (color[3] && color[3] != 1) {
242 field.value = "rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + color[3] + ");";
243 } else {
244 field.value = "rgb(" + color[0] + "," + color[1] + "," + color[2] + ");";
245 }
246 } else {
247 field.value = "rgb(0,0,0);";
248 }
249 }
250 }
251 }
253 });
254 })(wysihtml);
256 (function(wysihtml) {
257 wysihtml.toolbar.Dialog_createTable = wysihtml.toolbar.Dialog.extend({
258 show: function(elementToChange) {
259 this.base(elementToChange);
260 }
261 });
262 })(wysihtml);
264 (function(wysihtml) {
265 var dom = wysihtml.dom,
266 SELECTOR_FIELDS = "[data-wysihtml-dialog-field]",
267 ATTRIBUTE_FIELDS = "data-wysihtml-dialog-field";
269 wysihtml.toolbar.Dialog_fontSizeStyle = wysihtml.toolbar.Dialog.extend({
270 multiselect: true,
272 _serialize: function() {
273 return {"size" : this.container.querySelector('[data-wysihtml-dialog-field="size"]').value};
274 },
276 _interpolate: function(avoidHiddenFields) {
277 var focusedElement = document.querySelector(":focus"),
278 field = this.container.querySelector("[data-wysihtml-dialog-field='size']"),
279 firstElement = (this.elementToChange) ? ((wysihtml.lang.object(this.elementToChange).isArray()) ? this.elementToChange[0] : this.elementToChange) : null,
280 styleStr = (firstElement) ? firstElement.getAttribute('style') : null,
281 size = (styleStr) ? wysihtml.quirks.styleParser.parseFontSize(styleStr) : null;
283 if (field && field !== focusedElement && size && !(/^\s*$/).test(size)) {
284 field.value = size;
285 }
286 }
287 });
288 })(wysihtml);
290 (function(wysihtml) {
291 var SELECTOR_FIELDS = "[data-wysihtml-dialog-field]",
292 ATTRIBUTE_FIELDS = "data-wysihtml-dialog-field";
294 wysihtml.toolbar.Dialog_foreColorStyle = wysihtml.toolbar.Dialog.extend({
295 multiselect: true,
297 _serialize: function() {
298 var data = {},
299 fields = this.container.querySelectorAll(SELECTOR_FIELDS),
300 length = fields.length,
301 i = 0;
303 for (; i<length; i++) {
304 data[fields[i].getAttribute(ATTRIBUTE_FIELDS)] = fields[i].value;
305 }
306 return data;
307 },
309 _interpolate: function(avoidHiddenFields) {
310 var field, colourMode,
311 styleParser = wysihtml.quirks.styleParser,
312 focusedElement = document.querySelector(":focus"),
313 fields = this.container.querySelectorAll(SELECTOR_FIELDS),
314 length = fields.length,
315 i = 0,
316 firstElement = (this.elementToChange) ? ((wysihtml.lang.object(this.elementToChange).isArray()) ? this.elementToChange[0] : this.elementToChange) : null,
317 colourStr = (firstElement) ? firstElement.getAttribute("style") : null,
318 colour = (colourStr) ? styleParser.parseColor(colourStr, "color") : null;
320 for (; i<length; i++) {
321 field = fields[i];
322 // Never change elements where the user is currently typing in
323 if (field === focusedElement) {
324 continue;
325 }
326 // Don't update hidden fields3
327 if (avoidHiddenFields && field.type === "hidden") {
328 continue;
329 }
330 if (field.getAttribute(ATTRIBUTE_FIELDS) === "color") {
331 colourMode = (field.dataset.colormode || "rgb").toLowerCase();
332 colourMode = colourMode === "hex" ? "hash" : colourMode;
334 if (colour) {
335 field.value = styleParser.unparseColor(colour, colourMode);
336 } else {
337 field.value = styleParser.unparseColor([0, 0, 0], colourMode);
338 }
339 }
340 }
341 }
343 });
344 })(wysihtml);
346 /**
347 * Converts speech-to-text and inserts this into the editor
348 * As of now (2011/03/25) this only is supported in Chrome >= 11
349 *
350 * Note that it sends the recorded audio to the google speech recognition api:
351 * http://stackoverflow.com/questions/4361826/does-chrome-have-buil-in-speech-recognition-for-input-type-text-x-webkit-speec
352 *
353 * Current HTML5 draft can be found here
354 * http://lists.w3.org/Archives/Public/public-xg-htmlspeech/2011Feb/att-0020/api-draft.html
355 *
356 * "Accessing Google Speech API Chrome 11"
357 * http://mikepultz.com/2011/03/accessing-google-speech-api-chrome-11/
358 */
359 (function(wysihtml) {
360 var dom = wysihtml.dom;
362 var linkStyles = {
363 position: "relative"
364 };
366 var wrapperStyles = {
367 left: 0,
368 margin: 0,
369 opacity: 0,
370 overflow: "hidden",
371 padding: 0,
372 position: "absolute",
373 top: 0,
374 zIndex: 1
375 };
377 var inputStyles = {
378 cursor: "inherit",
379 fontSize: "50px",
380 height: "50px",
381 marginTop: "-25px",
382 outline: 0,
383 padding: 0,
384 position: "absolute",
385 right: "-4px",
386 top: "50%"
387 };
389 var inputAttributes = {
390 "x-webkit-speech": "",
391 "speech": ""
392 };
394 wysihtml.toolbar.Speech = function(parent, link) {
395 var input = document.createElement("input");
396 if (!wysihtml.browser.supportsSpeechApiOn(input)) {
397 link.style.display = "none";
398 return;
399 }
400 var lang = parent.editor.textarea.element.getAttribute("lang");
401 if (lang) {
402 inputAttributes.lang = lang;
403 }
405 var wrapper = document.createElement("div");
407 wysihtml.lang.object(wrapperStyles).merge({
408 width: link.offsetWidth + "px",
409 height: link.offsetHeight + "px"
410 });
412 dom.insert(input).into(wrapper);
413 dom.insert(wrapper).into(link);
415 dom.setStyles(inputStyles).on(input);
416 dom.setAttributes(inputAttributes).on(input);
418 dom.setStyles(wrapperStyles).on(wrapper);
419 dom.setStyles(linkStyles).on(link);
421 var eventName = "onwebkitspeechchange" in input ? "webkitspeechchange" : "speechchange";
422 dom.observe(input, eventName, function() {
423 parent.execCommand("insertText", input.value);
424 input.value = "";
425 });
427 dom.observe(input, "click", function(event) {
428 if (dom.hasClass(link, "wysihtml-command-disabled")) {
429 event.preventDefault();
430 }
432 event.stopPropagation();
433 });
434 };
435 })(wysihtml);
437 /**
438 * Toolbar
439 *
440 * @param {Object} parent Reference to instance of Editor instance
441 * @param {Element} container Reference to the toolbar container element
442 *
443 * @example
444 * <div id="toolbar">
445 * <a data-wysihtml-command="createLink">insert link</a>
446 * <a data-wysihtml-command="formatBlock" data-wysihtml-command-value="h1">insert h1</a>
447 * </div>
448 *
449 * <script>
450 * var toolbar = new wysihtml.toolbar.Toolbar(editor, document.getElementById("toolbar"));
451 * </script>
452 */
453 (function(wysihtml) {
454 var CLASS_NAME_COMMAND_DISABLED = "wysihtml-command-disabled",
455 CLASS_NAME_COMMANDS_DISABLED = "wysihtml-commands-disabled",
456 CLASS_NAME_COMMAND_ACTIVE = "wysihtml-command-active",
457 CLASS_NAME_ACTION_ACTIVE = "wysihtml-action-active",
458 dom = wysihtml.dom;
460 wysihtml.toolbar.Toolbar = Base.extend(
461 /** @scope wysihtml.toolbar.Toolbar.prototype */ {
462 constructor: function(editor, container, showOnInit) {
463 this.editor = editor;
464 this.container = typeof(container) === "string" ? document.getElementById(container) : container;
465 this.composer = editor.composer;
467 this._getLinks("command");
468 this._getLinks("action");
470 this._observe();
471 if (showOnInit) { this.show(); }
473 if (editor.config.classNameCommandDisabled != null) {
474 CLASS_NAME_COMMAND_DISABLED = editor.config.classNameCommandDisabled;
475 }
476 if (editor.config.classNameCommandsDisabled != null) {
477 CLASS_NAME_COMMANDS_DISABLED = editor.config.classNameCommandsDisabled;
478 }
479 if (editor.config.classNameCommandActive != null) {
480 CLASS_NAME_COMMAND_ACTIVE = editor.config.classNameCommandActive;
481 }
482 if (editor.config.classNameActionActive != null) {
483 CLASS_NAME_ACTION_ACTIVE = editor.config.classNameActionActive;
484 }
486 var speechInputLinks = this.container.querySelectorAll("[data-wysihtml-command=insertSpeech]"),
487 length = speechInputLinks.length,
488 i = 0;
489 for (; i<length; i++) {
490 new wysihtml.toolbar.Speech(this, speechInputLinks[i]);
491 }
492 },
494 _getLinks: function(type) {
495 var links = this[type + "Links"] = wysihtml.lang.array(this.container.querySelectorAll("[data-wysihtml-" + type + "]")).get(),
496 length = links.length,
497 i = 0,
498 mapping = this[type + "Mapping"] = {},
499 link,
500 group,
501 name,
502 value,
503 dialog,
504 tracksBlankValue;
506 for (; i<length; i++) {
507 link = links[i];
508 name = link.getAttribute("data-wysihtml-" + type);
509 value = link.getAttribute("data-wysihtml-" + type + "-value");
510 tracksBlankValue = link.getAttribute("data-wysihtml-" + type + "-blank-value");
511 group = this.container.querySelector("[data-wysihtml-" + type + "-group='" + name + "']");
512 dialog = this._getDialog(link, name);
514 mapping[name + ":" + value] = {
515 link: link,
516 group: group,
517 name: name,
518 value: value,
519 tracksBlankValue: tracksBlankValue,
520 dialog: dialog,
521 state: false
522 };
523 }
524 },
526 _getDialog: function(link, command) {
527 var that = this,
528 dialogElement = this.container.querySelector("[data-wysihtml-dialog='" + command + "']"),
529 dialog, caretBookmark;
531 if (dialogElement) {
532 if (wysihtml.toolbar["Dialog_" + command]) {
533 dialog = new wysihtml.toolbar["Dialog_" + command](link, dialogElement);
534 } else {
535 dialog = new wysihtml.toolbar.Dialog(link, dialogElement);
536 }
538 dialog.on("show", function() {
539 caretBookmark = that.composer.selection.getBookmark();
540 that.editor.fire("show:dialog", { command: command, dialogContainer: dialogElement, commandLink: link });
541 });
543 dialog.on("save", function(attributes) {
544 if (caretBookmark) {
545 that.composer.selection.setBookmark(caretBookmark);
546 }
547 that._execCommand(command, attributes);
548 that.editor.fire("save:dialog", { command: command, dialogContainer: dialogElement, commandLink: link });
549 that._hideAllDialogs();
550 that._preventInstantFocus();
551 caretBookmark = undefined;
553 });
555 dialog.on("cancel", function() {
556 if (caretBookmark) {
557 that.composer.selection.setBookmark(caretBookmark);
558 }
559 that.editor.fire("cancel:dialog", { command: command, dialogContainer: dialogElement, commandLink: link });
560 caretBookmark = undefined;
561 that._preventInstantFocus();
562 });
564 dialog.on("hide", function() {
565 that.editor.fire("hide:dialog", { command: command, dialogContainer: dialogElement, commandLink: link });
566 caretBookmark = undefined;
567 });
569 }
570 return dialog;
571 },
573 /**
574 * @example
575 * var toolbar = new wysihtml.Toolbar();
576 * // Insert a <blockquote> element or wrap current selection in <blockquote>
577 * toolbar.execCommand("formatBlock", "blockquote");
578 */
579 execCommand: function(command, commandValue) {
580 if (this.commandsDisabled) {
581 return;
582 }
584 this._execCommand(command, commandValue);
585 },
587 _execCommand: function(command, commandValue) {
588 // Make sure that composer is focussed (false => don't move caret to the end)
589 this.editor.focus(false);
591 this.composer.commands.exec(command, commandValue);
592 this._updateLinkStates();
593 },
595 execAction: function(action) {
596 var editor = this.editor;
597 if (action === "change_view") {
598 if (editor.currentView === editor.textarea || editor.currentView === "source") {
599 editor.fire("change_view", "composer");
600 } else {
601 editor.fire("change_view", "textarea");
602 }
603 }
604 if (action == "showSource") {
605 editor.fire("showSource");
606 }
607 },
609 _observe: function() {
610 var that = this,
611 editor = this.editor,
612 container = this.container,
613 links = this.commandLinks.concat(this.actionLinks),
614 length = links.length,
615 i = 0;
617 for (; i<length; i++) {
618 // 'javascript:;' and unselectable=on Needed for IE, but done in all browsers to make sure that all get the same css applied
619 // (you know, a:link { ... } doesn't match anchors with missing href attribute)
620 if (links[i].nodeName === "A") {
621 dom.setAttributes({
622 href: "javascript:;",
623 unselectable: "on"
624 }).on(links[i]);
625 } else {
626 dom.setAttributes({ unselectable: "on" }).on(links[i]);
627 }
628 }
630 // Needed for opera and chrome
631 dom.delegate(container, "[data-wysihtml-command], [data-wysihtml-action]", "mousedown", function(event) { event.preventDefault(); });
633 dom.delegate(container, "[data-wysihtml-command]", "click", function(event) {
634 var state,
635 link = this,
636 command = link.getAttribute("data-wysihtml-command"),
637 commandValue = link.getAttribute("data-wysihtml-command-value"),
638 commandObj = that.commandMapping[command + ":" + commandValue];
640 if (commandValue || !commandObj.dialog) {
641 that.execCommand(command, commandValue);
642 } else {
643 state = getCommandState(that.composer, commandObj);
644 commandObj.dialog.show(state);
645 }
647 event.preventDefault();
648 });
650 dom.delegate(container, "[data-wysihtml-action]", "click", function(event) {
651 var action = this.getAttribute("data-wysihtml-action");
652 that.execAction(action);
653 event.preventDefault();
654 });
656 editor.on("interaction:composer", function(event) {
657 if (!that.preventFocus) {
658 that._updateLinkStates();
659 }
660 });
662 this._ownerDocumentClick = function(event) {
663 if (!wysihtml.dom.contains(that.container, event.target) && !wysihtml.dom.contains(that.composer.element, event.target)) {
664 that._updateLinkStates();
665 that._preventInstantFocus();
666 }
667 };
669 this.container.ownerDocument.addEventListener("click", this._ownerDocumentClick, false);
670 this.editor.on("destroy:composer", this.destroy.bind(this));
672 if (this.editor.config.handleTables) {
673 editor.on("tableselect:composer", function() {
674 that.container.querySelectorAll('[data-wysihtml-hiddentools="table"]')[0].style.display = "";
675 });
676 editor.on("tableunselect:composer", function() {
677 that.container.querySelectorAll('[data-wysihtml-hiddentools="table"]')[0].style.display = "none";
678 });
679 }
681 editor.on("change_view", function(currentView) {
682 // Set timeout needed in order to let the blur event fire first
683 setTimeout(function() {
684 that.commandsDisabled = (currentView !== "composer");
685 that._updateLinkStates();
686 if (that.commandsDisabled) {
687 dom.addClass(container, CLASS_NAME_COMMANDS_DISABLED);
688 } else {
689 dom.removeClass(container, CLASS_NAME_COMMANDS_DISABLED);
690 }
691 }, 0);
692 });
693 },
695 destroy: function() {
696 this.container.ownerDocument.removeEventListener("click", this._ownerDocumentClick, false);
697 },
699 _hideAllDialogs: function() {
700 var commandMapping = this.commandMapping;
701 for (var i in commandMapping) {
702 if (commandMapping[i].dialog) {
703 commandMapping[i].dialog.hide();
704 }
705 }
706 },
708 _preventInstantFocus: function() {
709 this.preventFocus = true;
710 setTimeout(function() {
711 this.preventFocus = false;
712 }.bind(this),0);
713 },
715 _updateLinkStates: function() {
717 var i, state, action, command, displayDialogAttributeValue,
718 commandMapping = this.commandMapping,
719 composer = this.composer,
720 actionMapping = this.actionMapping;
721 // every millisecond counts... this is executed quite often
722 for (i in commandMapping) {
723 command = commandMapping[i];
724 if (this.commandsDisabled) {
725 state = false;
726 dom.removeClass(command.link, CLASS_NAME_COMMAND_ACTIVE);
727 if (command.group) {
728 dom.removeClass(command.group, CLASS_NAME_COMMAND_ACTIVE);
729 }
730 if (command.dialog) {
731 command.dialog.hide();
732 }
733 } else {
734 state = this.composer.commands.state(command.name, command.value);
735 dom.removeClass(command.link, CLASS_NAME_COMMAND_DISABLED);
736 if (command.group) {
737 dom.removeClass(command.group, CLASS_NAME_COMMAND_DISABLED);
738 }
739 }
740 if (command.state === state && !command.tracksBlankValue) {
741 continue;
742 }
744 command.state = state;
745 if (state) {
746 if (command.tracksBlankValue) {
747 dom.removeClass(command.link, CLASS_NAME_COMMAND_ACTIVE);
748 } else {
749 dom.addClass(command.link, CLASS_NAME_COMMAND_ACTIVE);
750 if (command.group) {
751 dom.addClass(command.group, CLASS_NAME_COMMAND_ACTIVE);
752 }
753 // commands with fixed value can not have a dialog.
754 if (command.dialog && (typeof command.value === "undefined" || command.value === null)) {
755 if (state && typeof state === "object") {
756 state = getCommandState(composer, command);
757 command.state = state;
759 // If dialog has dataset.showdialogonselection set as true,
760 // Dialog displays on text state becoming active regardless of clobal showToolbarDialogsOnSelection options value
761 displayDialogAttributeValue = command.dialog.container.dataset ? command.dialog.container.dataset.showdialogonselection : false;
763 if (composer.config.showToolbarDialogsOnSelection || displayDialogAttributeValue) {
764 command.dialog.show(state);
765 } else {
766 command.dialog.update(state);
767 }
768 } else {
769 command.dialog.hide();
770 }
771 }
772 }
773 } else {
774 if (command.tracksBlankValue) {
775 dom.addClass(command.link, CLASS_NAME_COMMAND_ACTIVE);
776 } else {
777 dom.removeClass(command.link, CLASS_NAME_COMMAND_ACTIVE);
778 if (command.group) {
779 dom.removeClass(command.group, CLASS_NAME_COMMAND_ACTIVE);
780 }
781 // commands with fixed value can not have a dialog.
782 if (command.dialog && !command.value) {
783 command.dialog.hide();
784 }
785 }
786 }
787 }
789 for (i in actionMapping) {
790 action = actionMapping[i];
792 if (action.name === "change_view") {
793 action.state = this.editor.currentView === this.editor.textarea || this.editor.currentView === "source";
794 if (action.state) {
795 dom.addClass(action.link, CLASS_NAME_ACTION_ACTIVE);
796 } else {
797 dom.removeClass(action.link, CLASS_NAME_ACTION_ACTIVE);
798 }
799 }
800 }
801 },
803 show: function() {
804 this.container.style.display = "";
805 },
807 hide: function() {
808 this.container.style.display = "none";
809 }
810 });
812 function getCommandState (composer, command) {
813 var state = composer.commands.state(command.name, command.value);
815 // Grab first and only object/element in state array, otherwise convert state into boolean
816 // to avoid showing a dialog for multiple selected elements which may have different attributes
817 // eg. when two links with different href are selected, the state will be an array consisting of both link elements
818 // but the dialog interface can only update one
819 if (!command.dialog.multiselect && wysihtml.lang.object(state).isArray()) {
820 state = state.length === 1 ? state[0] : true;
821 }
823 return state;
824 }
826 // Extend defaults
828 // Id of the toolbar element, pass falsey value if you don't want any toolbar logic
829 wysihtml.Editor.prototype.defaults.toolbar = undefined;
831 // Whether toolbar is displayed after init by script automatically.
832 // Can be set to false if toolobar is set to display only on editable area focus
833 wysihtml.Editor.prototype.defaults.showToolbarAfterInit = true;
835 // With default toolbar it shows dialogs in toolbar when their related text format state becomes active (click on link in text opens link dialogue)
836 wysihtml.Editor.prototype.defaults.showToolbarDialogsOnSelection= true;
838 // Bind toolbar initiation on editor instance creation
839 wysihtml.extendEditor(function(editor) {
840 if (editor.config.toolbar) {
841 editor.toolbar = new wysihtml.toolbar.Toolbar(editor, editor.config.toolbar, editor.config.showToolbarAfterInit);
842 editor.on('destroy:composer', function() {
843 if (editor && editor.toolbar) {
844 editor.toolbar.destroy();
845 }
846 });
847 }
848 });
850 })(wysihtml);

Impressum / About Us