I’m trying to find a way to solve this problem:
p {color: red}
p {color: —-var(defaultcolor)}
—-var(defaultcolor) doesn’t exist yet. it’s being created by JavaScript by clicking a button as a root value. How can I set p to red until the visitor actually click on it?
I can’t use the fallback function —-var(defaultcolor, red) cause I don’t know which color p is going to have. In the example I used red but could be any color.
The p{color:red} is in css file I have no control on. I’m trying to override p but keeping the value as “default” value.
Is there any way to “skip” the value to the second highest class?
Set defaultcolor in your css to your default value before using this in the rest of css.
:root { --defaultcolor: red; }
p {color: var(--defaultcolor); }
Alternatively, you can use inherit or any other fancy color value:
:root { --defaultcolor: inherit; }
p {color: var(--defaultcolor); }
For changing fixed css rule to unknown value variable, take a look at snippet
// wait for onload to get all polyfills and stuff initialised
window.onload = (event) => {
let el = document.getElementsByTagName('p')[0]
// get all applied styling
let matchedcss = window.getMatchedCSSRules(el, 'color')
// get original colour
let color = matchedcss[0].style.color
document.documentElement.style.setProperty('--defaultcolor', color)
// lets change this later
el.onclick = () => document.documentElement.style.setProperty('--defaultcolor', 'green')
}
// polyfill needed for newer browsers!
// polyfill https://stackoverflow.com/questions/2952667/find-all-css-rules-that-apply-to-an-element by 7vujy0f0hy
// polyfill window.getMatchedCSSRules() in FireFox 6+
if (typeof window.getMatchedCSSRules !== 'function') {
var ELEMENT_RE = /[\w-]+/g,
ID_RE = /#[\w-]+/g,
CLASS_RE = /\.[\w-]+/g,
ATTR_RE = /\[[^\]]+\]/g,
// :not() pseudo-class does not add to specificity, but its content does as if it was outside it
PSEUDO_CLASSES_RE = /\:(?!not)[\w-]+(\(.*\))?/g,
PSEUDO_ELEMENTS_RE = /\:\:?(after|before|first-letter|first-line|selection)/g;
// convert an array-like object to array
function toArray(list) {
return [].slice.call(list);
}
// handles extraction of `cssRules` as an `Array` from a stylesheet or something that behaves the same
function getSheetRules(stylesheet) {
var sheet_media = stylesheet.media && stylesheet.media.mediaText;
// if this sheet is disabled skip it
if ( stylesheet.disabled ) return [];
// if this sheet's media is specified and doesn't match the viewport then skip it
if ( sheet_media && sheet_media.length && ! window.matchMedia(sheet_media).matches ) return [];
// get the style rules of this sheet
return toArray(stylesheet.cssRules);
}
function _find(string, re) {
var matches = string.match(re);
return matches ? matches.length : 0;
}
// calculates the specificity of a given `selector`
function calculateScore(selector) {
var score = [0,0,0],
parts = selector.split(' '),
part, match;
//TODO: clean the ':not' part since the last ELEMENT_RE will pick it up
while (part = parts.shift(), typeof part == 'string') {
// find all pseudo-elements
match = _find(part, PSEUDO_ELEMENTS_RE);
score[2] += match;
// and remove them
match && (part = part.replace(PSEUDO_ELEMENTS_RE, ''));
// find all pseudo-classes
match = _find(part, PSEUDO_CLASSES_RE);
score[1] += match;
// and remove them
match && (part = part.replace(PSEUDO_CLASSES_RE, ''));
// find all attributes
match = _find(part, ATTR_RE);
score[1] += match;
// and remove them
match && (part = part.replace(ATTR_RE, ''));
// find all IDs
match = _find(part, ID_RE);
score[0] += match;
// and remove them
match && (part = part.replace(ID_RE, ''));
// find all classes
match = _find(part, CLASS_RE);
score[1] += match;
// and remove them
match && (part = part.replace(CLASS_RE, ''));
// find all elements
score[2] += _find(part, ELEMENT_RE);
}
return parseInt(score.join(''), 10);
}
// returns the heights possible specificity score an element can get from a give rule's selectorText
function getSpecificityScore(element, selector_text) {
var selectors = selector_text.split(','),
selector, score, result = 0;
while (selector = selectors.shift()) {
if (matchesSelector(element, selector)) {
score = calculateScore(selector);
result = score > result ? score : result;
}
}
return result;
}
function sortBySpecificity(element, rules) {
// comparing function that sorts CSSStyleRules according to specificity of their `selectorText`
function compareSpecificity (a, b) {
return getSpecificityScore(element, b.selectorText) - getSpecificityScore(element, a.selectorText);
}
return rules.sort(compareSpecificity);
}
// Find correct matchesSelector impl
function matchesSelector(el, selector) {
var matcher = el.matchesSelector || el.mozMatchesSelector ||
el.webkitMatchesSelector || el.oMatchesSelector || el.msMatchesSelector;
return matcher.call(el, selector);
}
//TODO: not supporting 2nd argument for selecting pseudo elements
//TODO: not supporting 3rd argument for checking author style sheets only
window.getMatchedCSSRules = function (element /*, pseudo, author_only*/) {
var style_sheets, sheet, sheet_media,
rules, rule,
result = [];
// get stylesheets and convert to a regular Array
style_sheets = toArray(window.document.styleSheets);
// assuming the browser hands us stylesheets in order of appearance
// we iterate them from the beginning to follow proper cascade order
while (sheet = style_sheets.shift()) {
// get the style rules of this sheet
rules = getSheetRules(sheet);
// loop the rules in order of appearance
while (rule = rules.shift()) {
// if this is an #import rule
if (rule.styleSheet) {
// insert the imported stylesheet's rules at the beginning of this stylesheet's rules
rules = getSheetRules(rule.styleSheet).concat(rules);
// and skip this rule
continue;
}
// if there's no stylesheet attribute BUT there IS a media attribute it's a media rule
else if (rule.media) {
// insert the contained rules of this media rule to the beginning of this stylesheet's rules
rules = getSheetRules(rule).concat(rules);
// and skip it
continue
}
// check if this element matches this rule's selector
if (matchesSelector(element, rule.selectorText)) {
// push the rule to the results set
result.push(rule);
}
}
}
// sort according to specificity
return sortBySpecificity(element, result);
};
}
/* original css*/
p {color: red; }
/* my css */
p {color: var(--defaultcolor); }
<p>click for colour change</p>
You can use Javascript to dynamically alter your style sheet reading the current color using getCurrentStyle()
var pTag = document.querySelector('p');
// Read the tag before creating the dynamic css rule
var pTagColor = getComputedStyle(pTag).color;
// There are other ways to do this, like creating a new style sheet altogether
const rule = `p { color: var(--default-color, ${pTagColor} )}`;
// Must be inserted after the existing rule
document.styleSheets[0].insertRule(rule, 1);
pTag.addEventListener('click', () => {
document.documentElement.style.setProperty('--default-color', 'green');
});
p { color: red }
<p> I am red and will turn to green when clicked</p>
DISCLAIMER
If you can change the place that is writing p {color: red} to
:root { --default-color: red }
p { color: var(--default-color, red) }
as Rauli's answer suggested, I would do that since it's the natural way of using css custom properties.
Related
I have a use case in CKEditor where a user may need to insert a Unordered or Ordered list, but due to the site's brand guidelines, we need to provide the option to color the bullets or numbers. I have looked at the List Style plugin (http://ckeditor.com/addon/liststyle) but it does not provide that featureset nor does it provide any insight on how to add that kind of setting in the plugin itself. What are my best options to add this functionality to CKEditor?
You can create a plugin or modify an existing plugin to color the list items with this code:
var colorStyleLi = {
element: 'li',
styles: { 'color': '#(color)' }
};
var sel = editor.getSelection();
var ranges = sel.getRanges();
var st = new CKEDITOR.style(colorStyleLi, { color: color } );
for (var i = 0, len = ranges.length; i < len; ++i) {
var walker = new CKEDITOR.dom.walker(ranges[i]),
node;
while((node = walker.next())) {
if(node.type==CKEDITOR.NODE_ELEMENT) {
st.applyToObject(node, editor);
} else {
var p = node.getParent();
st.applyToObject(p, editor);
}
}
}
I'd like to implement something like the following HTML helpers in MvcSiteMapProvider:
Html.MvcSiteMap().Previous()
Html.MvcSiteMap().Next()
However, I am quite new to their API, is it possible to do that, and if so, how?
You can accomplish this by building custom HTML helpers. I have answered this question already at GitHub and provided a working demo project, but I am copying here for reference.
The logic to walk up and down the document would look something like this, the rest of the code is for the most part boilerplate templated HTML helper code.
private static ISiteMapNode GetNextNode(ISiteMapNode startingNode, IDictionary<string, object> sourceMetadata)
{
ISiteMapNode nextNode = null;
if (startingNode.HasChildNodes)
{
// Get the first child node
nextNode = startingNode.ChildNodes[0];
}
else if (startingNode.ParentNode != null)
{
// Get the next sibling node
nextNode = startingNode.NextSibling;
if (nextNode == null)
{
// If there are no more siblings, the next position
// should be the parent's next sibling
var parent = startingNode.ParentNode;
if (parent != null)
{
nextNode = parent.NextSibling;
}
}
}
// If the node is not visible or accessible, run the operation recursively until a visible node is found
if (nextNode != null && !(nextNode.IsVisible(sourceMetadata) || nextNode.IsAccessibleToUser()))
{
nextNode = GetNextNode(nextNode, sourceMetadata);
}
return nextNode;
}
private static ISiteMapNode GetPreviousNode(ISiteMapNode startingNode, IDictionary<string, object> sourceMetadata)
{
ISiteMapNode previousNode = null;
// Get the previous sibling
var previousSibling = startingNode.PreviousSibling;
if (previousSibling != null)
{
// If there are any children, go to the last descendant
if (previousSibling.HasChildNodes)
{
previousNode = previousSibling.Descendants.Last();
}
else
{
// If there are no children, return the sibling.
previousNode = previousSibling;
}
}
else
{
// If there are no more siblings before this one, go to the parent node
previousNode = startingNode.ParentNode;
}
// If the node is not visible or accessible, run the operation recursively until a visible node is found
if (previousNode != null && !(previousNode.IsVisible(sourceMetadata) || previousNode.IsAccessibleToUser()))
{
previousNode = GetPreviousNode(previousNode, sourceMetadata);
}
return previousNode;
}
I want the list of all style properties/values applied to a UIComponent's selector via css but I can't seem to find a list of them anywhere.
For example, I have a BorderContainer and the CSS gives it
backgroundColor: #869ca7;
backgroundAlpha: .5;
and from an ActionScript function I would like to retrieve the list {backgroundColor:#869ca7, backgroundAlpha:.5}. But in an abstract way that works for all UIComponents (i.e. I can't just call getStyle("backgroundColor");
I've tried two ways and I feel very close but can't actually retrieve the list.
It feels like I should be able to get the list of properties from the UIComponents by using the styleDeclaration property on the UIComponent, but it doesn't seem to show the list of style properties it has.
It also seems like I should be able to get the values by calling "uiComponent.getStyle(_)" but that requires that I already know the property names.
Thank you for any insight you can help me with.
For reference, the CSSStyleDeclaration class:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/styles/CSSStyleDeclaration.html
So my initial research shows that there is no direct function call or list for retrieving an array of style properties.
I think the only way is to check the cascading arrays for the property name.
Code for getStyle for reference:
public function getStyle(styleProp:String):*
{
var o:*;
var v:*;
// First look in the overrides, in case setStyle()
// has been called on this CSSStyleDeclaration.
if (overrides)
{
// If the property exists in our overrides, but
// has 'undefined' as its value, it has been
// cleared from this stylesheet so return
// undefined.
if (styleProp in overrides &&
overrides[styleProp] === undefined)
return undefined;
v = overrides[styleProp];
if (v !== undefined) // must use !==
return v;
}
// Next look in the style object that this CSSStyleDeclaration's
// factory function produces; it contains styles that
// were specified in an instance tag of an MXML component
// (if this CSSStyleDeclaration is attached to a UIComponent).
if (factory != null)
{
factory.prototype = {};
o = new factory();
v = o[styleProp];
if (v !== undefined) // must use !==
return v;
}
// Next look in the style object that this CSSStyleDeclaration's
// defaultFactory function produces; it contains styles that
// were specified on the root tag of an MXML component.
if (defaultFactory != null)
{
defaultFactory.prototype = {};
o = new defaultFactory();
v = o[styleProp];
if (v !== undefined) // must use !==
return v;
}
// Return undefined if the style isn't specified
// in any of these three places.
return undefined;
}
Is there a CSS selector for the first element of every visual row of block items?
That is, imagine having 20 block elements such that they flow across multiple lines to fit in their parent container; can I select the leftmost item of each row?
It's doable in JavaScript by looking at the top position of all of the elements, but is it possible in plain CSS?
Yes, Its possible through CSS but only if you can fix the elements in every row.
Since you haven't provided your case, here is an example.
Suppose, your elements are stacked up in a ul and li pattern and are three lists in a row, then you can use the following css snippet.
li:first-child, li:nth-child(3n+1) {
background: red;
}
Demo
No, there is no selector for this, you'll need to use JavaScript.
For reference, the following is a good reference to CSS selectors:
http://www.w3.org/wiki/CSS/Selectors
Unfortunately this is not possible with CSS alone. I ran into this issue when I wanted to ensure that the left most floated elements on each row always start on a new line.
I know you were looking for a CSS solution but I wrote this jQuery plugin that identifies the first element on each visual row and applies "clear:left" to it (you could adapt it to do anything).
(function($) {
$.fn.reflow = function(sel, dir) {
var direction = dir || 'both';
//For each conatiner
return this.each(function() {
var $self = $(this);
//Find select children and reset clears
var $elems = sel ? $self.find(sel) : $self.children();
$elems.css('clear', 'none');
if ($elems.length < 2) { return; }
//Reference first child
var $prev = $elems.eq(0);
//Compare each child to its previous sibling
$elems.slice(1).each(function() {
var $elem = $(this);
//Clear if first on visual row
if ($elem.position().top > $prev.position().top) {
$elem.css('clear', direction);
}
//Move on to next child
$prev = $elem;
});
});
};
})(jQuery);
See this codepen example http://codepen.io/lukejacksonn/pen/EplyL
Based on the work by #lukejacksonn
This one adds or removes a class on window resize.
(function ($) {
$.fn.reflow = function (sel, className) {
if (className == null) throw new Error('className must be set');
//For each conatiner
return this.each(function () {
var $self = $(this);
//Find select children and reset clears
var $elems = sel ? $self.find(sel) : $self.children();
if ($elems.length < 2) {
return;
}
//Reference first child
var $prev = $elems.eq(0);
$elems.each(function () {
$(this).removeClass(className);
});
//Compare each child to its previous sibling
$elems.slice(1).each(function () {
var $elem = $(this);
//Clear if first on visual row
if ($elem.position().top > $prev.position().top) {
$elem.addClass(className);
}
//Move on to next child
$prev = $elem;
});
});
};
const markFirstRowElement = function () {
$(".cd-progress-indicator").reflow('li', 'first-row-element');
}
$(function () {
markFirstRowElement();
$(window).resize(markFirstRowElement);
});
})(jQuery);
I'm using tinyMCE for small site, that is used by people to write simple articles. Usualy they write in MS word and copy text to tinyMCE and submit this.
That's why I only allowed few tags:
valid_elements: "a[href|target],strong/b,em/i,div[align],br,p[style|align],ul,li,ol,table,tr,td,iframe[*],img[*]",
But despite allowing img[*] after inserting image by 'Insert/edit image' only:
<img alt=""/>
appears in code. Same goes for iframe (which is complitly removed)
I've already tried every combination of valid_elements with full list of img and iframe attributes and with extended_valid_elements.
When I remove valid_elements clause everything works fine, but then word formatting which is not allowed (h1, h2, etc) is messing up styles.
TinyMCE version is 3.4.2.
I am using the paste_preprocess setting with the tinymce paste plugin and i filter out unwanted tags there. Here is an example:
in your tinymce init:
paste_preprocess : function(pl, o) {
//if(console) console.log('Object', o);
//if(console) console.log('Content:', o.content);
// usage param1 = the string to strip out tags from, param2 = tags to keep in the string
o.content = ir.im.strip_tags( o.content,'<p><div><br><br/>' );
},
Help function to strip out tags:
strip_tags = function (str, allowed_tags) {
var key = '', allowed = false;
var matches = []; var allowed_array = [];
var allowed_tag = '';
var i = 0;
var k = '';
var html = '';
var replacer = function (search, replace, str) {
return str.split(search).join(replace);
};
// Build allowes tags associative array
if (allowed_tags) {
allowed_array = allowed_tags.match(/([a-zA-Z0-9]+)/gi);
}
str += '';
// Match tags
matches = str.match(/(<\/?[\S][^>]*>)/gi);
// Go through all HTML tags
for (key in matches) {
if (isNaN(key)) {
// IE7 Hack
continue; }
// Save HTML tag
html = matches[key].toString();
// Is tag not in allowed list? Remove from str!
allowed = false;
// Go through all allowed tags
for (k in allowed_array) { // Init
allowed_tag = allowed_array[k];
i = -1;
if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+'>');}
if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+' ');}
if (i != 0) { i = html.toLowerCase().indexOf('</'+allowed_tag) ;}
// Determine
if (i == 0) { allowed = true;
break;
}
}
if (!allowed) {
str = replacer(html, "", str); // Custom replace. No regexing
}
}
return str;
};