I am new to JQuery, and have been trying to implement a tabbed interface where the tabs are added dynamically and their contents loaded via Ajax. I am using JQuery-ui tabs. I have been trying to solve this problem for days, and have been googling all around and read all relevant threads here in SO. Right now, the interface works if I add only one tab - the tab is created, it is selected, and its content loaded via Ajax. However, when I add a second tab, its content seem to be properly loaded, but when I select the first tab, I see the contents of second tab appended to the contents of the first tab, then I am no longer able to switch between tabs.
I am working on Rails 3. The code is in Coffeescript, but I think it should be easy to read for any Javascript'er. Here are some notes:
$('a.edit') is my selector to add the tab. To avoid multiple firings, I first check if the selector has already been bound before biding the adding of the tab with the mouse click
the tab close works well
the urls and tab name are passed as attributes. The urls point to html forms (via partials in Rails)
in the generated html, when I add a tab, two ui-tab-panel's are created with ids "ui-tabs-1" and "ui-tabs-2". The tab has an href that points to the second. Only the first has ".ui-tabs-hide".
when I add the second tab, I'll have four ui-tab-panel's, with the tabs pointing to "ui-tabs-2" and "ui-tabs-4", but none of them have ".ui-tabs-hide".
Here is the code
$(->
if !($('a.edit').is('.bound'))
$('a.edit').on('click', ->
addTab($(this).attr('url'), $(this).attr('tag'))
)
$('a.edit').addClass('bound')
$tabs = $('#tabs').tabs
#$tabs.tabs
closable: true
cache: true
tabTemplate: '<li>#{label} <span class="ui-icon ui-icon-close">Remove Tab</span></li>'
add: (event, ui) ->
$tabs.tabs('select', '#' + ui.panel.id)
addTab = (url, tab_name)->
$tabs.tabs('add',url,tab_name)
$( "#tabs span.ui-icon-close" ).live(
"click", ->
index = $( "li", $tabs ).index( $( this ).parent() )
$tabs.tabs( "remove", index )
)
To fix the problem, I introduced some minor changes. The major one was to add the line $tabs = $('#tabs') so all the references and method calls to tab should refer to the selector itself. I am not sure why, but before I had $tabs = $('#tabs').tabs( ... ). Another change was one needed in the cases where the selector $('a.edit') was added dynamically. Because the selector may not exist when the page is initally loaded, I changed the binding from .on('click,-> ) to .live('click', ->), and changed the flag so a new '.bounded' class is added to #tabs to prevent multiple firing.
$(->
$tabs = $('#tabs')
if !($tabs.is('.bound'))
$('a.edit').live('click', ->
addTab($(this).attr('url'), $(this).attr('tag'))
)
$tabs.addClass('bound')
$tabs.tabs
closable: true
cache: true
tabTemplate: '<li>#{label} <span class="ui-icon ui-icon-close">Remove Tab</span></li>'
add: (event, ui) ->
$tabs.tabs('select', '#' + ui.panel.id)
addTab = (url, tab_name)->
$tabs.tabs('add',url,tab_name)
$( "#tabs span.ui-icon-close" ).live(
"click", ->
index = $( "li", $tabs ).index( $( this ).parent() )
$tabs.tabs( "remove", index )
)
Related
I'm using CKEditor and I want to indent just the first line of the paragraph. What I've done before is click "Source" and edit the <p> style to include text-indent:12.7mm;, but when I click "Source" again to go back to the normal editor, my changes are gone and I have no idea why.
My preference would be to create a custom toolbar button, but I'm not sure how to do so or where to edit so that clicking a custom button would edit the <p> with the style attribute I want it to have.
Depending on which version of CKE you use, your changes most likely disappear because ether the style attribute or the text-indent style is not allowed in the content. This is due to the Allowed Content Filter feature of CKEditor, read more here: http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter
Like Ervald said in the comments, you can also use CSS to do this without adding the code manually - however, your targeting options are limited. Either you have to target all paragraphs or add an id or class property to your paragraph(s) and target that. Or if you use a selector like :first-child you are restricted to always having the first element indented only (which might be what you want, I don't know :D).
To use CSS like that, you have to add the relevant code to contents.css, which is the CSS file used in the Editor contents and also you have to include it wherever you output the Editor contents.
In my opinion the best solution would indeed be making a plugin that places an icon on the toolbar and that button, when clicked, would add or remove a class like "indentMePlease" to the currently active paragraph. Developing said plugin is quite simple and well documented, see the excellent example at http://docs.ckeditor.com/#!/guide/plugin_sdk_sample_1 - if you need more info or have questions about that, ask in the comments :)
If you do do that, you again need to add the "indentMePlease" style implementation in contents.css and the output page.
I've got a way to indent the first line without using style, because I'm using iReport to generate automatic reports. Jasper does not understand styles. So I assign by jQuery an onkeydown method to the main iframe of CKEditor 4.6 and I check the TAB and Shift key to do and undo the first line indentation.
// TAB
$(document).ready(function(){
startTab();
});
function startTab() {
setTimeout(function(){
var $iframe_document;
var $iframe;
$iframe_document = $('.cke_wysiwyg_frame').contents();
$iframe = $iframe_document.find('body');
$iframe.keydown(function(e){
event_onkeydown(e);
});
},300);
}
function event_onkeydown(event){
if(event.keyCode===9) { // key tab
event.preventDefault();
setTimeout(function(){
var editor = CKEDITOR.instances['editor1'], //get your CKEDITOR instance here
range = editor.getSelection().getRanges()[0],
startNode = range.startContainer,
element = startNode.$,
parent;
if(element.parentNode.tagName != 'BODY') // If you take an inner element of the paragraph, get the parentNode (P)
parent = element.parentNode;
else // If it takes BODY as parentNode, it updates the inner element
parent = element;
if(event.shiftKey) { // reverse tab
var res = parent.innerHTML.toString().split(' ');
var aux = [];
var count_space = 0;
for(var i=0;i<res.length;i++) {
// console.log(res[i]);
if(res[i] == "")
count_space++;
if(count_space > 8 || res[i] != "") {
if(!count_space > 8)
count_space = 9;
aux.push(res[i]);
}
}
parent.innerHTML = aux.join(' ');
}
else { // tab
var spaces = " ";
parent.innerHTML = spaces + parent.innerHTML;
}
},200);
}
}
I want to make input type="file" becomes available and clicked only when I click on some element, which is also activated it (for example, stylized span).
For this I have the Javascript parameters on span:
onclick="document.getElementById('upload_hidden').Disabled = false;
document.getElementById('upload_hidden').Click();"
But the trouble is that in Firefox only first click removes the input attribute disabled and second - opens the file selection window. In Chrome - all OK: input become enabled and clicked by first span click.
Why, first click in Firefox does not work ? :(
http://jsfiddle.net/ey47G/
P.S. In firefox v21 - all OK. Firefox v25 and v26 - have this trouble.
I could imagine that the script is already ahead when it tries to click the button - but the button is still disabled
var f = document.getElementById('f');
var s = document.getElementById('s');
s.onclick = function () {
f.removeAttribute('disabled');
setTimeout(function(){ f.click(); }, 100); // run the explorer after 100 ms
}
This does work.
http://plnkr.co/edit/9syOfSJHaJ4b3bhRufpv?p=preview
I'm having a inline editable div. I can type, delete, add. Works great. I wanted the text within he div to be selected on focus (or if you click it). So I added the following to the code
var editor = CKEDITOR.instances.div#{attr};
var element = editor.document.getById('div#{attr}');
editor.getSelection().selectElement( element );
This works too. Fully selected on focus. However, if I press the delete key or any other character key to overwrite the programmatically selected text, it doesn't change. It's as if more than only the text is selected, and the browser doesn't let me delete it. If I select the text manually, it works.
The selection#selectElement method will start selection before passed element and end after it. This means that not only editable's content will be selected but also non-editable parts of contents outside it and therefore selection may not be editable.
This is a correct solution:
var editor = CKEDITOR.instances.editable,
el = CKEDITOR.document.getById( 'editable' ),
range = editor.createRange();
editor.focus();
range.selectNodeContents( el );
range.select();
But the easiest solution is to use selectAll command defined in selectall plugin:
editor.execCommand( 'selectAll' );
I created a simple Jquery slider:
<div id="slider"></div>
and attach one text input field to the slider handler by using Javascript:
$( "#slider" ).slider();
var value = "<input id='handler1InputValue' type = 'text' spellcheck = 'false' style='position:absolute;width:70px;height:15px;text-align:center;left:-2px;font-size:10px;display:block;' ></input>";
$( ".ui-slider-handle" ).html(value);
$( ".ui-slider-handle" ).unbind();
$( "#handler1InputValue" ).val(77777);
But in Firefox, the cursor does not follow mouse click in the text input field, mouse selection doesn't work as well, while everything works in Chrome side.
Anybody know how to solve the problem in Firefox side? And you can try the test sample here: slider with text input field
This seems like a really easy question, but I can't seem to find the answer.
Now that toggle() is deprecated for click events, how would I have say a button add DOM elements on the first click, then remove those same DOM elements on the second click?
Also.... how do I remove contents from a div I have inserted content into (using load()) without removing the div itself? Using remove() removes the div.
use empty() to clear an elements inner html
As for the toggle issue, you can toggle a class on the element and test for that class:
$('#myDiv').on('click', function(){
if(! $(this).hasClass('clicked') ){
/* code for first click*/
}else{
/* code for second click*/
}
$(this).toggleClass('clicked')
})
your click would first check for the presence of the dom elements that get added (use an id perhaps).
if $('div#id of the stuff you add')
$('element exists...').remove();
else
$('div#id of where you want to add stuff').add( new code );
You can clear a div contents with:
divSomeDiv.html("");
or
divSomeDiv.empty();