Suggestions for allowing content editors to center justify a tags content.
Closed this issue · 11 comments
Do you have any suggestions for how mobildoc could allow users to center text?
or
Is there any way text-align: center;
can be placed on elements?
For that to be possible, there should be a way to add attributes to sections (<p>
, <h1
> and such). Adding something like a data-text-align
attribute would be preferred over explicit styling as it would allow more flexibility over the styling for the user of mobiledoc-kit.
The bad news is that the Mobiledoc format does not allow attributes on sections, unlike markers.
Proposal
Right now a section looks like
[sectionTypeIdentifier, tagName, markers]
This would have to be extended to something like
[sectionTypeIdentifier, tagName, markers, optionalAttributesArray]
Indicating a piece of text to be centered would then look like:
onCenter() {
// I'm not 100% sure how to implement `getMarkupSectionsInRange` in the current API
const markupSections = getMarkupSectionsInRange(editor.range);
markupSections.forEach((markupSection) => {
// `setAttribute` does not exist right now. It would have to be added.
markupSection.setAttribute('data-text-align', 'center');
});
}
In your CSS you can then target those elements.
[data-text-align='center'] {
text-align: center;
}
Bottom line
So the bottom line is, I don't think it's possible right now. However, I believe it won't be too complicated to extend the library to support this use case. The biggest thing would be to extend the Mobiledoc format while still maintaining backwards compatibility.
I have solved this for my users with the following ugly hack....
toggleAlign: function (type) {
if (!this.editor.hasCursor()) {
return
}
let activeType = null
let marker = this.editor.range.head.marker
let parent = marker.parent
let head = parent.headPosition()
let tail = parent.tailPosition()
let range = head.toRange(tail)
this.editor.selectRange(range)
let alignments = ['div-left', 'div-center', 'div-right', 'div-justify']
for (let alignment of alignments) {
if (this.activeMarkupTags.includes(alignment)) {
activeType = alignment.split('-')[1]
}
}
if (activeType != null) {
this.editor.run((editor) => {
editor.toggleMarkup('div')
})
}
if (activeType !== type) {
this.editor.run((editor) => {
let markup = editor.builder.createMarkup('div', {style: `text-align: ${type};`})
editor.toggleMarkup(markup)
})
}
this.editor.selectRange(tail.toRange())
}
}
Which also required these modifications....
import * as tagNames from 'mobiledoc-dom-renderer/dist/commonjs/mobiledoc-dom-renderer/utils/tag-names'
import { VALID_ATTRIBUTES, VALID_MARKUP_TAGNAMES } from 'mobiledoc-kit/dist/commonjs/mobiledoc-kit/models/markup'
tagNames.isValidMarkerType = function () {
return true
}
VALID_ATTRIBUTES.push('style')
VALID_ATTRIBUTES.push('target')
VALID_ATTRIBUTES.push('class')
VALID_ATTRIBUTES.push('alt')
VALID_MARKUP_TAGNAMES.push('small')
VALID_MARKUP_TAGNAMES.push('div')
I realize this totally breaks compatibility and portability of mobiledoc, but those were never my reasons for using it.
Thank you for the taking the time to respond.
Justifying text is a totally reasonable thing someone would want to do in a rich text editor and there should be a first-class way to do it.
Thanks for the hack @internalfx I will probably end up doing something similar.
Actually I've been trying this today and cannot for the life of me get the over-riding of isValidMarkerType
to work in my environment.
I'm using ember.js and have tried:
import * as tagNames from 'mobiledoc-dom-renderer/utils/tag-names';
tagNames.isValidMarkerType = function() { return true; };
However it does not work. No errors, just doesn't render my <small>
markups.
I've also tried:
import { isValidMarkerType } from 'mobiledoc-dom-renderer/utils/tag-names';
isValidMarkerType = function() { return true; };
In this case, I get a build error: "isValidMarkerType" is read-only
I would very much appreciate some help!
Don't forget to also set small
as a valid tagname.
VALID_MARKUP_TAGNAMES.push('small')
I think @YoranBrondsema is basically on the right track. The proposal is:
- Add attributes to sections.
- Where the meaning of an attribute diverges from it's HTML implementation, let's namespace it with the prefix
data-md-
. For example the attribute ofhref
on ana
markup provides the link to be opened upon click. The attributedata-md-text-align
on ap
section would provide the text alignment. The HTML rendering implementation would be decoupled, but could be achieved with inline styles or by shipping a CSS stylesheet with the renderer. The editor itself already ships a stylesheet, so we would add style there for the editor.
Yeah @internalfx pushing 'small'
to VALID_MARKUP_TAGNAMES
works fine and it renders in the editor, but then it does not render with the dom renderer 😞
Whatever import * as foo from 'foo'
does in your environment, it doesn't do the same thing in Ember with broccoli I guess
@sdhull I remember now...
I also had to use jsdom for the renderer.
You can find the code I use to render the mobiledoc here
https://git.internalfx.com/internalfx/pageflo/src/branch/master/system/services/componentRender.js
Dang I can't add jsdom
as a dependency. Guess it's back to my fork of the renderer 😫
Thanks for replying @internalfx I appreciate it! I'm certain it will help someone else trying to do something similar.
@mixonic If a native way to handle this is ever implemented I will happily start using it.
I finally figured it out! I'll add it here for posterity (and any other ember.js devs who happen upon this issue):
For some reason, ember-mobiledoc-dom-renderer
namespaces the mobiledoc-dom-renderer, so the following works to override the isValidMarkerType
method:
import * as tagNames from 'ember-mobiledoc-dom-renderer/mobiledoc-dom-renderer/utils/tag-names';
tagNames.isValidMarkerType = function() { return true; }; // for renderer