jQuery Font Selector: show&hide with focus - javascript

I'm trying to implement a jQuery Font Selector in my project but I have some troubles to achieve it. I'm using the source code I found here jQuery Font Selector
You can see the demo here
Everything is working great, except the author of this code hasn't included a function that close the "scrolling menu" if we clicked anywhere else on the screen. You're forced to choose something inside that list for this list to close.
I'm going to paste the code here so it'll be easier to explain.
/**
* Font selector plugin
*/
jQuery.fn.fontSelector = function() {
var fonts = new Array(
'Arial,Arial,Helvetica,sans-serif',
'Arial Black,Arial Black,Gadget,sans-serif',
/* other fonts */);
return this.each(function(){
// Get input field
var sel = this;
// Add a ul to hold fonts
var ul = $('<ul class="fontselector"></ul>');
$('body').prepend(ul);
$(ul).hide();
jQuery.each(fonts, function(i, item) {
$(ul).append('<li>' + item.split(',')[0] + '</li>');
// Prevent real select from working
$(sel).focus(function(ev) {
ev.preventDefault();
// Show font list
$(ul).show();
// Position font list
$(ul).css({ top: $(sel).offset().top + $(sel).height() + 4,
left: $(sel).offset().left});
// Blur field
$(this).blur();
return false;
});
$(ul).find('a').click(function() {
var font = fonts[$(this).attr('class').split('_')[1]];
$(sel).val(font);
$(ul).hide();
return false;
});
});
});
}
From here I tried to modify the code, like adding $(ul).hide(); inside the blur function... Works BUT that i don't want the input to be manually editable. I don't want the user to be able to modify the content of the input except by selecting a font.
I hope you're not to confused with what I'm asking !
Thanks for your help

EDIT: Some changes after discussion:
http://jsfiddle.net/ahkEv/4/
Add the following inside jQuery.fn.fontSelector = function() {
$("body").click(function(){
$(".fontselector").hide();
});
Change $(sel).focus to
$(sel).click(function(ev) {
and add the following to $(ul).find('a').click(function(ev) {
ev.stopPropagation();

Related

jQuery slideDown not working on element with dynamically assigned id

EDIT: I cleaned up the code a bit and narrowed down the problem.
So I'm working on a Wordpress site, and I'm trying to incorporate drop-downs into my menu on mobile, which means I have to use jQuery to assign classes and id's to my already existing elements. I have this code that already works on premade HTML, but fails on dynamically created id's.
Here is the code:
...
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
$(document).on('click', '.dropdown-title', function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
//THIS LINE FAILS
$(currentAttrValue).slideDown(300).addClass('d-open');
}
e.preventDefault();
});
I've registered the elements with the class dropdown-title using $(document).on(...) but I can't figure out what I need to do to register the elements with the custom ID's. I've tried putting the event callback inside the .each functions, I've tried making custom events to trigger, but none of them will get the 2nd to last line of code to trigger. There's no errors in the console, and when I console log the selector I get this:
[ul#m0.sub-menu.dropdown-content, context: document, selector: "#m0"]
0
:
ul#m0.sub-menu.dropdown-content
context
:
document
length
:
1
selector
:
"#m0"
proto
:
Object[0]
So jQuery knows the element is there, I just can't figure out how to register it...or maybe it's something I'm not thinking of, I don't know.
If you are creating your elements dynamically, you should be assigning the .on 'click' after creating those elements. Just declare the 'on click' callback code you posted after adding the ids and classes instead of when the page loads, so it gets attached to the elements with .dropdown-title class.
Check this jsFiddle: https://jsfiddle.net/6zayouxc/
EDIT: Your edited JS code works... There also might be some problem with your HTML or CSS, are you hiding your submenus? Make sure you are not making them transparent.
You're trying to call a function for a attribute, instead of the element. You probably want $(this).slideDown(300).addClass('d-active'); (also then you don't need $(this).addClass('d-active'); before)
Inside submenus.each loop add your callback listener.
As you are adding the class dropdown-title dynamically, it was not available at dom loading time, that is why event listener was not attached with those elemnts.
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
// add callback here
$(this).click( function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
$(currentAttrValue).slideDown(300).addClass('d-active');
}
e.preventDefault();
});
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
Turns out my problem is that jQuery is adding to both the mobile menu and the desktop menu, where the desktop menu is being loaded first when I search for that ID that's the one that jQuery finds. So it turns out I was completely wrong about my suspicions.

Jquery hover event stuck on clone elements

I am creating an plugin with wordpress for the portfolio items. Everything works fine . But the issue is when i apply the filter the hover effect stopped working on the cloned items
also available JS FIDDLE
the jquery code is given below i tried
/* Scroll to Top Button */
jQuery(document).ready(function() {
// Animate Box Shadow on some elements
// Add the overlay. We don't need it in HTML so we create it here
// Clone portfolio items to get a second collection for Quicksand plugin
var $portfolioClone = jQuery(".rudra-portfolio").clone(true);
// Attempt to call Quicksand on every click event handler
jQuery(".rudra-portfolio-filter a").click(function(e) {
jQuery(".rudra-portfolio-filter li").removeClass("current");
// Get the class attribute value of the clicked link
var $filterClass = jQuery(this).parent().attr("class");
if ($filterClass == "all") {
var $filteredPortfolio = $portfolioClone.find("li");
} else {
var $filteredPortfolio = $portfolioClone.find("li[data-type~=" + $filterClass + "]");
}
// Call quicksand
jQuery("ul.rudra-portfolio").quicksand($filteredPortfolio, {
duration: 500,
easing: 'easeInOutQuad'
});
jQuery(this).parent().addClass("current");
// Prevent the browser jump to the link anchor
e.preventDefault();
})
jQuery(".port-li").click(function() {
jQuery(this).find('.content-wrapper').slideDown();
});
jQuery(".overeffect").mouseover(function() {
jQuery(this).find('.content-wrapper').slideDown();
});
jQuery("#portfolio-grid li").mouseleave(function() {
jQuery('.content-wrapper').slideUp(500);
});
});
hour effect is working fine for first and second time , but after that it stopped working .
Update
I also tried this Jquery clone
solved by me ..
i just need to use this
jQuery(document).on('hover',".overeffect",function(){
jQuery(this).find('.content-wrapper').slideDown();
});

CKEditor default style for styleCommand (format styles with buttons)

I have created a CKEditor plugin which does the base p, h2, h3, h4 formatting with custom buttons (instead of the stylescombo). It works great, but if I uncheck an element (ex. 'h2'), sets the 'div' tag as parent element for the row. I want to be the 'p' as the default element and also the 'p' button can't be unchecked (unless I clicking on another, ex. 'h2' button). How is this possible?
The plugin looks like:
CKEDITOR.plugins.add('stylesbuttons_custom',{
lang:'en',
icons:'p,h2,h3,h4',
init:function(editor){
var order=0;
var addButtonCommand=function(buttonName,buttonLabel,commandName,styleDefiniton){
if (!styleDefiniton)
return;
var style=new CKEDITOR.style(styleDefiniton);
editor.attachStyleStateChange(style,function(state){
!editor.readOnly && editor.getCommand(commandName).setState(state);
});
editor.addCommand(commandName,new CKEDITOR.styleCommand(style));
if (editor.ui.addButton){
editor.ui.addButton(buttonName,{
label:buttonLabel,
command:commandName,
toolbar:'basicstyles,'+(order+=10)
});
}
};
var lang=editor.lang.stylesbuttons_custom;
addButtonCommand('P',lang.p,'p',{element:'p'});
addButtonCommand('H2',lang.h2,'h2',{element:'h2'});
addButtonCommand('H3',lang.h3,'h3',{element:'h3'});
addButtonCommand('H4',lang.h4,'h4',{element:'h4'});
}
});
I load the plugin like:
config.extraPlugins='stylesbuttons_custom';
I put buttons to toolbar like:
config.toolbar:[['P','H2','H3','H4','Pre']];
Here is a screenshot about the problem:
Cross posting my answer from CKEditor forum.
I think that you need to write your own command instead of using CKEDITOR.styleCommand.
It should work exactly like CKEDITOR.styleCommand when style is not yet applied on current selection.
But when clicked again it should apply the paragraph style, not remove the previously applied style. E.g:
styleCommand.prototype.exec = function( editor ) {
editor.focus();
if ( this.state == CKEDITOR.TRISTATE_OFF )
editor.applyStyle( this.style );
else if ( this.state == CKEDITOR.TRISTATE_ON )
editor.applyStyle( paragraphStyle );
};
PS. I created a ticket: http://dev.ckeditor.com/ticket/10190 because I think that removing block style should revert back to paragraph (in enterMode=P). For now use the above workaround.
Yes, #Reinmar notifies that there is an error in the CKEditor's style.js where the this._.enterMode is not defined.
Doing this on style.js, resolve the problem:
this._ = {
definition: styleDefinition,
enterMode: CKEDITOR.config.enterMode
};
And from now on when a style button is unchecked the block changes to the default 'p' element.
Now my complete working plugin looks like:
(function(){
CKEDITOR.plugins.add('custombuttons',{
lang:'hu,en,de,ro',
init:function(editor){
var order=0,t=this,lang=editor.lang.custombuttons;
// addButtonCommand helper
var addButtonCommand=function(buttonName,buttonLabel,commandName,styleDefiniton){
var style=new CKEDITOR.style(styleDefiniton);
var styleCommand=function(style){
this.style=style;
this.allowedContent=style;
this.requiredContent=style;
this.contextSensitive=true;
};
styleCommand.prototype={
exec:function(editor){
editor.focus();
if (this.state==CKEDITOR.TRISTATE_OFF)
editor.applyStyle(this.style);
else if (this.state==CKEDITOR.TRISTATE_ON)
editor.removeStyle(this.style);
if(commandName!='fakecommand'){editor.execCommand('fakecommand');editor.execCommand('fakecommand');} /* hack to change button state properly */
},
refresh:function(editor,path){
this.setState(path&&this.style.checkApplicable(path)?(this.style.checkActive(path)?CKEDITOR.TRISTATE_ON:CKEDITOR.TRISTATE_OFF):CKEDITOR.TRISTATE_DISABLED);
}
};
editor.addCommand(commandName,new styleCommand(style));
if(editor.ui.addButton){editor.ui.addButton(buttonName,{label:buttonLabel,command:commandName,toolbar:'basicstyles,'+(order+=10),icon:t.path+'images/'+commandName+'.png'});}
};
// _fakebutton (hack)
addButtonCommand('_fakebutton','','fakecommand',{element:'span'});
// style buttons
addButtonCommand('P',lang.p,'p',{element:'p'});
addButtonCommand('H2',lang.h2,'h2',{element:'h2'});
addButtonCommand('H3',lang.h3,'h3',{element:'h3'});
addButtonCommand('H4',lang.h4,'h4',{element:'h4'});
addButtonCommand('Pre',lang.pre,'pre',{element:'pre'});
addButtonCommand('Mini',lang.mini,'mini',{element:'p',attributes:{class:'mini'}});
addButtonCommand('Important',lang.important,'important',{element:'span',attributes:{class:'important'}});
addButtonCommand('Comment',lang.comment,'comment',{element:'span',attributes:{class:'comment'}});
addButtonCommand('Mark',lang.mark,'mark',{element:'mark'});
addButtonCommand('ImgLeft',lang.imgLeft,'imgLeft',{element:'img',attributes:{class:'imgleft'}});
addButtonCommand('ImgRight',lang.imgRight,'imgRight',{element:'img',attributes:{class:'imgright'}});
addButtonCommand('ImgCenter',lang.imgCenter,'imgCenter',{element:'img',attributes:{class:'imgcenter'}});
// button shortcut keys
editor.setKeystroke(
[
[CKEDITOR.CTRL+48,'p'], // Ctrl+0
[CKEDITOR.CTRL+49,'h2'], // Ctrl+1
[CKEDITOR.CTRL+50,'h3'], // Ctrl+2
[CKEDITOR.CTRL+51,'h4'], // Ctrl+3
]);
}
});
})();
There is still a hack in the code. I needed to run a 'fakecommand' to really update (refilter?) the changed tags and all its parent tags. For example the 'p.mini' button caused problems (the state was not updated) when clicked multiple time. So there is still an unelegant solution. Any idea how to force to update or refilter the code after a style is applied?

JScrollPane Plugin - Reinitialize on Collapse

I'm trying to get JScrollPane to reinitialize on expand/collapse of my accordion found here. You can demo the accordion by clicking on one of the parents (Stone Tiles, Stone Sinks, Stone Wall Clading, etc).
Right now I set it as a click event using the following JQuery...
var pane = $('.menuwrap')
pane.jScrollPane();
var api = pane.data('jsp');
var i = 1;
$("ul#widget-collapscat-5-top > li.collapsing").click(function() {
$(this).delay(3000);
api.reinitialise();
});
It seems to work when you click the parent the second time, but not the first. I have no idea why but I went into trying to edit the JS for the accordion so that I can add this function when the collapse is complete (as opposed to trying to do this click workaround). The collapse JS can be viewed here.
I tried to add the JS for the reinitialize function here, but I think I'm not doing something properly.
May you point me in the right direction?
Thanks!
The api.reinitialise() is working properly. What is happening is that it updates the size when you click, and at this moment the element is not expanded yet. You may notice that if you expand, colapse and expand again the same section, nothing happens. But if you expand one and then click another one, the ScrollPane will adjust to the size of the first expanded element.
You can solve this with events: place $(this).trigger('colapseComplete') when the colapse ends. Then you can use:
//Listening to the colapseComplete event we triggered above
$("#widget-collapscat-5-top > li.collapsing").on('colapseComplete', function() {
api.reinitialise();
});
Maybe you can alter the addExpandCollapse function to call the reinitialise function at the end of each of its click actions this way :
function addExpandCollapse(id, expandSym, collapseSym, accordion) {
jQuery('#' + id + ' .expand').live('click', function() {
if (accordion==1) {
var theDiv = jQuery(this).parent().parent().find('span.collapse').parent().find('div');
jQuery(theDiv).hide('normal');
jQuery(this).parent().parent().find('span.collapse').removeClass('collapse').addClass('expand');
createCookie(theDiv.attr('id'), 0, 7);
}
jQuery('#' + id + ' .expand .sym').html(expandSym);
expandCat(this, expandSym, collapseSym);
api.reinitialise(); // HERE
return false;
});
jQuery('#' + id + ' .collapse').live('click', function() {
collapseCat(this, expandSym, collapseSym);
api.reinitialise(); // and HERE
return false;
});
}
and to be on a safer side, make sure you have the var api = pane.data('jsp'); line before the above piece of code anywhere in the file.

jQuery conditionally change events depending on .html( 'string' ) values

http://jsfiddle.net/motocomdigital/Qh8fL/4/
Please feel free to change the heading if you think I've worded it wrong.
General
I'm running a wordpress site with multilingual control. And my menu/navigation is dynamic, controlled via the wordpress admin. The multilingual language plugin also changes the dynamic menu/navigation content, as well as page content.
My Contact button, which is in the dynamic navigation, opens a sliding menu using jQuery. Very simple animation using top css. The contact button is on the page twice, hence why I'm not using the .toggle for iterations. See jsFiddle.
Script
var $button = $(".contact-button"),
// var for button which controls sliding div
$slide = $("#content-slide");
// var for the div which slides up and down
$button.on('click', function () {
// function for when button is clicked
if ($button.html() == 'Close') {
// run this if button says 'Close'
$slide.stop().animate({ top: "-269px" }, 300);
// close slide animation
$button.html('Contact');
// change text back to 'Contact'
} else {
// else if button says Contact or anything else
$slide.stop().animate({ top: "0" }, 300);
// open slide animation
$button.html('Close');
// change text to 'Close'
}
});
Problem
Because I'm running multilingual on the site. The navigation spelling changes. See jsFiddle flag buttons for example. This is fine, the animation still runs OK, because it's using the button class 'contact-button'.
But because I'm using the .html to replace the text of the button to "Close" and then on the second iteration, back to "Contact" - obviously this is a problem for other languages, as it always changes to English 'close' and back to English 'Contact'
But my three languages and words that I need the iterations to run through are...
Contact - Close
Contatto - Cerca
Contacto - Chiudere
Can anyone help me expand my script to accommodate three languages, all my attempts have failed. The jsFiddle has the script.
The language functionality in the fiddle is only for demo purposes, so the iteration sequence can be tested from the beginning. I understand if you change the language whilst the menu is open (in the fiddle), it will confused it. But when the language is changed on my site, the whole page refreshes, which closes the slide and resets the sequence. So it does not matter.
Any pro help would be awesome thanks!!!
MY POOR ATTEMPT, BUT YOU CAN SEE WHAT I'M TRYING TO ACHIEVE
var $button = $(".contact-button"),
// Var for button which controls sliding div
$slide = $("#content-slide");
// Var for the div which slides up and down
$button.on('click', function () {
// function for when button is clicked
if ($button.html() == 'Close' || 'Cerca'|| 'Chiudere' ) {
// run this if button says Close or Cerca or Chiudere
$slide.stop().animate({ top: "-269px" }, 300);
// Close slide animation
$(function () {
if ($button.html(== 'Close') {
$button.html('Contact'); }
else if ($button.html(== 'Cerca') {
$button.html('Contatto'); }
else ($button.html(== 'Chiudere') {
$button.html('Contacto'); }
});
// Change text back to Contact in correct language
} else {
// else if button says Contact or anything else
$slide.stop().animate({ top: "0" }, 300);
// Open slide animation
$(function () {
if ($button.html(== 'Contact') {
$button.html('Close'); }
else if ($button.html(== 'Contatto') {
$button.html('Cerca'); }
else ($button.html(== 'Contacto') {
$button.html('Chiudere'); }
});
// Change text back to Close in the correct language
}
});
See my attempt script above which is not working on this jsFiddle.
Here's a working example: http://jsfiddle.net/Qh8fL/2/
When one of the language buttons gets clicked, it stores the strings for Contact and Close using jQuery's .data() method. Then, when the contact/close button gets clicked, it refers to those strings rather than having it hard-coded.
Here are the relevant lines of code:
$("#english").click(function() {
$(".contact-button").html('Contact').data('langTxt',{contact:'Contact',close:'Close'});
});
$("#spanish").click(function() {
$(".contact-button").html('Contatto').data('langTxt',{contact:'Contatto',close:'Close'});
});
$("#italian").click(function() {
$(".contact-button").html('Contacto').data('langTxt',{contact:'Contacto',close:'Close'});
});
if ($button.html() == 'Close') {
//...
$button.html($button.data('langTxt').contact);
} else {
//...
$button.html($button.data('langTxt').close);
}
All you need to do to modify the "close" text appropriately is by editing the close property inside the calls to data() that occur in each of the click events.
You should never depend on label strings ... especially in a multilingual environment. Instead you should use placeholders that you store in an attribute (maybe using .data()). Then you write your own setters for the labels depending on the value of the attribute.
var myLabels = {'close': ['Close', 'Cerca', 'Chiudere'], 'contact' : ['Contact', 'Contatto', 'Contacto']};
var currLang = 2; // to select italian
....
// to set the label
$button.data('mylabel', 'close');
$button.html(myLabels['close'][currLang]);
....
if($button.data('mylabel') == 'close') {
$button.data('mylabel', 'contact');
$button.html(myLabels['contact'][currLang]);
} else {
$button.data('mylabel', 'close');
$button.html(myLabels['close'][currLang]);
}

Categories

Resources