I have a problem with my work which works good on Firefox and Google Chrome, but it wouldn't work in IE. Can you point out where I'm getting it wrong?
Scripts.js
$(document).ready(function () {
$('.delete').click(function () {
var contentId = $(this).attr('contentid');
$.confirm({
'title': 'Delete Confirmation',
'message': 'Are you sure you want to delete this record?',
'buttons': {
'Yes': {
'class': 'blue',
'action': function () {
DoDelete(contentId);
}
},
'No': {
'class': 'orange',
'action': function () {}
// Nothing to do in this case. You can as well omit the action property.
},
'close': {
'action': function () {}
// Nothing to do in this case. You can as well omit the action property.
}
}
});
});
});
confirmscript to generate HTML markup
(function ($) {
$.confirm = function (params) {
if ($('#confirmOverlay').length) {
return false;
}
var buttonHTML = '';
$.each(params.buttons, function (name, obj) {
buttonHTML += '' + name + '<span></span>';
if (!obj.action) {
obj.action = function () {};
}
});
var markup = [
'<div id="confirmOverlay">',
'<div id="confirmBox">',
'<div id="header">',
'<div id ="title">',
params.title,
'</div></div>',
'<div id ="textbox">',
'<p>',
params.message,
'</p></div>',
'<div id="confirmButtons">',
buttonHTML,
'</div></div></div>'
].join('');
$(markup).hide().appendTo('body').fadeIn();
var buttons = $('#confirmBox .button'),
i = 0;
$.each(params.buttons, function (name, obj) {
buttons.eq(i++).click(function () {
obj.action();
$.confirm.hide();
return false;
});
});
}
$.confirm.hide = function () {
$('#confirmOverlay').fadeOut(function () {
$(this).remove();
});
}
})(jQuery);
Well first off, the first line of your $('.delete') handler is:
var contentId = $(this).attr('contentid');
but your markup for .delete is:
<div class="delete"></div>
(notice the lack of a contentId attribute). Luckily(?) your code doesn't actually seem to use contentId :-)
More relevantly, you need to determine which part of your code is breaking (if you had a JS Fiddle of your code I could look, but since you don't you'll have to find out yourself). I would put an alert just before $.confirm is called, and then again inside $.confirm, to make sure the code is even getting to your plug-in (if not, that's your problem).
If it is, the next question to ask is "is your markup getting added, but not revealed, or is it simply not being added at all". Either alerts or the IE developer tools should let you inspect the DOM and find out if your markup is being added; if not, that's your problem. If it is being added, but isn't getting shown, then something is going wrong with your fadeIn, and that's your problem.
As a final note, there's a simpler way you could hook up your button events; instead of:
var buttons = $('#confirmBox .button'),
i = 0;
$.each(params.buttons, function (name, obj) {
buttons.eq(i++).click(function () {
obj.action();
$.confirm.hide();
return false;
});
});
you could just do:
$('#confirmBox .button').each(function(button) {
$(button).click(function () {
params.buttons[$(this).text()].action();
$.confirm.hide();
return false;
});
});
Related
function getEblockRow() {
let eBlockRow = ($('<div/>', {
'class': 'row'
}));
console.log(eBlockRow);
return eBlockRow;
}
function getEblock() {
let eBlock = ($('<div/>', {
'class': 'col-md-3'
}));
return eBlock;
}
how I append:
$(function () {
$(getEblock().appendTo(getEblockRow()));
$(getEblock().append(getTextArea(), submitButton())).appendTo('#form');
});
My console shows that I do have a row, but somehow the button and the texarea are put underneath each other, I have pretty much no css, so I can't have done something wrong there. What am I missing out on?
Working codepen.
The problem is in the way you're appending the divs to each other, check :
function getEblockRow() {
let eBlockRow = ($('<div/>', {
'class': 'row'
}));
console.log(eBlockRow);
return eBlockRow;
}
function getEblock() {
let eBlock = ($('<div/>', {
'class': 'col-md-3'
}));
return eBlock;
}
$(function () {
var container = getEblockRow();
var block = getEblock().append('<textarea></textarea>', '<button class="btn">Submit</button>')
container.append(block);
container.append(block.clone(true));
container.append(block.clone(true));
$('#form').append(container);
});
I am writing my first jQuery plugin which is a tree browser. It shall first show the top level elements and on click go deeper and show (depending on level) the children in a different way.
I got this up and running already. But now I want to implement a "back" functionality and for this I need to store an array of clicked elements for each instance of the tree browser (if multiple are on the page).
I know that I can put instance private variables with "this." in the plugin.
But if I assign an event handler of the onClick on a topic, how do I get this instance private variable? $(this) is referencing the clicked element at this moment.
Could please anyone give me an advise or a link to a tutorial how to get this done?
I only found tutorial for instance specific variables without event handlers involved.
Any help is appreciated.
Thanks in advance.
UPDATE: I cleaned out the huge code generation and kept the logical structure. This is my code:
(function ($) {
$.fn.myTreeBrowser = function (options) {
clickedElements = [];
var defaults = {
textColor: "#000",
backgroundColor: "#fff",
fontSize: "1em",
titleAttribute: "Title",
idAttribute: "Id",
parentIdAttribute: "ParentId",
levelAttribute: "Level",
treeData: {}
};
var opts = $.extend({}, $.fn.myTreeBrowser.defaults, options);
function getTreeData(id) {
if (opts.data) {
$.ajax(opts.data, { async: false, data: { Id: id } }).success(function (resultdata) {
opts.treeData = resultdata;
});
}
}
function onClick() {
var id = $(this).attr('data-id');
var parentContainer = getParentContainer($(this));
handleOnClick(parentContainer, id);
}
function handleOnClick(parentContainer, id) {
if (opts.onTopicClicked) {
opts.onTopicClicked(id);
}
clickedElements.push(id);
if (id) {
var clickedElement = $.grep(opts.treeData, function (n, i) { return n[opts.idAttribute] === id })[0];
switch (clickedElement[opts.levelAttribute]) {
case 1:
renderLevel2(parentContainer, clickedElement);
break;
case 3:
renderLevel3(parentContainer, clickedElement);
break;
default:
debug('invalid level element clicked');
}
} else {
renderTopLevel(parentContainer);
}
}
function getParentContainer(elem) {
return $(elem).parents('div.myBrowserContainer').parents()[0];
}
function onBackButtonClick() {
clickedElements.pop(); // remove actual element to get the one before
var lastClickedId = clickedElements.pop();
var parentContainer = getParentContainer($(this));
handleOnClick(parentContainer, lastClickedId);
}
function renderLevel2(parentContainer, selectedElement) {
$(parentContainer).html('');
var browsercontainer = $('<div>').addClass('myBrowserContainer').appendTo(parentContainer);
//... rendering the div ...
// for example like this with a onClick handler
var div = $('<div>').attr('data-id', element[opts.idAttribute]).addClass('fct-bs-col-md-4 pexSubtopic').on('click', onClick).appendTo(subtopicList);
// ... rendering the tree
var backButton = $('<button>').addClass('btn btn-default').text('Back').appendTo(browsercontainer);
backButton.on('click', onBackButtonClick);
}
function renderLevel3(parentContainer, selectedElement) {
$(parentContainer).html('');
var browsercontainer = $('<div>').addClass('myBrowserContainer').appendTo(parentContainer);
//... rendering the div ...
// for example like this with a onClick handler
var div = $('<div>').attr('data-id', element[opts.idAttribute]).addClass('fct-bs-col-md-4 pexSubtopic').on('click', onClick).appendTo(subtopicList);
// ... rendering the tree
var backButton = $('<button>').addClass('btn btn-default').text('Back').appendTo(browsercontainer);
backButton.on('click', onBackButtonClick);
}
function renderTopLevel(parentContainer) {
parentContainer.html('');
var browsercontainer = $('<div>').addClass('fct-page-pa fct-bs-container-fluid pexPAs myBrowserContainer').appendTo(parentContainer);
// rendering the top level display
}
getTreeData();
//top level rendering! Lower levels are rendered in event handlers.
$(this).each(function () {
renderTopLevel($(this));
});
return this;
};
// Private function for debugging.
function debug(debugText) {
if (window.console && window.console.log) {
window.console.log(debugText);
}
};
}(jQuery));
Just use one more class variable and pass this to it. Usually I call it self. So var self = this; in constructor of your plugin Class and you are good to go.
Object oriented way:
function YourPlugin(){
var self = this;
}
YourPlugin.prototype = {
constructor: YourPlugin,
clickHandler: function(){
// here the self works
}
}
Check this Fiddle
Or simple way of passing data to eventHandler:
$( "#foo" ).bind( "click", {
self: this
}, function( event ) {
alert( event.data.self);
});
You could use the jQuery proxy function:
$(yourElement).bind("click", $.proxy(this.yourFunction, this));
You can then use this in yourFunction as the this in your plugin.
Using tutorials found i'm currently loading new pages with this:
$("a.nav-link").click(function (e) {
// cancel the default behaviour
e.preventDefault();
// get the address of the link
var href = $(this).attr('href');
// getting the desired element for working with it later
var $wrap = $('#userright');
$wrap
// removing old data
.html('')
// slide it up
.hide()
// load the remote page
.load(href + ' #userright', function () {
// now slide it down
$wrap.fadeIn();
});
});
This loads the selected pages perfectly, however the pages have forms that themselves use ajax to send the following:
var frm = $('#profileform');
frm.submit(function (ev) {
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
success: function (data) {
alert(data)
}
});
However this is not sending the form as it did before the page itself was called to the parent page via ajax. Am I missing something? Can you not use an ajax call in a page already called by ajax?
I also have other issues, for example I disable the submit button unless there are any changes to the form, using:
var button = $('#profile-submit');
var orig = [];
$.fn.getType = function () {
return this[0].tagName == "INPUT" ? $(this[0]).attr("type").toLowerCase() : this[0].tagName.toLowerCase();
}
$("#profileform :input").each(function () {
var type = $(this).getType();
var tmp = {
'type': type,
'value': $(this).val()
};
if (type == 'radio') {
tmp.checked = $(this).is(':checked');
}
orig[$(this).attr('id')] = tmp;
});
$('#profileform').bind('change keyup', function () {
var disable = true;
$("#profileform :input").each(function () {
var type = $(this).getType();
var id = $(this).attr('id');
if (type == 'text' || type == 'select') {
disable = (orig[id].value == $(this).val());
} else if (type == 'radio') {
disable = (orig[id].checked == $(this).is(':checked'));
}
if (!disable) {
return false; // break out of loop
}
});
button.prop('disabled', disable);});
However this also doesn't work when pulled to the parent page. Any help much appreciated! I'm really new to ajax so please point out any obvious mistakes! Many thanks in advance.
UPDATE
Just an update to what i've found. I've got one form working by using:
$(document).on('mouseenter', '#profile', function() {
However the following:
$(document).on('mouseenter', '#cancelimage', function() {
$('#cancelimage').onclick=function() {
function closePreview() {
ias.cancelSelection();
ias.update();
popup('popUpDiv');
$('#imgForm')[0].reset();
} }; });
Is not working. I understand now that I need to make it realise code was there, so I wrapped all of my code in a mouseover for the new div, but certain parts still don't work, so I gave a mouseover to the cancel button on my image form, but when clicked it doesn't do any of the things it's supposed to.
For anyone else who comes across it, if you've got a function name assigned to it, it should pass fine regardless. I was trying to update it, and there was no need. Doh!
function closePreview() {
ias.cancelSelection();
ias.update();
popup('popUpDiv');
$('#imgForm')[0].reset();
};
Works just fine.
The confirm box only has two options: ok and cancel.
I'd like to make one myself, so I can add a third button: save and continue. But the issue I currently don't know how to solve, is that: once the custom confirm dialog is up, how do I block the previously running script (or navigation) from running? and then how do I make the buttons return values for the confirmation?
my understanding of the confirm dialog box is this:
it's a visual boolean, that has the power to block navigation and scripts on a page. So, how do I emulate that?
If you want a reliable proven solution... Use jQuery... it'll work on every browser without worrying about crappy IE etc. http://jqueryui.com/demos/dialog/
In javascript, you don't stop while you're waiting for a user action : you set a callback (a function) that your dialog will call on close.
Here's an example of a small dialog library, where you can see how callbacks can be passed.
dialog = {};
dialog.close = function() {
if (dialog.$div) dialog.$div.remove();
dialog.$div = null;
};
// args.title
// args.text
// args.style : "", "error" (optionnel)
// args.buttons : optional : map[label]->function the callback is called just after dialog closing
// args.doAfter : optional : a callback called after dialog closing
dialog.open = function(args) {
args = args || {};
if (this.$div) {
console.log("one dialog at a time");
return;
}
var html = '';
html += '<div id=dialog';
if (args.style) html += ' '+args.style;
html += '><div id=dialog-title>';
html += '</div>';
html += '<div id=dialog-content>';
html += '</div>';
html += '<div id=dialog-buttons>';
html += '</div>';
html += '</div>';
this.$div=$(html);
this.$div.prependTo('body');
$('#dialog-title').html(args.title);
$('#dialog-content').html(args.text);
var buttons = args.buttons || {'Close': function(){return true}};
for (var n in buttons) {
var $btn = $('<input type=button value="'+n+'">');
$btn.data('fun', buttons[n]);
$btn.click(function(){
if ($(this).data('fun')()) {
dialog.close();
if (args.doAfter) args.doAfter();
}
});
$btn.appendTo($('#dialog-buttons'));
}
this.$div.show('fast');
shortcuts.on('dialog', {
27: function(){ // 27 : escape
dialog.close();
}
});
}
Two call samples :
dialog.open({
title: 'ccccc Protection Error',
text: 'There was an error related to cccc Protection. Please consult <a href=../cccc.jsp>this page</a>.',
style: 'error'
});
var ok = false;
dialog.open({
title: sometitle,
text: someHtmlWithInputs,
buttons: {
'OK': function() {
if (// inputs are valid) ok = true;
return true;
},
'Cancel': function() {
return true;
}
},
doAfter: function() {
if (ok) {
if (newvg) {
cccmanager.add(vg);
} else {
cccmanager.store();
}
if (doAfter) doAfter();
}
}
});
As specified by others, you may not need your own library if you just want to make a dialog.
I am adding a button to tinyMCE and I want to know how to wrap text inside tags with javascript, for instance (this highlighted text gets wrapped inside [highlight][/highlight] tags).
and now the entire tinymce
(function() {
tinymce.create('tinymce.plugins.shoutButton', {
init : function(ed, url) {
ed.addButton('shout.button', {
title : 'shout.button',
image : 'viral.gif',
onclick : function() {
window.alert("booh");
});
},
createControl : function(n, cm) {
return null;
},
getInfo : function() {
return {
longname : "Shout button",
author : 'SAFAD',
authorurl : 'http://safadsoft.com/',
infourl : 'http://safadsoft.com/',
version : "1.0"
};
}
});
tinymce.PluginManager.add('shout.button', tinymce.plugins.ShoutButton);
})();
You can use the setSelectionRange (mozilla/webkit) or selection.createRange (IE) methods to find the currently highlighted text inside a textarea.
I put up an example on jsfiddle, but have commented out your regexp since it hangs the browser in many instances. You need to make it more restrictive, and it currently passes a lot of other things than youtube url's as well.
However, the example has a working solution how to get the currently selected text, which you can, after fixing your pattern, apply to the idPattern.exec().
idPattern = /(?:(?:[^v]+)+v.)?([^&=]{11})(?=&|$)/;
// var vidId = prompt("YouTube Video", "Enter the id or url for your video");
var vidId;
el = document.getElementById('texty');
if (el.setSelectionRange) {
var vidId = el.value.substring(el.selectionStart,el.selectionEnd);
}
else if(document.selection.createRange()) {
var vidId = document.selection.createRange().text;
}
alert(vidId);
EDIT: Wrapping the highlighted text and outputting it back to the element. example
el = document.getElementById('texty');
if (el.setSelectionRange) {
el.value = el.value.substring(0,el.selectionStart) + "[highlight]" + el.value.substring(el.selectionStart,el.selectionEnd) + "[/highlight]" + el.value.substring(el.selectionEnd,el.value.length);
}
else if(document.selection.createRange()) {
document.selection.createRange().text = "[highlight]" + document.selection.createRange().text + "[/highlight]";
}
The issue was syntax errors, not properly closed brackets and some missing semi-colons, using the help of the awesome Jsfiddle's JSHint and JSLint I fixed it :
(function () {
tinymce.create('tinymce.plugins.shoutButton', {
init: function (ed, url) {
ed.addButton('shout.button', {
title: 'shout.button',
image: 'viral.gif',
onclick: function () {
window.alert("booh");
}
});
createControl: function (n, cm) {
return null;
}
getInfo: function () {
return {
longname: "Shout button",
author: 'You !',
authorurl: 'http://example.com/',
infourl: 'http://example.com/',
version: "1.0"
};
}
}
});
tinymce.PluginManager.add('shout.button', tinymce.plugins.ShoutButton);
})();
Best Regards