Instantly share code, notes, and snippets.

Embed
What would you like to do?
/*
* Mixin properties of n objects into the given object - pass in as many objects to mix in as you like.
* Can perform a shallow or deep copy (shallow is default for performance reasons).
*
* Usage:
* mixin([Boolean deepCopy,] objectToExtend, objectToMixIn [, as many other objects as needed])
*
* Examples:
*
* var o1 = {
* foo:'bar',
* anObject: {
* some:'value'
* clobber:true
* }
* };
*
* var o2 = {
* foo:'bazooka',
* aNewProperty:'something',
* anObject: {
* some:'other value'
* }
* };
*
* //merge properties of o2 into o1
* mixin(o1,o2);
* alert(o1.foo); //gives 'bazooka'
* alert(o1.anObject.clobber); //exception - clobber was blown away on the shallow copy
*
* //recursively merge objects
* mixin(true,o1,02);
* alert(o1.anObject.some); //gives 'other value'
* alert(o1.anObject.clobber); //gives true, since the merge was recursive
*
* //clone o1:
* var clone = mixin({},o1);
* alert(clone.foo); //gives 'bar'
*
*/
//helper function for mixin - adapted from jQuery core
function _isPlainObject(obj) {
if(!obj || typeof obj !== 'object' || obj.nodeType) {
return false;
}
try {
// Not own constructor property must be Object
if(obj.constructor && !Object.prototype.hasOwnProperty.call(obj, "constructor") && !Object.prototype.hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")) {
return false;
}
} catch ( e ) {
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for(key in obj ) {}
return key === undefined || Object.prototype.hasOwnProperty.call(obj, key);
}
//helper for main mixin function interface, defined below this function as "mixin"
function _merge(obj1, obj2, recursive) {
for(var p in obj2) {
if(obj2.hasOwnProperty(p)) {
try {
if(recursive && _isPlainObject(obj2[p])) {
obj1[p] = _merge(obj1[p], obj2[p]);
}
else {
obj1[p] = obj2[p];
}
}
catch(e) {
obj1[p] = obj2[p];
}
}
}
return obj1;
}
//main interface, exposed in module
function mixin() {
var obj, mixins, deep = false;
if (typeof arguments[0] === 'boolean') {
deep = arguments[0];
obj = arguments[1];
mixins = Array.prototype.slice.call(arguments,2);
}
else {
obj = arguments[0];
mixins = Array.prototype.slice.call(arguments,1);
}
//mix in properties of given objects
for (var i = 0, l = mixins.length; i<l; i++) {
_merge(obj,mixins[i],deep);
}
return obj;
}
exports.mixin = mixin;
/*
* Platform helper functionality to allow you to branch values or
* logic based on platform.
*
* Examples:
*
*
*
*/
var osname = Ti.Platform.osname,
version = parseInt(Ti.Platform.version),
is = {}; //our public interface
//Set up boolean variables for the various checks we want to do
is.android = osname === 'android';
is.ios = osname === 'iphone' || osname === 'ipad';
//add to public API
exports.osname = osname;
exports.version = version;
exports.is = is;
/*
* Wrapper for Titanium UI components. This wrapper provides a few pieces of critical
* functionality, currently missing from Titanium UI objects:
* - The ability to safely extend components with new members
* - Resource management and object lifecycle handling
* - Some syntactical sugar
*
* Caveat Number One:
* Not all Titanium UI objects are perfectly wrappable. Some still need to be used directly,
* notably TableViews and TableViewRows, since they contain LOTS of magic - like purple, sparkly
* unicorn magic. If you need a TableView, it's best to have it as a child of a Component-ized
* view, and work with the TableView directly.
*
* Caveat Number Two:
* This is not an Appcelerator-supported API - this is one approach to accomplishing the goals of
* best-practice UI development. This Component wrapper can be considered an advanced use of the
* Titanium API, and should only be used by developers who are already knowledgeable about the core
* Titanium JavaScript APIs.
*
*/
function Component(/*Titanium Proxy Object*/ tiView) {
this.viewProxy = tiView;
this.globalHandlers = {};
}
//Wrappers for common Titanium view construction functions
Component.prototype.add = function(tiChildView) {
var v = tiChildView.viewProxy||tiChildView;
this.viewProxy.add(v);
};
Component.prototype.remove = function(tiChildView) {
var v = tiChildView.viewProxy||tiChildView;
this.viewProxy.remove(v);
};
Component.prototype.open = function(args) {
if (this.viewProxy.open) {
this.viewProxy.open(args||{animated:false});
}
};
Component.prototype.close = function(args) {
if (this.viewProxy.close) {
this.viewProxy.close(args||{animated:false});
}
};
Component.prototype.animate = function(args,callback) {
this.viewProxy.animate(args,callback||function(){});
};
//Getter/Setter for the wrapped Titanium view proxy object
Component.prototype.get = function(key) {
return this.viewProxy[key];
};
Component.prototype.set = function(key,value) {
this.viewProxy[key] = value;
};
//Event Handling
Component.prototype.on = function(event,callback) {
switch (event) {
case 'location':
this.globalHandlers.location = callback;
Ti.Geolocation.addEventListener('location', this.globalHandlers.location);
break;
case 'orientationchange':
this.globalHandlers.orientationchange = callback;
Ti.Gesture.addEventListener('orientationchange', this.globalHandlers.orientationchange);
break;
default:
this.viewProxy.addEventListener(event,callback);
break;
}
};
Component.prototype.fire = function(event,data) {
this.viewProxy.fireEvent(event,data||{});
};
//Sugar for handling orientation change
Component.prototype.orientation = function(branches) {
this.on('orientationchange', function(e) {
switch (e.orientation) {
case Ti.UI.PORTRAIT:
case Ti.UI.UPSIDE_PORTRAIT:
if (branches.portrait) {
branches.portrait.call(this);
}
break;
case Ti.UI.LANDSCAPE_LEFT:
case Ti.UI.LANDSCAPE_RIGHT:
if (branches.landscape) {
branches.landscape.call(this);
}
break;
}
});
};
//This should be overridden by any Components which wish to execute custom
//clean up logic, to release their child components, etc.
Component.prototype.onDestroy = function() {};
//Clean up resources used by this Component
Component.prototype.release = function() {
//remove global event handlers
if (this.globalHandlers.location) {
Ti.Geolocation.removeEventListener('location', this.globalHandlers.location);
}
if (this.globalHandlers.orientationchange) {
Ti.Gesture.removeEventListener('orientationchange', this.globalHandlers.orientationchange);
}
//force cleanup on proxy
this.viewProxy = null;
//run custom cleanup logic
this.onDestroy();
};
//adding to public interface
exports.Component = Component;
//Component-wrapped and sugared Titanium UI object constructors - most common ones included, add/remove as needed
exports.Window = function(args) {
return new Component(Ti.UI.createWindow(args));
};
exports.View = function(args) {
return new Component(Ti.UI.createView(args));
};
exports.Button = function(args) {
return new Component(Ti.UI.createButton(args));
};
exports.ScrollView = function(args) {
return new Component(Ti.UI.createScrollView(args));
};
exports.ScrollableView = function(args) {
var views = [],
newargs = args;
//unwrap child views of ScrollableView
for(var i = 0, l = _args.views.length; i<l; i++) {
var v = _args.views[i].viewProxy||_args.views[i];
views.push(v);
}
newargs.views = views;
return new Component(Ti.UI.createScrollableView(newargs));
};
exports.ImageView = function(image,args) {
var newargs = args||{};
newargs.image = image;
return new Component(Ti.UI.createImageView(newargs));
};
exports.Label = function(textOrKey, args) {
var newargs = args||{};
newargs.text = L(textOrKey,textOrKey);
return new Component(Ti.UI.createLabel(newargs));
};
@matthewlind

This comment has been minimized.

matthewlind commented Mar 3, 2017

Anybody know what this file (ti.js) is for??

@vlesc

This comment has been minimized.

vlesc commented May 29, 2018

Nobody knows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment