Using Material Icons in CKEDITOR - javascript

This is kind of an academic question because I've all but given up, but maybe we can learn a few things about CKEditor5 by trying to solve it!
I'm using a pretty bare-bones installation of CKEditor from https://ckeditor.com/ckeditor-5/online-builder with just some basic styling features.
My use case is pretty basic but my users need to enter certain special characters and I want to include support for material icons (from Google)
Something along these lines
If you're not familiar with material icons, they use a special font and some CSS wizardry to display icons similar to font awesome. They are here: https://fonts.google.com/icons?icon.set=Material+Icons they come in two varieties, icons and symbols which are very similar but we're concerned with icons in this case.
The syntax for the icons is
<span class="material-icons-outlined">
emoji_emotions
</span>
and it uses some font wizardry to make that turn into something like
You can also use a single entity such as  to accomplish the same behaviour and it's the option I've opted for in my implementation.
My chosen markup is
<material-icon class='material-icons'></material-icon>
A little redundant I know but I wanted to separate them from just spans.
Anyway, out of the box CKEditor doesn't allow pasting unknown elements and strips it down to just the html entity so you need to add a new schema, something like this
export default function schemaCustomization(editor) {
// Extend schema with custom HTML elements.
const dataFilter = editor.plugins.get('DataFilter');
const dataSchema = editor.plugins.get('DataSchema');
// Inline element
dataSchema.registerInlineElement({
view: 'material-icon',
model: 'materialIcon',
modelSchema: {
inheritAllFrom: '$inlineBlock'
},
attributeProperties: {
copyOnEnter: true,
},
});
// // Custom elements need to be registered using direct API instead of config.
dataFilter.allowElement('material-icon');
dataFilter.allowAttributes({ name: 'element-inline', classes: /^.*$/ });
}
This will register the element with the editor and allow it to be accepted into the document.
Then you add it to your options, alongside the previous htmlSupport plugin and you're good to go!
options = {
toolbar: {
items: [],
},
htmlSupport: {
allow: [
{
name: 'material-icon',
classes: /^.*$/,
},
],
disallow: [
/* HTML features to disallow */
],
},
extraPlugins: [schemaCustomization],
removePlugins: []
};
A lot of documentation I used comes from here: https://ckeditor.com/docs/ckeditor5/latest/framework/guides/deep-dive/schema.html
However, there's one problem!!
The element remains editable and if someone clicks inside the material-icon tag and starts entering text, it gets messed up.
I need a way to make the material-icon element be somehow self-contained or atomic and only allow a single character inside.
I've been playing around with all kinds of settings but I'm not sure which are the correct ones and where they're even meant to go.
For now I've switched to just using unicode emoji but they really don't look as nice.
I've tried a lot of the settings and options from https://ckeditor.com/docs/ckeditor5/latest/framework/guides/deep-dive/schema.html and I think there are multiple ways to register these sorts of elements.
I was expecting it to work somehow but the ability to edit within the tags and break the layout is an unintended side effect.
Does anyone have any experience with the latest version of CKEditor and performing these sorts of low-level mechanics? Any help is appreciated!

Related

Can I use javascript to change individual page css entries (as opposed to swapping stylesheets)?

I know it's possible to change css attributes on elements on the current page:
$('.changeMyStyle').css("color", "#FF0000");
But this won't affect new elements added after the change is made.
I know it's possible to remove, add, or swap out css stylesheets to re-style a page after it's been loaded:
$('link.swappableStylesheet').attr('href', 'path/to/new/style.css');
But this is a poor solution for changing one or two attributes, especially to programmatically-determined values (such as changing color from a colorpicker).
I could probably grab a stylesheet's raw data, search it, and modify it:
var sheet= document.styleSheets[0];
var rules= 'cssRules' in sheet? sheet.cssRules : sheet.rules; // IE compatibility
rules[0].style.padding= '0.32em 2em';
// assumes the first entry in the first stylesheet is the one you want to modify.
// if it's not, you have to search to find the exact selector you're looking for
// and pray it's not in a slightly different order
But that's also a poor solution and requires IE-compatibility hacks.
This linked answer also suggests appending another <style> element and adding css there. That could work for narrow cases, but it's still not ideal (and the answer is 5 years old, so new tools may be available now).
Is there a way to alter the page's css at a selector & attribute level instead of stylesheet level or DOM element level? jQuery and vanilla javascript solutions both welcome, as well as libraries designed to do this specifically. Ideally I'd like something that's as easy and versatile as
$(document).stylesheet('.arbitraryCssSelector.Here').put('color', '#FF0000');
...where .stylesheet('.Here.arbitraryCssSelector') would modify the exact same style entry.
Even Chrome's dev tools just modifies the stylesheet it's using when you make modifications or add new rules. There's not currently a way around it, but you can keep a dedicated stylesheet at the bottom of the page that you update with the newest rules. If it's empty or contains invalid rules it will just fall back to the current stylesheet. If any library exists out there this is how it would do it, and it's very little code.
I think the key to keeping it uncluttered is to simply keep overwriting one stylesheet instead of adding new stylesheets to the DOM.
document.getElementById("dynamic-color").addEventListener("input", function () {
document.getElementById("dynamic-styles").innerHTML = "label { color: " + this.value + " }";
});
label {
color: blue;
}
<label for="#dynamic-color">Change the label's color!</label>
<input id="dynamic-color" />
<style id="dynamic-styles"></style>

How to unbold text? A tiny WYSIWYG editor

Hey Stackoverflow comunity,
There is a method str.bold() to wrap a text in <b></b> tags. This is just perfect for a tiny WYSIWYG editor (I know some will say I should take one of hundrets open source solutions, but this is for learning purposes too).
The problem is how to unbold the text.
Here is my try http://jsfiddle.net/Kxmaf/178/
I know there is editor.execCommand('bold', false, ''); but this is producing different HTML results on each browser. I need to have only <b></b>, <i></i>, <u></u>
Any help is much appreciated :)
what about looping over a selected string with javascript when pushing the specific style-button. you just could save the several tags like , , .... inside an array, and than loop through the specific string you have selected. so you even can change the style of the style-buttons when any of the tags has been found, to let the user know which style is just used. After deselecting the style just loop again through and delete the tags from string.
You need to consider the case where the user's selection spans paragraphs. For example (selection boundaries indicated with pipes):
<p>One <b>t|wo</b></p>
<p>Thr|ee</p>
To handle this, you need to wrap and all the text nodes and partial text nodes within the user's selection in <b> tags while also detecting which text nodes are already bold and leaving them alone. This is non-trivial, and document.execCommand() handles it all for you, as do the big WYSIWYG editors.
Most browsers allow switching between style modes, allowing you to choose between styling using elements such as <b> and <i> or styling using <span> elements with style attributes. You can do this using the the "StyleWithCSS" command, falling back to "UseCSS" in older browsers. The following switches commands to use the non-CSS version:
try {
if (!document.execCommand("StyleWithCSS", false, useCss)) {
// The value required by UseCSS is the inverse of what you'd expect
document.execCommand("UseCSS", false, !useCss);
}
} catch (ex) {
// IE doesn't recognise these commands and throws.
}
Finally, if you switched to using CSS classes instead of <b> etc., you could use the CSS class applier module of my Rangy library.

How to remove CSS and JS from a certain content-type in Drupal 7

I've come here after looking for how to selectively add a CSS or JS to a given node based on its view mode and content type. That question is answered pretty straightforward here (http://stackoverflow.com/questions/8295498/how-to-add-css-and-js-files-on-node-pages-independent-of-the-theme).
Now I'd love to clear everything: I'm looking for a way to show my desired CSS and JS but only that, with no other JS and CSS. I'm trying to integrate Impress.js (And I don't like the available solutions) and it seems to be conflicting with Jquery, as both scripts are properly loaded but both latest Firefox and Chromium browsers throw the "old browser" message.
Any ideas on how to unset every single CSS and JS so that the CSS and JS I want to use are the only ones really active?
Thanks!
I've tried the following, to no success:
$mycss = $vars['styles'];
unset($micss[drupal_get_path('module','system') .'/system.base.css']);
...
unset($micss[drupal_get_path('module','toolbar') .'/toolbar.css']);
$vars['styles'] = $mycss;
(I added a lot of different css i want to get rid of, but this explains the idea). It didn't work, though :)
Edit. I'm sorry for the bad markup, I'm looking for a way to clean/mark code.
In your custom module use:
function yourmodule_js_alter(&$js) {
unset(
$js['misc/drupal.js'],
$js['misc/jquery.js']
.... etc.
);
}
You say you want to only do this for certain content types, so try:
if(arg(0) == 'node') {
$node = node_load(arg(1));
if($node->type == 'your_content_type') {
unset(
$js['misc/drupal.js'],
$js['misc/jquery.js']
.... etc.
);
}
}
Jonny

Need help with adding Classes to HTML Editor Elements

I'm using a WYSIWYG Editor called CKEditor and its really awesome. Inside the editor, whenever I add a new Heading/Text/DIV/Image/ anything else for that matter, I want it to stay attached with a class:
Like
<h2 class="blah">Sample Text</h2>
<img src="/abc.png" class="blah1" />
Here's a reference link:
http://docs.cksource.com/CKEditor_3.x/Developers_Guide
I'm not good with Javascript, if anyone can help me out, I would be really Grateful!
Thank you.
For example, the following code will ensure that elements will have their "alt" attribute filled:
editor.dataProcessor.htmlFilter.addRules(
{
elements :
{
img : function( element )
{
if ( !element.attributes.alt )
element.attributes.alt = 'An image';
}
}
});
Read the Overview (http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Data_Processor) this example was taken from there.
You can do the same for "class". Take a look at the existing output, then either add "class" if it's missing or replace them if that's your intent.
take a look at answers for this question.
customize the dialogs during the define, add a "class" field and then set and get the contents in the setup and commit functions.
look at ckeditor/_samples/api_dialog.html for background on modifying dialogs.
for the Headings you'd have to look at modifying the commands. Those don't have dialogs.
There's probably a way to always apply the same class based on the particular tag in the "data processor". Do you want to always set the same class everytime or allow the user to choose the class, that's important because it changes your options quite a bit.

How do I disable hotkeys in Dojo StackContainer

I am using Dojo 1.2 to implement some functionality on my customer's webpage. One of the widgets I use is the dijit.layout.TabContainer, which inherits StackContainer. The StackContainer subscribes on keyboard events and creates a few hotkeys, like arrow left to move one tab to the left and so on.
Now to the question: I would like to disable this hotkey feature in my TabContainer. Is there a configuration option I can set (can't find any in the API) to achieve this, or will have to hack the Dojo code or perhaps create my own versions of StackContainer and TabContainer in order to rid myself of the hotkeys? I would of course prefer not to mess with the Dojo code.
Best regards / Fredrik
Simply override _onKeyPress with an empty body:
<div dojoType='dijit.layout.TabContainer'>
<script type='dojo/method' event='_onKeyPress'></script>
...
<div>
Works like a charm.
I'm just coding off the cuff here, and I didn't test it out at all. I'm making this wikified, so post the correct source if there are any problems, please.
Use the following javascript within a file called com/stackoverflow/KeyPresslessTabContainer.js:
dojo.provide("com.stackoverflow. KeyPresslessTabContainer");
dojo.require("dijit.layout. TabContainer");
dojo.declare("com.stackoverflow.KeyPresslessTabContainer", dijit.layout. TabContainer, {
_controllerWidget: "com.stackoverflow.KeyPresslessTabController"
});
dojo.declare("com.stackoverflow.KeyPresslessTabController", dijit.layout.TabController, {
/*
* this is the important part. The original code was:
* templateString: "<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>"
* In the template below, we remove the onkeypress listener,
* and thus key presses should be ignored.
*/
templateString: "<div wairole='tablist'></div>"
});

Categories

Resources