I have an instance of CKEditor on a page. I am trying to give the CKEditor's body a class or ID so it matches some styles I have defined in a stylesheet.
There is a API documentation that should give access to the respective DOM elements, but I can't seem to get it working. All objects I try to query that way turn out undefined.
Does anybody know how to do this, or how to properly address CKEditor's dom elements?
Edit: Thanks folks, nemisj's answer did it for me but for some reason, I don't get to set the "accepted" checkmark in this question.
Although that part of the API wasn't ported from 2.x at the time that this question was placed, now it's easier to use the bodyId and bodyClass config options.
Of course, the explanation by nemisj is good and can be useful for other things, but you must remember that each time that you switch away from design (to source view), the iframe is destroyed, so you'll need to reassign your attributes if you do it manually.
If you are talking about CKEditor( version 3), then there is a possibility to get any DOM instance inside the editor itself. Every CKEditor instance has reference to it's document via "document" property.
var documentWrapper = edit.document;
This reference represent some public wrapper for all CKEditor nodes, but it also has the direct reference to its node. You can retrieve by getting ["$"] property.
var documentNode = documentWrapper.$; // or documentWrapper['$'] ;
documentNode will represent the DOM instance of the document node inside the iframe. After you have the DOM instance, you can do whatever you want to do with DOM structure, Append, remove, replace classes, rebuild, etc. For example
documentNode.body.className = "zork";
I hope this should be enough.
I had the same problem today in trying to set the bodyClass like this:
CKEDITOR.replace( 'editor1',
{
fullPage : true,
bodyClass : 'myClass'
});
What I found is that in this version (3.3.1), if you set fullpage = true, setting the bodyId or bodyClass does not work, but if you set fullPage = false, it does work.
Hope this helps.
From the Manual:
<static> {String|Array} CKEDITOR.config.contentsCss
The CSS file(s) to be used to apply style to the contents. It should reflect the CSS used in the final pages where the contents are to be used.
config.contentsCss = '/css/mysitestyles.css';
config.contentsCss = ['/css/mysitestyles.css', '/css/anotherfile.css'];
Default Value:
<CKEditor folder>/contents.css
Don't know that editor, but as they all work the same way, you probably can't access the DOM elements created by the instance because they are created after the page has finished loading, and the DOM is ready as well. So, any new DOM elements added after that, theorically will not exist.
Still, you can try TinyMCE editor, wich has a "partnership" with jQuery javascript library to manipulate all you want, and the editor itself is pretty easy to change in almost every way.
Your queries may return undefined because the editor instances are placed inside an iFrame and your query is not looking there?
In config.js, write this code
config.bodyId = 'contents_id';
then you see body id in Ckeditor but when you want to access this id please use
$('#parent_id').find('iframe').contents().find('#within_iframe')
there $('#parent_id') means form_id or any parent which is simply way to access iframe. follow this code to access element in iframe
Related
Well, out of the box, jQuery does not have support for selecting nodes inside webcomponent(s). (probably because document.querySelector() does not work for shadow DOM (nor it should, by definition)).
Our previous codebase was somewhat dependent on jQuery and many of the devs do not want to let go of the simplicity of $(...) selection. So, I wrapped up this quick and dirty trick.
window.$$ = function (that, selector) {
return $(that.shadowRoot.querySelectorAll(selector));
}
Usage (inside a lifetime callback or whenever the host node can be accessed):
jqel = $$(this, '.myClass'); // this has reference to the host
The question is, is there a better way to go about this?
i have created a jquery-polymer plugin that has a lot of functions that may help you dealing with polymer shadow dom
https://github.com/digital-flowers/jquery-polymer
to select any element inside a polymer element lets say
<my-button id='button1'></my-button>
first you need to get the button shadow root using
$("#button1").getShadowRoot()
or
$("#button1").shadow()
this will return the button shadow root as jquery object then you can select anything inside it for example
$("#button1").shadow().find("ul > li:first")
cheers ;)
As far as I know Jquery permits passing context as parameter JqueryContext, so the proper way would be:
$('selector',context)
As an example:
var component1 = document.querySelector('qr-code');
// Find some img inside qr-code component
var img1 = $('img',component1)
I have a modal form that is generated using bootstrap 3. It doesn't look like there is a reliable way to determine when that form is being shown onscreen. I am attempting to create one. I attached two events to my DOM element that signal when it is shown and when it is hidden.
jq_modal_login_form = $('#modal-login-form')[0]
jq_modal_login_form.on('shown.bs.modal', function () {
jq_modal_login_form.active_onscreen = true;
});
jq_modal_login_form.on('hidden.bs.modal', function () {
jq_modal_login_form.active_onscreen = false;
});
I tried to give an attribute named active_onscreen to the DOM element above. When I look at the DOM element in the debugger later, the attribute is not present.
I should mention that I am VERY new to javascript. Is attribute even the right word to use here? It looks like attribute is a bit of a misnomer as well. It could be an attribute of the object but could also be an attribute of the object.attributes attribute, right? I assume the later is where styling ect., goes and is not what I want to change. Does anyone have some insight as to what I should be doing here?
In jQuery:
$('selector').attr('attribute_name', 'value');
However, you can should only use predefined attributes as creating custom attributes requires additional setup (see this question) that is not necessary in your case.
In your case, you may just want to add a active_onscreen class to the element. Classes are meant to be used to identify elements (and not just for CSS), so they are perfect for this applicaiton. You would use this to add a class to an element:
$('selector').addClass('active_onscreen').
When it is no longer active, you would use this to remove the class:
$('selector').removeClass('active_onscreen').
What you are doing here is adding a property of the DOM object - not an attribute of the element.
Adding an attribute does not necessarily make the property mirror it. Only built-in properties do this.
If you want to set an attribute, but not the property, you can use jQuery's .attr() method.
If you just want to see if a given modal is open, Bootstrap does that for you. You can check the bs.modal data attribute:
$("element").data('bs.modal').isShown;
or a class (but this method is prone to race conditions):
$('#myModal').hasClass('in');
In the past I've been able to modify the CSS on a page via an inline style tag.
I know this sounds horrible but it's for custom CSS writing while working on a kind of WYSIWYG (not with text though).
I used to do something like:
tag.styleSheet.cssText = myrules;
I don't know when exactly, but at some point IE started saying "Invalid Argument" when I try this. The real crux is that doing tag.innerHTML = 'body {}' gives Unable to set value of the property 'innerHTML': object is null or undefined which doesn't happen in any other browser.
EDIT
To be clear I am using an inline style tag. I am not trying to use the inline style attribute.
<style type="text/css" id="mytag"></style>
How can I change the inside of that tag?
EDIT 2
Please see this fiddle:
http://jsfiddle.net/tTr5d/
It appears that my solution of tag.styleSheet.cssText is identical to using styleSheets property. You can comment out the last definition of cssText to see it working as proposed by #Teemu. So now I'm real lost why it's not working in my app. If anyone has ideas what could break that functionality that would be great. In the meantime I'll be tinkering around my app.
IE is limited to 32 stylesheets. I like to forget that fact apparently, which seems to include inline style tags, on top of <link>.
I changed my sandbox to turn on minification so it would put the files together.
Then my code worked.
So it appears that when you go over the limit and insert via JS, you don't get a real error until you try what I did.
You can get a reference to a styleSheet object only via styleSheets collection (or imports collection). If you refer direct to the style element, you'll just get a HTML-element. (Check properties in both objects within simple for..in-loop, and see the difference)
This works in all IEs, and results are rendered immediately:
document.styleSheets['mytag'].addRule('BODY', 'background-color:red');
More info in MSDN: styleSheet object
You can use jQuery. If it's the inline style, you can use the .attr() function.
$("#myElement").attr('style')
otherwise, you can see what .css() has to offer. You can use that to get and set various CSS styles.
Other CSS related jQuery methods
I never had much luck with style elements and IE's innerHTML.
The dom methods are surer, even if you need to branch for IE;
without jquery-
function addNewStyle(str, title){
var el= document.createElement('style');
if(title) el.title= title;
if(el.styleSheet) el.styleSheet.cssText= str;
else el.appendChild(document.createTextNode(str));
document.getElementsByTagName('head')[0].appendChild(el);
return el;
}
I have a div with id #test that contains lots of html, including some youtube-embeds etc.
Somewhere in this div there is this text: "[test]"
I need to replace that text with "(works!)".
The normal way of doing this would of course be:
document.getElementById("test").innerHTML = document.getElementById("test").replace("[test]","(works!)");
But the problem is that if i do that the youtube-embeds will reload, which is not acceptable.
Is there a way to do this?
You will have to target the specific elements rather than the parent block. Since the DOM is changing the videos are repainted to the DOM.
Maybe TextNode (textContent) will help you, MSDN documentation IE9, other browsers also should support it
Change your page so that
[test]
becomes
<span id="replace-me">[test]</span>
now use the following js to find and change it
document.getElementById('replace-me').text = '(works!)';
If you need to change more than one place, then use a class instead of an id and use document.getElementsByClassName and iterate over the returned elements and change them one by one.
Alternatively, you can use jQuery and do it even simpler like this:
$('#replace-me').text('(works!)');
Now for this single replacement using jQuery is probably overkill, but if you need to change multiple places (by class name), jQuery would definitely come in handy :)
I'm trying to write a Firefox extension that adds elements to the loaded page. So far, I get the root element of the document via
var domBody = content.document.getElementsByTagName("BODY").item(0);
and create the new elements via
var newDiv = content.document.createElement("div");
and everything worked quite well, actually. But the problems came when I added a button with on onclick attribute. While the button is correctly displayed, I get an error. I already asked asked here, and the answer with document.createElement() (without content) works.
But if I remove the 'content.' everywhere, the real trouble starts. Firstly, domBody is null/undefined, no matter how I try to access it, e.g. document.body (And actually I add all elements _after_the document is fully loaded. At least I think so). And secondly, all other elements look differently. It's seem the style information, e.g., element.style.width="300px" are no longer considered.
In short, with 'content.document' everything looks good, but the button.onclick throws an error. with only 'document' the button works, but the elements are no longer correctly displayed. Does anybody see a solution for that.
It should work fine if you use addEventListener [MDN] (at least this is what I used). I read somewhere (I will search for it) that you cannot attach event listener via properties when creating elements in chrome code.
You still should use content.document.createElement though:
Page = function(...) {
...
};
Page.prototype = {
...
addButton : function() {
var b = content.document.createElement('button');
b.addEventListener('click', function() {
alert('OnClick');
}, false);
},
...
};
I would store a reference to content.document somewhere btw.
The existing answer doesn't have a real explanation and there are too many comments already, so I'll add another answer. When you access the content document then you are not accessing it directly - for security reasons you access it through a wrapper that exposes only actual DOM methods/properties and hides anything that the page's JavaScript might have added. This has the side-effect that properties like onclick won't work (this is actually the first point in the list of limitations of XPCNativeWrapper). You should use addEventListener instead. This has the additional advantage that more than one event listener can coexist, e.g. the web page won't remove your event listener by setting onclick itself.
Side-note: your script executes in the browser window, so document is the XUL document containing the browser's user interface. There is no <body> element because XUL documents don't have one. And adding a button won't affect the page in the selected tab, only mess up the browser's user interface. The global variable content refers to the window object of the currently selected tab so that's your entry point if you want to work with it.