Created
August 2, 2012 15:46
-
-
Save egomez99/3238054 to your computer and use it in GitHub Desktop.
[ERROR] Script Error = 'undefined' is not an object (evaluating 'this._cp.tabs') at tabgroup.js (line 275).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Open the login window for user to get access key! | |
* Once user has access key, will be redirect to the Active tab | |
* | |
* @param tabGroup | |
*/ | |
function showLoginWindow() | |
{ | |
purgeAll(); | |
OF.mobile.UI.TabGroup.closeAllWindows(); | |
if(OF.isIOS()){ | |
(OF.mobile.UI.createWindow({ | |
tabBarHidden : true, | |
_url : 'login_window.js', | |
transition : false, | |
navBarHidden : true, | |
addToControl : false | |
})).ofOpen(); | |
} | |
else{ | |
var login = OF.mobile.UI.createSimpleView({ | |
tabBarHidden : true, | |
_url : 'login_window.js', | |
transition : false, | |
navBarHidden : true, | |
addToControl : false | |
}); | |
if(!OF.mobile.UI.create_login_window){ | |
OF.include('login_window.js'); | |
} | |
OF.mobile.UI.create_login_window(login); | |
OF.mobile.UI.TabGroup.getComponent().getMainWindow().add(login); | |
login.show(); | |
} | |
} | |
function runApplication(){ | |
if(OF.isIOS()){ | |
runApplication_IOS(); | |
} | |
else { | |
runApplication_ANDROID(); | |
} | |
logToServer('App launched'); | |
} | |
function runApplication_ANDROID(){ | |
OF.mobile.UI.Spinner.show(); | |
OF.mobile.UI.TabGroup.closeAllWindows(); | |
if(OF.mobile.UI.TabGroup.getComponent().getMainWindow()){ | |
OF.mobile.UI.TabGroup.resetTabGroup(); | |
OF.mobile.UI.create_dashboard(OF.mobile.UI.TabGroup.getComponent().getMainWindow()); | |
} | |
else { | |
OF.mobile.UI.createWindow({ | |
_url : 'dashboard.js', | |
navBarHidden : true, | |
exitOnClose: true, | |
addToControl : false, | |
ofRootWindow : true | |
}); | |
} | |
//OF.mobile.UI.TabGroup.setActiveTab(OF.mobile.UI.TabGroup['new']); | |
OF.mobile.UI.TabGroup.open(); | |
} | |
/** | |
* Show listview if accesskey is valid. Should only be called from app.js or from login callback function. | |
* @returns | |
*/ | |
function runApplication_IOS() | |
{ | |
var accesskey = get_string_from_cache(DEVICE_ID); | |
if (accesskey === null) | |
{ | |
showLoginWindow(); | |
return; | |
} | |
OF.mobile.UI.TabGroup.closeAllWindows(); | |
if(Ti.App.tabgroup) | |
{ | |
Ti.App.tv_today_obj.setNullState(); | |
Ti.App.tv_new_obj.setNullState(); | |
OF.mobile.UI.TabGroup.getComponent().tabs[OF.mobile.UI.TabGroup['new']].badge = null; | |
return OF.mobile.UI.TabGroup.setActiveTab(OF.mobile.UI.TabGroup['new']); | |
} | |
Titanium.UI.setBackgroundColor('#FFFF'); | |
// tab group singleton | |
Ti.App.tabgroup = OF.mobile.UI.TabGroup; | |
var tvA = OF.mobile.UI.createWindow({ | |
_url : 'tv_today.js', | |
title : "Today's Schedule", | |
fullscreen : false, | |
navBarHidden : true, | |
addToControl : false, | |
selectedView : VIEW_TODAY | |
}); | |
var tvN = OF.mobile.UI.createWindow({ | |
_url : 'tv_new.js', | |
title : "New Work Orders", | |
fullscreen : false, | |
navBarHidden : true, | |
addToControl : false | |
}); | |
var mW = OF.mobile.UI.createWindow({ | |
_url : 'more_window.js', | |
title : "More", | |
fullscreen : false, | |
navBarHidden : true, | |
addToControl : false | |
}); | |
OF.mobile.UI.TabGroup.addTab(Titanium.UI.createTab({ | |
icon : '/images/active_tabBarIcon.png', | |
title : 'Work Orders', | |
window : tvA, | |
ofWindow : tvA | |
})); | |
OF.mobile.UI.TabGroup.addTab(Titanium.UI.createTab({ | |
icon : '/images/new_tabBarIcon.png', | |
title : 'New', | |
window : tvN, | |
ofWindow : tvN | |
})); | |
OF.mobile.UI.TabGroup.addTab(Titanium.UI.createTab({ | |
icon : '/images/tabBar_more.png', | |
title : 'More', | |
window : mW, | |
ofWindow : mW | |
})); | |
OF.mobile.UI.TabGroup.setActiveTab(OF.mobile.UI.TabGroup['new']); | |
OF.mobile.UI.TabGroup.open({animated: true}); | |
Ti.App.addEventListener('resume', function(){ | |
if (Ti.App.countdown > 0) | |
{ | |
clearInterval(Ti.App.timerButton.countdownSeconds); | |
OF.mobile.api.Workorder.getWaitingPeriod({ | |
cb : function(t){ | |
var response = t.jsonobj; | |
Ti.App.countdown = ((response.data.timer_periodleft.minutes * 60) + (response.data.timer_periodleft.seconds)) * 1000; | |
Ti.App.timerButton.title = parseInt(Ti.App.countdown/1000) + 's'; | |
Ti.App.timerButton.addCountDownInterval(); | |
}, | |
params : { | |
workorderid : Ti.App.timerButton.workorderid | |
} | |
}); | |
} | |
/** | |
* Wait a second for the device to establish context... | |
*/ | |
var waitFor = setInterval(function() { | |
OF.mobile.UI.TabGroup.getComponent().fireEvent('blur'); | |
clearInterval(waitFor); | |
},1000); | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* OF mobile-js base file | |
* | |
* @class OF core utilities and functions | |
* @singleton | |
*/ | |
var OF = OF || {}; | |
/** | |
* Copies all properties of sendingObj to receivingObj | |
* | |
* @param {Object} the receiver of properties | |
* @param {Object} the source of properties | |
* @param {Object} a different object that will be applied for defaults | |
* @return {Object} | |
*/ | |
OF.apply = function(ro, so, defaults){ | |
if(defaults){ | |
OF.apply(ro, defaults); | |
} | |
if(ro && so && typeof so == 'object'){ | |
for(var i in so){ | |
ro[i] = so[i]; | |
} | |
} | |
return ro; | |
}; | |
/** | |
* Method to combine two objects and return the newly created combined object | |
* | |
* @param {Object} obj | |
* @param {Object} props | |
* @return {Object} | |
*/ | |
OF.combine = function(obj, props){ | |
var newObj = {}; | |
OF.apply(newObj, obj); | |
return OF.apply(newObj, props); | |
} | |
OF.apply(Array.prototype, { | |
indexOf : function(o) { | |
for ( var i = 0, len = this.length; i < len; i++) { | |
if (this[i] == o) | |
return i; | |
} | |
return -1; | |
}, | |
/** | |
* Removes the specified object from the array. If the object is not found nothing happens. | |
* @param {Object} o The object to remove | |
* @return {Array} this array | |
*/ | |
remove : function(o){ | |
var index = this.indexOf(o); | |
if(index != -1){ | |
this.splice(index, 1); | |
} | |
return this; | |
}, | |
removeIndex : function(index){ | |
this.splice(index, 1); | |
return this; | |
} | |
}); | |
OF.apply(String.prototype,{ | |
capitalize : function(){ | |
return this.replace( /(^|\s)([a-z])/g , function(m,p1,p2){ return p1+p2.toUpperCase(); } ); | |
}, | |
ellipsize : function(toLength) { | |
var ellipsis = '\u2026'; | |
if (this.length < toLength) return this.substr(0, this.length); // returning "this" should be sufficient - but Titanium screws this up :( | |
return this.substr(0, toLength-1) + ellipsis; | |
}, | |
//pads left | |
lpad : function(padString, length) { | |
var str = this; | |
while (str.length < length) | |
str = padString + str; | |
return str; | |
}, | |
//pads right | |
rpad : function(padString, length) { | |
var str = this; | |
while (str.length < length) | |
str = str + padString; | |
return str; | |
}, | |
/** | |
* Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each | |
* token must be unique, and must increment in the format {0}, {1}, etc. Example usage: | |
* <pre><code> | |
var cls = 'my-class', text = 'Some text'; | |
var s = String.format('<div class="{0}">{1}</div>', cls, text); | |
// s now contains the string: '<div class="my-class">Some text</div>' | |
* </code></pre> | |
* @param {String} string The tokenized string to be formatted | |
* @param {String} value1 The value to replace token {0} | |
* @param {String} value2 Etc... | |
* @return {String} The formatted string | |
* @static | |
*/ | |
format : function(){ | |
var format = this; | |
var args = OF.toArray(arguments, 0); | |
return format.replace(/\{(\d+)\}/g, function(m, i){ | |
return args[i]; | |
}); | |
} | |
}); | |
(function(){ | |
var stripTagsRE = /<\/?[^>]+>/gi, | |
stripBR = /<br[^\s]*\/?[^>]+>/gi; | |
OF.apply(OF, { | |
isIOS : function(){ | |
return (OSNAME == OSNAME_IPHONE) | |
}, | |
isAndroid : function(){ | |
return (OSNAME == OSNAME_ANDROID) | |
}, | |
includes : [], | |
include : function(){ | |
for(var i = 0; i < arguments.length; i++){ | |
if(OF.includes.indexOf(arguments[i]) < 0){ | |
//Titanium.API.info('{guto} adding file '+arguments[i]); | |
Titanium.include('/' + arguments[i]);//doesnt work on 1.75 | |
OF.includes.push(arguments[i]); | |
} | |
} | |
}, | |
/** | |
* Copies all the properties of config to obj if they don't already exist. | |
* @param {Object} obj The receiver of the properties | |
* @param {Object} config The source of the properties | |
* @return {Object} returns obj | |
*/ | |
applyIf : function(o, c){ | |
if(o){ | |
for(var p in c){ | |
if(OF.isEmpty(o[p])){ | |
o[p] = c[p]; | |
} | |
} | |
} | |
return o; | |
}, | |
USE_NATIVE_JSON : false, | |
/** | |
* Extends one class with another class and optionally overrides members with the passed literal. This class | |
* also adds the function "override()" to the class that can be used to override | |
* members on an instance. | |
* * <p> | |
* This function also supports a 2-argument call in which the subclass's constructor is | |
* not passed as an argument. In this form, the parameters are as follows:</p><p> | |
* <div class="mdetail-params"><ul> | |
* <li><code>superclass</code> | |
* <div class="sub-desc">The class being extended</div></li> | |
* <li><code>overrides</code> | |
* <div class="sub-desc">A literal with members which are copied into the subclass's | |
* prototype, and are therefore shared among all instances of the new class.<p> | |
* This may contain a special member named <tt><b>constructor</b></tt>. This is used | |
* to define the constructor of the new class, and is returned. If this property is | |
* <i>not</i> specified, a constructor is generated and returned which just calls the | |
* superclass's constructor passing on its parameters.</p></div></li> | |
* </ul></div></p><p> | |
* For example, to create a subclass of the OF GridPanel: | |
* <pre><code> | |
MyGridPanel = OF.extend(OF.grid.GridPanel, { | |
constructor: function(config) { | |
// Your preprocessing here | |
MyGridPanel.superclass.constructor.apply(this, arguments); | |
// Your postprocessing here | |
}, | |
yourMethod: function() { | |
// etc. | |
} | |
}); | |
</code></pre> | |
* </p> | |
* @param {Function} subclass The class inheriting the functionality | |
* @param {Function} superclass The class being extended | |
* @param {Object} overrides (optional) A literal with members which are copied into the subclass's | |
* prototype, and are therefore shared between all instances of the new class. | |
* @return {Function} The subclass constructor. | |
* @method extend | |
*/ | |
extend : function(){ | |
// inline overrides | |
var io = function(o){ | |
for(var m in o){ | |
this[m] = o[m]; | |
} | |
}; | |
var oc = Object.prototype.constructor; | |
return function(sb, sp, overrides){ | |
if(OF.isObject(sp)){ | |
overrides = sp; | |
sp = sb; | |
sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);}; | |
} | |
var F = function(){}, | |
sbp, | |
spp = sp.prototype; | |
F.prototype = spp; | |
sbp = sb.prototype = new F(); | |
sbp.constructor=sb; | |
sb.superclass=spp; | |
if(spp.constructor == oc){ | |
spp.constructor=sp; | |
} | |
sb.override = function(o){ | |
OF.override(sb, o); | |
}; | |
sbp.superclass = sbp.supr = (function(){ | |
return spp; | |
}); | |
sbp.override = io; | |
OF.override(sb, overrides); | |
sb.extend = function(o){OF.extend(sb, o);}; | |
return sb; | |
}; | |
}(), | |
/** | |
* Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name. | |
* Usage:<pre><code> | |
OF.override(MyClass, { | |
newMethod1: function(){ | |
// etc. | |
}, | |
newMethod2: function(foo){ | |
// etc. | |
} | |
}); | |
</code></pre> | |
* @param {Object} origclass The class to override | |
* @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal | |
* containing one or more methods. | |
* @method override | |
*/ | |
override : function(origclass, overrides){ | |
if(overrides){ | |
var p = origclass.prototype; | |
OF.apply(p, overrides); | |
} | |
}, | |
/** | |
* Takes an object and converts it to an encoded URL. e.g. OF.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value. | |
* @param {Object} o | |
* @param {String} pre (optional) A prefix to add to the url encoded string | |
* @return {String} | |
*/ | |
urlEncode : function(o, pre){ | |
var empty, | |
buf = [], | |
e = encodeURIComponent; | |
OF.iterate(o, function(key, item){ | |
empty = OF.isEmpty(item); | |
OF.each(empty ? key : item, function(val){ | |
buf.push('&', e(key), '=', (!OF.isEmpty(val) && (val != key || !empty)) ? (OF.isDate(val) ? OF.encode(val).replace(/"/g, '') : e(val)) : ''); | |
}); | |
}); | |
if(!pre){ | |
buf.shift(); | |
pre = ''; | |
} | |
return pre + buf.join(''); | |
}, | |
/** | |
* Taken from Ext Core | |
* | |
* Iterates either the elements in an array, or each of the properties in an object. | |
* <b>Note</b>: If you are only iterating arrays, it is better to call {@link #each}. | |
* @param {Object/Array} object The object or array to be iterated | |
* @param {Function} fn The function to be called for each iteration. | |
* The iteration will stop if the supplied function returns false, or | |
* all array elements / object properties have been covered. The signature | |
* varies depending on the type of object being interated: | |
* <div class="mdetail-params"><ul> | |
* <li>Arrays : <tt>(Object item, Number index, Array allItems)</tt> | |
* <div class="sub-desc"> | |
* When iterating an array, the supplied function is called with each item.</div></li> | |
* <li>Objects : <tt>(String key, Object value, Object)</tt> | |
* <div class="sub-desc"> | |
* When iterating an object, the supplied function is called with each key-value pair in | |
* the object, and the iterated object</div></li> | |
* </ul></div> | |
* @param {Object} scope The scope (<code>this</code> reference) in which the specified function is executed. Defaults to | |
* the <code>object</code> being iterated. | |
*/ | |
iterate : function(obj, fn, scope){ | |
if(OF.isEmpty(obj)){ | |
return; | |
} | |
if(OF.isIterable(obj)){ | |
OF.each(obj, fn, scope); | |
return; | |
}else if(OF.isObject(obj)){ | |
for(var prop in obj){ | |
if(obj.hasOwnProperty(prop)){ | |
if(fn.call(scope || obj, prop, obj[prop], obj) === false){ | |
return; | |
}; | |
} | |
} | |
} | |
}, | |
isIterable : function(v){ | |
//check for array or arguments | |
if(OF.isArray(v) || v.callee){ | |
return true; | |
} | |
//check for node list type | |
if(/NodeList|HTMLCollection/.test(toString.call(v))){ | |
return true; | |
} | |
//NodeList has an item and length property | |
//IXMLDOMNodeList has nextNode method, needs to be checked first. | |
return ((typeof v.nextNode != 'undefined' || v.item) && OF.isNumber(v.length)); | |
}, | |
/** | |
* Takes an encoded URL and and converts it to an object. Example: <pre><code> | |
OF.urlDecode("foo=1&bar=2"); // returns {foo: "1", bar: "2"} | |
OF.urlDecode("foo=1&bar=2&bar=3&bar=4", false); // returns {foo: "1", bar: ["2", "3", "4"]} | |
</code></pre> | |
* @param {String} string | |
* @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false). | |
* @return {Object} A literal with members | |
*/ | |
urlDecode : function(string, overwrite){ | |
var obj = {}, | |
pairs = string.split('&'), | |
d = decodeURIComponent, | |
name, | |
value; | |
for(var i = 0; i < pairs.length; i++){ | |
var pair = pairs[i].split('='); | |
name = d(pair[0]); | |
value = d(pair[1]); | |
obj[name] = overwrite || !obj[name] ? value : | |
[].concat(obj[name]).concat(value); | |
} | |
return obj; | |
}, | |
/** | |
* Appends content to the query string of a URL, which handles logic for whether to place | |
* a question mark or ampersand. | |
* @param {String} url The url to append to. | |
* @@param {String} s The content to append to the url. | |
* @return (String) The appended string | |
*/ | |
urlAppend : function(url, s){ | |
if(!OF.isEmpty(s)){ | |
return url + (url.indexOf('?') === -1 ? '?' : '&') + s; | |
} | |
return url; | |
}, | |
/** | |
* Converts any iterable (numeric indices and a length property) into a true array | |
* Don't use this on strings. IE doesn't support "abc"[0] which this implementation depends on. | |
* For strings, use this instead: "abc".match(/./g) => [a,b,c]; | |
* @param {Iterable} the iterable object to be turned into a true Array. | |
* @return (Array) array | |
*/ | |
toArray : function(){ | |
return function(a, i, j){ | |
return Array.prototype.slice.call(a, i || 0, j || a.length); | |
} | |
}(), | |
/** | |
* Iterates an array calling the passed function with each item, stopping if your function returns false. If the | |
* passed array is not really an array, your function is called once with it. | |
* The supplied function is called with (Object item, Number index, Array allItems). | |
* @param {Array/NodeList/Mixed} array | |
* @param {Function} fn | |
* @param {Object} scope | |
*/ | |
each: function(array, fn, scope){ | |
if(OF.isEmpty(array, true)){ | |
return; | |
} | |
if(!OF.isIterable(array) || OF.isPrimitive(array)){ | |
array = [array]; | |
} | |
for(var i = 0, len = array.length; i < len; i++){ | |
if(fn.call(scope || array[i], array[i], i, array) === false){ | |
return i; | |
}; | |
} | |
}, | |
/** | |
* <p>Returns true if the passed value is empty.</p> | |
* <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul> | |
* <li>null</li> | |
* <li>undefined</li> | |
* <li>an empty array</li> | |
* <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li> | |
* </ul></div> | |
* @param {Mixed} value The value to test | |
* @param {Boolean} allowBlank (optional) true to allow empty strings (defaults to false) | |
* @return {Boolean} | |
*/ | |
isEmpty : function(v, allowBlank){ | |
return v === null || v === undefined || ((OF.isArray(v) && !v.length)) || (!allowBlank ? v === '' : false); | |
}, | |
/** | |
* Returns true if the passed object is a JavaScript array, otherwise false. | |
* @param {Object} object The object to test | |
* @return {Boolean} | |
*/ | |
isArray : function(v){ | |
return toString.apply(v) === '[object Array]'; | |
}, | |
/** | |
* Returns true if the passed object is a JavaScript Object, otherwise false. | |
* @param {Object} object The object to test | |
* @return {Boolean} | |
*/ | |
isObject : function(v){ | |
return v && typeof v == "object"; | |
}, | |
/** | |
* Returns true if the passed object is a JavaScript 'primitive', a string, number or boolean. | |
* @param {Mixed} value The value to test | |
* @return {Boolean} | |
*/ | |
isPrimitive : function(v){ | |
return OF.isString(v) || OF.isNumber(v) || OF.isBoolean(v); | |
}, | |
/** | |
* Returns true if the passed object is a JavaScript Function, otherwise false. | |
* @param {Object} object The object to test | |
* @return {Boolean} | |
*/ | |
isFunction : function(v){ | |
return toString.apply(v) === '[object Function]'; | |
}, | |
/** | |
* Returns true if the passed object is a number. Returns false for non-finite numbers. | |
* @param {Object} v The object to test | |
* @return {Boolean} | |
*/ | |
isNumber: function(v){ | |
return typeof v === 'number' && isFinite(v); | |
}, | |
/** | |
* Returns true if the passed object is a string. | |
* @param {Object} v The object to test | |
* @return {Boolean} | |
*/ | |
isString: function(v){ | |
return typeof v === 'string'; | |
}, | |
/** | |
* Returns true if the passed object is a boolean. | |
* @param {Object} v The object to test | |
* @return {Boolean} | |
*/ | |
isBoolean: function(v){ | |
return typeof v === 'boolean'; | |
}, | |
/** | |
* Returns true if the passed object is not undefined. | |
* @param {Object} v The object to test | |
* @return {Boolean} | |
*/ | |
isDefined: function(v){ | |
return typeof v !== 'undefined'; | |
}, | |
/** | |
* Returns true if the passed object is not undefined. | |
* @param {Object} v The object to test | |
* @return {Boolean} | |
*/ | |
isDate : function(v) | |
{ | |
var result = false; | |
if(v.getTime && this.isNumber(v.getTime())){ | |
result = true; | |
} | |
return result; | |
}, | |
/** | |
* Rounds the passed number to the required decimal precision. | |
* @param {Number/String} value The numeric value to round. | |
* @param {Number} precision The number of decimal places to which to round the first parameter's value. | |
* @return {Number} The rounded value. | |
*/ | |
round : function(value, precision) { | |
var result = Number(value); | |
if (!isNaN(result) && typeof precision == 'number') { | |
var decimals = precision; | |
precision = Math.pow(10, precision); | |
result = Math.round(value * precision) / precision; | |
result = result.toFixed(decimals); | |
} | |
return result; | |
}, | |
/** | |
* Strips all HTML tags | |
* @param {Object} value The text from which to strip tags | |
* @return {String} The stripped text | |
*/ | |
stripTags : function(v) { | |
return !v ? v : String(v).replace(stripTagsRE, ""); | |
}, | |
/** | |
* Strips all br tags and replace with \n | |
* @param {Object} value The text from which to strip tags | |
* @return {String} The stripped text | |
*/ | |
stripBRTags : function(v) { | |
return !v ? v : String(v).replace(stripTagsRE, "\n"); | |
} | |
}); | |
/** | |
* @class OF.mobile | |
* @singleton | |
*/ | |
OF.mobile = { | |
/** | |
* The version of the mobile lib | |
* @type String | |
*/ | |
version : '1.0', | |
/** | |
* Creates namespaces to be used for scoping variables and classes so that they are not global. | |
* Specifying the last node of a namespace implicitly creates all other nodes. Usage: | |
* <pre><code> | |
OF.mobile.namespace('Company', 'Company.data'); | |
OF.mobile.namespace('Company.data'); // equivalent and preferable to above syntax | |
Company.Widget = function() { ... } | |
Company.data.CustomStore = function(config) { ... } | |
</code></pre> | |
* @param {String} namespace1 | |
* @param {String} namespace2 | |
* @param {String} etc | |
* @method namespace | |
*/ | |
namespace : function(){ | |
var o, d; | |
OF.each(arguments, function(v) { | |
d = v.split("."); | |
o = d[0] = d[0] || {}; | |
OF.each(d.slice(1), function(v2){ | |
o = o[v2] = o[v2] || {}; | |
}); | |
}); | |
return o; | |
} | |
}; | |
/** | |
* Alias for namespaces to be used for scoping variables and classes so that they are not global. | |
* Specifying the last node of a namespace implicitly creates all other nodes. Usage: | |
* <pre><code> | |
OF.namespace('Company', 'Company.data'); | |
OF.namespace('Company.data'); // equivalent and preferable to above syntax | |
Company.Widget = function() { ... } | |
Company.data.CustomStore = function(config) { ... } | |
</code></pre> | |
* @param {String} namespace1 | |
* @param {String} namespace2 | |
* @param {String} etc | |
* @method namespace | |
*/ | |
OF.ns = OF.mobile.namespace; | |
})(); | |
/** | |
* @class OF.util.JSON | |
* Modified version of Douglas Crockford"s json.js that doesn"t | |
* mess with the Object prototype | |
* http://www.json.org/js.html | |
* @singleton | |
*/ | |
OF.util = OF.util || {}; | |
OF.util.JSON = new (function(){ | |
var useHasOwn = !!{}.hasOwnProperty, | |
isNative = function() { | |
var useNative = null; | |
return function() { | |
if (useNative === null) { | |
useNative = OF.USE_NATIVE_JSON && JSON && JSON.toString() == '[object JSON]'; | |
} | |
return useNative; | |
}; | |
}(), | |
pad = function(n) { | |
return n < 10 ? "0" + n : n; | |
}, | |
doDecode = function(json){ | |
return eval("(" + json + ')'); | |
}, | |
doEncode = function(o){ | |
if(!OF.isDefined(o) || o === null){ | |
return "null"; | |
}else if(OF.isArray(o)){ | |
return encodeArray(o); | |
}else if(OF.isDate(o)){ | |
return OF.util.JSON.encodeDate(o); | |
}else if(OF.isString(o)){ | |
return encodeString(o); | |
}else if(typeof o == "number"){ | |
//don't use isNumber here, since finite checks happen inside isNumber | |
return isFinite(o) ? String(o) : "null"; | |
}else if(OF.isBoolean(o)){ | |
return String(o); | |
}else { | |
var a = ["{"], b, i, v; | |
for (i in o) { | |
// don't encode DOM objects | |
if(!o.getElementsByTagName){ | |
if(!useHasOwn || o.hasOwnProperty(i)) { | |
v = o[i]; | |
switch (typeof v) { | |
case "undefined": | |
case "function": | |
case "unknown": | |
break; | |
default: | |
if(b){ | |
a.push(','); | |
} | |
a.push(doEncode(i), ":", | |
v === null ? "null" : doEncode(v)); | |
b = true; | |
} | |
} | |
} | |
} | |
a.push("}"); | |
return a.join(""); | |
} | |
}, | |
m = { | |
"\b": '\\b', | |
"\t": '\\t', | |
"\n": '\\n', | |
"\f": '\\f', | |
"\r": '\\r', | |
'"' : '\\"', | |
"\\": '\\\\' | |
}, | |
encodeString = function(s){ | |
if (/["\\\x00-\x1f]/.test(s)) { | |
return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) { | |
var c = m[b]; | |
if(c){ | |
return c; | |
} | |
c = b.charCodeAt(); | |
return "\\u00" + | |
Math.floor(c / 16).toString(16) + | |
(c % 16).toString(16); | |
}) + '"'; | |
} | |
return '"' + s + '"'; | |
}, | |
encodeArray = function(o){ | |
var a = ["["], b, i, l = o.length, v; | |
for (i = 0; i < l; i += 1) { | |
v = o[i]; | |
switch (typeof v) { | |
case "undefined": | |
case "function": | |
case "unknown": | |
break; | |
default: | |
if (b) { | |
a.push(','); | |
} | |
a.push(v === null ? "null" : OF.util.JSON.encode(v)); | |
b = true; | |
} | |
} | |
a.push("]"); | |
return a.join(""); | |
}; | |
/** | |
* <p>Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression. | |
* <b>The returned value includes enclosing double quotation marks.</b></p> | |
* <p>The default return format is "yyyy-mm-ddThh:mm:ss".</p> | |
* <p>To override this:</p><pre><code> | |
OF.util.JSON.encodeDate = function(d) { | |
return d.format('"Y-m-d"'); | |
}; | |
</code></pre> | |
* @param {Date} d The Date to encode | |
* @return {String} The string literal to use in a JSON string. | |
*/ | |
this.encodeDate = function(o){ | |
return '"' + o.getFullYear() + "-" + | |
pad(o.getMonth() + 1) + "-" + | |
pad(o.getDate()) + "T" + | |
pad(o.getHours()) + ":" + | |
pad(o.getMinutes()) + ":" + | |
pad(o.getSeconds()) + '"'; | |
}; | |
/** | |
* Encodes an Object, Array or other value | |
* @param {Mixed} o The variable to encode | |
* @return {String} The JSON string | |
*/ | |
this.encode = function() { | |
var ec; | |
return function(o) { | |
if (!ec) { | |
// setup encoding function on first access | |
ec = isNative() ? JSON.stringify : doEncode; | |
} | |
return ec(o); | |
}; | |
}(); | |
/** | |
* Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set. | |
* @param {String} json The JSON string | |
* @return {Object} The resulting object | |
*/ | |
this.decode = function() { | |
var dc; | |
return function(json) { | |
if (!dc) { | |
// setup decoding function on first access | |
dc = isNative() ? JSON.parse : doDecode; | |
} | |
return dc(json); | |
}; | |
}(); | |
})(); | |
/** | |
* Shorthand for {@link OF.util.JSON#encode} | |
* @param {Mixed} o The variable to encode | |
* @return {String} The JSON string | |
* @member OF | |
* @method encode | |
*/ | |
OF.encode = OF.util.JSON.encode; | |
/** | |
* Shorthand for {@link OF.util.JSON#decode} | |
* @param {String} json The JSON string | |
* @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid. | |
* @return {Object} The resulting object | |
* @member OF | |
* @method decode | |
*/ | |
OF.decode = OF.util.JSON.decode; | |
OF.ns("OF.util", "OF.lib", "OF.mobile.UI"); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @author Guto Dasilva | |
*/ | |
/** | |
* This wrapper class will add some functionality to the Ti.UI.TabGroup | |
* and also manage the windows that are left open | |
* | |
* Upon a window creation through OF.mobile.UI.Window your instance | |
* will automatically be added to the tabgroup control that in turn will | |
* close all opened windows on logout or when a user press a single tab twice | |
* | |
* <pre> | |
* //close all open windows (beside root windows) | |
* OF.mobile.UI.TabGroup.closeAllWindows(); | |
* | |
* //close windows within a tab | |
* OF.mobile.UI.TabGroup.closeWindows(tabIndex); | |
* </pre> | |
* | |
* @class OF.mobile.UI.TabGroup | |
* @singleton | |
*/ | |
(function(){ | |
/** | |
* Android tab object | |
* | |
*/ | |
var androidTab = function(config){ | |
OF.apply(this,{ | |
active : false, | |
window : null, | |
badge : null, | |
_ui : null | |
}); | |
config = config || {}; | |
OF.apply(this, config); | |
}; | |
androidTab.prototype = { | |
click : function(){ | |
this.fireEvent('android-tab:click', this); | |
if(this.window) | |
this.window.open(); | |
}, | |
fireEvent : function(e, obj){ | |
Ti.App.fireEvent(e, obj); | |
printLog('androidTab fake fireEvent {' + e + '}'); | |
} | |
} | |
var createTab = function(config){ | |
var tab = new androidTab(config); | |
tab._ui = new OF.mobile.UI.ActionListRow(OF.apply({ | |
type : OF.mobile.UI.ActionListRow.typeDashboard},config)); | |
return tab; | |
} | |
/** | |
* this is like a Ti.UI.TabGroup | |
*/ | |
var androidTabgroup = function(){ | |
this.tabs = []; | |
this.activeTab = null; | |
this._mainWindow = null; | |
this._ui = null; | |
} | |
var createTabGroup = function(){ | |
return new androidTabgroup(); | |
} | |
OF.apply(androidTabgroup.prototype, { | |
addMainWindow : function(window){ | |
this._mainWindow = window; | |
}, | |
addEventListener : function(event, handler){printLog('{adroidTabGroup} adding fake event ' + event);}, | |
addTab : function(tab){ | |
tab.ofWindow = this.getMainWindow(); | |
var newIndex = this.tabs.length, | |
o = this; | |
var oldHandler = tab.handler || function(){}; | |
tab.handler = function(e){ | |
OF.mobile.UI.TabGroup.setActiveTab(e.index); | |
oldHandler.apply(this, Array.prototype.slice.call(arguments, 0)); | |
OF.mobile.UI.TabGroup.getActiveTab().click(); | |
}; | |
var tab = createTab(tab); | |
this.tabs.push(tab); | |
return tab; | |
}, | |
removeTab : function(tab){ | |
this.tabs.remove(tab); | |
}, | |
removeAllTabs : function(){ | |
for(var i = 0; i < this.tabs.length;i++){ | |
this.tabs.remove(tab); | |
} | |
}, | |
setActiveTab : function(tabIndex){ | |
for(var i = 0, l = this.tabs.length; i < l; i++){ | |
if(this.tabs[i].active){ | |
this.fireEvent('android-tabgroup:blur', {index : i, tab : this.tabs[i]}); | |
} | |
this.tabs[i].active = false; | |
if(i == tabIndex){ | |
this.fireEvent('android-tabgroup:focus', {index : i, tab : this.tabs[i]}); | |
this.tabs[i].active = true; | |
} | |
} | |
}, | |
getMainWindow : function(){ | |
return this._mainWindow; | |
}, | |
open : function() { | |
if(this._mainWindow) { | |
this._mainWindow.open(); | |
//TODO split this later (add a setter) | |
this._ui = new OF.mobile.UI.ActionListDashboard({ | |
window : this._mainWindow, | |
top : HEADER_HEIGHT, | |
addToView : OF.mobile.UI.createScrollView({ | |
backgroundColor : '#4487AD', | |
top : HEADER_HEIGHT, | |
addToView : this._mainWindow | |
}) | |
}); | |
for(var i = 0; i < this.tabs.length; i++) { | |
this._ui.addRow(this.tabs[i]._ui); | |
} | |
Ti.App.fireEvent('android-tabgroup:open', { | |
event : 'open' | |
}) | |
} else { | |
throw 'Main window of tabgroup needs to be set {androidTabgroup}'; | |
} | |
}, | |
fireEvent : function(e, obj){ | |
Ti.App.fireEvent(e, obj); | |
printLog('androidTabgroup fake fireEvent {' + e + '}'); | |
} | |
}); | |
/** | |
* Wrapper to decide which creator to use | |
* | |
*/ | |
OF.mobile.UI.Tab = function(config){ | |
OF.mobile.UI.Tab.superclass.constructor.call(this, config); | |
this.creator = OF.isIOS() ? Titanium.UI.createTab : createTab; | |
this._init(); | |
} | |
OF.extend(OF.mobile.UI.Tab, OF.mobile.UI.Component,{ | |
createTab : function(config){ | |
var tab = new OF.mobile.UI.Tab(config); | |
return tab._cp; | |
} | |
}); | |
/** | |
* @private | |
*/ | |
var tabGroup = function(){ | |
/** | |
* Variable to hold the component creator | |
* @access protected | |
*/ | |
this.creator = OF.isIOS() ? Titanium.UI.createTabGroup : createTabGroup; | |
/** | |
* @private | |
*/ | |
this._windows = []; | |
this._init(); | |
} | |
OF.extend(tabGroup, OF.mobile.UI.Component,{ | |
/** | |
* constants for the tabs index | |
*/ | |
accepted : 0, | |
'new' : 1, | |
more : 2, | |
today : 3, | |
acceptedColor : $$.tabColor.accepted, | |
newColor : $$.tabColor['new'], | |
moreColor : $$.tabColor.more, | |
/** | |
* @private Initializer | |
* | |
*/ | |
_init : function(){ | |
tabGroup.superclass._init.call(this); | |
/** | |
* this variable should hold date that the blur last ran, for some reason | |
* on startup every tab that is added it creates a blur event and we need to prevent multiple | |
* event firing | |
*/ | |
var lastcalled = null; | |
var o = this; | |
function caseEvents(e) | |
{ | |
if(!e.bypass && (lastcalled && lastcalled.clone().addMilliseconds(500).compareTo(new Date()) == 1)){ | |
return; | |
} | |
if(!e.index && e.source.activeTab){ | |
for(var i = 0; i < e.source.tabs.length; i++){ | |
if(e.source.tabs[i].active){ | |
e.index = i; | |
break; | |
} | |
} | |
} | |
switch (e.index) | |
{ | |
case o['new']: | |
//printLog('firing new ' + o.canRefreshTab(o['new'])); | |
if (o.canRefreshTab(o['new'])) | |
Ti.App.fireEvent('refresh-new-list'); | |
break; | |
case o.accepted: | |
//printLog('firing accept '+o.canRefreshTab(o.accepted)); | |
if (o.canRefreshTab(o.accepted)) | |
Ti.App.fireEvent('refresh-list'); | |
break; | |
case o.more: | |
//printLog('firing More '+o.canRefreshTab(o.more)); | |
if (o.canRefreshTab(o.more)) | |
Ti.App.fireEvent('refresh-more'); | |
break; | |
} | |
lastcalled = new Date(); | |
} | |
this._cp.addEventListener('blur', function(e) | |
{ | |
OF.isIOS() ? caseEvents(e) : ''; | |
}); | |
this._cp.addEventListener('focus', function(e){ | |
OF.isAndroid() ? caseEvents(e) : ''; | |
if(e.index == e.previousIndex){ | |
OF.mobile.UI.TabGroup.closeWindows(e.index); | |
//focus comes after blur, so workaround to force refresh | |
OF.mobile.UI.TabGroup.getComponent().fireEvent('blur',{ bypass : true}); | |
} | |
}) | |
}, | |
/** | |
* Method to see if a tab can be refreshed | |
* | |
* @public | |
* @return boolean | |
*/ | |
canRefreshTab : function(index){ | |
if(OF.isDefined(this._windows[index])){ | |
return (this._windows[index].length > 0 ? false : true) | |
} | |
return null; | |
}, | |
/** | |
* Method to set the active tab | |
* | |
* @public | |
* return void | |
*/ | |
setActiveTab : function(tabIndex){ | |
//Ti.API.info( JSON.stringify( this ) ); | |
Ti.API.info('======'); | |
//Ti.API.info( JSON.stringify(this._cp)); | |
if(OF.isDefined(this._cp.tabs[tabIndex])){ | |
return this._cp.setActiveTab(tabIndex); | |
} | |
throw '{tabgroup} No tabs found in index: ' + tabIndex; | |
}, | |
/* | |
[INFO] OnForce/1.0 (2.1.1.GA.0fd84a2) | |
2012-08-01 22:27:40.126 OnForce[21067:1b503] +[TiWindowProxy boundBridge:withKrollObject:]: unrecognized selector sent to class 0x4d11d0 | |
2012-08-01 22:28:11.592 OnForce[21067:1b503] +[TiWindowProxy unboundBridge:]: unrecognized selector sent to class 0x4d11d0 | |
2012-08-01 22:28:11.595 OnForce[21067:1b503] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[TiWindowProxy unboundBridge:]: unrecognized selector sent to class 0x4d11d0' | |
*** First throw call stack: | |
(0x2f75022 0x2d95cd6 0x2f76aad 0x2edbed0 0x2edbcb2 0x4a6a1 0x57de2 0x26ca4c 0x2a4daa 0x2a5cd6 0x2a5c31 0x26b6b1 0x4faeb 0x50ae2 0x78c4d6 0x78c447 0x99a5ded9 0x99a616de) | |
terminate called throwing an exception | |
*/ | |
/** | |
* Method to open the tabgroup | |
* | |
* @public | |
* @return void | |
*/ | |
open : function(obj){ | |
return this._cp.open(obj); | |
}, | |
/** | |
* Method to add a tab to the tabgroup | |
* | |
* @public | |
* @return void | |
*/ | |
addTab : function(tab){ | |
//printLog('this._windows.length ' + this._windows.length); | |
this._windows.push([]); | |
//printLog('this._windows.length ' + this._windows.length); | |
this._cp.addTab(tab); | |
//printLog('added a tab: this._cp.tabs.length '+ this._cp.tabs.length); | |
}, | |
/** | |
* Method to the current active tab | |
* | |
* @public | |
* @return Ti.UI.Tab | |
*/ | |
getActiveTab : function(){ | |
var index = this.getActiveTabIndex(); | |
if(index !== null) | |
return this._cp.tabs[index]; | |
return null; | |
}, | |
getActiveTabColor : function(){ | |
var index = this.getActiveTabIndex(), | |
color = OF.mobile.UI.TabGroup.moreColor; | |
switch (index) { | |
case OF.mobile.UI.TabGroup.today: | |
case OF.mobile.UI.TabGroup.accepted: | |
color = OF.mobile.UI.TabGroup.acceptedColor; | |
break; | |
case OF.mobile.UI.TabGroup['new'] : | |
color = OF.mobile.UI.TabGroup.newColor; | |
} | |
return color; | |
}, | |
/** | |
* Method to get the active tab index | |
* | |
* @public | |
* @return int | |
*/ | |
getActiveTabIndex : function(){ | |
if(this._cp.tabs){ | |
for(var i = 0; i < this._cp.tabs.length; i++){ | |
if(this._cp.tabs[i].active){ | |
return i; | |
} | |
} | |
} | |
return null; | |
}, | |
/** | |
* Method to add the window to the control system | |
* | |
* @public | |
* @return void | |
*/ | |
addWindow : function(window){ | |
var i = this.getActiveTabIndex(); | |
if(i === null){ | |
i = OF.mobile.UI.TabGroup.accepted; | |
} | |
this._windows[i].push(window); | |
//printLog('{tabgroup.js} adding window ' + window._url + ' to index ' + i +' windows.length ' + this._windows[i].length); | |
}, | |
/** | |
* Method to remove a window from the control system | |
* | |
* @public | |
* @return void | |
*/ | |
removeWindow : function(){ | |
var index = this.getActiveTabIndex(); | |
if(index !== null){ | |
//this._cp.tabs[index].ofWindow.remove(this._windows[index][this._windows[index].length -1]);//removing the rigth view | |
//printLog('{tabgroup.js} before pop ' + this._windows[index].length); | |
this._windows[index].pop(); | |
//printLog('{tabgroup.js} after pop ' + this._windows[index].length); | |
} | |
}, | |
getLastWindowInTab : function(){ | |
var index = this.getActiveTabIndex(); | |
printLog('{tabgroup getlastWindowInTab} ' + index); | |
if(index !== null){ | |
return this._windows[index][this._windows[index].length -1]; | |
} | |
throw '{tabgroup.js} no window to return'; | |
}, | |
/** | |
* Method to close windows in a tab | |
* | |
* @public | |
* @return void | |
*/ | |
closeWindows : function(tabIndex){ | |
if(this._windows[tabIndex]){ | |
for(var i = 0; i < this._windows[tabIndex].length;i++){ | |
this._windows[tabIndex][i].ofClose({bypassTabgroupRemove : true}); | |
} | |
this._windows[tabIndex] = []; | |
} | |
}, | |
/** | |
* Method to close all windows in a tabgroup | |
* | |
* @public | |
* @void | |
*/ | |
closeAllWindows : function(){ | |
for(var i = 0; i < this._windows.length; i++){ | |
this.closeWindows(i); | |
} | |
} | |
}); | |
/** | |
* Android specific methods | |
*/ | |
if(OF.isAndroid()){ | |
OF.apply(tabGroup.prototype, { | |
/** | |
* constants for the tabs index | |
*/ | |
'new' : 0, | |
accepted : 1, | |
today : 2, | |
more : 3, | |
/** | |
* Method to set a bab | |
* | |
* @public | |
*/ | |
setTab : function(tab, index){ | |
this.resetTab(tab); | |
this.addTab(tab); | |
}, | |
/** | |
* Method to set the window for this tab | |
* | |
* @public | |
*/ | |
setTabWindow : function(window, index){ | |
this._cp.tabs[index].window = window; | |
}, | |
/** | |
* Method to reset a specific tab | |
* | |
* @public | |
*/ | |
resetTab : function(tab){ | |
var index = this._cp.tabs.indexOf(tab); | |
this.closeWindows(index); | |
this._cp.removeTab(tab); | |
this._windows.removeIndex(index); | |
}, | |
/** | |
* Method to reset the entire tabgroup | |
* | |
* @public | |
*/ | |
resetTabGroup : function(){ | |
this.closeAllWindows(); | |
this._windows = []; | |
this._cp.tabs = [] | |
} | |
}); | |
} | |
OF.mobile.UI.TabGroup = new tabGroup(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment