I've just started to use CKEditor and I can't manage to understand the API well enough to accomplish what I am aiming for.
Essentially, I have a few instances of the editor on the page. However, for the editor by the name of htmlInput, I want to collect the names of the form elements that are added to the editor. The closest I've gotten is to have an alert pop up when the appropriate dialogs are opened, but I haven't been able to extract the value of the name field of these boxes.
Here's what I have so far.
CKEDITOR.on('dialogDefinition', function (e) {
var dialogName = e.data.name;
var dialog = e.data.definition.dialog;
if(e.editor.name == 'htmlInput' && (dialogName=='checkbox' || dialogName=='radio' || dialogName=='textfield' || dialogName == 'textarea' || dialogName == 'select'))
{
dialog.on('show', function (ev) {
alert('here');
});
}
});
What you're trying to do is very unsafe. Imagine what if someone pasted such form element or used editor.insertHtml() method. They won't be collected. The better approach is as follows:
var form = {};
CKEDITOR.instances.editor1.dataProcessor.htmlFilter.addRules({
elements: {
$: function( element ) {
if ( element.name in { 'input' : 1, 'textarea': 1, 'button' : 1 } ) {
if ( !form[ element.name ] )
form[ element.name ] = [];
form[ element.name ].push( element );
}
}
}
});
Now when you can basically do the following:
CKEDITOR.instances.editor1.getData();
console.log( form );
Then you'll retrieve all the form elements (or elements of any kind) that belong to the document. Just make sure your form object is empty when serializing forms since i.e. htmlFilter is also executed when switching between souce mode <-> wysiwyg and it will continuously populate your list.
You can also basically use the following to retrieve elements by tag name (simple way IMO):
CKEDITOR.instances.editor1.document.getElementsByTag( 'input' );
Related
I have one Backbone Collection (named themeCollection) which items are listed on the webpage (DOM). The user can select one item from that list. I need to save user's selected item into the database together with other information. It comes out two ways from my head to implement this feature.
1) Get the selected list item from the DOM (by jquery)
addCard: function(e) {
e.preventDefault();
var formData = {};
// Get data from the form
$( '#modal-new-card form' ).children( 'input' ).each( function( i, el ) {
if ( $(el).val() != '' ) {
formData[ el.id ] = $(el).val();
}
$(el).val('');
});
// Get selected listed item from the DOM.
formData['theme'] = this.$el.find('div.colorSelected').attr('color');
// Code for saving into the database
// ...
}
2) Get the selected list item from the Backbone Collection
addCard: function(e) {
e.preventDefault();
var formData = {};
$( '#modal-new-card form' ).children( 'input' ).each( function( i, el ) {
if ( $(el).val() != '' ) {
formData[ el.id ] = $(el).val();
}
$(el).val('');
});
formData['theme'] = this.themeCollection.findWhere({selected: true});
}
The first way seems to me a little awkward. It touches DOM so it closely coupled upon the DOM. That's not good. Whenever the CSS class is changed, my app would be stopped working.
The second way would be a little more jobs to be done. I have to change themeModel's selected attribute to be true whenever the user clicks. When changing, I also have to set false to selected attributes of all other models in the collection.
Which way would be the better choice? If you have any other ways, please share me and suggest me.
It appears you need to learn more about Backbone, but I'll try to help...
You should be using a Model for maintaining the form data and add events via View to update model when things change. Upon submit, you can call model.toJSON() to save to the DB.
var NewCard = Backbone.Model.extend({
defaults: {
question: '',
explanation: '',
color: 'Blue'
}
})
Then setup a collection to hold the colors to select
var colors = new Backbone.Collection([
{color: 'Blue'},
{color: 'Gray'}
]);
Here is a working example
The example is far from complete, but should give you a picture.
Looks like that you shouldn't store it like Collection.
If it's only about choosing a color, it's better store it as model attribute ({"theme": "purple"}) and then send this model to server.
Markup:
<input type="radion" name="theme" value="yellow">
<input type="radion" name="theme" value="purple">
Your view:
function changeTheme() {
var cardData = this.$el.serializeArray(); // jQuery just for brevity
this.model.trigger('THEME_CHANGE', cardData);
}
Backbone.Collection.extend({
tagName: 'form',
events: {
'change [name="theme"]': changeTheme
}
});
Model just listen for THEME_CHANGE and process data.
A client has asked for all of the trademark symbols (™ and ®) on their website to be styled in a specific way; given the quantity in which they appear—everywhere from titles to body text and navigation—we've decided to do this with JavaScript.
What we want to do is find every instance of ™ and ® in the page text (but not inside element attributes) and wrap them in <sup> tags so we can style them in CSS.
This is the code we currently have:
Trademark = {
init: function () {
$('body').contents().each(function () {
var element = $(this);
if (element.html()) {
element.html(element.html().replace(/(?![^<]+>)™/gi, '<sup class="trademark">™</sup>'));
element.html(element.html().replace(/(?![^<]+>)®/gi, '<sup class="trademark">®</sup>'));
}
});
}
}
$(function () {
Trademark.init();
})
It works well, but we're now suffering the problem that JavaScript click events aren't being registered on elements that have had their contents replaced—I'm assuming because they're being removed from the DOM when they're being manipulated.
Is there a modification to this (to the JS or regex) that will stop this from happening? Thanks!
Filter for textNodes only and replace the innerHTML of the parentNode, that way the elements themselves are never replaced and the event handlers should stay intact.
Trademark = {
init: function () {
$('*').contents().each(function() {
if (this.nodeType == 3 && this.nodeValue) {
if ( this.nodeValue.indexOf('™') != -1 || this.nodeValue.indexOf('®') != -1 ) {
this.parentNode.innerHTML = this.parentNode.innerHTML.replace(/(?![^<]+>)(™|®)/gi, '<sup class="trademark">$1</sup>');
}
}
});
}
}
FIDDLE
I am displaying datas in a grid ,on click of active or inactive button i have to change the button ,functionality is working fine ,for changing icon i am unable to find the active clicked button ,in jquery we can use "this" ,but no idea in angular js ,pls help
$scope.activeSource = function(datasource,status)
{
$scope.loading = true;
$scope.activeInfo = {
datasource:datasource,
};
$scope.alerts = [];
if(status == "Stopped")
{
$scope.entityService.activeInfo($scope.activeInfo,
function( msg ) // success
{
$scope.loading = false;
$rootScope.successMsg.push(msg);
$('.icon-play').hide(); // this.
$('.icon-stop').show(); // this. no idea
},
function( msg ) // error
{
$scope.loading = false;
$rootScope.successMsg.push(msg);
}
);
You don't need to use this to access the button. Instead, in your controller create a javascript object that holds all the attributes for the button. Something like this:
$scope.myButton = {
src : 'foobar.png',
isVisible : true
};
Then, define your button like this:
<img ng-src="myButton.src" ng-show="myButton.isVisible" />
Now, when you want to modify any attribute of the button, you just need to change the javascript object myButton, and angular will take care of updating the actual button.
For example, if you want to hide the button:
// you don't need to do this
// $('#myButton').hide();
// instead just do this
$scope.myButton.isVisible = false;
Similarly, you can change the src of the image as well.
Please help me with a form I'm trying to do.
I have a dropdown select, all the options in the < select > have ID's, for example: one option has id="hide_me", other option has id="hide_none".
Here is the JS that I have for the form:
<?php
$script = "window.addEvent('domready', function() {
$('recipe').addEvent('change', function(event) {
if ( $('recipe')document.getElementById('hide_it').selected === true ) {
$('hide_me1').setStyle('opacity', '1');
$('hide_me2').setStyle('opacity', '1');
}
});
$('recipe').addEvent('change', function(event) {
if ( $('recipe')document.getElementById('hide_none').selected === true ) {
$('hide_me1').setStyle('opacity', '0');
$('hide_me2').setStyle('opacity', '0');
}
});
});
";
$doc =&JFactory::getDocument();
$doc->addScriptDeclaration( $script );
?>
"recipe" is the name and ID of the dropdown < select >
At the moment it's giving me a JS error like "SyntaxError: Unexpected identifier", could somebody help me please with this
your generated js looks like this:
window.addEvent('domready', function() {
$('recipe').addEvent('change', function(event) {
if ($('recipe') document.getElementById('hide_it').selected === true) {
$('hide_me1').setStyle('opacity', '1');
$('hide_me2').setStyle('opacity', '1');
}
});
$('recipe').addEvent('change', function(event) {
if ($('recipe') document.getElementById('hide_none').selected === true) {
$('hide_me1').setStyle('opacity', '0');
$('hide_me2').setStyle('opacity', '0');
}
});
});
if you use something like jslint / jshint or even paste in jsfiddle and press the jslint button, it will immediately report the problems.
however:
$('recipe') document.getElementById('hide_it').selected === true) makes no sense. I guess you are trying to read the option with id hide_it that is a child of recipe?
its the wrong thing to do but this would be something like:
$('recipe').getElement('#hide_it').get('selected'); // pointless as by id alone is faster and id is meant to be unique
document.getElement('#receipe #hide_id').get('selected'); // also pointless like above, alt syntax that allows you to combine selectors.
$('hide_it').get('selected'); // works but also wrong, not how you work with selects.
The correct way to obtain the value of a select with mootools will be simply:
$('receip').addEvent('change', function(){
// within this function, this === $('recipe');
var opacity = this.get('value') === 'hide_it' ? 1 : 0;
$$('#hide_me1,#hide_me2').setStyle('opacity', opacity);
// w/o a reference you could do in a single line:
$$('#hide_me1,#hide_me2').setStyle('opacity', +(this.get('value') == 'hide_it'));
});
this is still somewhat ineffective as it will lookup the 2 hide_me els every change event when they are probably static.
you should also stop using ids and pattern this based around classes, ids does not scale well.
I'm developing an extension, which listens to click events on elements.
Now I have two questions:
Is there a convenient way to detect whether an element is an input element? Like input, textarea in HTML, and textbox in XUL.
If the user clicked on an input element, how to get the position where the user clicked?
For example, there's an <input> element, with its value set to blah, and the user clicked between 'l' and 'a', how can I get the index(in this case it's 2)?
Every event has some data that gets passed with it in the event param. You can do something like this to figure out what was clicked on:
function clickFun(event){
if (event.target.nodeName == "INPUT") {
var type = event.target.getAttribute('type').toLowerCase();
if (type == 'text') {
console.log('text input');
} else if (type == 'checkbox') {
console.log('checkbox');
}
} else if (event.target.nodeName == "TEXTAREA") {
console.log('text area');
}
}
thing.onclick = clickFun;
You can do this with jQuery which gives you some easy functions to check out information about elements. Up to you if you want to try out a javascript framework.
$(':input').click(function(event){
var $this = $(this);
if ($this.is(':text')) {
console.log('text input');
} else if ($this.is(':checkbox')) {
console.log('checkbox');
} else if ($this.is(':textarea')) {
console.log('textarea');
}
});
To get the position of the cursor when they click in a text box or area try checking out this article:
http://www.dedestruct.com/2008/03/22/howto-cross-browser-cursor-position-in-textareas/
For #1: it's convenient to use the jQuery ":input" selector like this:
if ($(node).is(":input"))
alert("It's an input element!");
But generally, I don't think there is an easy way to tell XUL elements. Enumerating node names would be the simplest solution I could think of.