I am using jSignature on my web page. This jquery plugin deletes one stroke at a time. I want behavior of "Undo last stroke" to clear out the complete signature in one click.
I have changed the style of "Undo last stroke" to style of close button. So in my jSignature.UndoButton.js, the style code of "Undo last stroke" button is like below:
var undoButtonSytle = 'position:relative;display:none;float: right;margin-right: 5px;outline:0;cursor: pointer;color: rgb(218, 216, 217);font-size: 1.5em;'
, $undoButton = $('<i class="fa fa-window-close" style="'+undoButtonSytle+'" aria-hidden="true"></i>').append('<link rel="stylesheet" href="../../css/font-awesome.css" type="text/css" />')
.appendTo(this.$controlbarLower)
Undo function from jSignature.UndoButton.js (there is more code in this file)
function attachHandlers(buttonRenderer, apinamespace, extensionName) {
var $undoButton = buttonRenderer.call(this)
;(function(jSignatureInstance, $undoButton, apinamespace) {
jSignatureInstance.events.subscribe(
apinamespace + '.change'
, function(){
if (jSignatureInstance.dataEngine.data.length) {
$undoButton.show()
} else {
$undoButton.hide()
}
}
)
})( this, $undoButton, apinamespace )
;(function(jSignatureInstance, $undoButton, apinamespace) {
var eventName = apinamespace + '.undo'
$undoButton.bind('click', function(){
jSignatureInstance.events.publish(eventName)
})
// This one creates new "undo" event listener to jSignature instance
// It handles the actual undo-ing.
jSignatureInstance.events.subscribe(
eventName
, function(){
var data = jSignatureInstance.dataEngine.data
if (data.length) {
data.pop()
jSignatureInstance.resetCanvas(data)
}
}
)
})(
this
, $undoButton
, this.events.topics.hasOwnProperty( apinamespace + '.undo' ) ?
// oops, seems some other plugin or code has already claimed "jSignature.undo" event
// we will use this extension's name for event name prefix
extensionName :
// Great! we will use 'jSignature' for event name prefix.
apinamespace
)
}
I am not very known with Jquery. Can anyone please tell me how should I should I achieve clearing sign in one stroke?
Can be used in this way.
<button id="clear">Clear</button>
$('#clear').click(function () {
$('#signature').jSignature("reset");
});
Related
Is there a 'right way' to run JS in the WP Block editor when a block style is selected?
I've searched through documentation and google but can't see an example of anyone running a JS script on a block style.
Essentially, I want to inject two elements around a core/group block, if it has a particular style.
My code works just fine on the front end, but in the backend, I can only get it working on a page refresh, after the block style is selected. Here is what i've got so far:
Registerd by block style with php:
register_block_style(
'core/group',
array(
'name' => 'shape-pattern-1',
'label' => 'Shape Pattern 1'
)
);
Function I want to run when style is in use
var initialiseShapePatterns = function($block) {
$block.prepend('<span class="shape-before"></span>');
$block.append('<span class="shape-after"></span>');
$(window).on('load scroll', function() {
if( $block.isInViewport() ) {
$block.addClass('animate');
} else {
$block.removeClass('animate');
}
});
}
Calling function on front-end (working)
$(document).ready(function() {
$('.is-style-shape-pattern-1, .is-style-shape-pattern-2, .is-style-shape-pattern-3').each(function() {
initialiseShapePatterns( $(this) );
});
});
Calling function in block editor (only works if style is already selected on page load)
if( wp.domReady ) {
wp.domReady(function() {
$('.is-style-shape-pattern-1, .is-style-shape-pattern-2, .is-style-shape-pattern-3').each(function() {
initialiseShapePatterns( $(this) );
});
});
}
I get that I'm only telling it to run when the dom is loaded, but I can't find anything in the documentation about running code on style select.
Any ideas?
In jquery, you can add event listners, which will trigger an action when a event happens.
The following code snippet will execute when a button with the id 'myButtonId' is clicked.
$( "#myButtonId" ).click(function() {
//myButtonId was clicked.
$('.is-style-shape-pattern-1, .is-style-shape-pattern-2, .is-style-shape-pattern-3').each(function() {
initialiseShapePatterns( $(this) );
});
});
You will need to set the id of the button which you want to trigger this function. You can do this with the html id attribute
<button id='myButtonId'> Button Text </button>
In wordpress you can add custom HTML.You mentioned blocks so i assume you are using the gutenburg block editor. This means that you can find the block 'custom HTML' and then put that html button in the custom code.
Add an even listener to the clicked object when selecting style that does it for you. Something like this (change #styleselectbutton to the correct element).
$( "#styleselectbutton" ).click(function() {
$('.is-style-shape-pattern-1, .is-style-shape-pattern-2, .is-style-shape-pattern-3').each(function() {
initialiseShapePatterns( $(this) );
});
});
You can try like as follows..
function my_plugin_blocks() {
wp_add_inline_script( 'wp-edit-post', "
wp.blocks.registerBlockStyle( 'core/group', {
name: 'shape-pattern-1',
label: 'Shape Pattern 1',
});
jQuery.fn.isInViewport = function() {
var elementTop = jQuery(this).offset().top;
var elementBottom = elementTop + jQuery(this).outerHeight();
var viewportTop = jQuery(window).scrollTop();
var viewportBottom = viewportTop + jQuery(window).height();
return elementBottom > viewportTop && elementTop < viewportBottom;
};
var initialiseShapePatterns = function(\$block) {
if(\$block.find('> span.shape-before').length == 0)
\$block.prepend('<span class=\"shape-before\"></span>');
if(\$block.find('> span.shape-after').length == 0)
\$block.append('<span class=\"shape-after\"></span>');
};
const getBlockList = () => wp.data.select( 'core/block-editor' ).getBlocks();
let blockList = getBlockList();
wp.data.subscribe(() => {
const newBlockList = getBlockList();
const blockListChanged = newBlockList !== blockList;
blockList = newBlockList;
if ( blockListChanged ) {
jQuery('.is-style-shape-pattern-1, .is-style-shape-pattern-2, .is-style-shape-pattern-3').each(function() {
initialiseShapePatterns( jQuery(this) );
});
}
});
function scrollcontent()
{
jQuery('.is-style-shape-pattern-1, .is-style-shape-pattern-2, .is-style-shape-pattern-3').each(function() {
if(jQuery(this).isInViewport()) {
jQuery(this).addClass('animate');
} else {
jQuery(this).removeClass('animate');
}
});
};
setTimeout(function(){
scrollcontent();
jQuery('.edit-post-layout__content').on('load scroll resize', function() { scrollcontent(); });
}, 500); ");
}
add_action( 'enqueue_block_editor_assets', 'my_plugin_blocks' );
Here i hooked script from functions.php and registerBlockStyle using js not php.You can use any other ways.
I guess you need to write animate when content area scrolls not for window. Because content area is fixed in Wordpress block editor.
Here the helpful docs:
Doc1
Doc2
None of the answers were satisfying to me, so here's my solution. I am using a block called section and I want a trigger when the style variant dark is selected. I am using WordPress 5.6.
My first approach:
document.querySelectorAll('.block-editor-block-styles__item').forEach(
(element) => addClickListener(element)
);
// get the title of the block to make sure to only target this block with the style variant 'dark' (because there might be other blocks which also have this variant name.
const blockTitle = document.querySelector('.block-editor-block-card__title');
function addClickListener(styleButton) {
styleButton.addEventListener('click', () => {
if (blockTitle && blockTitle.textContent === 'Section') {
// Get the right styleButton by the label that is assigned to it.
if(styleButton.getAttribute('aria-label') === 'Dark'){
soSomething(); // Execute this function when the style 'Dark' is selected.
}
}
})
}
Now as you can tell, this approach is quite bad. It uses the title of the block that is rendered in some HTML and also the label of the style variant to apply an event listener to. It does work, but chances are the markup (HTML) of the editor will change in the future, breaking this code.
My second (better) approach:
// Checking for changes in the classNames to make changes to the bloc (only when the block is selected).
if (props.isSelected) {
const getCurrentBlock = () => wp.data.select('core/editor').getBlock(props.clientId);
let oldBlock = getCurrentBlock();
wp.data.subscribe(() => {
const newBlock = getCurrentBlock();
// Change this line with your classname and callback function.
whenStyleIsChanged('is-style-dark', () => doSomething() )
function whenStyleIsChanged(style, callback) {
if (newBlock?.attributes?.className?.includes(style) && !oldBlock?.attributes?.className?.includes(style)) {
oldBlock = newBlock; // Reset to prevent never-ending recursion.
callback()
}
}
})
}
Not only is the second approach much cleaner and future-proof, it is also the 'Gutenberg way' (Redux in reality) and I can trigger my function only when my block style is changed, as opposed to whenever a click is registered on the "style button". This is done by comparing the classnames of the block before and after the update, in my case the class is-style-dark. Make sure to change this and the callback function accordingly.
I'm looking for best-practice advice.
I'm writing a small jQuery plugin to manage horizontal scroll on elements.
I need all the dom elements targeted by that plugin to update on window resize.
Fact is, my website is a full ajax 'app' so when I remove DOM elements, I need them gone so memory doesn't leak.
But I can't find a way to bind the resize event without keeping a reference to the DOM node.
EDIT :
Actually I need the resize handler to get the plugin-targeted elements at 'call' time, coz I don't want to keep any reference to those elements in memory, because I might call .html('') on a parent of theirs...
I did not paste all my code, just an empty shell. I already have a destroy method that unbinds handlers. But I'm generating, removing and appending html nodes dynamically and I the the elements targeted by the plugin to remove silently.
Kevin B stated I could override jQuery .remove method to deal with the handlers, but would have to load jQuery UI for it to work. I don't want that either..
Here is what I tried (attempts commented):
(function($) {
// SOLUTION 2 (see below too)
// Not good either coz elements are not removed until resize is triggered
/*
var hScrolls = $([]);
$(window).bind('resize.hScroll',function(){
if(!hScrolls.length) return;
hScrolls.each(function(){
if($(this).data('hScroll')) $(this).hScroll('updateDimensions');
else hScrolls = hScrolls.not($(this));
});
});
*/
// END SOLUTION 2
// SOLUTION 3 (not implemented but I think I'm on the right path)
$(window).bind('resize.hScroll',function(){
// need to get hScroll'ed elements via selector...
$('[data-hScroll]').hScroll('updateDimensions');
// I don't know how....
});
// END SOLUTION 3
var methods = {
init : function(options) {
var settings = $.extend( {
defaults: true
}, options);
return this.each(function() {
var $this = $(this),
data = $this.data('hScroll');
if (!data) {
$this.data('hScroll', {
target: $this
});
// SOLUTION 1
// This is not good: it keeps a reference to $this when I remove it...
/*
$(window).bind('resize.hScroll', function(){
$this.hScroll('updateDimensions');
});
*/
// END SOLUTION 1
$this.hScroll('updateDimensions');
// SOLUTION 2 (see above too)
hScrolls = hScrolls.add(this);
}
});
},
updateDimensions: function(){
var hScroll = this.data('hScroll');
// do stuff with hScroll.target
}
}
$.fn.hScroll = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if ( typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.hScroll');
}
};
})(jQuery);
Thanks all in advance!
jQuery calls cleanData any time you do something that removes or replaces elements (yes, even if you use parent.html("") ). You can take advantage of that by extending it and having it trigger an event on the target elements.
// This is taken from https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js 10/17/2012
if (!$.widget) { // prevent duplicating if jQuery ui widget is already included
var _cleanData = $.cleanData;
$.cleanData = function( elems ) {
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
try {
$( elem ).triggerHandler( "remove" );
// http://bugs.jquery.com/ticket/8235
} catch( e ) {}
}
_cleanData( elems );
};
}
Now you can bind to the remove event when setting up your plugin and have it run your destroy method.
$(elem).bind("remove",methods.destroy)
You might use a class name and forward the resize event:
$.fn.hScroll = function(method) {
this
.addClass('hScroll')
.data('method', arguments)
};
var methods['alert_text'] = function(config){
alert( config + " " + $(this).text() );
}
$(window).bind('resize.hScroll',function(){
$(".hScroll").each(function(){
var method_config = $(this).data('method');
var method = method_config.shift();
// Forward the resize event with all resize event arguments:
methods[method].apply(this, method_config);
})
})
// Register a resize event for all a.test elements:
$("a.test").hScroll('alert_text', "hey");
// Would alert "hey you" for <a class="test">you</a> on every resize
Update
If you change the dom and want to keep the selector you might try this one:
var elements = [];
$.fn.hScroll = function(method) {
elements.push({'selector' : this.selector, 'arguments' : arguments });
};
var methods['alert_text'] = function(config){
alert( config + " " + $(this).text() );
}
$(window).bind('resize.hScroll',function(){
$.each(elements,function(i, element){
$(element.selector).each(function(){
var method_config = element.arguments;
var method = method_config.shift();
// Forward the resize event with all resize event arguments:
methods[method].apply(this, method_config);
})
})
})
// Register a resize event for all a.test elements:
$("a.test").hScroll('alert_text', "hey");
$(document.body).html("<a class='test'>you</a>");
// Would alert "hey you" for every window resize
You should have the scroll event bound in the extension. Also, you will want to add a "destroy" method to your extension as well. Before you remove the element from the DOM, you will want to call this method. Inside the detroy method is where you will want to unbind the resize event.
One important thing in making this work is that you have a reference to each handler method that is bound to the resize event. Alternatively, you can unbind All resize events upon the removal on an element and then rebind the scroll event to the remaining elements that require it.
In our application we use a general function to create jQuery dialogs which contain module-specific content. The custom dialog consists of 3 buttons (Cancel, Save, Apply). Apply does the same as Save but also closes the dialog.
Many modules are still using a custom post instead of an ajax-post. For this reason I'm looking to overwrite/redefine the buttons which are on a specific dialog.
So far I've got the buttons, but I'm unable to do something with them. Is it possible to get the buttons from a dialog (yes, I know) but apply a different function to them?
My code so far:
function OverrideDialogButtonCallbacks(sDialogInstance) {
oButtons = $( '#dialog' ).dialog( 'option', 'buttons' );
console.log(oButtons); // logs the buttons correctly
if(sDialogInstance == 'TestInstance') {
oButtons.Save = function() {
alert('A new callback has been assigned.');
// code for ajax-post will come here.
}
}
}
$('#dialog').dialog({
'buttons' : {
'Save' : {
id:"btn-save", // provide the id, if you want to apply a callback based on id selector
click: function() {
//
},
},
}
});
Did you try this? to override button's callback based on the need.
No need to re-assign at all. Try this.
function OverrideDialogButtonCallbacks(dialogSelector) {
var button = $(dialogSelector + " ~ .ui-dialog-buttonpane")
.find("button:contains('Save')");
button.unbind("click").on("click", function() {
alert("save overriden!");
});
}
Call it like OverrideDialogButtonCallbacks("#dialog");
Working fiddle: http://jsfiddle.net/codovations/yzfVT/
You can get the buttons using $(..).dialog('option', 'buttons'). This returns an array of objects that you can then rewire by searching through them and adjusting the click event:
// Rewire the callback for the first button
var buttons = $('#dialog').dialog('option', 'buttons');
buttons[0].click = function() { alert('Click rewired!'); };
See this fiddle for an example: http://jsfiddle.net/z4TTH/2/
If necessary, you can check the text of the button using button[i].text.
UPDATE:
The buttons option can be one of two forms, one is an array as described above, the other is an object where each property is the name of the button. To rewire the click event in this instance it's necessary to update the buttons option in the dialog:
// Rewire the callback for the OK button
var buttons = $('#dialog').dialog('option', 'buttons');
buttons.Ok = function() { alert('Click rewired!'); };
$('#dialog').dialog('option', 'buttons', buttons);
See this fiddle: http://jsfiddle.net/z4TTH/3/
Can you try binding your new function code with Click event of Save?
if(sDialogInstance == 'TestInstance') {
$('#'+savebtn_id).click(function() {
alert('A new callback has been assigned.');
// code for ajax-post will come here.
});
}
I have something like
"_onmouseover" : "this.className=this.className.replace(' hover',
'')";
I'm trying to execute it like
buttonObject.onmouseover = function( ) {
window [ this.someObject.__onmouseover ] () ; };
And I don't know how it is possible.
Let me tell you guys my scenario. I am creating this plugin to generate four types of dialogue messages in a jquery dialogue box. Those being 'Warning', 'Error', 'Note' and 'Confirm'. So lets say there are 4 spans in dom which should trigger these four.
<span id='DialogueWarning'> Warning </span>
<span id='DialogueError'> Error </span>
<span id='DialogueNote'> Note </span>
<span id='DialogueConfirm'> Confirm </span>
Now lets hadle the click to show the dialogue
jQuery('#DialogueWarning').click(function(){
var dialogue = new Dialogue({
"type":"Warning",
"message":"Are you sure you want to close this window without saving your changes?",
"buttons":
[
{
"text":"Close without saving",
"_onmouseover": "this.className+=' hover'",
"_onmouseout":"this.className=this.className.replace(' hover', '')",
"bClass":"e_customButton"
},
{
"text":"Don't Close",
"_onmouseover": "this.className+=' hover'",
"_onmouseout":"this.className=this.className.replace(' hover', '')",
"bClass":"e_customButton"
}
],
"closeOnBackgroundClick" : true
});
});
See the "_onmouseover" and _onmouseout thingy, I need those. Is there any way I can pass those in another way
If you need an eval, I bet you have some problems in your application's design.
E.g. you can avoid such things:
// ...
var eventHandlers = {
"_onmouseover" : "this.className=this.className.replace(' hover', '')"
};
// ...
eval(eventHandlers._onmouseover);
and just do it like
var eventHandlers = {
_onmouseover: function(e) {
this.className=this.className.replace(' hover', '');
}
};
buttonObject.onmouseover = eventHandlers._onmouseover;
Some articles to read:
# 1
# 2
# 3
Why does it have to be a string in the first place?
If you had something like:
var someObject = {
_onmouseover: function() {
this.className = this.className.replace(' hover', '');
}
}
You could execute it like:
buttonObject.onmouseover = someObject.__onmouseover;
If you need this to be the button object, you might do something like this:
buttonObject.onmouseover = function() {
someObject.__onmouseover.call( buttonObject );
};
You can use Function . demo
buttonObject.onmouseover = Function(window [ this.someObject.__onmouseover ] );
I try to convert a div tag into something I can drag and drop in CKEditor (as asked in another question).
Do you know how I can trigger the event when someone switches between source view and WYSIWYG mode?
I think this is what you are looking for:
CKEDITOR.on('instanceCreated', function(e) {
e.editor.on('mode', function(e){
// Do your stuff here
alert(e.editor.mode);
});
});
If you mean, you want to capture source mode changes , then you could try something like this:
//add this to your CKeditor’s config.js
$('textarea.cke_source').live('keyup', function() {
$(this)
.closest('.cke_wrapper')
.parent()
.parent()
.prev()
.ckeditorGet()
.fire('change');
});
This discussion might help as well: ckEditor
Hope it helps
CKEditor onChange plugin:
Get a notification (new event) whenever the content of CKEditor changes.
http://ckeditor.com/addon/onchange
I think you should write a plugin to make a fake element for the wysiwyg-view.
Ckeditor is able to recognize elements that need to be replaced with fake-elements.
I made a start for you:
(function() {
CKEDITOR.plugins.add('myPlugin', {
requires : ['fakeobjects'],
init: function(editor) {
var me = this;
var pluginName = 'myPlugin';
editor.addCommand(pluginName, new CKEDITOR.dialogCommand(pluginName));
editor.addCss( // your custom css for your placeholder here
'div.myPluginElement' +
'{' +
'border: 1px solid #a9a9a9;' +
'width: 70px;' +
'height: 50px;' +
'}'
);
},
afterInit : function(editor) {
var dataProcessor = editor.dataProcessor,
dataFilter = dataProcessor && dataProcessor.dataFilter;
if (dataFilter) {
dataFilter.addRules({
elements : {
div : function(element) {
if (typeof element.attributes['class'] !== 'undefined' && element.attributes['class'].indexOf('myPluginElement') != -1)
return editor.createFakeParserElement(element, 'myPluginElement', 'div', false);
else return;
}
}
});
}
}
});
})();