Revealing module pattern and jquery failed - javascript

I have a file call text.js and it has
var Text = function(canvas){
var textField = $('#textField'),
addTextButton = $('#addText');
var init = function(){
addTextButton.click(function(){
alert('won"t work?')
});
},
resetTextField = function(){
// it work if I put the selector here like var textField = $('#textField'),
textField.val(''); // won't work
};
return{
init:init
}
}();
It's included in my index.html. In there I do init like
$(function(){
Text.init();
}());
The problem is the even't can't be fired. I think I messed up something.

The code in Text is run immediately, and returns the object with init on it. If you run that code before the elements it looks up exist, for instance:
<!doctype html>
<html>
<head>
<!-- ... --->
<script src="text.js"></script><!-- Problem here -->
<script>
$(function(){
Text.init();
}());
</script>
</head>
<body>
<!-- ... --->
<input id="textField"><input id="addText" type="button" value="Add">
<!-- ... -->
</body>
</html>
... you'll end up with empty jQuery objects in textField and addTextButton.
Separately, you're also running the function you're trying to pass ready immediately (and then passing undefined into ready), the problem is here:
$(function(){
Text.init();
}());
// ^^---------- problem
You don't want those (). You want to pass the function into ready:
$(function(){
Text.init();
}); // <== Note no ()
If you're going to have the init method, it would be best to put all your initialization inside it rather than putting it in two places:
var Text = function(canvas){
var textField, addTextButton;
var init = function(){
textField = $('#textField');
addTextButton = $('#addText');
addTextButton.click(function(){
alert('won"t work?')
});
},
resetTextField = function(){
// it work if I put the selector here like var textField = $('#textField'),
textField.val(''); // won't work
};
return{
init:init
}
}();
Note, though, that if you follow the usual best practice of putting your scripts at the end of the document, just prior to the closing </body> tag, the elements defined above that will exist and be available, which would make using ready (and init) unnecessary. So if you control where the script tags go, that's an option.
So for instance:
<!doctype html>
<html>
<head>
<!-- ... --->
</head>
<body>
<!-- ... -->
<input id="textField"><input id="addText" type="button" value="Add">
<!-- ... -->
<script src="text.js"></script>
<script>
$(function(){
Text.init();
});
</script>
</body>
</html>

You are invoking the function once defined using () at a point where DOM is not loaded. Thus, all selectors return zero nodes.
var Text = function(canvas){
// ...
}();
^^
Remove that. And when you call it, you need to instance the function first, and keep that instance reference (if you wish to).
var text = new Text();
text.init();

Related

how to fix the closure bug in my jQuery code

the page always alert "btn2" ,whenever I click btn1 or btn2. it's seem the problem caused the "click" closures.but I don't know how to fixed it.
thanks in advance.
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>untitled</title>
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
(function(){
$.fn.test = function(){
F.init.apply(this,arguments)
};
var F ={
that:null,
init:function(){
F.that = this;
$(F.that).click(function(e) {
F.method();
});
},
method:function(){
var text =$(F.that).html();
alert(text);
}
}
})();
$(function(){
$("#btn1").test(); //alert btn2---bug
$("#btn2").test(); //alert btn2
});
</script>
</head>
<body>
<button id="btn1">btn1</button>
<button id="btn2">btn2</button>
</body>
</html>
You have referred to your object class F by that name from within the class.
Your line F.that = this is effectively therefore creating what would in other OO languages be considered a "static member" of the class, so both #btn2 and #btn1 ended up sharing the same that member.
Furthermore, your click handler is trying to call F.method() - in effect also a static method call.
You'll need to create a new object of type F each time you wish to wrap it around an element. Only then will you get a separate this for each element.
I suggest using an off-the-shelf jQuery plugin model such as http://jqueryboilerplate.com/ instead of trying to invent your own. See this extract from that code:
$.fn[ pluginName ] = function ( options ) {
return this.each(function() {
if ( !$.data( this, "plugin_" + pluginName ) ) {
$.data( this, "plugin_" + pluginName, new Plugin( this, options ) );
}
});
};
Note how it uses new Plugin to create the plugin instance, and then stores it on the element using $.data, but only the first time the plugin is invoked against each element.
1)F is a static Object
2)So F.that is also static
3)so
F.that = this
line will set 'this' to F.that.
4)first time you call
$("#btn1").test();
then F.that will be equal to $("#btn1");//this will be equal to $("#btn1")
5)Next time you call
$("#btn2").test();
then F.that will be equal to $("#btn2");//this will be equal to $("#btn2")
6) So finally to F.that you are setting $("#btn2")
7)hence the $(F.that).html(); is essentially $($("#btn2").html()) which is further same as $("#btn2").html()
8)Hence alert is showing "btn2"

How do dynamically handle onmousemove inside object constructor?

I've got this set up:
<html>
...
<section id="main" onmousemove="view.updateLocation(event.clientX, event.clientY)">
...
</section>
<script>
var view = new PageObj();
view.show();
</script>
...
<script src="main.js"></script>
</html>
With an event inside main.js called updateLocation(x, y), but I want to move the onmousemove to be handled by JavaScript entirely. How do I define a handler inside the PageObj() constructor to replace the onmousemove="..." property?
Something along the lines of:
function PageObj() {
var section = document.getElementById("main");
addEventListener('mousemove', function() {
//mousemove stuff
});
}

Display MathJax dynamically only when there are delimiters

I have been tweaking with below sample code. The documentation for MathJax isn't very complete. Could someone more experience tell how I should modify the below code so that Tex is only parse when I have specified delimiters like $\alpha$. I would like to make it work like on math.stackexchange.
<html>
<head>
<title>MathJax Dynamic Math Test Page</title>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [["$","$"],["\\(","\\)"]]
}
});
</script>
<script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML-full">
</script>
</head>
<body>
<script>
//
// Use a closure to hide the local variables from the
// global namespace
//
(function () {
var QUEUE = MathJax.Hub.queue; // shorthand for the queue
var math = null; // the element jax for the math output.
//
// Get the element jax when MathJax has produced it.
//
QUEUE.Push(function () {
math = MathJax.Hub.getAllJax("MathOutput")[0];
});
//
// The onchange event handler that typesets the
// math entered by the user
//
window.UpdateMath = function (TeX) {
QUEUE.Push(["Text",math,"\\displaystyle{"+TeX+"}"]);
}
})();
</script>
<textarea id="MathInput" size="50" onkeyup="UpdateMath(this.value)"></textarea>
<div id="MathOutput">
You typed: ${}$
</div>
</body>
</html>
The sample code you posted takes the contents of the MathInput and replaces the first MathJax element with the new "math" from the MathInput. What you want is to Typeset the MathInput and create new MathJax elements for the delimited text. I setup a jsFiddle example here:
http://jsfiddle.net/Zky72/2/
The main change is in the UpdateMath function:
window.UpdateMath = function (TeX) {
//set the MathOutput HTML
document.getElementById("MathOutput").innerHTML = TeX;
//reprocess the MathOutput Element
MathJax.Hub.Queue(["Typeset",MathJax.Hub,"MathOutput"]);
}

Two Javascript scripts conflicting (show/hide)

I have two Javascript scripts on a site. One is an accordion (show/hide) and the other is a basic script to show/hide based on a hyperlink click. Both scripts work fine independently, but once together on the same page the accordion one stops working: the click to display the items in the accordion stops working. Here's the code:
<link rel="stylesheet" href="[template_url]/js/tinycord/tinycord.css" type="text/css" />
<style>
.inner-boxes .box3, .details1 {
display:none;
}
</style>
<script type="text/javascript">
var parentAccordion=new TINY.accordion.slider("parentAccordion");
parentAccordion.init("acc","h3",0,-1);
</script>
<script>
$(function(){
$(".para").click(function(){
$("#fillit").html($(this).next(".details1").html());
});
$(".details1:first").clone().appendTo("#fillit").show();
});
</script>
<script type="text/javascript" src="[template_url]/js/tinycord/script.js"></script>
content of script.js
var TINY={};
function T$(i){return document.getElementById(i)}
function T$$(e,p){return p.getElementsByTagName(e)}
TINY.accordion=function(){
function slider(n){this.n=n; this.a=[]}
slider.prototype.init=function(t,e,m,o,k){
var a=T$(t), i=s=0, n=a.childNodes, l=n.length; this.s=k||0; this.m=m||0;
for(i;i<l;i++){
var v=n[i];
if(v.nodeType!=3){
this.a[s]={}; this.a[s].h=h=T$$(e,v)[0]; this.a[s].c=c=T$$('div',v)[0]; h.onclick=new Function(this.n+'.pr(0,'+s+')');
if(o==s){h.className=this.s; c.style.height='auto'; c.d=1}else{c.style.height=0; c.d=-1} s++
}
}
this.l=s
};
slider.prototype.pr=function(f,d){
for(var i=0;i<this.l;i++){
var h=this.a[i].h, c=this.a[i].c, k=c.style.height; k=k=='auto'?1:parseInt(k); clearInterval(c.t);
if((k!=1&&c.d==-1)&&(f==1||i==d)){
c.style.height=''; c.m=c.offsetHeight; c.style.height=k+'px'; c.d=1; h.className=this.s; su(c,1)
}else if(k>0&&(f==-1||this.m||i==d)){
c.d=-1; h.className=''; su(c,-1)
}
}
};
function su(c){c.t=setInterval(function(){sl(c)},20)};
function sl(c){
var h=c.offsetHeight, d=c.d==1?c.m-h:h; c.style.height=h+(Math.ceil(d/2)*c.d)+'px';
c.style.opacity=h/c.m; c.style.filter='alpha(opacity='+h*100/c.m+')';
if((c.d==1&&h>=c.m)||(c.d!=1&&h==1)){if(c.d==1){c.style.height='auto'} clearInterval(c.t)}
};
return{slider:slider}
}();
I don't think these scripts actually conflict. You are loading the accordion code after you try to use it. Perhaps reorder your script tags.
<script type="text/javascript" src="[template_url]/js/tinycord/script.js"></script>
should go before the use of TINY.accordion which it defines:
var parentAccordion=new TINY.accordion.slider("parentAccordion");
I don't know enough about the meaning of the string arguments in the call to init, but perhaps you could change the script element that creates the accordion and initializes it to happen on document load, for example by delaying it using jQuery's $.ready or by moving it after any elements whose ids appear in those string arguments.
Also the accordion code is unintentionally using a global s. And short names like s can easily collide which is a maintenance hazard even if not the cause of your immediate problem.
var a=T$(t), i=s=0, ...
is not declaring s locally. Perhaps edit it to say
var a=T$(t), s, i=s=0, ...
<script language="javascript">
jQuery.noConflict();
var b=jQuery.noConflict() || $.noConflict;
b(document).ready(function(){
b(".btn-slide").click(function(){
b("#panel").slideToggle("slow");
b(this).toggleClass("active"); return false;
});
});
</script>
Then instead of $ use b to access jQuery.

how to get tinyMCE editable for a cloned textarea by cloneNode(true) function

When I try to clone a textarea by using cloneNote(true), the cloned textarea is not editable. Does anyone know how to resolve the problem? The sample codes show as following:
<html>
<head>
<script type="text/javascript" src="/javascripts/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({
theme : "advanced",
mode : "textareas",
});
</script>
<script type="text/javascript">
testclonenode = {
addAbove : function (element) {
var rowEl = element.parentNode.parentNode.parentNode;
var rowElClone = rowEl.cloneNode(true);
rowEl.parentNode.insertBefore(rowElClone, rowEl);
return false;
}
};
</script>
</head>
<body>
<table>
<tr><td>
<textarea name="content" style="width:100%">this is a test </textarea>
<p> <button onclick='return testclonenode.addAbove.call(testclonenode, this);'> Add above </button>
</td></tr>
</table>
</body></html>
It does not work that way. Also, it is impossible to move a tinymce editor using dom manipulation.
The tinymce wiki states the following:
mceAddControl
Converts the specified textarea or div
into an editor instance having the
specified ID.
Example:
tinyMCE.execCommand('mceAddControl',false,'mydiv');
So when you clone a textarea there is another problem: You will have the same id twice which will result in errors accessing the right tinymce instance.
I got this to work by using an ID which is incremented each time my clone function is triggered, so
var insertslideID = 0;
function slideclone() {
$('<div class="slides"><textarea name="newslide['+insertslideID+'][slide_desc]" id="mydiv'+insertslideID+'"></textarea></div>').insertAfter('div.slides:last');
tinyMCE.execCommand('mceAddControl',false,'mydiv'+insertslideID);
insertslideID++;
}
$('input[name=addaslidebtn]').click(slideclone);
Seems to work.
A wee bit tidier, I just use a number for my id - copy1 is the name of my button - I add the new element to the end of my container.
var count = 0;
$("#copy1").click(function(){
var newId = count;
$( "#first" ).clone().appendTo( "#container" ).prop({ id: newId, });
tinyMCE.execCommand('mceAddControl',false,newId);
count++;
});
I ran into a similar problem, except my element IDs (not just textareas) could be anything, and the same ID was always appearing twice. What I did is supposed to be horribly inefficient but there was no noticeable performance loss with dozens of elements on the page.
Basically I removed the TinyMCE ID first (uses jQuery):
$(new_element).find('.mce-content-body').each(function () {
$(this).removeAttr('id');
});
Then I reinitialized TinyMCE for all relevant elements.

Categories