Polymer change custom element - javascript

I have a question regarding custom elements in polymer.
I have acustom element that has a style nested inside it's template, for a div inside the template like so:
<template>
<style>
#navWrapper{
height: auto;;
color:red;
position:fixed;
background-color:black;
width: 100%;
}
</style>
<div id="navWrapper"><content></content></div>
</template>
Now, I'd like to change the color of navWrapper when I scroll down the page.
I want to use jquery for that.
Therefore I have a script inside of my custom element like so:
<script>
Polymer('responsive-nav',{ready: function() {
$(window).scroll (function () {
var sT = $(this).scrollTop();
if (sT >= 100) {
$(this.$.navWrapper).css({backgroundColor : 'rgba(0,0,0,0.0)' })
}else {
...
}
})
} });
</script>
Now sadly that does nothing. I have put an alert(test) before the $(this.$.navWrapper) to find out if I even get to that point and I do. Also when I want to change the background color or something else from an element that lives in my normal HTML file it works. For example $("#testDiv").css({...}) changes. So my question is: How do I access the css of my element properly?

Looks like your JQuery CSS call is wrong.
I think it should be:
.css("background-color", "rgba(0,0,0,0.0)")
rather than
.css({backgroundColor : 'rgba(0,0,0,0.0)' })
Cross referencing what you've done with the JQuery docs, you've definately missed the '-' out of 'backgroundColor', but also I don't see anything in the docs that states using a JSON object to make the change.
You can however use an array of property names and values (Which is what I suspect you may have been trying to do)
Update (Approx 1 hour later)
Since Iv'e been wrestling with a not too dissimilar problem today (but involving bootstrap rather than jquery) I was already investigating things around similar concepts.
As a result, I took the OP's original code and started playing with it.
What I present below is a partial JQuery solution (we still use JQ's scroll detection) where I also figured out an alternate way of changing the style using polymers conditional binding syntax.
http://www.polymer-project.org/docs/polymer/expressions.html
Essentially what i did was to pass a user data object into the scroll event at set-up time.
This user object contained a property that reflects the current polymer object (This is needed so that the JQ handler when it fires can update polymer properties)
When the window scroll event occurs, the handler extracts this property, then uses it to get at a local variable inside the polymer element, and thus updating it with the current scroll top value.
Since that locally scoped property is part of the actual polymer object, ANY polymer data-binding can read it, at this point it's simply just a matter of creating a couple of styles, then using the expression binding to pick the correct style.
Remember, styles cascade, so you can easily just make one master style for the whole thing, then 2 styles that simply just change the background color as appropriate.
Expression bindings work by using the text on the left side of the : only if the expression on the right evaluates to true eg:
{{ {frogs: a == 1} }}
would replace the expression binding with '' if property 'a' was NOT equal to 1 and set it to 'frogs' if property 'a' was equal to 1.
Expression bindings however are singular in nature, so in order to have more than 1 expression binding you need to pass the entire thing through one of polymers filters, specifically the 'tokenList' filter.
once you do this, you can build a whole object of different checks up, so expanding on our previous example:
{{ {frogs: a == 1, tadpoles: a == 2} | tokenList }}
will now make the result be equal to '' if property 'a' was NOT equal to 1 and NOT equal to 2 , while setting the result to 'frogs' if property 'a' was equal to 1 and setting the result to 'tadpoles' if property 'a' was equal to 2.
you can expand this to as many checks as you like, but the more you add in (I'm guessing anyway - iv'e not tested it) the slower performance is likely to be.
For now, the code below will do exactly what you need, well once you make a few alterations so that it targets your own elements and set's your own styles up anyway :-)
<link rel="import" href="polymer.html">
<polymer-element name="x-mypolymercomponent">
<template>
<style>
.under100
{
background-color: green;
}
.over100
{
background-color: red;
}
</style>
<h1 class="{{ {under100: scroll_top <= 100, over100: scroll_top > 100} | tokenList }}">This header has a dynamic class</h1>
</template>
<script>
Polymer('x-mypolymercomponent', {
ready: function ()
{
$(window).scroll({scope: this}, function(event) {
var sT = $(this).scrollTop();
event.data.scope.scroll_top = sT;
})
},
scroll_top: 0,
});
</script>
</polymer-element>
Iv'e just tested this in the .NET project I'm currently working on, and it works fine in chrome 36, there are still problems in Firefox though, but this I think is possibly due to a bug I discovered last night so I wouldn't worry too much about it.
I have JQuery loaded at page level too, so it would appear that the component can pick up the page events just fine from it.
Give it a try see where you go from here, I'm about to adapt it for my specific issue, then turn it into a typescript module :-)

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>

Prototype not defined when accessing children on creation of custom-tag

__What I am trying todo____
Right now I am working with custom HTML5 tags. I am trying to create a tab-control element that is easy to set up. Todo this I create a parent element called 'tab-set' which works much like the 'ul' tag.
To insert tabs, you simply insert 'tab-element' tags (like 'li' tags). The tags can implement own behavior through custom prototypes which extend standardized element-prototypes such as the basic HTMLElement and are then registered with 'document.registerElement()'. At that point there are also opportunities to set callbacks that let you know whenever your element has been created or attached to something, which is what I use to do the necessary calculations on the placement of the individual tabs on the tab-control.
Let me say up-front that I've had trouble with this at first, then got it working, but upon rewriting the whole thing had troubles again for who knows why.
So, in the creation routine of the tab-set I iterate through all the child-tab-elements, calling their custom function 'setDimension', or atleast I am trying to. For some reason Chrome won't initialize the tab-element prototype (setDimension etc) before it has called both 'createdCallback' and 'attachedCallback' on my tab-set. This means that I can't call the child elements custom functions to set it's placement on creation of the tab-set.
Here you have some code samples of what I just described.
simple.html
...
<tab-set>
<tab-element>
<img>guybrush</img>
</tab-element>
<tab-element>
<img>le chuck</img>
</tab-element>
</tab-set>
...
tabs.js
...
tabSet = Object.create(HTMLDivElement.prototype);
tabSet.attachedCallback = function(){
for(/** calculations here **/)
listOfChildren[index].setDimensions(/** placement info **/);
//
// Chrome console: 'setDimensions' is not a function!
//
}
tabElement = Object.create(HTMLDivElement.prototype);
tabElement.setDimensions = function(/** placement info **/){
$(this).css(...);
}
document.registerElement('tab-set',tabSet);
document.registerElement('tab-element',tabElement);
...
The weird thing is that I have a working version of this, and yes, I have tried to emulate it's particular conditions such as for example loading the html-portion through jquery's .load() routine. But no matter what I do, I can not get this to work in my current script. What knowledge am I missing?
Thanks in advance for any help.
__ Solved __
All I had todo was add a link-tag inside the tab-set and have the tab-elements load it's containing style-class. I guess making the tab-elements have a css-class is somehow provoking Chrome to load their prototypes 'prematurely'.

Listen to specific changes on contenteditable?

Warning: not duplicate with existing questions, read through
I know I can have an event listen on changes on an contenteditable element.
What I would like is to be able to know what the changes are.
For example:
inserted "This is a sentence." at position X.
deleted from position X to Y.
formatted from X to Y with <strong>
Is that possible? (other than by doing a diff I mean)
The reason for this is to make a WYSIWYG editor of other languages than HTML, for example Markdown.
So I'd like to apply the changes to the Markdown source (instead of having to go from HTML to Markdown).
You may be able to do something with MutationObservers (falling back to DOM Mutation events in older browsers, although IE <= 8 supports neither) but I suspect it will still be hard work to achieve what you want.
Here's a simple example using MutationObservers:
http://jsfiddle.net/timdown/4n2Gz/
Sorry, but there is no way to find out what the changes are without doing a diff between the original content and the modified one when changes occur.
Are you looking for this
var strong=document.createElement("strong");
var range=window.getSelection().toString().getRangeAt(0);
range.surroundContents(strong);
this was for third part
You just need to select what you want to surround using real User interaction.
If you wanna do it dynamically
var range=document.createRange();
range.setStart(parentNode[textNode],index to start[X])
range.setEnd(parentNode[textNode],index to end[Y])
range.surroundContents(strong);
For 2nd Part
range.deleteContents()
1st part can be done by using simple iteration
var textnode=// node of the Element you are working with
textnode.splitText(offset)
offset- position about which text node splitting takes place[here==X]
Two child Nodes have been created of the parent editable Element
Now use simple insertBefore() on parent editable Element Node.
hope you will find it useful
The API you're looking for does not exist, as DOM nodes do not store their previous states.
The data / events you're wishing to get back are not native implementations in any browser Ive come across, and I struggle to think of a datatype that would be able to generically handle all those cases. perhaps something like this:
function getChanges() {
/* do stuff here to analyse changes */
var change = {
changeType : 'contentAdded',
changeStart : 50, /* beginning character */
changeContent : 'This is a sentence'
}
return change;
}
Since you're trying to get custom events / data, you're probably going to need a custom module or micro-library. Either way, to look at the changes of something, you need somehow be aware of what has changed, which can only be done by comparing what it was to what it is now.

DOCTYPE breaks style.display

I have a (legacy) JS function, that shows or hides child nodes of argument element. It is used in mouseover and mouseout event handlers to show-hide img tags.
The function looks like this:
function displayElem(elem, value, handlerRoot){
try{
var display = 'inline';
if(!value)
display = 'none';
if(handlerRoot)
elem.style.display = display;
var childs = elem.childNodes;
for (i = 0; i < childs.length; i++){
if(childs[i].nodeType == Node.ELEMENT_NODE){
childs[i].style.display = display;
alert("Node "+childs[i].tagName+" style set to " +childs[i].style.display);
}
}
}catch(e){
alert('displayElem: ' + e);
}
}
Here, value and handlerRoot are boolean flags.
This function works perfectly, if target html page has no doctype. Adding any doctype (strict or transitional) breaks this. Alert shows style has been set to the right value, but child elements are not displayed.
Would be good, if this function could work with any DOCTYPE.
Image (a child node of elem) is initialized like this (perhaps something is wrong here?):
var img = new Image();
img.style.cssText =
'background: transparent url("chrome://{appname}/content/dbutton.png") right top no-repeat;' +
'position: relative;' +
'height:18px;'+
'width:18px;'+
'display:none;';
JavaScript doesn't really work over plain HTML but on the DOM tree generated by the browser. Thus the DOCTYPE does not have a direct influence on JavaScript but on the way the browser handles invalid HTML and CSS.
I think the first step is to clean-up the HTML and make sure it's valid, esp. that tags are used in allowed places and properly nested. That will guarantee that the generated node tree is the same no matter the rendering mode.
You can also use your favourite browser tool (such as Firebug) the inspect the real tree and make sure nodes are placed where you think they are.
Update:
I wonder if when dealing with a document in standards mode (the document has a DOCTYPE), Firefox is inserting an implied element that it doesn't insert in backward-compat mode (no DOCTYPE), and so the image isn't an immediate child of elem but instead a child of this implied element that's then a child of elem; so you won't see the image in elem.childNodes. Walking through the code in a debugger is the best way to tell, but failing that, alert the tagName of each of the child nodes you're iterating through in the loop.
For example, with this markup:
<table id='theTable'>
<tr><td>Hi there</td></tr>
</table>
...Firefox will insert a tbody element, so the DOM looks like this:
<table id='theTable'>
<tbody>
<tr><td>Hi there</td></tr>
</tbody>
</table>
...but it won't be that specific example unless the DOCTYPE is a red herring, because I just tested and Firefox does that even in backward-compat mode. But perhaps you were testing two slightly different documents? Or perhaps it does it with some elements only in standards mode.
Original:
Not immediately seeing the problem, but I do see two issues:
i isn't declared in the function, and so you're falling prey to the Horror of Implicit Globals. Since your alert is showing the correct value, I can't see why that would be the problem.
url(..) in CSS doesn't use quotes. Yes they can, optionally.
Thanks to Álvaro G. Vicario. Though he didn't gave an exact answer, the direction was right.
I've checked the page with w3c validator, and found that my Image objects were missing src attribute. Thus, adding img.src = "chrome://{appname}/content/dbutton.png"; helped.
Still, I'm not sure, why the original code author used background style instead of src... Perhaps, that would remain a mystery. :)

In firefox, how can I change an existing CSS rule

In firefox, I have the following fragment in my .css file
tree (negative){ font-size: 120%; color: green;}
Using javascript, how do I change the rule, to set the color to red?
NOTE:
I do not want to change the element.
I want to change the rule.
Please do not answer with something like
...
element.style.color = 'red';
What you're looking for is the document.styleSheets property, through which you can access your css rules and manipulate them. Most browsers have this property, however the interface is slightly different for IE.
For example, try pasting the following in FF for this page and pressing enter:
javascript:alert(document.styleSheets[0].cssRules[1].cssText)
For me that yields the string "body { line-height: 1; }". There are methods/properties that allow you to manipulate the rules.
Here's a library that abstracts this interface for you (cross-browser): http://code.google.com/p/sheetup/
function changeCSSRule (stylesheetID, selectorName, replacementRules) {
var i, theStylesheet = document.getElementById(stylesheetID).sheet,
thecss = (theStylesheet.cssRules) ? theStylesheet.cssRules : theStylesheet.rules;
for(i=0; i < thecss.length; i++){
if(thecss[i].selectorText == selectorName) {
thecss[i].style.cssText = replacementRules;
}
}
};
You can change CSS rules in style sheets through the CSS Object Model (currently known as DOM Level 2 Style). However, if you literally have "tree (negative)" in your style sheet that rule will be dropped and not appear in the Object Model at all.
As there is no HTML element tree I am going to assume that tree is the id or class of another element.
You would first retrieve the DOM element by id:
var tree = document.getElementById("tree");
Now tree represents your DOM element and you can manipulate it any way you like:
tree.style.color = "red";
Here is a great reference for mapping css properties to their javascript equivalent.
I'm not sure you can do actual class/selector overrides. You would need to target each element that used the .tree class and set the CSS. The quickest and easiest way would be through jQuery (or another similar framework):
$('.tree').each(function() { this.style.color = "red"; });
You could even use the built-in CSS functions:
$('.tree').css('color', 'red');
(I did it the first way to show you how standard JS would do it. The $(...) part is jQuery for selecting all elements with the .tree class. If you're not using jQuery, you'd need alternative code.)
If tree is an ID, not a class (there should only be one on the page) so using getElementById should be fine. Your code should look like the other answer.
for( var i in document.getElementsByTagName("tree") ){
document.getElementsByTagName("tree")[i].style.color = "red";
}
As I said in another answer's comment, I've never seen this done how you want. I've only ever targeted elements the same way as the CSS renderer would and changed each element style.
I did see this though: jQuery.Rule
It sounds like it does what you want but the demo causes my browser to flip out a bit. I'd invite you to look at the source to see it really does do what you want, and if you want to use it without jQ, use it as a starting point.
Edit: yes this should work. It works by appending another <style> tag to the page and writing out your overrides within. It's fairly simple to follow if you wanted to port it to plain JS.
For debugging, you can use Firebug to change the CSS rules on-the-fly.
If you want to change the rendered css rules from one page request to the next then some sort of server-side scripting will be required. Otherwise the original style sheet would simply reload at the next page request.
If you want to use an event on the first page to force the server-side action then you can use AJAX to actually change the CSS rule for the user.
"I want to change the rule so that
when I navigate to the next page, I
don't have to make all the changes
again."
It sounds like what you might want then is a remote request ("ajax") back to the server with the request you want to make, and generate a dynamic stylesheet which is sent back to the client?
How/why is this Firefox specific?
I want to change the rule so that when I navigate to the next page, I don't have to make all the changes again.
There are two approaches I can think of here. Namely client side and/or server side.
Client side:
Store the theme setting into cookies and load them up next time by javascript.
Server side:
If your site have an login system, you may also store the user preference into the database and generate the webpages with this inforamtion in mind next time on.
Utimately, you are still writing things like element.style.color =. But, they should get what you want.

Categories

Resources