Show/Hide elements by dependency - javascript

I was inspired by this topic Show/Hide form fields based on value of other fields and made some changes to working it not only on select.
Here is example:
var ObserverPlugin = (function(){
// here will be stored every DOM object which has
// data-observe attr and data-name attr (data-name will be served
// as a key , which will store another object with a reference to the DOM object
// how many object does it observe)
var observers = {},
publishers = [];
var _setStylesheet = (function() {
// Create the <style> tag
var style = document.createElement("style");
// Add a media (and/or media query) here if you'd like!
// style.setAttribute("media", "screen")
// style.setAttribute("media", "only screen and (max-width : 1024px)")
// WebKit hack :(
style.appendChild(document.createTextNode(""));
// Add the <style> element to the page
document.head.appendChild(style);
return style.sheet;
})();
// observer pattern & revealing module pattern
var observer = (function(){
var topics = {};
var publish = function(topic, reference) {
// if there is no topic on the publish call, well get out !
if (!topics[topic]) {
return false;
}
// self invoked funciton, which calls the function passed when
// the topic was subscribed (if more then one function was published on the same topic
// then call each one of them)
(function(){
var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(topic, reference);
}
})();
};
var subscribe = function(topic, func) {
if (!topics[topic]) {
topics[topic] = [];
}
topics[topic].push({
func: func
});
};
return {
subscribe: subscribe,
publish: publish,
topics: topics
}
})();
// creates random string, used to make data-name random for observers
var _makeRandomString = function() {
var text = "";
var possible = "abcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 5; i++ ) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
// verifies if eleme existis in array, if not, returns false
var _isInside = function( elem, array ) {
return array.indexOf(elem) > -1;
};
// topic is the topic
// reference is a reference to the DOM object clicked
var _observerFunction = function(topic, reference) {
var number = reference.attr('data-publish-value');
var topics = topic.toString().split(' ');
var length = topics.length;
//var display;
for( var key in observers ) {
for( var i = 0; i < length; i +=1 ) {
if( _isInside( topics[i], observers[key].topicsObserved ) ) {
// it exists
observers[key].sum += Number(number);
// 'number' is a string, so we have to convert it back to number
}
}
if( observers[key].sum === 1 ) {
// it is 0, so show that goddam DOM obj ! :))
// again, put here 'var' for clarity
// does not affect the code
//display = 'block';
_changeProperty(key,observers[key].property,1);
}
else {
// it is not 0, so hide it
//display = 'none';
_changeProperty(key,observers[key].property,0);
}
//observers[key].reference.css('display', display);
}
// change value to -1 or 1
if( number === '-1' ) {
reference.attr('data-publish-value', '1');
}
else {
reference.attr('data-publish-value', '-1');
}
};
/*
* lets say we have 3 DOM objects with data-publish="1"
and 2 DOM objects with data-publish="2"
and one with data-observe="1 2";
so data-observe has to be called 5 times in order for him to be shown on the page;
each DOM object with data-publish will be added at runtime a data-value attribute
which will be -1 or 1. each time it is clicked or changed, it changes to the opposite.
this serves as data-observes will have a property named sum, which will be in the previous case 5
5 gets calculated with -1, or 1 when clicked data-publish DOM object.
So if i click first at data-publish="1" , 5 becomes 4. if i click again the same data-publish, becomes 5.
when sum property becomes 0, the data-observe is shown.
this function calculates how many data-publish="1" exists and so on
(it also does the other stuff needed for publishers)
*/
var _managePublishers = function() {
$('[data-publish]').each(function(){
var el = $(this);
// adds that value data, remember it? :D
el.attr('data-publish-value', '-1');
// trim in case data-publish = "1 2 3" and store in an array
var publisher = el.data('publish').toString();
// we subscripe 'publisher' topic, but we check each string in topic
// here is tricky. if one publishers has more than one topic inside data-publish
// then we subscribe topic, but we check for topic's substring in publishers
var topics = publisher.split(' ');
if( !observer.topics[publisher] ) {
// we subscribe data-publish topic, becouse when we click it we want to fire something, no?
observer.subscribe( publisher, _observerFunction );
}
// but here in publishers we add only the substrings
for( var key in topics ) {
if( publishers[topics[key]] ) {
// the publisher exists
publishers[topics[key]] += 1;
}
else {
// the publisher doesn't exist
publishers[topics[key]] = 1;
}
}
});
};
// gets the observers, calculates sum, caches their reference
var _manageObservers = function() {
$('[data-observe]').each(function(){
var el = $(this);
// create random data-name
el.attr('data-observe-name', _makeRandomString());
var datas = el.data('observe').toString().split(' '); // make an array again if we have multiple attachments
observers[el.data('observe-name')] = (function(){
var sum = (function(){
var sum2 = 0;
// if datas[key] is found in publishers array, add it to sum
for( var key in datas ) {
var temp = publishers[datas[key]];
if( temp ) {
sum2 += temp;
}
}
return sum2;
})();
var reference = el, topicsObserved = datas; // caching, so it is faster !
// we need this when a user clicks data-publish, we need to see which DOM obj. are observing this.
// i really like revealing module pattern...i got used to it
return {
sum: sum,
reference: reference,
topicsObserved: topicsObserved,
property: $(reference).data('observe-property') //style-display[none/block],attr-disable/-,class-active/inactive
}
})();
})
};
var _changeProperty = function(observer, property, status) {
if(property === "style") {
if(status === 1) {
observers[observer].reference.css('display', 'block');
}
else {
observers[observer].reference.css('display', 'none');
}
}
else if(property === "attr") {
if(status === 1) {
$(observers[observer].reference).removeAttr('disabled');
}
else {
$(observers[observer].reference).attr('disabled','disabled');
}
}
else if(property === "class") {
if(status === 1) {
$(observers[observer].reference).removeClass('inactive');
}
else {
$(observers[observer].reference).addClass('inactive');
}
}
};
var init = function() {
_managePublishers();
_manageObservers();
$('[data-publish]:not(select)').on( 'click', function(){
observer.publish( $(this).data('publish'), $(this) );
});
$('select[data-publish]').on('change', function(){
var cache = $(this);
// if in this select there is an option which has value 1(there is chance that it triggered a succesfull publish) we publish that too
//observer.publish( cache.find('[data-value="1"]').data('publish'), cache.find('[data-value="1"]') );
var el = cache.find(':selected');
observer.publish( el.data('publish'), el );
});
$('[data-publish]').each( function() {
if(this.type !== 'radio' || this.type !== 'checkbox' || this.nodeName !== 'SELECT') {
observer.publish( $(this).data('publish'), $(this) );
}
});
// when observers[xx].sum is 0 it must be activated always, otherwise it is always invisible
$.each( observers, function( key, value ) {
if(value.topicsObserved) {
$.each( value.topicsObserved, function( key2, value2 ) {
if(!publishers.hasOwnProperty(value2)) {
$(value.reference).css('display', 'block');
return;
}
if(value.property === "style") {
_setStylesheet.insertRule('[data-observe-name="'+key+'"] {display: none;}', _setStylesheet.rules.length);
}
else if(value.property === "attr") {
$(value.reference).attr('disabled','disabled');
_setStylesheet.insertRule('[disabled] {cursor: not-allowed;}', _setStylesheet.rules.length);
}
else if(value.property === "class") {
$(value.reference).addClass('inactive');
}
});
}
});
};
return {
init: init,
publish: observer.publish,
subscribe: observer.subscribe
}
})();
ObserverPlugin.init();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form method="post" name="form">
<input type="text" name="text" value="">
<div class="wraper">
<label><input type="radio" name="typ" value="subscribe" checked data-publish="newslist" >Subscribe</label>
<label><input type="radio" name="typ" value="unsubscribe" data-publish="unsubscribe" >Unsubscribe</label>
</div>
<div class="wraper">
<button type="submit" name="subscription" value="1" data-observe="newslist" data-observe-property="attr" >
<span>Send</span>
</button>
</div>
<div data-observe="unsubscribe" data-observe-property="style">
<label>
<input type="checkbox" name="confirm" value="1" data-publish="newslist">
<span>Confirm</span>
</label>
</div>
</form>
jsfiddler also here https://jsfiddle.net/ogxusLja/
Problem is that radio inputs fired click event always, not only on
change to second radio input.
Another problem is that Confirm
checkbox is hidden on load.
Expected behavior:
Selected Unsubscribe radio will enable the Send button and hide the Confirm checkbox.
Selected Subscribe radio and Confirm checkbox will together enable the Send button.
Selected Subscribe radio or 'Confirm checkbox' (if only one is selected) Send button will be disabled.

Related

How to run 2 js functions

I have 2 function that I am trying to run, one after another. For some reason they both run at the same time, but the second one does not load properly. Is there a way to run the first function wait then run the second function?:
//run this first
$('#abc').click(function() {
$('.test1').show();
return false;
});
//run this second
(function ($) {
"use strict";
// A nice closure for our definitions
function getjQueryObject(string) {
// Make string a vaild jQuery thing
var jqObj = $("");
try {
jqObj = $(string)
.clone();
} catch (e) {
jqObj = $("<span />")
.html(string);
}
return jqObj;
}
function printFrame(frameWindow, content, options) {
// Print the selected window/iframe
var def = $.Deferred();
try {
frameWindow = frameWindow.contentWindow || frameWindow.contentDocument || frameWindow;
var wdoc = frameWindow.document || frameWindow.contentDocument || frameWindow;
if(options.doctype) {
wdoc.write(options.doctype);
}
wdoc.write(content);
wdoc.close();
var printed = false;
var callPrint = function () {
if(printed) {
return;
}
// Fix for IE : Allow it to render the iframe
frameWindow.focus();
try {
// Fix for IE11 - printng the whole page instead of the iframe content
if (!frameWindow.document.execCommand('print', false, null)) {
// document.execCommand returns false if it failed -http://stackoverflow.com/a/21336448/937891
frameWindow.print();
}
// focus body as it is losing focus in iPad and content not getting printed
$('body').focus();
} catch (e) {
frameWindow.print();
}
frameWindow.close();
printed = true;
def.resolve();
}
// Print once the frame window loads - seems to work for the new-window option but unreliable for the iframe
$(frameWindow).on("load", callPrint);
// Fallback to printing directly if the frame doesn't fire the load event for whatever reason
setTimeout(callPrint, options.timeout);
} catch (err) {
def.reject(err);
}
return def;
}
function printContentInIFrame(content, options) {
var $iframe = $(options.iframe + "");
var iframeCount = $iframe.length;
if (iframeCount === 0) {
// Create a new iFrame if none is given
$iframe = $('<iframe height="0" width="0" border="0" wmode="Opaque"/>')
.prependTo('body')
.css({
"position": "absolute",
"top": -999,
"left": -999
});
}
var frameWindow = $iframe.get(0);
return printFrame(frameWindow, content, options)
.done(function () {
// Success
setTimeout(function () {
// Wait for IE
if (iframeCount === 0) {
// Destroy the iframe if created here
$iframe.remove();
}
}, 1000);
})
.fail(function (err) {
// Use the pop-up method if iframe fails for some reason
console.error("Failed to print from iframe", err);
printContentInNewWindow(content, options);
})
.always(function () {
try {
options.deferred.resolve();
} catch (err) {
console.warn('Error notifying deferred', err);
}
});
}
function printContentInNewWindow(content, options) {
// Open a new window and print selected content
var frameWindow = window.open();
return printFrame(frameWindow, content, options)
.always(function () {
try {
options.deferred.resolve();
} catch (err) {
console.warn('Error notifying deferred', err);
}
});
}
function isNode(o) {
/* http://stackoverflow.com/a/384380/937891 */
return !!(typeof Node === "object" ? o instanceof Node : o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName === "string");
}
$.print = $.fn.print = function () {
// Print a given set of elements
var options, $this, self = this;
// console.log("Printing", this, arguments);
if (self instanceof $) {
// Get the node if it is a jQuery object
self = self.get(0);
}
if (isNode(self)) {
// If `this` is a HTML element, i.e. for
// $(selector).print()
$this = $(self);
if (arguments.length > 0) {
options = arguments[0];
}
} else {
if (arguments.length > 0) {
// $.print(selector,options)
$this = $(arguments[0]);
if (isNode($this[0])) {
if (arguments.length > 1) {
options = arguments[1];
}
} else {
// $.print(options)
options = arguments[0];
$this = $("html");
}
} else {
// $.print()
$this = $("html");
}
}
// Default options
var defaults = {
globalStyles: true,
mediaPrint: false,
stylesheet: null,
noPrintSelector: ".no-print",
iframe: true,
append: null,
prepend: null,
manuallyCopyFormValues: true,
deferred: $.Deferred(),
timeout: 750,
title: null,
doctype: '<!doctype html>'
};
// Merge with user-options
options = $.extend({}, defaults, (options || {}));
var $styles = $("");
if (options.globalStyles) {
// Apply the stlyes from the current sheet to the printed page
$styles = $("style, link, meta, base, title");
} else if (options.mediaPrint) {
// Apply the media-print stylesheet
$styles = $("link[media=print]");
}
if (options.stylesheet) {
// Add a custom stylesheet if given
$styles = $.merge($styles, $('<link rel="stylesheet" href="' + options.stylesheet + '">'));
}
// Create a copy of the element to print
var copy = $this.clone();
// Wrap it in a span to get the HTML markup string
copy = $("<span/>")
.append(copy);
// Remove unwanted elements
copy.find(options.noPrintSelector)
.remove();
// Add in the styles
copy.append($styles.clone());
// Update title
if (options.title) {
var title = $("title", copy);
if (title.length === 0) {
title = $("<title />");
copy.append(title);
}
title.text(options.title);
}
// Appedned content
copy.append(getjQueryObject(options.append));
// Prepended content
copy.prepend(getjQueryObject(options.prepend));
if (options.manuallyCopyFormValues) {
// Manually copy form values into the HTML for printing user-modified input fields
// http://stackoverflow.com/a/26707753
copy.find("input")
.each(function () {
var $field = $(this);
if ($field.is("[type='radio']") || $field.is("[type='checkbox']")) {
if ($field.prop("checked")) {
$field.attr("checked", "checked");
}
} else {
$field.attr("value", $field.val());
}
});
copy.find("select").each(function () {
var $field = $(this);
$field.find(":selected").attr("selected", "selected");
});
copy.find("textarea").each(function () {
// Fix for https://github.com/DoersGuild/jQuery.print/issues/18#issuecomment-96451589
var $field = $(this);
$field.text($field.val());
});
}
// Get the HTML markup string
var content = copy.html();
// Notify with generated markup & cloned elements - useful for logging, etc
try {
options.deferred.notify('generated_markup', content, copy);
} catch (err) {
console.warn('Error notifying deferred', err);
}
// Destroy the copy
copy.remove();
if (options.iframe) {
// Use an iframe for printing
try {
printContentInIFrame(content, options);
} catch (e) {
// Use the pop-up method if iframe fails for some reason
console.error("Failed to print from iframe", e.stack, e.message);
printContentInNewWindow(content, options);
}
} else {
// Use a new window for printing
printContentInNewWindow(content, options);
}
return this;
};
})(jQuery);
How would I run the first one wait 5 or so seconds and then run the jquery print? I'm having a hard time with this. So the id would run first and then the print would run adter the id="abc" Here is an example of the code in use:
<div id="test">
<button id="abc" class="btn" onclick="jQuery.print(#test1)"></button>
</div>
If I understand your problem correctly, you want the jQuery click function to be run first, making a div with id="test1" visible and then, once it's visible, you want to run the onclick code which calls jQuery.print.
The very first thing I will suggest is that you don't have two different places where you are handling the click implementation, that can make your code hard to follow.
I would replace your $('#abc').click with the following:
function printDiv(selector) {
$(selector).show();
window.setTimeout(function () {
jQuery.print(selector);
}, 1);
}
This function, when called, will call jQuery.show on the passed selector, wait 1ms and then call jQuery.print. If you need the timeout to be longer, just change the 1 to whatever you need. To use the function, update your example html to the following:
<div id="test">
<button id="abc" class="btn" onclick="printDiv('#test1')"</button>
</div>
When the button is clicked, it will now call the previously mentioned function and pass it the ID of the object that you want to print.
As far as your second function goes, where you have the comment **//run this second**, you should leave that alone. All it does is extend you jQuery object with the print functionality. You need it to run straight away and it currently does.

Transforming old code to ember component

currently i'm starting with Ember, and i'm loving it! I'm with some difficulties, especially when it comes to components.
For you to understand, I'm going through old code to Ember, and I would like to turn this code into a Component, but I do not know actually how to start, since I do not know how to catch the button being clicked, and I also realized that Ember has several helpers, maybe I do not need any of this giant code to do what I want.
This is the old code result: http://codepen.io/anon/pen/WQjobV?editors=110
var eventObj = {};
var eventInstances = {};
var actual;
var others;
var clicked;
var createEventInstance = function (obj) {
for (var key in obj) {
eventInstances[key] = new Event(obj[key]);
}
};
var returnStyle = function (inCommon) {
var $inCommon = inCommon;
$inCommon.css({
width: '342.4px',
minWidth: '342.4px'
});
$inCommon.find('.cta').removeClass('hidden');
$inCommon.find('.event-close').removeClass('inline');
$inCommon.find('.event-info_list').removeClass('inline');
$inCommon.removeClass('hidden');
$inCommon.find('.expanded').slideUp();
$inCommon.find('.expanded').slideUp();
$inCommon.find('.event-arrow').remove();
$inCommon.find('h2').find('ul').remove('ul');
};
var Event = function (id) {
this.id = id;
};
Event.prototype.expandForm = function () {
actual.css('width', '100%');
actual.find('.event-info_list').addClass('inline');
actual.find('.expanded').slideDown().css('display', 'block');
actual.find('.event-close').addClass('inline');
};
Event.prototype.close = function () {
returnStyle(actual);
returnStyle(others);
};
Event.prototype.hideElements = function () {
clicked.addClass('hidden');
others.addClass('hidden');
};
Event.prototype.maskPhone = function () {
$('[name$=phone]').mask('(99) 99999-9999', {
placeholder: '(00) 0000-0000'
});
};
$('.submit-form').on('click', function (e) {
e.preventDefault();
var id = '.' + $(this).data('id');
var name = $(id).children('#person-name').val();
var email = $(id).children('#person-email').val();
var guests = $(id).children('#person-obs.guests').val();
var phone = $(id).children('#person-phone').val();
var participants = $(id).children('#booking-participants').val();
if (name === '' || email === '' || phone === '' || participants === '' || guests === '') {
alert('Preencha os campos obrigatórios.');
} else {
$(id).submit();
}
});
Event.prototype.createDropDown = function () {
actual.find('h2').addClass('event-change')
.append('<span class="event-arrow" aria-hidden="true">â–¼</span>')
.append(function () {
var self = $(this);
var list = '<ul class="dropdown hidden">';
$('.event').each(function (index) {
if ($(this).find('h2')[0] != self[0]) {
list += '<li data-index="' + index + '">' + $(this).find('h2').text() + '</li>';
}
});
return list;
}).click(function () {
if ($(this).attr('data-expanded') == true) {
$(this).find('ul').toggleClass('hidden');
$(this).attr('data-expanded', false);
} else {
$(this).find('ul').toggleClass('hidden');
$(this).attr('data-expanded', true);
}
}).find('li').click(function (e) {
e.stopPropagation();
actual.find('.event-info_list').removeClass('inline');
actual.find('h2').attr('data-expanded', false);
actual.find('h2').removeClass('event-change');
actual.find('.expanded').slideUp().css('display', 'inline-block');
others.removeClass('hidden');
actual.find('.cta').removeClass('hidden');
actual.find('h2').find('.event-arrow').remove();
actual.find('h2').off('click');
actual.find('h2').find('ul').remove('ul');
$($('.event')[$(this).attr('data-index')]).find('.cta').trigger('click');
});
};
Event.prototype.open = function () {
actual = $('[data-id="' + this.id + '"]');
others = $('.event').not(actual);
clicked = actual.find('.cta');
this.hideElements();
this.expandForm();
this.createDropDown();
this.maskPhone();
};
$('.event').each(function (i, event) {
var prop = 'id' + $(event).data('id');
var value = $(event).data('id');
eventObj[prop] = value;
});
createEventInstance(eventObj);
Basically i have this boxes, which box represent one booking in some event (will be populate by the server). When the user clicks in one box, this boxes expands and the other disappear. But than a dropbox will be created with the other boxes, so the user can navigate in the events by this dropdown.
I didn't do much with Ember, i transform the "events" div into a component with the name "BookingBoxComponent" and two actions:
SiteApp.BookingBoxComponent = Ember.Component.extend({
actions:
open: function() {
// HOW COULD I ACCESS THE CLICKED BUTTON HERE?
},
close: function() {
}
});
As you can see, i put two actions, one for opening the box and other for closing, should i just put the logic in both, or i can improve this like a Ember way?
I don't know if i am asking to much here, so if i am, at least i would like to know how to access the button clicked in the open method, i was trying passing as a parameter, like:
<button {{action 'open' this}}></button>
But didn't work.
I could offer 50 of my points to someone who help transform the old cold in a Ember way code.
Thanks.
The event object will be passed with every action as the last parameter, so when you specified this you were actually passing whatever object has context in that block. In your open function, do not pass this and do
open: function(event) {
// event.currentTarget would be the button
}
And now you can do something like event.currentTarget or event.target

Scan DIVs for specific classes to generate unique links

I have a list of divs containing images/videos/galleries etc.
The structure is as follows:
<div class="item image">image content</div>
<div class="item video">video content</div>
<div class="item gallery">gallery content</div>
<div class="item image">image content</div>
<div class="item image">image content</div>
<div class="item video">video content</div>
As you can see, there can be more than one div with the same content type.
What I want to achieve is scan the list of divs with class=item and generate a button for each content type.
This is what I have so far, using jQuery EACH function
$(document).ready(function () {
$(".item").each(function () {
if ($(this).hasClass("image")) {
alert('image found');
};
if ($(this).hasClass("video")) {
alert('video found');
};
});
});
Problem is the alert get executed multiple times, for each div with the class equal to my condition. As I am planning to generate buttons for each content type this current code will add duplicate buttons as more than one div can have a class of video/image.
I have tried using "return false" inside the IF condition but that breaks my whole EACH function, stopping it at the first reference.
You can create a temporary variable that keeps track of which item types you have already traversed
(function() {
var types = {},
type_re = /\b(?:audio|video|quote|link|image|gallery|status|chat)\b/g;
$('.item').each(function() {
var m = this.className.match(type_re);
if (m !== null && !types.hasOwnProperty(m[0])) {
// code to add button
console.log('add button for type ' + m[0]);
types[m[0]] = true;
}
});
}());
Demo
Previous answers
You can create an array first that will contain all the types found in the document:
var types = [],
type_re = /audio|video|quote|link|image|gallery|status|chat/g;
$('.item').each(function() {
var m;
while ((m = type_re.exec(this.className)) !== null) {
if (!$.inArray(types, t[0])) {
types.push(t[0]);
}
}
});
// types is an array with all types found
Alternatively, iterate over all possible types and filter the items based on each type:
var $items = $('.item'),
types = ['audio', 'video', 'quote', 'link', 'image', 'gallery', 'status', 'chat'];
$.each(types, function(_, type) {
var $itemsOfType = $items.filter(function() {
return (' ' + this.className + ' ').indexOf(type) != -1;
});
if ($itemsOfType.length) {
}
});
Some really easy approach would be to add a status variable for each possible content type and check it:
$( document ).ready(function() {
var _image = true,
_video = true;
$( ".item" ).each(function() {
if ($(this).hasClass( "image" ) && _image) {
_image = false;
alert('image found');
};
if ($(this).hasClass( "video" ) && _video) {
_video = false;
alert('video found');
};
});
});
You can do this.
if($(".image").length>0)
{
alert("image Found")
//generate button
}
JSFIDDLE http://jsfiddle.net/rWrCA/
You can easily use an array for the types and another array for whether or not those exist. That looks something like:
$(document).ready(function () {
// a list of all types and a list of types that were found
var allTypes = ["image", "video", "gallery"];
var typesFound = [];
// loop over all items and add types to the list of found types
$(".item").each(function () {
for (var idx = 0; idx < allTypes.length; idx++) {
if ($(this).hasClass(allTypes[idx])) {
if (typesFound.indexOf(allTypes[idx]) < 0) {
typesFound.push(allTypes[idx]);
}
}
}
});
// as in the original code - prove this worked by displaying alerts!
for (var idx = 0; idx < typesFound.length; idx++) {
alert(typesFound[idx] + ' found');
}
});
I think that should do it!
Make an object in your jQuery ready function. When finished looping, write your buttons using the buttons object.
$(document).ready(function () {
var buttons = {};
$(".item").each(function () {
if ($(this).hasClass("image")) {
buttons.image = 1;
};
if ($(this).hasClass("video")) {
buttons.video = 1;
};
});
// write buttons
for (var type in buttons) {
$('<button/>', {
text: type,
id: 'btn_'+ type,
click: function () { alert('hi'); }
}).appendTo('body');
}
})

Uncaught ReferenceError: X is not defined

This code is being used on a Chrome Extension.
When I call the "showOrHideYT()" function, I get a
"Uncaught ReferenceError: showOrHideYT is not defined | (anonymous
function) | onclick"
This code will search for youtube links in a page, and it will add a button (it's really a div with an event) next to the link to show the iframe with the embedded video, pretty much like Reddit Enhancement Suite. Consider the code, per se, incomplete. I just want to know what am i missing when i call the "showOrHideYT(frameZES12345)" function.
if needed, i can provide manifest.json.
Thanks
function showOrHideYT(id)
{
var YTvidWidth = 420;
var YTvidHeight = 315;
frameYT=getElementById(id);
console.log(frameYT.style.visibility);
if (frameYT.style.visibility == "hidden")
{
frameYT.style.width = YTvidWidth+"px";
frameYT.style.height = YTvidHeight+"px";
frameYT.style.visibility = "visible";
}
if (frameYT.style.visibility == "visible")
{
frameYT.style.width = "0px";
frameYT.style.height = "0px";
frameYT.style.visibility = "hidden";
}
};
// DOM utility functions
function insertAfter( referenceNode, newNode ) {
if ((typeof(referenceNode) == 'undefined') || (referenceNode == null)) {
console.log(arguments.callee.caller);
} else if ((typeof(referenceNode.parentNode) != 'undefined') && (typeof(referenceNode.nextSibling) != 'undefined')) {
if (referenceNode.parentNode == null) {
console.log(arguments.callee.caller);
} else {
referenceNode.parentNode.insertBefore( newNode, referenceNode.nextSibling );
}
}
};
function createElementWithID(elementType, id, classname) {
obj = document.createElement(elementType);
if (id != null) {
obj.setAttribute('id', id);
}
if ((typeof(classname) != 'undefined') && (classname != '')) {
obj.setAttribute('class', classname);
}
return obj;
};
///////////////////////////////////////
$(document).ready(function() {
var vidWidth = 420;
var vidHeight = 315;
var linksSemID = document.getElementsByTagName("a") ;
for (var i = 0; i < linksSemID.length; i++){
if (/id=$/.test(linksSemID[i].href)) links[i].href += "1";
}
i=0;
var youTubeRegExp = /(?:v=)([\w\-]+)/g;
var forEach = Array.prototype.forEach;
var linkArray = document.getElementsByTagName('a');
forEach.call(linkArray, function(link){
linkArray.id="zes" + i++;
var linkTarget = link.getAttribute('href');
if (linkTarget!=null)
{
if (linkTarget.search(youTubeRegExp) !=-1)
{
console.log (linkTarget);
idVideo=linkTarget.match(/(?:v=)([\w\-]+)/g);
//idVideo = idVideo.replace("v=", "");
//add buton
botaoMais = document.createElement('DIV');
botaoMais.setAttribute('class','expando-button collapsed video');
botaoMais.setAttribute('onclick','showOrHideYT(frameZES'+ i +')');
insertAfter(link, botaoMais);
//add iframe
ifrm = document.createElement('IFRAME');
ifrm.setAttribute('src', 'http://www.youtube.com/embed/'+ idVideo);
ifrm.style.width = '0px';
ifrm.style.height = '0px';
ifrm.style.frameborder='0px';
ifrm.style.visibility = 'hidden';
ifrm.setAttribute('id', 'frameZES' + i);
insertAfter(link, ifrm);
}
}
});
});
When you use setAttribute with a string, the event will be executed in the context of the page. The functions which are defined in a Content script are executed in a sandboxed scope. So, you have to pass a function reference, instead of a string:
Replace:
botaoMais.setAttribute('onclick','showOrHideYT(frameZES'+ i +')');
With:
botaoMais.addEventListener('click', (function(i) {
return function() {
showOrHideYT("frameZES"+ i);
};
})(i));
Explanation of code:
(function(i) { ..})(i) is used to preserve the value of i for each event.
Inside this self-invoking function, another function is returned, used as an event listener to click.
I see that you are using jQuery in your code. I personally think if we are using a library like jQuery, then we should not mix the native javascript code and jQuery code.
You can use jQuery bind to bind your the functions you need to call on dom ready.
Read below to know more.
suppose you want to call a javascript function on a button click, Here is the HTML for the same.
<div id="clickme">
<input id= "clickmebutton" type="button" value = "clickme" />
</div>
suppose "test" is the function you need to call, here is the code for test function.
function test() {
alert("hello");
}
you now need to bind the test function on the button click.
$(document).ready(function() {
$("#clickmebutton").bind("click", function(){
// do what ever you want to do here
test();
});
});

How to detect if some text box is changed via external script?

I have some jQuery plugin that changes some elements, i need some event or jQuery plugin that trigger an event when some text input value changed.
I've downloaded jquery.textchange plugin, it is a good plugin but doesn't detect changes via external source.
#MSS -- Alright, this is a kludge but it works:
When I call boxWatcher() I set the value to 3,000 but you'd need to do it much more often, like maybe 100 or 300.
http://jsfiddle.net/N9zBA/8/
var theOldContent = $('#theID').val().trim();
var theNewContent = "";
function boxWatcher(milSecondsBetweenChecks) {
var theLoop = setInterval(function() {
theNewContent = $('#theID').val().trim();
if (theOldContent == theNewContent) {
return; //no change
}
clearInterval(theLoop);//stop looping
handleContentChange();
}, milSecondsBetweenChecks);
};
function handleContentChange() {
alert('content has changed');
//restart boxWatcher
theOldContent = theNewContent;//reset theOldContent
boxWatcher(3000);//3000 is about 3 seconds
}
function buttonClick() {
$('#theID').value = 'asd;lfikjasd;fkj';
}
$(document).ready(function() {
boxWatcher(3000);
})
try to set the old value into a global variable then fire onkeypress event on your text input and compare between old and new values of it. some thing like that
var oldvlaue = $('#myInput').val();
$('#myInput').keyup(function(){
if(oldvlaue!=$('#myInput').val().trim())
{
alert('text has been changed');
}
});
you test this example here
Edit
try to add an EventListner to your text input, I don't know more about it but you can check this Post it may help
Thanks to #Darin because of his/her solution I've marked as the answer, but i have made some small jQuery plugin to achieve the same work named 'txtChgMon'.
(function ($) {
$.fn.txtChgMon = function (func) {
var res = this.each(function () {
txts[0] = { t: this, f: func, oldT: $(this).val(), newT: '' };
});
if (!watchStarted) {
boxWatcher(200);
}
return res;
};
})(jQuery);
var txts = [];
var watchStarted = false;
function boxWatcher(milSecondsBetweenChecks) {
watchStarted = true;
var theLoop = setInterval(function () {
for (var i = 0; i < txts.length; i++) {
txts[i].newT = $(txts[i].t).val();
if (txts[i].newT == txts[i].oldT) {
return; //no change
}
clearInterval(theLoop); //stop looping
txts[i].f(txts[i], txts[i].oldT, txts[i].newT);
txts[i].oldT = $(txts[i].t).val();
boxWatcher(milSecondsBetweenChecks);
return;
}
}, milSecondsBetweenChecks);
}

Categories