tinyMCE 4: add Class to selected Element - javascript

I created a tinymce menu item and what I want it to do is add a class to the selected text element. I cannot seem to figure out how to do this. Any suggestions?
Adding my menu item looks like this:
tinymce.PluginManager.add('button', function(editor, url) {
editor.addMenuItem('button', {
icon: '',
text: 'Button',
onclick: function() {
tinyMCE.activeEditor.dom.addClass(tinyMCE.activeEditor.selection, 'test'); //not working
},
context: 'insert',
prependToContext: true
});
});
I'd be very thankful for any helpful hint.

I found a solution that may not be perfect (for example, if you select part of a text then this doesn't work as I hoped), but for now it does what I want:
tinyMCE.activeEditor.dom.addClass(tinyMCE.activeEditor.selection.getNode(), 'test');
if I do this on a link, for example, the scripts add the classname "test" to my tag.

In order to be able to add a class to the editor you need a dom element in the editor to add the class to. Textnodes may not hold a class.
So i propose you insert a span element with the class you want to add wrapped around the actual selection. Be aware that this won't work if the selection leaps over paragraph boundaries (in this case you will need a bit more complicated code). Try this:
onclick: function() {
var ed = tinyMCE.activeEditor;
var content = ed.selection.getContent({'format':'html'});
var new_selection_content = '<span class="test">' + content + '</span>';
ed.execCommand('insertHTML', false, new_selection_content);
},

this works for me:
setup: function(editor) {
editor.ui.registry.addButton("addClassBtn", {
icon: "insertdatetime",
text: "Highlight ",
onAction: function (_) {
var newContent = "<span class='test'>" + editor.selection.getContent() + "</span>";
editor.selection.setContent(newContent);
}
}
}

Related

Highlight text with TinyMCE

Currently I have a textarea using TinyMCE: http://fiddle.tinymce.com/D2gaab
I want to highlight the text between the opening/closing braces. Does someone know if this is possible, and how I can do this?
You could consider inserting a <mark> tag, or another element with inline styling. Also, maybe only insert when the selection has any length.
editor.addButton('spintax', {
text: 'Spintax',
icon: false,
onclick: function () {
editor.focus();
if (editor.selection.getContent().length) {
editor.selection.setContent("{<mark>" + editor.selection.getContent() + '</mark>}');
}
}
});
http://fiddle.tinymce.com/E2gaab

How to use createElement() in JavaScript?

var htmlComponent = [
{
element : 'button',
text : "Addition"
},
{
element : 'h1',
text : "This is the heading"
},
{
element : 'p',
text : "This is the paragraph."
}
];
htmlComponent.forEach(function(item) {
// Problem here
document.body.appendChild(document.createElement(item.element).appendChild(document.createTextNode(item.text)));
}
Actually I wanted to create an html element using DOM Object but this is not working. I mean my code is not working properly..
but when I changed something Like that:
htmlComponent.forEach(function(item) {
var _element = document.createElement(item.element);
var text = document.createTextNode(item.text);
_element.appendChild(text);
document.body.appendChild(_element);
}
Then the code is working.
Here the main question is why 2nd code is working and the 1st one is not working...... what is the problem in my code.
please Explain me........
You are chaining the calls together like body.createElement().appendChild() where you shouldn't.
This works with createElement() because it returns the element you want to append to, but it doesn't work with appendChild() because that returns the child you just appended, which you are then appending again to the body.
This programming style is known as a "fluent" interface. It is supported by some libraries e.g. jQuery, but not by native Javascript DOM functions.
See https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild
Try as follows
appendChild does not return parent
var htmlComponent = [{
element: 'button',
text: "Addition"
},
{
element: 'h1',
text: "This is the heading"
},
{
element: 'p',
text: "This is the paragraph."
}
];
htmlComponent.forEach(function(element) {
var btn = document.createElement(element.element);
var t = document.createTextNode(element.text);
btn.appendChild(t);
document.body.appendChild(btn);
});
According to the documentation for appendChild:
The returned value is the appended child except when the given child
is a DocumentFragment, in which case the empty DocumentFragment is
returned.
You are appending a text node to the button, then trying to append the returned result to the body. This is the reason why you are not seeing the button being appended to the body.
If you break it down like this, it's easier to see what's going on:
document.body.appendChild(
// createElement returns button
document.createElement("button")
// button.appendChild then returns the appended child (a text node)
.appendChild(document.createTextNode("text"))
)

Dynamically insert angularJS contextMenu on HTML tags

I am using this angularJS contextMenu module on my application and I need to insert this inside some HTML tags dynamically. I am trying something like this but it isn't working.
e.client.html("<a context-menu=\"menuOptions\">click here</a>");
I have menuOptionsdeclared on my scope like this:
$scope.menuOptions = [
{
text: 'Object-Select',
click: function ($itemScope, $event, modelValue, text, $li) {
$scope.selected = $itemScope.item.name;
}
},
{
text: 'Object-Remove',
click: function ($itemScope, $event, modelValue, text, $li) {
$scope.items.splice($itemScope.$index, 1);
}
}
];
Someone know how to do that?
You need angular to compile your dynamic context menu, so it can handle the context-menu directive. The best way doing this is:
//define the Html to insert in a variable:
var dynContextMenu = "<a context-menu=\"menuOptions\">click here</a>";
//append to content
e.client.html(dynContextMenu);
//then compile it
$compile(dynContextMenu)($scope);
I hope this helps.

How to add multiple items to context menu in Kendo Scheduler?

"kendoContextMenu" is one of control from Telerik suit. I am trying to attach it with Kendo Scheduler control.
Below is the code to render scheduler and menu
Part of it taken from Kendo sample site
<div id="example">
<div id="scheduler"></div>
<ul id="contextMenu"></ul>
</div>
Here is Context Menu Initialization
$("#contextMenu").kendoContextMenu({
filter: ".k-event, .k-scheduler-table td",
target: "#scheduler",
select: function(e) {
var target = $(e.target);
if (target.hasClass("k-event")) {
var occurrenceByUid = scheduler.occurrenceByUid(target.data("uid"));
} else {
var slot = scheduler.slotByElement(target);
}
},
open: function(e) {
var menu = e.sender;
var text = $(e.target).hasClass("k-event") ? "Edit Title" : "Block";
menu.remove(".myClass");
menu.append([{text: text, cssClass: "myClass" }]);
}
});
});
The above code adds only ONE item in context menu and click event directly fires up. I would like to have multiple items in a context menu and each should have its own event so that I can use them as it clicked.
Below image shows right click behavior, where it shows only Block in a menu
I am trying to get menu as below- which has multiple items and have its own click events
I am trying like below by appending text but it's seems to be wrong way to do and it can not have separate click event.
open: function(e) {
var menu = e.sender;
var text = $(e.target).hasClass("k-event") ? "Edit event" : "Add Event";
text = text + "|" + "Cancel"
menu.remove(".myClass");
menu.append([{text: text, cssClass: "myClass" }]);
}
Kindly help
I'm afraid you're appending it wrong. By concatenating "| Cancel" you're not adding a new item, but adding text to the existing one.
Try creating a new object and append it with append():
menu.append([{text: "Cancel", cssClass: "cancel-opt" }]);
Then you check by the class inside the select event:
if (target.hasClass("cancel-opt"))

TinyMCE Enable button while in read only mode

I have a TinyMCE 4.x instance where the text should be in read only mode. But I still have some buttons that I want to have enabled. For example, one button could provide a character count for the part of the text I've selected.
But when I turn on read only mode for TinyMCE all buttons are disabled. Can I enable just my buttons while still retaining read only mode?
It's probably too late for you but other people may pass by here.
I came up by writing this function
function enableTinyMceEditorPlugin(editorId, pluginName, commandName) {
var htmlEditorDiv = document.getElementById(editorId).previousSibling;
var editor = tinymce.get(editorId);
var buttonDiv = htmlEditorDiv.querySelectorAll('.mce-i-' + pluginName.toLowerCase())[0].parentElement.parentElement;
buttonDiv.className = buttonDiv.className.replace(' mce-disabled', '');
buttonDiv.removeAttribute('aria-disabled');
buttonDiv.firstChild.onclick = function () {
editor.execCommand(commandName);
};
}
It does the trick in 2 steps:
make the button clickable (remove mce-disabled CSS class and remove the aria-disabled property)
assign the good command to the click event
And in my editor init event I call the function.
editor.on('init', function () {
if (readOnly) {
editor.setMode('readonly');
enableTinyMceEditorPlugin(htmlEditorId, 'preview', 'mcePreview');
enableTinyMceEditorPlugin(htmlEditorId, 'code', 'mceCodeEditor');
}
});
Current version of TinyMCE for which I wrote this code is 4.4.3. It may break in a future version, specifically about the selectors to get and modify the good HTML elements.
Command identifiers can be found at this page otherwise you can also find them under tinymce\plugins\PluginName\plugin(.min).js
Here is a simple way to enable your custom toolbar button and attach a click event handler inside a read only TinyMCE editor using JQUERY:
//Initialize read only Tinymce editor so that Lock button is also disabled
function initReadOnlyTinyMCE() {
tinymce.init({
selector: '#main'
, toolbar: 'myLockButton'
, body_class: 'main-div'
, content_css: 'stylesheets/index.css'
, readonly: true
, setup: function (readOnlyMain) {
readOnlyMain.addButton('myLockButton', { //Lock button is disabled because readonly is set to true
image: 'images/lock.png'
, tooltip: 'Lock Editor'
});
}
});
}
function displayReadOnlyTinyMCEwithLockButtonEnabled() {
var edContent = $('main').html();
$("#main").empty();
initReadOnlyTinyMCE(true);
tinyMCE.activeEditor.setContent(edContent);
//enable the lock button and attach a click event handler
$('[aria-label="Lock Editor"]').removeClass("mce-disabled");
$('[aria-label="Lock Editor"]').removeAttr("aria-disabled");
$('[aria-label="Lock Editor"]').attr("onclick", "LockEditor()");
}
function LockEditor() {
alert("Tiny mce editor is locked by the current user!!");
//Write your logic to lock the editor...
}
I couldn't find an easy way to do this. The simplest way is to remove the contenteditable attribute from the iframe body instead and substitute a read only toolbar set. It also means that people will still be able to copy content from the editor.
$("iframe").contents().find("body").removeAttr("contenteditable");
How about this :
editor.addButton('yourButton', {
title: 'One can Enable/disable TinyMCE',
text: "Disable",
onclick: function (ee) {
editor.setMode('readonly');
if($(ee.target).text() == "Disable"){
var theEle = $(ee.target).toggle();
var edit = editor;
var newBut = "<input type='button' style='opacity:1;color:white; background-color:orange;' value='Enable'/>";
$(newBut).prependTo($(theEle).closest("div")).click(function(e){
edit.setMode('design');
$(e.target).remove();
$(theEle).toggle();
});
}
}
});
You can try to run the code below:
$("#tinymce").contentEditable="false";
if you have more than one editors, you can use their id like below
$("#tinymce[data-id='idOfTheEditor']").contentEditable="false";

Categories

Resources