jQuery events not firing - javascript

I'm creating a simple jQuery editor, nothing complicated, and just can't seem to find out why the events do not work. See code below.
var $editor = $('<div>').addClass('editor')
.insertBefore(this.$element)
.append(this.$element);
var $b = $('<div>').addClass('button-wrapper')
.appendTo($editor);
this.$element.css({height:this.opts.height,width:this.opts.width});
//Load up each button.
$.each(this.opts.buttons.split(' '), function(i, button)
{
//If its an empty string keep going.
if(button == '')return true;
//Generate a button.
$('<div>').data('buttonName', button)
.addClass(button.toLowerCase())
.click(clicked)
.hover(hover, hover)
.appendTo($b);
});
To go over it, simply, $element represents the textarea that I am using as the base element, $b represents the button wrapper, and $editor is the div to wrap around all of these things. When I append the buttons to $editor none of the events fire, however, when I append to document.body it works perfectly fine. For the record, the event clicked and hover are nothing special, just testers to see if the events are working.

I guess the issue is actually at all places you are using <div> but it should be just div
like below -
var $editor = $('div').addClass('editor')
.insertBefore(this.$element)
.append(this.$element);

I've rewritten your code a little bit, just to figure out what you're doing. This seems to work for me, unless I didn't understand what the problem is that you're describing. The buttons react to hover as well as click events. Aside from writing the things you're doing differently, there's no substantial change in the code.
I suppose there's a chance that Val was right in that there may be other elements overlaying your buttons. You haven't shown us your CSS, so it's hard to tell what's going on on your side.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<style>
.bold, .italic, .underline{ width: 50px; height: 20px; background: green; margin: 10px; }
</style>
</head>
<body>
<textarea class="demo">
</textarea>
<script type="text/javascript">
jQuery(
function($)
{
(function($){
//Constructor to make a new editor.
function TEditor(element, opts)
{
//Load in the element.
this.$element = $(element);
this.opts = opts;
//Let the browser know the object is ready.
this.enabled = true;
}
//The actual editor class.
TEditor.prototype = {
display: function()
{
var
$editor = this.$element.wrap('<div class="editor" />').parent(),
$b = $('<div class="button-wrapper" />').appendTo($editor);
this.$element.css({height:this.opts.height,width:this.opts.width});
//Load up each button.
$.each(this.opts.buttons.split(' '), function(i, button)
{
//If its an empty string keep going.
if(button == '') return true;
//Generate a button.
$('<div class="' + button.toLowerCase() + '" />')
.data('buttonName', button)
.appendTo($b)
.click(clicked)
.hover(hover, hover);
});
},
enable: function()
{
this.enabled = true;
},
disable: function()
{
this.enabled = false;
},
validate: function()
{
if(!this.$element[0].parentNode)
{
this.destroy();
this.$element = null;
this.options = null;
}
}
}
//JQuery function extension.
$.fn.teditor = function(options)
{
options = $.extend({}, $.fn.teditor.defaults, options);
//On load create a new editor.
function get(ele)
{
var editor = $.data(ele, 'editor');
if(!editor)
{
editor = new TEditor(ele, options);
editor.display();
$.data(ele, 'editor', editor);
}
return editor;
}
//Initialize.
this.each(function(){get(this);})
return this;
};
$.fn.teditor.defaults = {
buttons: 'Bold Italic Underline',
height: '150px',
width: '500px'
};
function clicked(e)
{
alert(e);
}
function hover(e)
{
console.log('hover');
}
})(jQuery);
$('.demo').teditor();
}
);
</script>
</body>
</html>

Related

When user touches and moves his finger, how to get which elements (vms) were touched with knockout.js

I'm using knockout and I'm trying to achieve is this:
I want the user to select some blocks:
click the first block (it is selected)
without releasing the mouse button, move the mouse around
every block you pass through is selected
release the button to stop selecting.
It's very easy to do it using mouse events, but I need to target touch devices too (android, iphone, touch notebooks).
How to have the same behavior using touch events with knockout?
touch the first block
without releasing the finger, move around
select all touched blocks
release the finger
ps: I got stuck because when using touch events, the event source is locked to the first touched element (oh god, why???) and I can't figure out which others blocks the user touches.
Here is a jsfiddle with my code:
https://jsfiddle.net/m38tfpq4/2/
var vmBlock = function(label) {
var self = this;
self.text = label;
self.color = ko.observable('grey');
}
var vm = function() {
var self = this;
self.isSelecting = false;
self.blocks = [new vmBlock('a'), new vmBlock('b'), new vmBlock('c')];
self.selectStart = function(block) {
console.log('start');
self.isSelecting = true;
self.select(block);
}
self.selectEnd = function(block) {
console.log('end');
self.isSelecting = false;
}
self.select = function(block) {
console.log('select: ' + self.isSelecting);
if (!self.isSelecting) {
return;
}
block.color('red');
};
};
ko.applyBindings(new vm());
.block {
width: 100px;
height: 100px;
margin: 6px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="container" data-bind="foreach: blocks">
<div class="block" onselectstart="return false" data-bind="text: text, style:{ 'background-color' : color }, event: { mousedown: $parent.selectStart, mouseover: $parent.select, mouseup: $parent.selectEnd }">
</div>
</div>
You could use document.elementFromPoint, but I can't imagine it's the best/only way...
Feels hacky and slow, since it first uses the x and y of a touch to pinpoint an element, and then uses ko.dataFor to get to the block viewmodel... It does work though...
An interim solution could be to store a block id property in an attribute on the element, and keep a Map linking id props to block viewmodels in your $parent vm. Might speed up some parts of the logic.
I'm curious to see if anyone else comes up with a more logical way of linking those weird touch events to an element :)
To test this snippet, set your developer tools to emulate touches
var vmBlock = function(label) {
var self = this;
self.text = label;
self.color = ko.observable('grey');
}
var vm = function() {
var self = this;
self.isSelecting = false;
self.blocks = [new vmBlock('a'), new vmBlock('b'), new vmBlock('c')];
self.select = function(block) {
block.color("red");
};
self.startTouch = function(data, event) {
self.isSelecting = true;
};
self.endTouch = function(data, event) {
self.isSelecting = false;
};
self.touch = function(data, event) {
if (!self.isSelecting) return;
var x = event.touches[0].clientX;
var y = event.touches[0].clientY;
var target = document.elementFromPoint(x, y);
var vm = ko.dataFor(target);
if (vm && vm.color) self.select(vm);
}
};
ko.applyBindings(new vm());
.block {
display: inline-block;
width: 100px;
height: 100px;
margin: 6px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="container" data-bind="foreach: blocks, event: {
touchstart: startTouch,
touchend: endTouch,
touchmove: touch
}">
<div class="block" onselectstart="return false" data-bind="text: text, style:{ 'background-color' : color }">
</div>
</div>

How to prevent Wordpress built-in “browse link” entering the data in wp-editor

Working with Wordpress Meta Box and I used the code of Dale Sattler from this How can I use the built in Wordpress “browse link” functionality? to create a custom field with wp browse link it works fine, but it inserted the data in wp-editor too.
I try to prevent the default event using code here Use WordPress link insert dialog in metabox? but doesn't work, I try that code too but it have a bug too.
here is my code
var _link_sideload = false; //used to track whether or not the link dialogue actually existed on this page, ie was wp_editor invoked.
var link_btn = (function($){
'use strict';
var _link_sideload = false; //used to track whether or not the link dialogue actually existed on this page, ie was wp_editor invoked.
var input_field = '';
/* PRIVATE METHODS
-------------------------------------------------------------- */
//add event listeners
function _init() {
$('body').on('click', '.link-btn', function(event) {
_addLinkListeners();
_link_sideload = false;
input_field = $(this).attr('href');
var link_val_container = $(input_field);
if ( typeof wpActiveEditor != 'undefined') {
wpLink.open();
wpLink.textarea = $(link_val_container);
} else {
window.wpActiveEditor = true;
_link_sideload = true;
wpLink.open();
wpLink.textarea = $(link_val_container);
}
return false;
});
}
/* LINK EDITOR EVENT HACKS
-------------------------------------------------------------- */
function _addLinkListeners() {
$('body').on('click', '#wp-link-submit', function(event) {
var linkAtts = wpLink.getAttrs();
console.log(linkAtts);
var link_val_container = $(input_field);
link_val_container.val(linkAtts.href);
_removeLinkListeners();
return false;
});
$('body').on('click', '#wp-link-cancel', function(event) {
_removeLinkListeners();
return false;
});
}
function _removeLinkListeners() {
if(_link_sideload){
if ( typeof wpActiveEditor != 'undefined') {
wpActiveEditor = undefined;
}
}
wpLink.close();
wpLink.textarea = $('html');//focus on document
$('body').off('click', '#wp-link-submit');
$('body').off('click', '#wp-link-cancel');
}
/* PUBLIC ACCESSOR METHODS
-------------------------------------------------------------- */
return {
init: _init,
};
})(jQuery);
please help, please ....
Ok I think I found a way to remove the link from the content. In your submit event you need to add:
$('body').on('click', '#wp-link-submit', function(event) {
var linkAtts = wpLink.getAttrs();
var link_val_container = $(input_field);
link_val_container.val(linkAtts.href);
var $frame = $('#content_ifr'),
$added_links = $frame.contents().find("a[data-mce-href]");
$added_links.each(function(){
if ($(this).attr('href') === linkAtts.href) {
$(this).remove();
}
});
_removeLinkListeners();
return false;
});
$('#content_ifr') is the iframe that loads tinymce editor with content inside. Since the iframe is loaded from the same domain you can mess around it (luckily). So you just go through its contents and you're looking for anchors that have data attribute called mce-href, and if the link that you've just added has the href value as the one you've added it removes them.
I re did this part of the code because I've noticed that all the links in my content had this attribute so you cannot just remove all anchors that have
data-mce-href attribute because that would remove all of them. And you only want to remove those you've added in your metabox.
This did the trick for me :)

Hide empty fields from print view with JavaScript

I have a form that requires printing. However, there might be fields that will be left blank and I would like them to be excluded from my print view altogether. I am talking about the JavaScript window.print(); function and the print window that it opens.
Is there a way I can do something like this? Is there a way for me to handle logic in such events (ie. before print?).
You could use CSS #media combined with some javascript to change the class dependent on whether the field is empty or not. Something like this...
var fields = document.getElementsByClassName("field");
for(var i=0; i < fields.length; i++){
fields[i].addEventListener('keyup', function() {
if(this.value.length) {
this.parentElement.className = "";
} else {
this.parentElement.className = "empty";
}
});
}
#media print {
.empty {
display: none;
}
}
<div class="empty">Name: <input class="field"></div>
<div class="empty">Field: <input class="field"></div>
<div class="empty">Foo: <input class="field"></div>
(In the snippet, add something to a field but not all and then hit ctrl+p. you wont see the empty fields in the print preview)
If using jQuery you could cleanup the selectors and looping making the js something like this
$(".field").on("keyup", function () {
$this = $(this);
if ($this.val().length) {
$this.parent().removeClass("empty");
} else {
$this.parent().addClass("empty");
}
});
You can watch for the window.print event and use some jquery or javascript to check for empty inputs and hide them.
(function() {
var beforePrint = function() {
$('input').each(function(i,el){
if($(el).val() == ''){
$(el).hide();
}
});
};
var afterPrint = function() {
$('input').show();
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function(mql) {
if (mql.matches) {
beforePrint();
} else {
afterPrint();
}
});
}
window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
}());
https://jsbin.com/gacikezulo/edit?html,js,console,output
Read this article here. But I took the combined script which should work in everything except Opera

On Clicking Link Highlight the Text Within Tooltip

I would like to highlight the text within a tooltip when the user clicks the Short Url anchor so he can copy paste it. The tooltip is served by Twitter Bootstrap and the markup looks like this:
<div class="shorturl">
Short URI
</div>
I found this snippet which I think would work just right except that I have not yet figured out how to handle the clicking of the link (which both does not scroll and highlights the text within the tooltip).
function selectText() {
if (document.selection) {
var range = document.body.createTextRange();
range.moveToElementText(document.getElementByClass('tooltip'));
range.select();
}
else if (window.getSelection) {
var range = document.createRange();
range.selectNode(document.getElementByClass('tooltip'));
window.getSelection().addRange(range);
}
}
How can I make this work? Input very much appreciated!
This is what I would suggest to you : Live demo (jsfiddle)
var selector = '[rel="tooltip_r"]'; // Links that will have the feature
var tooltipOptions = { // Some options for the tooltips (careful if you override the "defaults" set below)
placement: 'right'
};
var attribute = 'data-url'; // Attribute where to find the url, could be href
/* Be sure of what you are doing if you modify below this */
$elts = $(selector);
var defaultOptions = {
trigger: 'manual',
title: '<input type="text" readonly="readonly"/>'
};
var opts = $.extend({}, defaultOptions, tooltipOptions);
$elts.each(function() {
var $this = $(this);
var url = $this.attr(attribute);
$this.tooltip(opts);
$this.on('click.tooltip',function(e) {
$this.tooltip('show');
$this.data('tooltip').$tip.find('input').val(url).select()
.on('click', function(e){ e.stopPropagation(); });
e.preventDefault();
e.stopPropagation();
});
});
$('html').on('click.tooltip', function() {
$elts.tooltip('hide');
});
And you might use some styles to improve the input in the tooltip. For example :
.tooltip .tooltip-inner > input[type="text"] {
background: transparent;
border: none;
max-width: 100%;
width: auto;
padding: 0;
color: inherit;
}
Update
If you need the same feature in dynamically loaded content, delegated events need to be used. Here is a working jsfiddle.
var selector = '[rel="tooltip_r"]'; // Links that will have the feature
var tooltipOptions = { // Some options for the tooltips (careful if you override the "defaults" set below)
placement: 'right'
};
var attribute = 'data-url'; // Attribute where to find the url, could be href
var onClass = 'on'; // Class used to determine which tooltips are displayed
/* Be sure of what you are doing if you modify below this */
var defaultOptions = {
trigger: 'manual',
title: '<input type="text" readonly="readonly"/>'
};
var opts = $.extend({}, defaultOptions, tooltipOptions);
var selectorOn = selector+'.'+onClass;
$('body').on('click.tooltip', selector, function(e) {
var $this = $(this);
var url = $this.attr(attribute);
$this.data('tooltip') || $this.tooltip(opts);
$this.tooltip('show').addClass(onClass);
$this.data('tooltip').$tip.find('input').val(url).select()
.on('click', function(e){ e.stopPropagation(); });
e.preventDefault();
e.stopPropagation();
})
.on('click.tooltip', function() {
var $elts = $(selectorOn);
$elts.tooltip('hide');
});

Combining two functions not working

I attempted to combine two functions in the code below. All seems to be working except I cannot get the variable currentImage.metaData.something to work in the second function. I appreciate your advice.
<script type="text/javascript" src="code.photoswipe-2.1.5.min.js"></script>
<script type="text/javascript">
(function(window, PhotoSwipe){
document.addEventListener('DOMContentLoaded', function(){
var
options = {
getImageMetaData: function(el){
return {
href: el.getAttribute('href'),
something: el.getAttribute('data-something'),
anotherThing: el.getAttribute('data-another-thing')
}
}
},
instance = PhotoSwipe.attach( window.document.querySelectorAll('#Gallery a'), options );
instance.addEventHandler(PhotoSwipe.EventTypes.onDisplayImage, function(e){
var currentImage = instance.getCurrentImage();
console.log(currentImage.metaData.something);
console.log(currentImage.metaData.anotherThing);
});
}, false);
}(window, window.Code.Util, window.Code.PhotoSwipe));
(function(window, Util, PhotoSwipe){
document.addEventListener('DOMContentLoaded', function(){
var
sayHiEl,
sayHiClickHandler = function(e){
alert('yo!!!');
}
options = {
getToolbar: function(){
return '<div class="ps-toolbar-close" style="padding-top: 12px;">Close</div><div class="ps-toolbar-play" style="padding-top: 12px;">Play</div><div class="ps-toolbar-previous" style="padding-top: 12px;">Previous</div><div class="ps-toolbar-next" style="padding-top: 12px;">Next</div><div class="say-hi" style="padding-top: 12px;">Say Hi!</div>';
// NB. Calling PhotoSwipe.Toolbar.getToolbar() wil return the default toolbar HTML
}
},
instance = PhotoSwipe.attach( window.document.querySelectorAll('#Gallery a'), options );
// onShow - store a reference to our "say hi" button
instance.addEventHandler(PhotoSwipe.EventTypes.onShow, function(e){
sayHiEl = window.document.querySelectorAll('.say-hi')[0];
});
// onToolbarTap - listen out for when the toolbar is tapped
instance.addEventHandler(PhotoSwipe.EventTypes.onToolbarTap, function(e){
if (e.toolbarAction === PhotoSwipe.Toolbar.ToolbarAction.none){
if (e.tapTarget === sayHiEl || Util.DOM.isChildOf(e.tapTarget, sayHiEl)){
alert(currentImage.metaData.anotherThing);
}
}
});
// onBeforeHide - clean up
instance.addEventHandler(PhotoSwipe.EventTypes.onBeforeHide, function(e){
sayHiEl = null;
});
}, false);
}(window, window.Code.Util, window.Code.PhotoSwipe));
You're declaring the currentImage variable within the first function. Variables created with the var keyword are function-scoped, meaning that it isn't visible outside of the function (and hence not visible in your second function, in this case).
I would probably suggest some more general code reorganization, but an easy fix would be to declare the variable above both of your functions, making it visible to both.

Categories

Resources