How to edit ol tags in rich text editor - css

I am creating and ordered list using Text Angular and able to create orderlist which starts with 1,2,3 by default. Text angular has 2 modes
1. Rich Text mode
1. HTML mode
HTML mode shows
<ol>
<li>test</li>
<li>test</li>
</ol>
Rich Text mode will show as:
test
test
If I need to start ordered list with number 5, I need to switch to HTML mode first and do the below change
<ol start="5">
<li>test</li>
<li>test</li>
</ol>
Now the Rich Text mode starts the numbering with 5
test
test
The real problem is how to change the numbering by clicking on the pseudo element generated by the < ol> tag while on the rich text editor mode. After googling and research it seems the pseudo element cannot be changed.
Stack overflow editor gives the option of changing this in Rich Text mode itself!
So while adding the below data in Rich Text mode starting with 4 for example
4. number 4
3. number 3
The preview mode ends up displaying buggy result.
number 4
number 3
if you noticed 5. number 3. this was generated from the Rich text editor.
There are JS way to replace tags in the DOM and give a simlar tag look n feel using combination of html tags etc which I am not looking for at this point.
Would there be a creative CSS way to change the number on the fly in the rich text mode (rather than doing html mode) in Text Angular.

As I understood, what you need is a feature for changing the starting number when using the ordered list which is not implemented by the text-angular editor at the moment. What text-angular provides you in such cases is easy extending of the toolbar by adding new or overriding existing functionalities.
Here is a Plunker with an example implementation of the feature you need. I have implemented it by overriding the ol button configuration like this:
app.decorator('taTools', function ($delegate, $document, taSelection) {
// NOTE: override the ol action
var olAction = $delegate.ol.action;
$delegate.ol.action = function () {
if (!this.active) {
// NOTE: replace with better way for integrating the feature
var startingNumber = $document.find('#startingNumber').val();
// do the ordering
var result = olAction.apply(this, arguments);
// change the starting number
var element = angular.element(taSelection.getSelection().start.element);
var parentOls = element.parents('ol');
if (parentOls.length > 0) {
angular.element(parentOls[0]).attr('start', startingNumber);
}
// clean up
element = null;
parentOl = null;
return result;
} else {
return olAction.apply(this, arguments);
}
};
return $delegate;
});
The way for configuring the starting number IMO is not so good, it's just for showcase because replacing it with better way takes more effort (ex. dropdown on the ol button). You can replace it with what is most convenient for you.
For more information and examples on Text-Angular editor you can check its documentation and the page for customizing the toolbar.

Edit: After the question was edited my answer no longer fits very well. Since it still received upvotes afterwards I'm going to assume that it was nonetheless helpful and just leave it here.
As has been mentioned in comments and other answers, the clicking part is not possible. It is possible to highlight the numbering.
Add a custom counter in the :before part of your <li> tags and have them react to hovering:
ol {
counter-reset: my-counter;
}
ol > li {
list-style-type:none;
}
ol > li:before {
counter-increment: my-counter;
content: counter(my-counter) '. ';
}
ol > li:hover:before {
color: red;
}
Example here: http://jsfiddle.net/u1uhr7s8/
Again, it is not possible to add anything clickable in place of the numbers because the before: bit does not truly become part of the DOM.

'selected' here could mean a number of different things. You'll need to clarify your question to get the answers you're after, but if you're looking to reference this in Javascript somewhere, you can use any of the following:
document.getElementsByTagName('ol') //Will return a list of all OLs on the page
document.querySelectorAll('ol') //Will return a list of all OLs on the page
$('ol') //Will return a list of all OLs on the page, but requires JQuery
To get the '1' or '2' li elements, you'd include the LI within the query, or select it as a child of what's returned:
var myOL = document.getElementsByTagName('ol')[0];
var myItems = myOL.children;
or with JQuery
var myItems = $('ol li');
If you're talking about targeting the OL with CSS rules, you just use the tag name, e.g.
ol {
background-color: #FF0000;
}
and again, if you're after the LIs you can either target them all:
ol li {
background-color: #FFFF00;
}
or target a specific child using nth-child:
ol li:nth-child(2) { /* second child - '2' in your case */
background-color: #FFFF00;
}

Below solution is inspired by S.Klechkovski's answer. On the editor type a number, say 5 , select the number, click on on ol tag in TextAngular, the old now starts with 5
The difference is in var startingNumber = parseInt($(taSelection.getSelectionElement()).text());
$provide.decorator('taTools', function ($delegate, $document, taSelection) {
// NOTE: override the ol action
var olAction = $delegate.ol.action;
$delegate.ol.action = function () {
if (!this.active) {
// NOTE: replace with better way for integrating the feature
var startingNumber = parseInt($(taSelection.getSelectionElement()).text());
// do the ordering
var result = olAction.apply(this, arguments);
// change the starting number
var element = angular.element(taSelection.getSelection().start.element);
var parentOls = element.parents('ol');
if (parentOls.length > 0) {
angular.element(parentOls[0]).attr('start', startingNumber);
}
// clean up
element = null;
parentOl = null;
return result;
} else {
return olAction.apply(this, arguments);
}
};
return $delegate;
});

Related

Anyone have solutions for table>th with position:sticky not working on FF & IE?

I have an idea to make sticky header of table and I have tried with position:sticky. It's
working fine on Chrome but on Firefox and IE not working as I think. Below is my CSS
.myTable--mof thead th {
position: -webkit-sticky;
position: sticky;
top: 0;
z-index:100;
}
position:sticky is not supported for child table elements in some browsers. The 'why' I don't know.. Will it be supported in the future? I sure hope so!
I recently wrote this jQuery solution. It'll work for simple tables with simple headers. Does not look for colspans or multiple rows in thead!
I tried some plugins before, but they all listened for the scroll event which throws alerts in some browsers. They caused flickering/jumping in some cases, and a delay was noticable when hitting the position to stick at.
Using position:sticky for other elements and liking those transitions more, I came up with the following piece of code.
jQuery.fn.stickTableHeaders = function() {
return this.each(function()
{
var table = $(this),
header = table.find('thead'),
sticked = $('<table></table>').addClass('table').append(header.clone()); // Needs to be wrapped in new table since table child elements can't be sticky? (FF)
sticked.find('th').css({ // You'll have to copy the original thead (th's) CSS manualy
'backgroundColor': '#DEE5EA',
'color': '#606060',
'padding':'8px',
'color':'#606060'
}).removeAttr('width'); // And remove the width attr from the clone th's since we'll be setting them again later
sticked.find('th:not(:last-child)').css({ // More CSS
'borderRight': '1px solid #ddd'
});
sticked.find('a').css({ // More CSS
'color':'#606060'
});
// I tried different things, most of the original th's should have a width attribute set (not in CSS and avoid percent) for best results
$(window).resize(function() {
sticked.width(table.width());
sticked.find('th').each(function() {
var headerTH = header.find('th').eq($(this).index());
if(headerTH.is('[width]') || headerTH.is(':first-child') || headerTH.is(':last-child')) { // First and last th are allready calculated by another function in my app. See what suits for you here...
$(this).width(header.find('th').eq($(this).index()).width());
}
else {
var cellWidth = header.find('th').eq($(this).index()).width(true),
tableWidth = table.width(true),
percent = 100*(cellWidth/tableWidth);
$(this).css({'width':percent+'%'});
}
});
// We keep the original thead to avoid table collapsing, we just slide the whole table up.
table.css({
'marginTop':-header.height()
});
}).trigger('resize');
// Apply stickyness
sticked.css({
'display':'table',
'position':'sticky',
'top':$('#header-menu').height(), // My sticky nav is my top position, adjust this to your needs
'zIndex':'10'
});
// Insert clone before original table
$(this).before(sticked);
});
};
Now I just use this on each page load:
$("table").stickTableHeaders();
You might want to filter out nested tables from the above selector...
Hope this helps someone.

Hide a whole div with CSS with part of it is empty

Is there a way to hide a whole div if part of it is empty? For example if "dd" is empty as shown below can I hide the whole class "test" so the keyword Restrictions does not show either. I tried .test dd:empty { display: none; } but this does not work. thanks!
<div class="test"><dt>Restrictions:</dt>
<dd></dd></div>
I don't think there's any easy way to do what you're talking about with just CSS. Better to test it server-side if you can. But if you can't here's some JS that will do the job.
<script type="text/javascript">
// handles multiple dt/dd pairs per div and hides them each conditionally
function hideIfEmpty() {
// get all the elements with class test
var els = document.getElementsByTagName('dl');
// for every 'test' div we find, go through and hide the appropriate elements
Array.prototype.map.call(els, function(el) {
var children = el.childNodes;
var ddEmpty = false;
for(var i = children.length - 1; i >= 0; i--) {
if(children[i].tagName === 'DD' && !children[i].innerHTML.trim()) {
ddEmpty = true;
} else if(children[i].tagName === 'DT') {
if(ddEmpty) {
children[i].style.display = 'none';
}
// reset the flag
ddEmpty = false;
}
}
});
}
window.addEventListener('load', hideIfEmpty);
</script>
<div class="test">
<div style="clear: both;"></div>
<dl>
<dt>Restrictions:</dt>
<dd></dd>
<dt>Other Restrictions:</dt>
<dd>Since I have content, I won't be hidden.</dd>
</dl>
</div>
Just a fair warning: the code uses some functions that may not exist in older IE, such as Array.prototype.map, String.prototype.trim, and addEventListener. There are polyfills available for these and you could also write your own pretty easily (or just do it with a for loop instead).
CSS alone can't do that. Either, you need a javascript to retrieve empty elements and hide their parents, or your CMS applies special CSS classes if there's no content.
Put as an answer as requested by #Barett.
You could update your CSS to be
.test{
display: none;
color: transparent;
}
This would make the text transparent too, but display:none should hide it anyway.
To make the div with the id test ONLY show when the dd tag is EMPTY, and you can use jQuery, try the following JavaScript along with the CSS:
if($("dd").html().length ==0)
{show();
}
Note: this solution requires jQuery, which is a JavaScript library.

dynamic stylesheet with angularjs

I have and angularjs application that fetches data via api, and builds a webpage with it.
Usually I use ng-style to create dynamic styling, but now I have to use the nth-of-type attribute that can only be used in a css stylesheet (I cannot use individual styling since the number and order of elements always change).
I have tried this naive code (in the html page):
<style ng-if="styles.sc && styles.sc.length==3">
a.mosection:nth-of-type(3n) > div {
background-color: {{styles.sc[0]}} !important;
}
a.mosection:nth-of-type(3n+1) > div {
background-color: {{styles.sc[1]}} !important;
}
a.mosection:nth-of-type(3n+2) > div {
background-color: {{styles.sc[2]}} !important;
}
</style>
But it didn't work... Apparently angular doesn't bind the data inside the style tag (the ng-if attribute does get digested properly)
Does anyone have any idea how this can be done?
Thanks!
You should checkout those three ng-*
https://docs.angularjs.org/api/ng/directive/ngClass
https://docs.angularjs.org/api/ng/directive/ngClassOdd
https://docs.angularjs.org/api/ng/directive/ngClassEven
all of them can accept functions as attributes, you can also checkout
https://docs.angularjs.org/api/ng/directive/ngStyle
which might be actually the best in your case
Thanks!
I indeed solved it by using ng-style with a function
The HTML
<div class="widget widget-people" ng-style="{backgroundColor: staggerBgColors('widget', 'widget-people', '#333333')}"></div>
<div class="widget widget-property" ng-style="{backgroundColor: staggerBgColors('widget', 'widget-property', '#24d10f')}"></div>
The scope function
$scope.staggerBgColors = function(elesClass, eleClass, defaultColor){
if (!$scope.styles || !$scope.styles.sc || $scope.styles.sc.length!=3){
return defaultColor;
}else{
var listItem = $('.'+eleClass);
var n = $('.'+elesClass).index( listItem ) % 3;
return '#' + $scope.preview.moment.sc[n];
}
}
I had to implement the same functionality of the css property "nth-of-type" using jQuery, but it works prefectly!

Style an ordered list with Cyrillic letters

There are many possible values for list-style-type CSS property (e. g. decimal, lower-latin, upper-greek and so on). However there are none for the Cyrillic alphabet (which, btw, has different variations for different languages).
What is the best way to style an ordered list with Cyrillic letters?
(I'm providing a solution I ended up with despite I'm not very happy with it.)
I know nothing about Cyrillic list schemes so I’m at risk of a bit of cultural embarrassment here, but CSS3 Lists module (still in working draft) defines quite a few Cyrillic alphabetic list types: lower-belorussian, lower-bulgarian, lower-macedonian, lower-russian, lower-russian-full, lower-serbo-croatian, lower-ukrainian, lower-ukrainian-full, upper-belorussian, upper-bulgarian, upper-macedonian, upper-russian, upper-russian-full, upper-serbo-croatian, upper-ukrainian, upper-ukrainian-full. As expected, the state of support for these is deplorable currently (certainly nothing in Gecko or WebKit), but hopefully going forwards these will start to be implemented.
Update: some changes have been made – the definition of list types has been moved into the CSS3 Counter Styles module whose current draft (Feb 2015) has unfortunately lost all alphabetical Cyrillic types. This is in Candidate Recommendation stage so it’s unlikely that additions will be made at the point. Perhaps in CSS4 List Styles?
In this method I'm using CSS-generated content in before each list item.
.lower-ukrainian {
list-style-type: none;
}
.lower-ukrainian li:before {
display: inline-block;
margin-left: -1.5em;
margin-right: .55em;
text-align: right;
width: .95em;
}
.lower-ukrainian li:first-child:before {
content: "а.";
}
.lower-ukrainian li:nth-child(2):before {
content: "б.";
}
/* and so on */
Disadvantages
Hardcoded, restrict list to a certain max length.
Not pixel-perfect as compared to a regular order list
Here is another solution for Cyrillic letters with pretty clear code: jsfiddle.net
(() => {
const selector = 'ol.cyrillic',
style = document.createElement('style');
document.head.appendChild( style );
'абвгдежзиклмнопрстуфхцчшщэюя'.split('').forEach((c, i) =>
style.sheet.insertRule(
`${selector} > li:nth-child(${i+1})::before {
content: "${c})"
}`, 0)
);
})();
PS. You can convert this next-gen code to old one with Babel: babeljs.io
I'm surprised that there is no Cyrillic numbering. Here's a quick JS solution for you:
function base_convert(n, base) {
var dictionary = '0123456789abcdefghijklmnopqrstuvwxyz';
var m = n.toString(base);
var digits = [];
for (var i = 0; i < m.length; i++) {
digits.push(dictionary.indexOf(m.charAt(i)) - 1);
}
return digits;
}
var letters = {
'russian': {
'lower': 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя',
'upper': 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'
}
}
$('ul, ol').each(function() {
if (!(results = $(this).prop('class').match(/(upper|lower)-([a-z]+)/i))) return;
var characters = letters[results[2]][results[1]];
$('> li', this).each(function(index, element) {
var number = '', converted = base_convert(++index, characters.length);
for (var i = 0; i < converted.length; i++) {
number += characters.charAt(converted[i]);
}
$(this).attr('data-letter', number);
});
});​
My written Russian is admittedly bad, as you can see by my inability to count with letters, so change the letters object appropriately.
Demo: http://jsfiddle.net/JFFqn/14/

Attach an image to any word

I'd like to attach images to specific words but cannot find the right CSS selector to do so.
I have a portion of my site which displays data as it's pulled from a database, so adding classes or id's to certain words is not an option for me. I need the css to simply display a background image wherever that word (or in this case, name) is found on the page.
For example, in the following (which is pulled from a database):
<td class="data1"><font face="Verdana, Arial, Helvetica, sans-serif" size="1">Patrick</font></td>
I would like to add a background image where the name Patrick is found.
I tried variations of,
td[.table1 *='Parick'] {
background-image:url(../images/accept.png);
but that didn't get me anywhere. And since it's not in a <span> or <div> or even a link, I can't figure it out. If you have any ideas or a jQuery workaround, please let me know. Thanks!
If you can guarantee the names only appear as the only text nodes in elements, you can use a simple jQuery selector...
$(':contains("Patrick")').addClass('name');
jsFiddle.
If there may be surrounding whitespace and/or the search should be case insensitive, try...
$('*').filter(function() {
return $.trim($(this).text()).toLowerCase() == 'patrick';
}).addClass('name');
jsFiddle.
If you need to find the name anywhere in any text node and then you need to wrap it with an element, try...
$('*').contents().filter(function() {
return this.nodeType == 3;
}).each(function() {
var node = this;
this.data.replace(/\bPatrick\b/i, function(all, offset) {
var chunk = node.splitText(offset);
chunk.data = chunk.data.substr(all.length);
var span = $('<span />', {
'class': 'name',
text: all
});
$(node).after(span);
});
});​
jsFiddle.
I would recommend using the third example.

Resources