All mootools more modules are included in my app, but I would like to remove the ones I am not using. Is there a quick way to know which modules I am using starting from the script depending on mootools more?
no easy way, I am afraid. you can spy on stuff while your app runs so you can get some usage/coverage stats but because mootools is prototypal, the extensions to Array/String/Function/Date etc that more does may be more complicated to catch.
To catch classes that have been instantiated, build a list and use something like that:
Object.monitor = function(obj, match){
var keys = (function(obj){
// include from prototype also, any function.
var keys = [], key;
for (key in obj) typeof obj[key] === 'function' && keys.push(key);
return keys;
}(obj)),
log = function(what, method){
// more use goes red in console.
console.log(obj, method, what);
},
counters = {};
keys.forEach(function(key){
var orig = obj[key];
Object.defineProperty(obj, key, {
get: function(){
key in counters || (counters[key] = 0);
counters[key]++;
key.test(match) && log(counters[key], key);
return orig;
}
});
});
};
var protos = [Fx.Reveal, Fx.Slide, Request.JSONP]; // etc etc - stuff you are unsure of.
protos.forEach(function(klass){
Object.monitor(klass.prototype, /\$constructor/);
});
new Request.JSONP({});
as soon as any of these items gets instantiated OR extended, the constructor will get referenced and you will get the log to show it. http://jsfiddle.net/dimitar/8nCe6/ - this will instantiate Request.JSONP().
I wrote the Object.monitor to spy on methods being called on a particular instance but the same principle applies. The console formatting only works nice in FireBug and WebInspector - native FF console needs to be made simple.
http://fragged.org/spy-on-any-method-on-an-object-and-profile-number-of-times-called_1661.html
you can use it to spy on say, Array.prototype or any suchlike as well - but the difficulty is the code complexity of more. Hard to really nail it down :(
probably easier to concatenate all your scripts EXCEPT for mootools-more then grep for known classes / methods from the Types.
Did you compress the file?
If you haven't removed the original comments from your build, there should be a link at the top of your file with a list of the included packages and a link. e.g.
// Load this file's selection again by visiting: http://mootools.net/more/065f2f092ece4e3b32bb5214464cf926
If you don't have the link, but other comments are included, search the file for script: and you should get a list back of all the included packages.
Related
I currently have a Web Application that runs off a global Javascript-based API, and it is initialized like this:
var Api = {
someVar: "test",
someFunction: function() {
return "foo";
}
}
This API is shared across many "Widgets" that live in the Web Application, and they should all run off this single Api instance so they can pass data to each other.
AJAX is currently used to load these Widgets, for example in widgets/mywidget.html, and it's placed in, say, <div id='widget_<random number>'>...</div>
Certain other parts of the code may choose to add more functionality to Api, and it's currently done like this:
Api.myExtension = {
myNewFunction: function() {
return "bar";
}
}
However, some issues arise from this kind of usage:
Problem One: What if one Widget (these may be provided by third-parties) decides to hide some code within, and does something similar to Api = {}, destroying the global Api var everything lives on, and breaking the whole Application? Is it possible to protect this Api variable from being overwritten from outside? Only "extending" is allowed (adding new things), but "removing/changing" is not allowed. i.e.:
Api.foo = { test: "bar" } // allowed
Api.someVar = "changing the existing someVar"; // not allowed
The following code is located "inside" Api, for example:
var Api = {
Debug: {
Messages = new Array,
Write: function() {
Api.Debug.Messages.push("test"); // allowed
}
}
}
Api.Debug.Messages.push("test 2"); // not allowed
Probable Solutions I've Thought Of:
Suppose we simply use frames to resolve this issue. The Apis provided are now separate from each other. However, there's additional overhead when loading Api again and again if I have many Widgets running, and they can no longer communicate with the "Host" of the widgets (the page where frames reside in), for example, I may want to tell the host to show a notification: Api.Notify.Show("Test"), but it cannot do so because this Api is completely independent from other instances, and it cannot communicate with the "Host"
Using something like a "getter" and "setter" function for the Api to be read and written. I'm unsure on how to implement this, so any help on directions on how to implement this is welcome!
A mixture of 1/2?
There's no good way to prevent having a "third party" widget overwrite the a global variable. Generally it is the responsibility of whoever is putting together the final application to ensure that whatever JavaScripts they are using aren't littering the global namespace and conflicting. The best thing you can do in that direction is give your "Api" a nice, unique name.
What I think can help you a lot is something like the "revealing pattern", which would be a way of doing the "getters and setters" you mentioned, plus more if you needed it.
A simple, useless example would be like the following:
var Api = (function () {
// private variable
var myArray = [];
return {
addItem: function (newItem) {
myArray.push(newItem);
},
printItems: function () {
console.log("lots if items");
}
};
})();
Api.addItem("Hello, world");
Api.extensionValue = 5;
I think you should make a clear delineation of what is shared, or "singleton" data, and keep those items private, as with myArray in my example.
Make it a constant:
const Api = "hi";
Api = 0;
alert(Api); //"hi"
Take a look at
Object.freeze
More info here
Here is a code example from Mozilla's page:
var obj = {
prop: function (){},
foo: "bar"
};
// New properties may be added, existing properties may be changed or removed
obj.foo = "baz";
obj.lumpy = "woof";
delete obj.prop;
var o = Object.freeze(obj);
assert(Object.isFrozen(obj) === true);
// Now any changes will fail
obj.foo = "quux"; // silently does nothing
obj.quaxxor = "the friendly duck"; // silently doesn't add the property
// ...and in strict mode such attempts will throw TypeErrors
function fail(){
"use strict";
obj.foo = "sparky"; // throws a TypeError
delete obj.quaxxor; // throws a TypeError
obj.sparky = "arf"; // throws a TypeError
}
fail();
// Attempted changes through Object.defineProperty will also throw
Object.defineProperty(obj, "ohai", { value: 17 }); // throws a TypeError
Object.defineProperty(obj, "foo", { value: "eit" }); // throws a TypeError
However browser support is still partial
EDIT: see Kernel James's answer, it's more relevant to your question (freeze will protect the object, but not protect reassigning it. however const will) same issue with limited browser support though.
The only way (at least that I can think of) to protect your global variable is to prevent the Widgets from having a direct access to it. This can be achieved by using frames functions, as you suggested. You should create an object that contains all the functions that the Widgets should be able to use, and pass such to each Widget. For example:
var Api = {
widgetApi = {
someFunction: function(){
// ...
}
},
addWidget:function(){
var temp = this.widgetApi.constructor();
for(var key in this.widgetApi)
temp[key] = clone(this.widgetApi[key]);
return temp;
}
// Include other variables that Widgets can't use
}
This way, the Widgets could execute functions and communicate with the host or global variable Api. To set variables, the Widget would be editing its private object, rather than the global one. For every frame (that represents a Widget), you must initialize or create a copy of the widgetApi object, and probably store it inside an array, in such a way that an instance of a Widget is stored in the main Api object.
For example, given <iframe id="widget"></iframe>
You would do the following:
var widget = document.getElementById("widget");
widget.contentWindow.Api = Api.addWidget();
widget.contentWindow.parent = null;
widget.contentWindow.top = null;
Additionally, in every frame you would need to set the parent and top variables to null so that the Widgets wouldn't be able to access the data of the main frame. I haven't tested this method in a while, so there might be ways to get around setting those variables to null.
I'm trying to write 'better' javascript.
Below is one pattern I've found, and am trying to adopt. However, I'm slightly confused about its use.
Say, for example, I've got a page called "Jobs". Any JS functionality on that page would be encapsulated in something like:
window.jobs = (function(jobs, $, undefined){
return {
addNew: function(){
// job-adding code
}
}
})(window.jobs|| {}, jQuery);
$(function(){
$('.add_job').on('click', function(event){
event.preventDefault();
window.jobs.addNew();
});
});
As you can probably deduct, all I've done is replaced all the code that would have sat inside the anonymous event-handler function, with a call to a function in my global jobs object. I'm not sure why that's a good thing, other than it's reduced the possibility of variable collisions and made the whole thing a bit neater, but that's good enough for me.
The - probably fairly obvious - question is: all my event-binding init-type stuff is still sitting outside my shiny new jobs object: where should it be? Inside the jobs object? Inside the return object inside the jobs object? Inside an init() function?
I'm just trying to get a sense of a stable, basic framework for putting simple functionality in. I'm not building JS apps, I'd just like to write code that's a little more robust and maintainable than it is currently. Any and all suggestions are warmly welcomed :)
You can break down your application in whatever number of modules / objects you like too.
For instance, you can have another object / module which caches and defines all your DOM nodes and another one, which just handles any event. So for instance:
(function ( win, doc, $, undef ) {
win.myApp = win.myApp || { };
var eventHandler = {
onJobClick: function( event ) {
event.preventDefault();
myApp.addNew();
}
};
var nodes = (function() {
var rootNode = $( '.myRootNode' ),
addJob = rootNode.find( '.add_job' );
return {
rootNode: rootNode,
addJob: addJob
};
}());
$(function() {
myApp.nodes.addJob.on( 'click', myApp.handler.onJobClick );
});
myApp.nodes = nodes;
myApp.handler = eventHandler;
}( this, this.document, jQuery ));
It doesn't really matter how you create singletons in this (module) pattern, either as literal, constructor, Object.create() or whatnot. It needs to fit your requirements.
But you should try to create as many specific modules/objects as necesarry. Of course, if makes even more sense to separate those singletons / modules / objects into multiple javascript files and load them on demand and before you can say knife, you're in the world of modular programming patterns, dealing with requireJS and AMD or CommonJS modules.
Encapsulation-wise, you're fine: you could even just declare addNew in the jQuery closure and you'd still avoid the global scope. I think what you're getting at is more of implementing something close to an MVC architecture.
Something I like to do is create an object that you instantiate with a DOM element and that takes care of its own bindings/provides methods to access its controls etc.
Example:
// (pretend we're inside a closure already)
var myObj = function(args){
this.el = args.el; // just a selector, e.g. #myId
this.html = args.html;
this.bindings = args.bindings || {};
}
myObj.prototype.appendTo = function(elem){
elem.innerHTML += this.html;
this.bindControls();
};
myObj.prototype.remove = function(){
$(this.el).remove(); // using jQuery
};
myObj.prototype.bindControls = function(){
for(var i in this.bindings){ // event#selector : function
var boundFunc = function(e){ return this.bindings[i].call(this,e); };
$(this.el).on(i,boundFunc);
}
};
The way you are doing it right now is exactly how I do it also, I typically create the window objects inside the anonymous function itself and then declare inside that (in this case: jClass = window.jClass).
(function (jClass, $, undefined) {
/// <param name="$" type="jQuery" />
var VERSION = '1.31';
UPDATED_DATE = '7/20/2012';
// Private Namespace Variables
var _self = jClass; // internal self-reference
jClass = window.jClass; // (fix for intellisense)
$ = jQuery; // save rights to jQuery (also fixes vsdoc Intellisense)
// I init my namespace from inside itself
$(function () {
jClass.init('branchName');
});
jClass.init = function(branch) {
this._branch = branch;
this._globalFunctionality({ globalDatePicker: true });
this._jQueryValidateAdditions();
//put GLOBAL IMAGES to preload in the array
this._preloadImages( [''] );
this._log('*******************************************************');
this._log('jClass Loaded Successfully :: v' + VERSION + ' :: Last Updated: ' + UPDATED_DATE);
this._log('*******************************************************\n');
};
jClass._log = function() {
//NOTE: Global Log (cross browser Console.log - for Testing purposes)
//ENDNOTE
try { console.log.apply(console, arguments); }
catch (e) {
try { opera.postError.apply(opera, arguments); }
catch (e) { /* IE Currently shut OFF : alert(Array.prototype.join.call(arguments, ' '));*/ }
}
};
}(window.jClass= window.jClass|| {}, jQuery));
The reason I leave them completely anonymous like this, is that let's say in another file I want to add much more functionality to this jClass. I simply create another:
(function jClass, $, undefined) {
jClass.newFunction = function (params) {
// new stuff here
};
}(window.jClass = window.jClass || {}, jQuery))
As you can see I prefer the object.object notation, but you can use object literals object : object, it's up to you!
Either way by leaving all of this separate, and encapsulated without actual page logic makes it easier to have this within a globalJS file and every page on your site able to use it. Such as the example below.
jClass._log('log this text for me');
You don't want to intertwine model logic with your business logic, so your on the right path separating the two, and allowing for your global namespace/class/etc to be more flexible!
You can find here a comprehensive study on module pattern here: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html It covers all the aspects of block-scoped module approach. However in practice you gonna have quite a number files encapsulating you code, so the question is how to combine them property. AMD... multiple HTTP requests produced by every module loading will rather harm your page response time. So you can go with CommonJS compiled to a single JavaScript file suitable for in-browser use. Take a look how easy it is http://dsheiko.github.io/cjsc/
What are the hidden or obscure features of MooTools that every MooTools developer should be aware of?
One feature per answer, please.
Class Mutators
MooTools has a wonderful feature that allows you to create your own Class mutators. Eg, to add a logger for particular class methods being referenced, you can do:
// define the mutator as 'Monitor', use as Mointor: ['methodname', 'method2'...]
Class.Mutators.Monitor = function(methods){
if (!this.prototype.initialize) this.implement('initialize', function(){});
return Array.from(methods).concat(this.prototype.Monitor || []);
};
Class.Mutators.initialize = function(initialize){
return function(){
Array.from(this.Monitor).each(function(name){
var original = this[name];
if (original) this[name] = function() {
console.log("[LOG] " + name, "[SCOPE]:", this, "[ARGS]", arguments);
original.apply(this, arguments);
}
}, this);
return initialize.apply(this, arguments);
};
};
and then in the Class:
var foo = new Class({
Monitor: 'bar',
initialize: function() {
this.bar("mootools");
},
bar: function(what) {
alert(what);
}
});
var f = new foo();
f.bar.call({hi:"there from a custom scope"}, "scope 2");
Try the jsfiddle: http://jsfiddle.net/BMsZ7/2/
This little gem has been instrumental to me catching nested bugfoot race condition issues inside a HUUUGE async webapp that would have been so difficult to trace otherwise.
Function.prototype.protect is maybe a lesser known nice one.
Is used to have protected methods in classes:
var Foo = new Class({
fooify: function(){
console.log('can\'t touch me');
}.protect(),
barify: function(){
this.fooify();
}
});
var foo = new Foo();
foo.fooify(); // throws error
foo.barify(); // logs "can't touch me"
Personally I don't use it very often, but it might be useful in some cases.
Function.prototype.overloadGetter and Function.prototype.overloadSetter
See this post: What does MooTools' Function.prototype.overloadSetter() do?
There are many features that one can use if you read the source code, although the official line is: if it's not in the documentation, it is not in the api and it's not supported so do not base your code around it as it may change
That being said, there are a few things that really can be quite useful. One of my favourites undocumented features is this:
Referenced Elements have a uid
Any element that has either being created or is passed on through a selector, gets assigned a property uid, which is incremental and unique. Since MooTools 1.4.2, this is only readable via Slick.uidOf(node) and not via the old element attr .uid. You can now use the new uniqueNumber property of any MooTools Element object.
How is that being used? For starters, Element Storage. It relies on the uid as the key in the Storage object inside a closure, which will have anything you have .store'd for that element.
element.store('foo', 'bar');
translates to:
Storage[Slick.uidOf(element)].foo = 'bar';
and
element.retrieve('foo'); // getter of the storage key
element.eliminate('foo'); // delete Storage[Slick.uidOf(element)].foo
Initializing storage for an element you have created externally, eg, via var foo = document.createElement('div') and not Element constructor
Slick.uidOf(foo); // makes it compatible with Storage
// same as:
document.id(foo);
Things that are stored by the framework into Storage also include all events callbacks, validators instances, Fx instances (tween, morph etc) and so forth.
What can you do knowing the UIDs of elements? Well, cloning an element does NOT get the element's storage or events. You can actually write a new Element.cloneWithStorage prototype that will also copy all of the stored values you may have, which is useful upto a point - instances that reference a particular element (such as, Fx.Tween) will continue referencing the old element, so it may have unexpected results. This can be useful in moving your own storage, though, all you need is a similar method that will record what you have stored and allow you to clone it.
Example Storage puncture of another Element's data:
var foo = new Element('div'),
uid = foo.uniqueNumber;
foo.store('foo', 'foo only');
var bar = new Element('div');
console.log(bar.retrieve('foo')); // null
bar.uniqueNumber = uid; // force overwrite of uid to the other el
console.log(bar.retrieve('foo')); // foo only - OH NOES
console.log(Object.keys(foo)); // ["uniqueNumber"] - oh dear. enumerable!
One of my favorite features that I learned later but wished I knew from the beginning - event pseudos, especially :once.
See http://mootools.net/docs/more/Class/Events.Pseudos#Pseudos:once
I'd recommend reading the excellent Up the Moo Herd series by Mark Obcena, author of Pro Javascript With MooTools :)
My team and I want to maintain a low cost for switching from Zepto to another framework or native browser calls (we only target WebKit) while using it.
What are the tactics of keeping track of the places in the code where Zepto is used?
Is there anything better that maintaining a Readme list of methods used?
How would you do it?
jQuery: You can use noConflict to assign some nice, unique name to the jQuery function (perhaps jQuery itself as that's built-in, but if that's a pain something else readily distinguished from other things, like $jq or some such — noConflict returns the jQuery function so you can do that, e.g. var $jq = jQuery.noConflict();).
Zepto: Despite claiming a "jQuery-compatible syntax," it doesn't appear to support noConflict per se. However, it looks like if $ is already defined on the window object, it will leave it alone, because of this line:
'$' in window || (window.$ = Zepto);
So define $ before loading Zepto and then only use Zepto in your code (or assign something to it that's equally unique, like $jq or $zt, etc. — e.g., var $zt = Zepto;).
In either case: Then search your code for those if/when you need to find those bits.
Beyond searching for $ and specific methods, you could identify which methods are in use by logging their usage in running code.
The following code will log the function used and the stack trace every time you make a jQuery call but not log any internal calls made by jQuery.
<script>
(function(){
var insideJQuery = false;
function replaceMethod(obj, method, prefix) {
var oldMethod = obj[method];
if(typeof oldMethod !== "function")
return;
obj[method] = function() {
var externalCall = !insideJQuery;
insideJQuery = true;
var output = oldMethod.apply(this, arguments);
if(externalCall) {
console.log(prefix + method + ' called');
console.trace();
insideJQuery = false;
}
return output;
}
}
for(var method in $.fn) {
if(method != 'constructor' &&
method != 'init')
replaceMethod($.fn, method, '$.fn.');
}
for(var method in $) {
if(method != 'Event')
replaceMethod($, method, '$.');
}
})();
</script>
The exception of course would be jQuery calls inside jQuery calls like $(document).ready(function(){$('div')});.
Um, you could search for the $ sign?
Every method like parents() will be called on something that was ultimately created with the $ sign. So if you find all instances of $ and trace the use of the resulting variables you'll have everything.
I'm using Google's Closure Compiler in advanced mode, and I'm having a strange issue. Here is the uncompiled code, with returned log statement from the compiled version running:
goog.provide('frame.store');
goog.require('frame.storeBack.LocalStore');
goog.require('frame.storeBack.Mem');
frame.store = (function() {
/** prioritised list of backends **/
var backends = [
frame.storeBack.LocalStore,
frame.storeBack.Mem
];
frame.log(backends);
// [function rc(){}, function tc(){this.q={}}]
frame.log(frame.storeBack.LocalStore === backends[0]);
// true
frame.log(frame.storeBack.LocalStore.isAvailable === backends[0].isAvailable);
// false
frame.log(frame.storeBack.LocalStore.isAvailable);
// function sc(){try{return"localStorage"in window&&window.localStorage!==k}catch(a){return l}}
frame.log(backends[0].isAvailable);
// undefined
for (var i=0, len=backends.length; i<len; i++)
if (backends[i].isAvailable())
return new backends[i]();
// Uncaught TypeError: Object function rc(){} has no method 'Ga'
throw('no suitable storage backend');
})();
For some reason the static method isAvailable is not present when LocalStore is accessed via the backends array, and is present when it's accessed via it's global namespace.
Can anyone see why?
EDIT: for reference, here is the method declaration:
frame.storeBack.LocalStore.isAvailable = function() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
}catch (e) {
return false;
}
};
Turn on --debug true to check your output and what frame.storeBack.LocalStore.isAvailable is renamed to.
Dump a variables name map to check whether frame.storeBack.LocalStore.isAvailable has been flattened.
For example, the Closure Compiler may flatten frame.storeBack.LocalStore.isAvailable first to frame$storeBack$LocalStore$isAvailable, then rename the whole thing to the global function "a" or something. This is called flattening of namespaces. Check the debug output to see whether your function declaration has been renamed to:
$frame$storeBack$LocalStore$isAvailable$$ = function() {
In such case, calling frame.storeBack.LocalStore.isAvailable() directly will still call the flattened global version, no prob here! However, you can't expact that isAvailable() exists in frame.storeBack.LocalStore (another object) any more. In the compiled output, frame.storeBack.LocalStore.isAvailable and frame.storeBack.LocalStore are now separated. This is the behavior of the compiler's namespace flattening, if it happens.
You're asking for trouble putting properties into a constructor function itself -- the compiler does a lot of optimizations on classes that you may not expect.
Check the debug output and variable names map to confirm. You may have to remove the closure wrapper function in order to see the actual names in the map file.
Not sure what your back ends are exactly...
But shouldn't you instantiate them?
var backends = { localStore : new frame.storeBack.LocalStore(),
mem: new frame.storeBack.Mem() };