Permalink
Browse files

[ALOY-522] add support for loading a custom UI via a module

[ALOY-523] fix problem with multiple log severity labels when running from CLI
[ALOY-524] show filename in error log
  • Loading branch information...
1 parent acefe52 commit 92bbaf0c9f07878eb0c970e4f71831b061609f33 Jeff Haynie committed Feb 17, 2013
@@ -119,7 +119,7 @@ module.exports = function(args, program) {
logger.debug('app path = ' + paths.app);
// create compile config from paths and various alloy config files
- compileConfig = CU.createCompileConfig(paths.app, paths.project, alloyConfig);
+ compileConfig = CU.compileConfig = CU.createCompileConfig(paths.app, paths.project, alloyConfig);
buildPlatform = compileConfig.alloyConfig.platform;
theme = compileConfig.theme;
logger.debug('platform = ' + buildPlatform);
@@ -192,6 +192,8 @@ module.exports = function(args, program) {
var fp = path.join(collection.dir,view.substring(0,view.lastIndexOf('.')));
if (tracker[fp]) { return; }
+ U.currentFile = path.join(collection.dir,CONST.DIR.VIEW,view);
+
// generate runtime controller
logger.debug('[' + view + '] ' + (collection.manifest ? collection.manifest.id + ' ' : '') + 'view processing...');
parseAlloyComponent(view, collection.dir, collection.manifest);
@@ -207,13 +209,18 @@ module.exports = function(args, program) {
var fp = path.join(collection.dir,controller.substring(0,controller.lastIndexOf('.')));
if (tracker[fp]) { return; }
+ U.currentFile = path.join(collection.dir,CONST.DIR.CONTROLLER,controller);
+
// generate runtime controller
logger.debug('[' + controller + '] ' + (collection.manifest ? collection.manifest.id + ' ' : '') + 'controller processing...');
parseAlloyComponent(controller, collection.dir, collection.manifest, true);
tracker[fp] = true;
}
});
});
+
+ U.currentFile = null;
+
logger.debug('');
// BENCHMARK('process all controllers');
@@ -8,7 +8,7 @@ exports.parse = function(node, state) {
function parse(node, state, args) {
if (!state.itemsArray) {
- U.die('Invalid use of <Label>. Must be the child of <Labels>.');
+ U.dieWithNode(node, 'Invalid use of <Label>. Must be the child of <Labels>.');
}
// grab BarItemType attributes from node
@@ -8,7 +8,7 @@ exports.parse = function(node, state) {
function parse(node, state, args) {
if (!state.itemsArray) {
- U.die('Invalid use of <ButtonName>. Must be the child of <ButtonNames>.');
+ U.didieWithNode(node, 'Invalid use of <ButtonName>. Must be the child of <ButtonNames>.');
}
var string = U.trim(U.XML.getNodeText(node) || '').replace(/"/g,'\\"');
@@ -8,7 +8,7 @@ exports.parse = function(node, state) {
function parse(node, state, args) {
if (!state.itemsArray) {
- U.die('A CoverFlowImageType element must the child of a CoverFlowImageTypes element');
+ U.dieWithNode(node, 'A CoverFlowImageType element must the child of a CoverFlowImageTypes element');
}
var obj = {};
@@ -8,7 +8,7 @@ exports.parse = function(node, state) {
function parse(node, state, args) {
if (!state.itemsArray) {
- U.die('Invalid use of <Option>. Must be the child of <Options>.');
+ U.dieWithNode(node, 'Invalid use of <Option>. Must be the child of <Options>.');
}
var string = U.trim(U.XML.getNodeText(node) || '').replace(/"/g,'\\"');
@@ -59,7 +59,7 @@ function parse(node, state, args) {
if (isSingleton) {
if (id) {
logger.warn([
- 'Warning with <' + nodeName + '> at line ' + node.lineNumber,
+ 'Warning with <' + nodeName + '> at line ' + node.lineNumber + ' in ' + U.currentFile,
'id="' + id + '" will be ignored, as only ' + nodeName + ' instances can have ids, not singletons',
'To create an instance of the ' + nodeName + ', add instance="true"',
'This instance will be accessible in your controller as $.' + id,
@@ -20,7 +20,8 @@ function parse(node, state, args) {
// Ensure that this _ItemArray has an appropriate parent
if (!state.itemsArray) {
- U.die([
+ U.dieWithNode(node,
+ [
'Invalid use of <' + node.nodeName + '> at line ' + node.lineNumber,
'Must be the child one of the following: [' + def.parents.join(',') + ']'
]);
@@ -59,7 +60,7 @@ function parse(node, state, args) {
// Make sure the children match the parent
} else if (!_.contains(def.children, childArgs.fullname)) {
- U.die('Invalid child of <' + node.nodeName + '> on line ' + child.lineNumber + ': ' + childArgs.fullname);
+ U.dieWithNode(node, 'Invalid child of <' + node.nodeName + '> on line ' + child.lineNumber + ': ' + childArgs.fullname);
}
});
@@ -71,7 +71,7 @@ function parse(node, state, args) {
logger.warn('Additional views in ' + theNode + ' only supported on Android');
}
} else {
- U.die(theNode + ' can only have one androidView');
+ U.dieWithNode(theNode, theNode + ' can only have one androidView');
}
}
});
@@ -18,9 +18,9 @@ function parse(node, state, args) {
// validate src
if (!src) {
- U.die('<Require> elements must have a "src" attribute.');
+ U.dieWithNode(node, '<Require> elements must have a "src" attribute.');
} else if (U.XML.getElementsFromNodes(node.childNodes).length !== 0) {
- U.die('<Require> elements may not have child elements.');
+ U.dieWithNode(node, '<Require> elements may not have child elements.');
}
// determine which Alloy method to use
@@ -39,7 +39,7 @@ function parse(node, state, args) {
alloyRequirePath = path.join(moduleRoot,'widgets',src,CONST.DIR.VIEW,CONST.NAME_WIDGET_DEFAULT);
break;
default:
- U.die('Invalid <Require> type "' + type + '"');
+ U.dieWithNode(node, 'Invalid <Require> type "' + type + '"');
}
// make sure the required file exists at compile time, rather than
@@ -52,7 +52,7 @@ function parse(node, state, args) {
}
if (!(path.existsSync(requirePath) || (type === 'widget' && path.existsSync(alloyRequirePath)))) {
- U.die(type + ' "' + src + '" at path "' + requirePath + '"' + (type === 'widget' ? ' or "' + alloyRequirePath + '"' : '') + ' does not exist.');
+ U.dieWithNode(node, type + ' "' + src + '" at path "' + requirePath + '"' + (type === 'widget' ? ' or "' + alloyRequirePath + '"' : '') + ' does not exist.');
}
// Remove <Require>-specific attributes from createArgs
@@ -31,7 +31,7 @@ function parse(node, state, args) {
// assert that the parent is a Ti.UI.Window
var parentNode = CU.validateNodeName(state.parent.node, 'Ti.UI.Window');
if (!parentNode) {
- U.die([
+ U.dieWithNode(node, [
'Invalid parent type for <Menu>: ' + state.parent.node.nodeName,
'<Menu> must have a Ti.UI.Window as a parent'
]);
@@ -46,7 +46,7 @@ function parse(node, state, args) {
// Make sure we are dealing with MenuItems
if (!theNode) {
- U.die([
+ U.dieWithNode(node, [
'Invalid child type under <Menu>: ' + childArgs.fullname,
'<Menu> must have only <MenuItem> elements as children'
]);
@@ -30,7 +30,7 @@ function parse(node, state, args) {
(childArgs.name === 'Column' && !child.getAttribute('ns'))) {
foundColumn = true;
if (foundRow) {
- U.die([
+ U.dieWithNode(node, [
err,
'You can\'t mix columns an rows as children of <Picker>'
]);
@@ -40,7 +40,7 @@ function parse(node, state, args) {
(childArgs.name === 'Row' && !child.getAttribute('ns'))) {
foundRow = true;
if (foundColumn) {
- U.die([
+ U.dieWithNode(node, [
err,
'You can\'t mix columns an rows as children of <Picker>'
]);
@@ -26,7 +26,7 @@ function parse(node, state, args) {
(childArgs.name === 'Row' && !child.getAttribute('ns'))) {
child.nodeName = 'PickerRow';
} else {
- U.die(err);
+ U.dieWithNode(node, err);
}
// generate the code for each row and add it to the array
@@ -13,7 +13,7 @@ function parse(node, state, args) {
// Tab must have 1 window as a child
if (children.length !== 1) {
- U.die(err);
+ U.dieWithNode(node, err);
}
var child = children[0],
@@ -31,7 +31,7 @@ function parse(node, state, args) {
});
} else {
err.unshift('Invalid Tab child "' + childArgs.fullname + '"');
- U.die(err);
+ U.dieWithNode(node, err);
}
// create tab with window
@@ -23,7 +23,7 @@ function parse(node, state, args) {
}
});
} else {
- U.die([
+ U.dieWithNode(node, [
'Invalid <TabGroup> child type: ' + CU.getNodeFullname(child),
'All <TabGroup> children must be <Tab>'
]);
@@ -38,7 +38,7 @@ function parse(node, state, args) {
// the table data, a searchbar, or a proxy property assigment
var theNode = CU.validateNodeName(child, ALL_VALID);
if (!theNode) {
- U.dieWithNode(child, 'Child element must be on of the following: [' + ALL_VALID.join(',') + ']');
+ U.dieWithNode(node, 'Child element must be on of the following: [' + ALL_VALID.join(',') + ']');
} else if (theNode === 'Ti.UI.SearchBar') {
isSearchBar = true;
} else if (_.contains(PROXY_PROPERTIES, theNode)) {
@@ -13,7 +13,7 @@ function parse(node, state, args) {
// SplitWindow must have 2 windows as children
if (children.length !== 2) {
- U.die('SplitWindow must have exactly 2 children that are Windows, a master and detail respectively');
+ U.dieWithNode(node, 'SplitWindow must have exactly 2 children that are Windows, a master and detail respectively');
}
_.each(children, function(child) {
@@ -27,7 +27,7 @@ function parse(node, state, args) {
}
});
} else {
- U.die([
+ U.dieWithNode(node, [
'Invalid <SplitWindow> child type: ' + childArgs.fullname,
'<SplitWindow> must have 2 Windows as children'
]);
@@ -13,7 +13,7 @@ function parse(node, state, args) {
// NavigationGroup must have 1 window as a child
if (children.length !== 1) {
- U.die(err);
+ U.dieWithNode(node, err);
}
var child = children[0],
@@ -31,7 +31,7 @@ function parse(node, state, args) {
});
} else {
err.unshift('Invalid NavigationGroup child "' + childArgs.fullname + '"');
- U.die(err);
+ U.dieWithNode(node, err);
}
// create navgroup with window
@@ -17,6 +17,23 @@ function parse(node, state, args) {
args.symbol = CU.generateUniqueId();
}
+ var module = node.getAttribute('module');
+
+ // check to see if this tag's view is coming from a user module instead of builtin Ti API
+ // and if so, we need to load the module and use it by prefixing it to the API
+ if (module)
+ {
+ if (!U.tiapp.isModuleDeclared(module,CU.compileConfig.alloyConfig.platform))
+ {
+ U.dieWithNode(node,'Required module ' + module.yellow + ' is not declared in tiapp.xml or is not available for ' + CU.compileConfig.alloyConfig.platform.blue);
+ }
+ var p = module.split('.'),
+ m = p[p.length-1],
+ createFunc = node.getAttribute('method') || 'create' + m[0].toUpperCase() + m.substring(1) + 'View';
+ args.ns = 'require("'+module+'")';
+ delete args.createArgs['module'] && delete args.createArgs['method'];
+ }
+
// Generate runtime code
code += (state.local ? 'var ' : '') + args.symbol + " = " + args.ns + "." + createFunc + "(\n";
code += CU.generateStyleParams(
View
@@ -14,6 +14,8 @@ var path = require('path'),
CONST = require('./common/constants')
;
+exports.currentFile = null;
+
exports.XML = {
getNodeText: function(node) {
if (!node) { return ''; }
@@ -90,13 +92,21 @@ exports.XML = {
};
exports.tiapp = {
+ _xml:null,
+ getDocument: function() {
+ if (this._xml) return this._xml;
+ // shouldn't ever get here
+ U.die('programming error. called getDocument before parse has been called at least once');
+ },
parse: function(dir) {
+ if (this._xml) return this._xml;
dir || (dir = './');
var tiappPath = path.join(dir,'tiapp.xml');
if (!path.existsSync(tiappPath)) {
U.die('tiapp.xml file does not exist at "' + tiappPath + '"');
}
- return exports.XML.parseFromFile(tiappPath);
+ this._xml = exports.XML.parseFromFile(tiappPath);
+ return this._xml;
},
getTitaniumSdkVersion: function(doc) {
var elems = doc.documentElement.getElementsByTagName('sdk-version');
@@ -110,7 +120,59 @@ exports.tiapp = {
}
}
return null;
- },
+ },
+ isModuleDeclared: function (name, platform) {
+ var module = this.getModule(this._xml, name);
+ // if we've specified a platform, make sure we're running on that platform
+ if (module)
+ {
+ if (module.platform)
+ {
+ if (module.platform === platform)
+ {
+ return true;
+ }
+ else if (module.platform === 'ios' &&
+ (platform === 'ios' || platform === 'iphone' || platform === 'ipad'))
+ {
+ return true;
+ }
+ else if (module.platform === 'iphone' &&
+ (platform === 'ios' || platform === 'iphone'))
+ {
+ return true;
+ }
+ else if (module.platform === 'ipad' &&
+ (platform === 'ios' || platform === 'ipad'))
+ {
+ return true;
+ }
+ return false;
+ }
+ // otherwise if not specified, it's cross platform
+ return true;
+ }
+ // we couldn't find the module in tiapp.xml
+ return false;
+ },
+ getModule: function(doc, name) {
+ var modules = doc.documentElement.getElementsByTagName('modules');
+ if (modules.length > 0)
+ {
+ modules = modules.item(0).getElementsByTagName('module');
+ for (var i = 0; i < modules.length; i++) {
+ var node = modules.item(i);
+ var moduleId = exports.XML.getNodeText(node);
+ if (moduleId === name) {
+ return {
+ version: node.getAttribute('version'),
+ platform: node.getAttribute('platform')
+ }
+ }
+ }
+ }
+ return null;
+ },
upStackSizeForRhino: function(dir) {
var doc = exports.tiapp.parse(dir);
var runtime = exports.XML.getNodeText(exports.tiapp.getProperty(doc, 'ti.android.runtime'));
@@ -133,6 +195,7 @@ exports.tiapp = {
// serialize the xml and write to tiapp.xml
var serializer = new XMLSerializer();
+ this._xml = doc;
var newxml = serializer.serializeToString(doc);
fs.writeFileSync(path.join(dir,'tiapp.xml'),newxml,'utf8');
}
@@ -198,6 +261,7 @@ exports.tiapp = {
// serialize the xml and write to tiapp.xml
var serializer = new XMLSerializer();
+ this._xml = doc;
var newxml = serializer.serializeToString(doc);
fs.writeFileSync(tiappPath,newxml,'utf8');
@@ -570,7 +634,7 @@ exports.die = function(msg, e) {
exports.dieWithNode = function(node, msg) {
msg = _.isArray(msg) ? msg : [msg];
- msg.unshift('Error with <' + node.nodeName + '> at line ' + node.lineNumber);
+ msg.unshift('Error with <' + node.nodeName + '> at line ' + node.lineNumber + (exports.currentFile ? ' in '+exports.currentFile : ''));
exports.die(msg);
}
Oops, something went wrong.

0 comments on commit 92bbaf0

Please sign in to comment.