Socket
Socket
Sign inDemoInstall

alloy

Package Overview
Dependencies
Maintainers
4
Versions
269
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

alloy - npm Package Compare versions

Comparing version 0.1.29 to 0.2.0

Alloy/commands/compile/parsers/Alloy.Require.js

2

Alloy/alloy.js

@@ -56,2 +56,3 @@ /**

.usage('ACTION [ARGS] [OPTIONS]')
.option('-a, --allStackTrace', 'No limit to the size of stack traces')
.option('-o, --outputPath <outputPath>', 'Output path for generated code')

@@ -81,2 +82,3 @@ .option('-l, --logLevel <logLevel>', 'Log level (default: 3 [DEBUG])')

// Setup up logging output
if (program.allStackTrace) { Error.stackTraceLimit = Infinity; }
logger.stripColors = (program.colors===false);

@@ -83,0 +85,0 @@ banner();

35

Alloy/commands/compile/compilerUtils.js

@@ -28,2 +28,3 @@ var U = require('../../utils'),

PLATFORMS = ['ios', 'android', 'mobileweb'],
NS_ALLOY = 'Alloy',
NS_TI_MAP = 'Ti.Map',

@@ -36,2 +37,6 @@ NS_TI_MEDIA = 'Ti.Media',

IMPLICIT_NAMESPACES = {
// Alloy
Require: NS_ALLOY,
Include: NS_ALLOY,
// Ti.Map

@@ -73,3 +78,4 @@ Annotation: NS_TI_MAP,

},
RESERVED_ATTRIBUTES = ['id', 'class', 'require', 'platform'],
RESERVED_ATTRIBUTES = ['id', 'class', 'platform'],
RESERVED_ATTRIBUTES_REQ_INC = ['id', 'class', 'platform', 'type', 'src'],
RESERVED_EVENT_REGEX = /^on([A-Z].+)/;

@@ -80,2 +86,6 @@

//////////////////////////////////////
exports.getCompilerConfig = function() {
return compilerConfig;
}
exports.generateVarName = function(id) {

@@ -92,4 +102,4 @@ return '$.' + id;

var name = node.nodeName,
ns = node.getAttribute('ns') || IMPLICIT_NAMESPACES[name] || 'Ti.UI',
req = node.getAttribute('require'),
ns = node.getAttribute('ns') || IMPLICIT_NAMESPACES[name] || CONST.NAMESPACE_DEFAULT,
fullname = ns + '.' + name,
id = node.getAttribute('id') || state.defaultId || exports.generateUniqueId(),

@@ -128,5 +138,6 @@ platform = node.getAttribute('platform'),

var createArgs = {}, events = [];
var attrs = _.contains([], fullname) ? RESERVED_ATTRIBUTES_REQ_INC : RESERVED_ATTRIBUTES;
_.each(node.attributes, function(attr) {
var attrName = attr.nodeName;
if (_.contains(RESERVED_ATTRIBUTES, attrName)) { return; }
if (_.contains(attrs, attrName)) { return; }
var matches = attrName.match(RESERVED_EVENT_REGEX);

@@ -142,5 +153,5 @@ if (matches !== null) {

ns: ns,
name: name,
id: id,
fullname: ns + '.' + name,
req: req,
fullname: fullname,
symbol: exports.generateVarName(id),

@@ -155,3 +166,3 @@ classes: node.getAttribute('class').split(' ') || [],

exports.generateNode = function(node, state, defaultId, isRoot) {
exports.generateNode = function(node, state, defaultId, isTopLevel) {
if (node.nodeType != 1) return '';

@@ -184,3 +195,3 @@ if (defaultId) { state.defaultId = defaultId; }

code.content += state.code;
if (isRoot) { code.content += '$.setRoot(' + args.symbol + ');\n'; }
if (isTopLevel) { code.content += '$.addRoot(' + args.symbol + ');\n'; }
if (args.events && args.events.length > 0) {

@@ -264,3 +275,3 @@ _.each(args.events, function(ev) {

U.ensureDir(obj.dir.resourcesAlloy);
exports.generateConfig(obj.dir.config, alloyConfig, obj.dir.resourcesAlloy);
exports.generateConfig(obj.dir.home, alloyConfig, obj.dir.resourcesAlloy);

@@ -287,3 +298,3 @@ // keep a copy of the config for this module

} else {
logger.warn('No "app/config/config."' + CONST.FILE_EXT.CONFIG + ' file found');
logger.warn('No "app/config."' + CONST.FILE_EXT.CONFIG + ' file found');
}

@@ -497,5 +508,3 @@

var copyrights = show_copyright(c.comments_before);
//var ast = jsp.parse(code);
//var newCode = exports.formatAST(ast,config,fn);
return (copyrights ? copyrights + '\n' : '' ) + code; //newCode;
return (copyrights ? copyrights + '\n' : '' ) + code;
};

@@ -502,0 +511,0 @@

@@ -6,2 +6,3 @@ var path = require('path'),

DOMParser = require("xmldom").DOMParser,
XMLSerializer = require('xmldom').XMLSerializer,
U = require('../../utils'),

@@ -13,3 +14,4 @@ _ = require("../../lib/alloy/underscore")._,

CU = require('./compilerUtils'),
CONST = require('../../common/constants');
CONST = require('../../common/constants'),
optimizer = require('./optimizer');

@@ -26,3 +28,2 @@ var alloyRoot = path.join(__dirname,'..','..'),

var inputPath = args.length > 0 ? args[0] : U.resolveAppHome(),
alloyConfigPath = path.join(inputPath,'config','alloy.' + CONST.FILE_EXT.CONFIG),
alloyConfig = {},

@@ -47,7 +48,3 @@ outputPath, tmpPath, compilerMakeFile;

// construct compiler config from alloy.json and the command line config parameters
if (path.existsSync(alloyConfigPath)) {
alloyConfig = JSON.parse(fs.readFileSync(alloyConfigPath, 'utf8'));
logger.info("found alloy configuration at " + alloyConfigPath.yellow);
}
// construct compiler config from command line config parameters
if (program.config && _.isString(program.config)) {

@@ -98,5 +95,5 @@ _.each(program.config.split(','), function(v) {

// create components directory for view/controller components
// create generated controllers folder in resources
U.copyAlloyDir(alloyRoot, 'lib', compileConfig.dir.resources);
wrench.mkdirSyncRecursive(path.join(compileConfig.dir.resourcesAlloy, 'components'), 0777);
wrench.mkdirSyncRecursive(path.join(compileConfig.dir.resourcesAlloy, CONST.DIR.COMPONENT), 0777);
wrench.mkdirSyncRecursive(path.join(compileConfig.dir.resourcesAlloy, 'widgets'), 0777);

@@ -115,2 +112,5 @@

// include all necessary widgets
// TODO: include widgets automatically
// Process all views, including all those belonging to widgets

@@ -164,4 +164,5 @@ var viewCollection = U.getWidgetDirectories(outputPath);

///////////////////////////////////////
// function parseView(viewName,dir,viewId,manifest) {
function parseView(view,dir,manifest) {
logger.debug('Now parsing view ' + view + '...');
// validate parameters

@@ -174,7 +175,5 @@ if (!view) { U.die('Undefined view passed to parseView()'); }

viewName = basename,
viewId = basename,
template = {
viewCode: '',
controllerCode: '',
onCreate: ''
controllerCode: ''
},

@@ -213,30 +212,76 @@ state = { parent: {} },

var doc = new DOMParser().parseFromString(xml);
var docRoot = doc.documentElement;
// Give our document the <Alloy> root element if it doesn't already have one
if (doc.documentElement.nodeName !== CONST.ROOT_NODE) {
var tmpDoc = new DOMParser().parseFromString('<' + CONST.ROOT_NODE + '></' + CONST.ROOT_NODE + '>');
tmpDoc.documentElement.appendChild(doc.documentElement);
doc = tmpDoc;
// Make sure the markup has a top-level <Alloy> tag
if (docRoot.nodeName !== CONST.ROOT_NODE) {
U.die([
'Invalid view file "' + view + '".',
'All view markup must have a top-level <Alloy> tag'
]);
}
var docRoot = doc.documentElement;
var id = viewId || doc.documentElement.getAttribute('id') || viewName;
// handle component-level events
_.each(['onCreate'], function(evt) {
var attr = docRoot.getAttribute(evt);
template[evt] = attr ? attr + '($);\n' : '';
});
// Process all <Include> tags
function processInclude(node) {
var ns = node.getAttribute('ns');
if (node.nodeName === 'Include' && (!ns || ns === 'Alloy')) {
if (U.XML.getElementsFromNodes(node.childNodes).length !== 0) {
U.die('<Include> elements may not have child elements.');
}
// Generate Titanium code from the markup
var src = node.getAttribute('src');
if (!src) {
U.die('<Include> element must have a "src" attribute');
} else if (node.attributes.length !== 1) {
U.die('<Include> must have only one attribute, and it must be "src"');
}
var fullpath = path.join(dir,CONST.DIR.VIEW,src) + '.' + CONST.FILE_EXT.VIEW;
if (!path.existsSync(fullpath)) {
U.die('<Include> "src" attribute path "' + src + '" does not exist');
}
var xml = fs.readFileSync(fullpath,'utf8');
var doc = new DOMParser().parseFromString(xml);
_.each(U.XML.getElementsFromNodes(doc.documentElement.childNodes), function(n) {
node.parentNode.appendChild(n);
});
node.parentNode.removeChild(node);
}
}
// need to loop in case <Include> tag contains other <Include> tags
var includeElems;
while ((includeElems = docRoot.getElementsByTagName('Include')).length > 0) {
_.each(includeElems, processInclude);
}
var rootChildren = U.XML.getElementsFromNodes(docRoot.childNodes);
for (var i = 0, l = rootChildren.length; i < l; i++) {
template.viewCode += CU.generateNode(
rootChildren[i],
state,
i === 0 ? (viewId||viewName) : undefined,
i === 0);
// Don't process any further if "controller" is set to false. This view
// does not need a runtime controller.
if (docRoot.getAttribute('controller') === 'false') { return; }
// make sure we have a Window, TabGroup, or SplitWindow
if (viewName === 'index') {
var found = _.find(rootChildren, function(node) {
var ns = node.getAttribute('ns') || CONST.NAMESPACE_DEFAULT;
return node.nodeName === 'Window' ||
node.nodeName === 'SplitWindow' ||
node.nodeName === 'TabGroup';
});
if (!found) {
U.die([
'Compile failed. index.xml must have a top-level container element.',
'Valid elements: [ Window, TabGroup, SplitWindow]'
]);
}
}
// Generate each node in the view
_.each(rootChildren, function(node, i) {
var defaultId = i === 0 ? viewName : undefined;
template.viewCode += CU.generateNode(node, state, defaultId, true);
});
template.controllerCode += CU.loadController(files.CONTROLLER);
// create component module code for this view/controller or widget
// create generated controller module code for this view/controller or widget
var code = _.template(fs.readFileSync(path.join(compileConfig.dir.template, 'component.js'), 'utf8'), template);

@@ -243,0 +288,0 @@ try {

@@ -11,2 +11,3 @@ /**

logger = require('../../common/logger.js'),
U = require('../../utils'),
platformDefines,

@@ -259,3 +260,3 @@ platformName

var newArgs = '(function(t) {' +
'return (_.isObject(t) && t.__iamalloy__ ? t.getRoot() : t) || t;' +
'return (_.isObject(t) && t.__iamalloy ? t.getRoot() : t) || t;' +
'})(' + argsStr + ')';

@@ -281,2 +282,44 @@ ast[2][0] = jsp.parse(newArgs)[1][0][1];

exports.dissectController = function(code) {
var ast;
try {
ast = jsp.parse(code);
} catch(e) {
U.die([
code,
e.stack,
'Failed to parse controller file'
]);
}
var w = pro.ast_walker();
var initFunction = 'function init(){}';
var postLayoutCode = '';
var new_ast = w.with_walkers({
"toplevel": function() {
for (var i = 0, l = this[1].length; i < l; i++) {
if (this[1][i][0] === 'defun' && this[1][i][1] === 'init') {
//delete this[1][i][1];
initFunction = pro.gen_code(this[1][i]);
delete this[1][i];
}
}
return this;
}
}, function() {
return w.walk(ast);
});
postLayoutCode = pro.gen_code(new_ast);
return {
init: initFunction,
post: postLayoutCode
}
// console.log('----------------------------------------');
// console.log(require('util').inspect(ast, false, null));
// console.log('-');
// console.log(require('util').inspect(new_ast, false, null));
}
function optimize(ast, defines, fn)

@@ -283,0 +326,0 @@ {

@@ -19,3 +19,3 @@ var CU = require('../compilerUtils'),

node.nodeName,
_.defaults(state.extraStyle || {}, args.createArgs || {}) //state.extraStyle
_.defaults(state.extraStyle || {}, args.createArgs || {})
) + '\n';

@@ -22,0 +22,0 @@ code += "),'" + node.nodeName + "', " + (args.parent.symbol || 'null') + ");\n";

@@ -40,3 +40,12 @@ var jsp = require("../../uglify-js/uglify-js").parser,

var code = String(fs.readFileSync(fn,'utf-8'));
var ast = jsp.parse(code);
var ast;
try {
ast = jsp.parse(code);
} catch(e) {
U.die([
code,
e.stack,
'Failed to parse code in ' + fn
]);
}
var w = pro.ast_walker();

@@ -43,0 +52,0 @@ var requires = [];

@@ -5,3 +5,3 @@ var _ = require("../../lib/alloy/underscore")._,

// TODO: generate TARGETS array by reading the Alloy/commands/generate files
var TARGETS = ['component', 'controller', 'view', 'model', 'migration', 'styles', 'widget'];
var TARGETS = ['controller', 'model', 'migration', 'widget'];

@@ -8,0 +8,0 @@ function generate(args, program) {

@@ -1,2 +0,3 @@

var GU = require('../generateUtils'),
var _ = require("../../../lib/alloy/underscore")._,
GU = require('../generateUtils');
logger = require('../../../common/logger');

@@ -7,3 +8,4 @@

var info = GU.generate(name, type, program);
logger.info('Generated ' + type.toLowerCase() + ' named ' + name);
require('./view')(name, args, program);
logger.info('Generated view-style-controller named '+name);
}

@@ -91,3 +91,3 @@ var path = require('path'),

function newproject(args, program) {
var dirs = ['controllers','styles','views','models','migrations','config','assets','lib','vendor'],
var dirs = ['controllers','styles','views','models','assets'],
templateDir = path.join(alloyRoot,'template'),

@@ -99,3 +99,2 @@ defaultDir = path.join(templateDir,'default'),

README = fs.readFileSync(path.join(templateDir, 'README'),'utf8'),
defaultConfig = {},
projectPath, appPath, tmpPath, alloyJmkTemplate, cfg;

@@ -105,3 +104,3 @@

if (!_.isArray(args) || args.length === 0) {
U.die("\"alloy new\" requires an [OUTPUT_DIR]");
args[0] = '.';
}

@@ -133,3 +132,2 @@

fs.writeFileSync(path.join(appPath,'controllers','index.'+CONST.FILE_EXT.CONTROLLER),INDEX_C,'utf-8');
fs.writeFileSync(path.join(appPath,'config','alloy.'+CONST.FILE_EXT.CONFIG),U.stringifyJSON(defaultConfig),'utf-8');
fs.writeFileSync(path.join(appPath,'README'),README,'utf-8');

@@ -153,3 +151,3 @@

cfg = {global:{}, "env:development":{}, "env:test":{}, "env:production":{}, "os:ios":{}, "os:android":{}};
fs.writeFileSync(path.join(appPath,"config","config.json"), U.stringifyJSON(cfg),'utf-8');
fs.writeFileSync(path.join(appPath,"config.json"), U.stringifyJSON(cfg),'utf-8');

@@ -156,0 +154,0 @@ // install the plugin

exports.ALLOY_DIR = 'app';
exports.GLOBAL_STYLE = 'app.tss';
exports.ROOT_NODE = 'Component';
exports.ROOT_NODE = 'Alloy';
exports.NAMESPACE_DEFAULT = 'Ti.UI';

@@ -25,3 +26,3 @@ exports.FILE_EXT = {

VENDOR: 'vendor',
COMPONENT: 'components'
COMPONENT: 'controllers'
};

@@ -1,2 +0,1 @@

var _ = require('alloy/underscore')._,

@@ -107,7 +106,7 @@ Backbone = require('alloy/backbone'),

exports.getWidget = function(id, name) {
return require('alloy/widgets/' + id + '/components/' + (name || 'widget'));
return require('alloy/widgets/' + id + '/controllers/' + (name || 'widget'));
}
exports.getComponent = function(name) {
return require('alloy/components/' + name);
exports.getController = function(name) {
return require('alloy/controllers/' + name);
}

@@ -114,0 +113,0 @@

@@ -5,3 +5,4 @@ /**

var Alloy = require('alloy'),
_ = require("alloy/underscore")._;
_ = require("alloy/underscore")._,
TAP = Ti.App.Properties;

@@ -19,51 +20,33 @@ // make sure we have a unique list of IDs for adapter models

function TiAppPropertiesSync(model) {
var self = this;
var prefix = model.config.adapter.prefix ? model.config.adapter.prefix + '-' : '';
var adapterName = 'TiAppPropertiesSync';
function Sync(model, method, opts) {
var prefix = model.config.adapter.prefix ? model.config.adapter.prefix : 'default';
var regex = new RegExp("^(" + prefix + ")\\-(\\d+)$");
// save the model and columns
this.model = model;
this.columns = model.config.columns;
function debug(funcName) {
if (ENV_DEV) { Ti.API.debug(adapterName + '.' + funcName + '(): ' + JSON.stringify(self.model.attributes)); }
if (method === 'read') {
if (opts.parse) {
// is collection
var list = [];
_.each(TAP.listProperties(), function(prop) {
var match = prop.match(regex);
if (match !== null) {
list.push(TAP.getObject(prop));
}
});
model.reset(list);
var maxId = _.max(_.pluck(list, 'id'));
model.maxId = (_.isFinite(maxId) ? maxId : 0) + 1;
} else {
// is model
var obj = TAP.getObject(prefix + '-' + model.get('id'));
model.set(obj);
}
}
else if (method === 'create' || method === 'update') {
TAP.setObject(prefix + '-' + model.get('id'), model.toJSON() || {});
} else if (method === 'delete') {
TAP.removeProperty(prefix + '-' + model.get('id'));
model.clear();
}
function setModel(opts) {
_.each(self.columns, function(v,k) {
Ti.App.Properties['set'+v](prefix + k, self.model.get(k));
});
}
this.create = function(opts) {
debug('create');
setModel(opts);
};
this.read = function(opts) {
debug('read');
_.each(self.columns, function(v,k) {
var obj = {};
obj[k] = Ti.App.Properties['get'+v](prefix + k, self.model.config.defaults[k]);
self.model.set(obj);
});
};
this.update = function(opts) {
debug('update');
setModel(opts);
};
this['delete'] = function(opts) {
debug('delete');
self.model.clear();
};
}
function Sync(model, method, opts) {
var sync = new TiAppPropertiesSync(model);
return sync[method](opts);
}
module.exports.sync = Sync;

@@ -77,3 +60,3 @@ module.exports.beforeModelCreate = function(config) {

// add this adapter's values
config.columns.id = 'String';
config.columns.id = 'Int';
config.defaults.id = getUniqueId();

@@ -80,0 +63,0 @@

@@ -9,4 +9,3 @@ /**

// TODO: Use AST to create these Alloy namespace shortcuts at compile time
Alloy.CFG = require('alloy/CFG');
(require('alloy/components/index')).create();
new (Alloy.getController('index'))();

@@ -1,17 +0,20 @@

var Alloy = require("alloy"),
_ = Alloy._,
A$ = Alloy.A;
var Alloy = require('alloy'),
Backbone = Alloy.Backbone,
_ = Alloy._,
A$ = Alloy.A,
$ = {};
exports.create = function() {
var $ = require('baseComponent').create();
<%= onCreate %>
// generated from view markup
<%= viewCode %>
// generated from controller
<%= controllerCode %>
return $;
};
var __obj = _.isFunction(module.exports.extend) ? module.exports : Alloy.getController('BaseController');
module.exports = __obj.extend({
__init: function() {
$ = this;
},
__layout: function($) {
<%= viewCode %>
},
__final: function(thisRef) {
$ = thisRef || $;
}
}, {}, true);

@@ -1,5 +0,11 @@

$.t.on('click',function(e) {
alert($.t.text);
function onReady(args) {
$.index.open();
}
function doClick(e) {
alert($.label.text);
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});
$.index.open();

@@ -16,3 +16,3 @@ {

],
"version": "0.1.29",
"version": "0.2.0",
"author": "Appcelerator, Inc. <info@appcelerator.com>",

@@ -34,3 +34,2 @@ "maintainers": [

"colors": "0.6.0-1",
"optimist": "0.3.4",
"pkginfo": "0.2.2",

@@ -37,0 +36,0 @@ "commander": "0.6.1",

@@ -31,10 +31,18 @@ Alloy

1. Download and install [Node.js](http://nodejs.org/), if necessary
2. At the command line: `sudo npm install -g alloy`
2. Downaload and install [npm](https://github.com/isaacs/npm/), if necessary
3. At the command line: `sudo npm install -g alloy`
* Do this for each project you create:
3. Create a new mobile project in Titanium Studio, we'll call its path **PATH/TO/PROJECT**.
4. `cd PATH/TO/PROJECT`
5. `alloy new .`
4. Create a new mobile project in Titanium Studio, we'll call its path **PATH/TO/PROJECT**.
5. `cd PATH/TO/PROJECT`
6. `alloy new .`
After these steps, you can now run your projects in Titanium Studio. Be aware when working with an Alloy project that all files in your **Resources** directory are subject to being overwritten. All your work should be done in your project's **app** folder.
If your new to Titanium development there is a web based guide to building your first Alloy app. To view the guide download the Alloy repository as a zip file, then open the zip file and in the docs/Alloy-bootstrap/folder you'll find the guide.
Environment requirements:
Titanium SDK 2.1.0 and greater
At this point we only support Alloy development on OSX.
Installation

@@ -84,3 +92,3 @@ -------------

Directory Structure
--------------------
-------------------

@@ -97,5 +105,8 @@ Alloy has directories that should be familiar if you've used any of the popular web MVC frameworks like Ruby on Rails.

- *migrations* - this is where your database migration files will be stored.
The following folders are not created automatically by Alloy but can be created and used by developers to add application libraries.
- *lib* - this is where you should put application specific files, typically in the CommonJS format.
- *vendor* - this is where you should put any vendor specific modules, typically in the CommonJS format. Do not place native modules in this folder.
- *config* - Contains application specific config.

@@ -110,15 +121,12 @@ Compiling an App

If you run this from the projects directory, it will compile the files to the correct location automatically.
Generating Views
-----------------
To generate an empty view and the associated style files, you can run the following command:
Debugging an App
----------------
alloy generate view <name>
Alloy apps can be debugged from within Titanium Studio by setting breakpoints in the generated controller in the Resources/alloy/controllers folder.
Generating Controllers
---------------------
----------------------
To generate an empty controller, you can run the following command:
To generate an empty controller, style and view file you can run the following command:

@@ -128,3 +136,3 @@ alloy generate controller <name>

Generating Models
---------------------
-----------------

@@ -159,3 +167,2 @@ To generate a model, you can run the following command:

Developing in Alloy

@@ -170,3 +177,3 @@ -------------------

In Alloy, any view styles will automatically be loaded from a file with the same name as the view and an `.json` file extension and located in the `styles` directory. The file format is JSON. Each of the objects in the view that you want to be referenceable either through styling or programmatically must have an `id` attribute on the object.
In Alloy, any view styles will automatically be loaded from a file with the same name as the view and an `.tss` file extension and located in the `styles` directory. The file format is JSON. Each of the objects in the view that you want to be referenceable either through styling or programmatically must have an `id` attribute on the object.

@@ -274,2 +281,3 @@ You define a style in the JSON like this:

- the order of precedence is: Object Type, Classes, ID
- You can put globals is a file called app.tss

@@ -311,19 +319,16 @@ Titanium Namespacing

For models, we specify the schema of our model using JSON as the name of the model ending with `.json`.
For models, we specify the descriptor of our model using JSON as the name of the model ending with `.json`.
You should generate a model using the `alloy generate model` command so that you can get automatic migration support.
All model classes are automatically defined and available in your controller scope as the name of the model.
A model and collection class are automatically defined and available in your controller scope as the name of the model (name of descriptor JSON file).
For example, if you defined a model named `todo`, it would be available as the same variable name under the `$.` object.
For example, if you defined a model named `Book`, it would be available as the same name in Alloy using the methods Alloy.getCollection('Book') or Alloy.getModel('Book').
To create a new model object:
To create a new collect with a single model:
```javascript
var todo = new $.Todo({
name:"hello",
done:false
});
todo.save();
var books = new (Alloy.getCollection('Book'));
var book = new (Alloy.getModel('Book'))({book:"Jungle Book", author:"Kipling"});
books.add(book);
```

@@ -333,9 +338,2 @@

Collections of your models are automatically also created with the plural name of your model class. For example, if you defined a model named `todo`, you could automatically create a collection of models by using the following code:
```javascript
var list = new $.TodoCollection();
var results = list.find();
```
Collections inherit from Backbone.Collections.

@@ -374,2 +372,10 @@

The pattern for creating Alloy markup is to have the XML element name match the corresponding Titanium API name. Nested elements get added to parent element, for example the Button element below is added as a child to the Window element. Titanium styles are applied through the attributes of the style files described above.
```xml
<Window>
<Button id="b"></Button>
</Window>
```
Exporting Properties & Functions from Controllers

@@ -410,3 +416,3 @@ -------------------------------------------------

<View>
<Widget require="com.foo.widget" id="foo"/>
<Require widgetid="com.foo.widget" id="foo"/>
</View>

@@ -504,3 +510,3 @@ ```

Alloy provides an ability to have project configurations stored as JSON which will be compiled and conditionalized at build time.
The configuration will be available in your app at runtime in the variable `CFG$`. The config file is generated under the config folder with the name `config.json`.
The configuration will be available in your app at runtime in the variable `Alloy.CFG`. The config file is generated under the app folder with the name `config.json`.

@@ -548,3 +554,3 @@ In the config file, you can specify a set of global key/value pairs, as well as conditional configuration based on build environment and/or operating system target. The order of precedence for key merging is `global`, `env` and then `os`.

```javascript
alert(CFG$.foo);
alert(Alloy.CFG.foo);
```

@@ -608,11 +614,6 @@

Alloy compiler configuration
-----------------------------
You can control some settings of the compiler on a per project basis by modifying settings in the `alloy.json` in your root alloy app directory.
Running the Test Harness
------------------------
To run the sample Alloy apps in the included test harness, you will need to have the Jake build tool installed. Jake is like Rake for Ruby, which its self is based on make. Jake can be installed via npm:
To run the sample Alloy apps in the included test harness, you will need to have the Jake build tool installed. Jake is like Rake for Ruby, which itself is based on make. Jake can be installed via npm:

@@ -661,8 +662,4 @@ [sudo] npm install -g jake

- integration into Titanium Studio wizards
- DB migration support implementation [TEST]
- support for SQLite backed Model implementation [TEST]
- support for ACS backed Model implementation
- uglify all JS files, not just the app.js
- generation of scaffolding
- add support for TDD testing (possibly Jasmine?)
- possible view template support?

@@ -669,0 +666,0 @@ - full implementation of different views based on os, screen size, etc.

@@ -9,9 +9,14 @@ // These "builtin" requires will be detected by the alloy compile process.

$.shake.on('click', function(e) {
animation.shake($.mover);
function onReady(args) {
$.shake.on('click', function(e) {
animation.shake($.mover);
});
$.trim.on('click', function(e) {
$.label.text = string.trim($.label.text);
});
$.index.open();
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});
$.trim.on('click', function(e) {
$.label.text = string.trim($.label.text);
});
$.index.open();

@@ -0,15 +1,7 @@

function onReady(args) {
$.index.open();
}
// top is the first view we defined
$.top.updateLayout({
backgroundColor:"black",
borderRadius:2,
borderColor:"blue",
height:100
});
$.bottom.b.addEventListener('click',function(){
$.middle.t.text = "You clicked me";
});
$.index.open();
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});

@@ -1,1 +0,7 @@

$.win.open();
function onReady(args) {
$.win.open();
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});

@@ -1,50 +0,56 @@

// Function to keep a Ti.TableView in sync with Backbone Model.
$.table.updateContent = function(collection) {
var rows = [];
for (var i = 0; i < collection.length; i++) {
var model = collection.at(i).attributes, title = "";
for (var key in model) { if (key !== "id") { title += model[key] + " " }}
rows.push(Ti.UI.createTableViewRow({"title":title}));
}
this.setData(rows);
};
function onReady(args) {
// Function to keep a Ti.TableView in sync with Backbone Model.
$.table.updateContent = function(collection) {
var rows = [];
for (var i = 0; i < collection.length; i++) {
var model = collection.at(i).attributes, title = "";
for (var key in model) { if (key !== "id") { title += model[key] + " " }}
rows.push(Ti.UI.createTableViewRow({"title":title}));
}
this.setData(rows);
};
// Now let's create a Backbone collection that will hold our models,
// the classes that represent our model have been generated automatically
// as Alloy components. Use new on the component to create the model or
// collection.
var books = new (Alloy.getCollection('Book'));
// Now let's create a Backbone collection that will hold our models,
// the classes that represent our model have been generated automatically
// as Alloy components. Use new on the component to create the model or
// collection.
var books = new (Alloy.getCollection('Book'));
// You can bind any Backbone event to models or collections but fetch is convenient because
// fetch occurs when the persistent store is sync'd to the local Backbone server.
books.bind("fetch", function() { $.table.updateContent(books); });
// You can bind any Backbone event to models or collections but fetch is convenient because
// fetch occurs when the persistent store is sync'd to the local Backbone server.
books.bind("fetch", function() { $.table.updateContent(books); });
// Fetch will load models from persistent starage, sync'ing Backbone and persistent store.
books.fetch();
// Fetch will load models from persistent starage, sync'ing Backbone and persistent store.
books.fetch();
// Now we can add items to the model.
var book = new (Alloy.getModel('Book'))({book:"Jungle Book", author:"Kipling"});
books.add(book);
// Now we can add items to the model.
var book = new (Alloy.getModel('Book'))({book:"Jungle Book", author:"Kipling"});
books.add(book);
// Use Backbone shortcut to create a model and add to collection in single step. Does the same
// thing as the creating a new model and then adding it to the collection.
books.add({book:"War and Peace", author:"Tolstoy"});
// Use Backbone shortcut to create a model and add to collection in single step. Does the same
// thing as the creating a new model and then adding it to the collection.
books.add({book:"War and Peace", author:"Tolstoy"});
// Add will add models to local Backbone server but save triggers the CRUD create opperation
// causing the model to get added to the persistent store. During create an id is added to the
// model signaling that the model has been persisted and no longer in the new state.
books.forEach(function(model){ model.save();});
// Add will add models to local Backbone server but save triggers the CRUD create opperation
// causing the model to get added to the persistent store. During create an id is added to the
// model signaling that the model has been persisted and no longer in the new state.
books.forEach(function(model){ model.save();});
// UPDATE - update the model save here triggers the CRUD update opperation
book.save({author:"R Kipling"});
// UPDATE - update the model save here triggers the CRUD update opperation
book.save({author:"R Kipling"});
// Okay time to show the results. Remember this sync's local Backbone server with persitent store.
books.fetch();
// Okay time to show the results. Remember this sync's local Backbone server with persitent store.
books.fetch();
// DELETE - destroy triggers the CRUD delete opperation
for(i=books.length-1; i>=0; i--) {
var model = books.at(i);
model.destroy();
};
// DELETE - destroy triggers the CRUD delete opperation
for(i=books.length-1; i>=0; i--) {
var model = books.at(i);
model.destroy();
};
$.index.open();
$.index.open();
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});
localStorage Model
==================
The sample show how to use the full CRUD features of Backbone when runing on Mobile Web.
This sample shows how to use the features of Alloy's built-in Backbone support when running on the Mobile Web platform. For Mobile Web a HTML5 localStorage adpater will persist the Backbone model.
The JSON model descriptor file show below is used to hook the model to the persistant store adapter. The name of file becomes a model and collection class available to create objects from within the code.
The JSON model descriptor below is used to create the localStorage and store the model. The file name book is the name of the model and the adapter name is the name that the key/value is stored under.
books.json
book.json
{
"defaults": {
},
"adapter": {
"type": "localStorage",
"filename": "books"
"name": "books"
}

@@ -24,5 +22,1 @@ }

ToDo
====
Handle multiple persistent stores. Delete is not completly clearing all models.

@@ -0,1 +1,5 @@

function onReady(args) {
$.index.open();
}
function doClick(e) {

@@ -5,2 +9,4 @@ alert($.t.text);

$.index.open();
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});

@@ -1,6 +0,12 @@

var foo = require("foo"),
bar = require("vendor/bar");
function onReady(args) {
var foo = require("foo"),
bar = require("vendor/bar");
Ti.API.info(bar.helloize(foo.generate()));
Ti.API.info(bar.helloize(foo.generate()));
$.index.open();
$.index.open();
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});

@@ -20,5 +20,2 @@ Modules

QUESTIONS
----------
- for the selector engine, since we might have different view hierarchies, do we need to define the `$` in each views controller scope instead of global?

@@ -1,1 +0,7 @@

$.index.open();
function onReady(args) {
$.index.open();
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});

@@ -1,22 +0,7 @@

var app = new (Alloy.getModel('App'));
function onReady(args) {
$.index.open();
}
// TODO: Should we always do this? Could put it in the model code itself
// save all changes to Ti.App.Properties
app.on('change', function() { app.save(); });
// Change label when 'count' changes on model
app.on('change:count', function(model) {
$.label.text = 'model: ' + JSON.stringify(model.attributes);
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});
// fetch model from Ti.App.Properties adapter
app.fetch();
$.win.open();
////////////////////////////////////
////////// event handlers //////////
////////////////////////////////////
function create(e) { app.save(app.defaults); }
function destroy(e) { app.destroy(); }
function increment(e) { app.set({'count':app.get('count')+1}); }
ALLOY
=====
This is a set of real code examples of the new Alloy framework. These are hand written as a demonstration of how a developer would write the code and how our compiler would generate the written code. I have not tested each line of code so it should be viewed more as intended to be real code.
This is a set of real code examples of the Alloy framework.
For each example, I have provided a `_generated` folder with an `app.js` that would be generated from the resulting code by the compiler.
For a basic amount of documentation, see the [README](https://github.com/appcelerator/alloy/blob/master/simple/README.md) file in the [Simple](https://github.com/appcelerator/alloy_examples/blob/master/simple) example.
Examples
--------
- *Simple*: the most basic example
- *Complex*: a more complex example that shows decomposing a view into subviews
- *Widget*: an example of building a widget and then using it in an app
- *Simple Model*: an example of a model based system that includes migrations
- *masterdetail*: a lesson in louse-coupling through MVC, delegates, and custom events in alloy
- *Multiplatform*: an example of building a multi screen app
- *Modules*: an example that shows an app built module and a vendor module. This also demonstrates the selector engine.
- *Namespaces*: Shows you how you can use UI components outside of the `Ti.UI` namespace in your markup view hierarchy.
- *No Ids*: Build a view hierarchy without explicitly giving the elements IDs.
Issues to be resolved
----------------------
- Where should normal resources files such as images go?
- Do we really need a selector engine if we go this route? Is it too complexed?
- Do we need a way to define a root window? I'm going for pre-defined window to be generated by the app and then referencable. I think this is probably the best and most simple right now.
- Do we really need backbone for models? seems like overkill but we could use for our model implementation. maybe strip out routes, etc.
- Would be nice to have config file support to allow developer to have project specific or deployment specific (simulator vs install) config
- Would be nice to integration something like Jasmine support for TDD
Stuff we should support
-----------------------
- built-in ACS models
- built-in SQLite models
- built-in analytics generation
- would be nice to have a Rakefile like file that can be generated and then customized by user to control specific project processing

@@ -1,17 +0,13 @@

function showAlert()
{
alert("Click! Shouldn't do it again though");
// test removing it
$.b.off("click",showAlert);
}
function onReady() {
function showAlert() {
alert("Click! Shouldn't do it again though");
$.b.off("click",showAlert);
}
$.b.on("click",showAlert);
$.b.on("click",showAlert);
if (ENV_DEV) {
alert('development mode');
$.index.open();
}
$.index.open();
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});

@@ -1,1 +0,7 @@

$.index.open();
function onReady(args) {
$.index.open();
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});

@@ -1,50 +0,56 @@

// Function to keep a Ti.TableView in sync with Backbone Model.
$.table.updateContent = function(collection) {
var rows = [];
for (var i = 0; i < collection.length; i++) {
var model = collection.at(i).attributes, title = "";
for (var key in model) { if (key !== "id") { title += model[key] + " " }}
rows.push(Ti.UI.createTableViewRow({"title":title}));
}
this.setData(rows);
};
function onReady(args) {
// Function to keep a Ti.TableView in sync with Backbone Model.
$.table.updateContent = function(collection) {
var rows = [];
for (var i = 0; i < collection.length; i++) {
var model = collection.at(i).attributes, title = "";
for (var key in model) { if (key !== "id") { title += model[key] + " " }}
rows.push(Ti.UI.createTableViewRow({"title":title}));
}
this.setData(rows);
};
// Now let's create a Backbone collection that will hold our models,
// the classes that represent our model have been generated automatically
// as Alloy components. Use new on the component to create the model or
// collection.
var books = new (Alloy.getCollection('Book'));
// Now let's create a Backbone collection that will hold our models,
// the classes that represent our model have been generated automatically
// as Alloy components. Use new on the component to create the model or
// collection.
var books = new (Alloy.getCollection('Book'));
// You can bind any Backbone event to models or collections but fetch is convenient because
// fetch occurs when the persistent store is sync'd to the local Backbone server.
books.bind("fetch", function() { $.table.updateContent(books); });
// You can bind any Backbone event to models or collections but fetch is convenient because
// fetch occurs when the persistent store is sync'd to the local Backbone server.
books.bind("fetch", function() { $.table.updateContent(books); });
// Fetch will load models from persistent starage, sync'ing Backbone and persistent store.
books.fetch();
// Fetch will load models from persistent starage, sync'ing Backbone and persistent store.
books.fetch();
// Now we can add items to the model.
var book = new (Alloy.getModel('Book'))({book:"Jungle Book", author:"Kipling"});
books.add(book);
// Now we can add items to the model.
var book = new (Alloy.getModel('Book'))({book:"Jungle Book", author:"Kipling"});
books.add(book);
// Use Backbone shortcut to create a model and add to collection in single step. Does the same
// thing as the creating a new model and then adding it to the collection.
books.add({book:"War and Peace", author:"Tolstoy"});
// Use Backbone shortcut to create a model and add to collection in single step. Does the same
// thing as the creating a new model and then adding it to the collection.
books.add({book:"War and Peace", author:"Tolstoy"});
// Add will add models to local Backbone server but save triggers the CRUD create opperation
// causing the model to get added to the persistent store. During create an id is added to the
// model signaling that the model has been persisted and no longer in the new state.
books.forEach(function(model){ model.save();});
// Add will add models to local Backbone server but save triggers the CRUD create opperation
// causing the model to get added to the persistent store. During create an id is added to the
// model signaling that the model has been persisted and no longer in the new state.
books.forEach(function(model){ model.save();});
// UPDATE - update the model save here triggers the CRUD update opperation
book.save({author:"R Kipling"});
// UPDATE - update the model save here triggers the CRUD update opperation
book.save({author:"R Kipling"});
// Okay time to show the results. Remember this sync's local Backbone server with persitent store.
books.fetch();
// Okay time to show the results. Remember this sync's local Backbone server with persitent store.
books.fetch();
// DELETE - destroy triggers the CRUD delete opperation
for(i=books.length-1; i>=0; i--) {
var model = books.at(i);
model.destroy();
};
// DELETE - destroy triggers the CRUD delete opperation
for(i=books.length-1; i>=0; i--) {
var model = books.at(i);
model.destroy();
};
$.index.open();
$.index.open();
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});

@@ -29,7 +29,1 @@ SQL Model

ToDo
====
1) Add the XML binding as described above using templates
2) Put logic to see if an object added to db is a new, and if so add to local server model

@@ -1,1 +0,7 @@

$.index.open();
function onReady(args) {
$.index.open();
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});

@@ -1,19 +0,25 @@

$.sfb.setHandlers({
success: function(books) {
var data = [];
_.each(books, function(book) {
var row = Alloy.getComponent('row').create({
title: book.title,
authors: book.authors,
image: book.image
}).getRoot();
data.push(row);
});
$.table.setData(data);
}
// You can override error handling with the 'error' property
// error: function(e) {
// alert('ERROR: ' + e.error);
// }
function onReady(args) {
$.sfb.setHandlers({
success: function(books) {
var data = [];
_.each(books, function(book) {
var row = new (Alloy.getController('row'))({
title: book.title,
authors: book.authors,
image: book.image
}).getRoot();
data.push(row);
});
$.table.setData(data);
}
// You can override error handling with the 'error' property
// error: function(e) {
// alert('ERROR: ' + e.error);
// }
});
$.win.open();
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});
$.win.open();

@@ -1,5 +0,10 @@

var args = arguments[0] || {};
function onReady(args) {
args || (args = {});
$.thumbnail.image = args.image;
$.title.text = args.title || '';
$.authors.text = args.authors || '';
}
$.thumbnail.image = args.image;
$.title.text = args.title || '';
$.authors.text = args.authors || '';
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});

@@ -1,13 +0,19 @@

var args = arguments[0] || {}; for (var k in args) { $.loading[k] = args[k]; }
function onReady(args) {
args || (args = {});
if (Ti.Platform.osname === 'mobileweb') {
$.loading.duration = 100;
}
$.loading.start();
for (var k in args) {
$.loading[k] = args[k];
}
////////////////////////////////////////////////////////
////////// Exposed component object functions //////////
////////////////////////////////////////////////////////
$.setOpacity = function(opacity) {
$.loading.opacity = opacity;
};
if (Ti.Platform.osname === 'mobileweb') {
$.loading.duration = 100;
}
$.loading.start();
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady,
setOpacity: function(opacity) {
$.loading.opacity = opacity;
}
});

@@ -9,19 +9,18 @@ var API_URL = 'https://www.googleapis.com/books/v1/volumes?q=';

// react to changes in the model state
model.on('change:loading', function(m) {
if (m.get('loading')) {
$.searchView.touchEnabled = false;
$.search.opacity = 0;
$.loading.setOpacity(1.0);
} else {
$.loading.setOpacity(0);
$.search.opacity = 1;
$.searchView.touchEnabled = true;
}
});
function onReady(args) {
// react to changes in the model state
model.on('change:loading', function(m) {
if (m.get('loading')) {
$.searchView.touchEnabled = false;
$.search.opacity = 0;
$.loading.setOpacity(1.0);
} else {
$.loading.setOpacity(0);
$.search.opacity = 1;
$.searchView.touchEnabled = true;
}
});
}
////////////////////////////////////
///////// public functions /////////
////////////////////////////////////
$.setHandlers = function(args) {
function setHandlers(args) {
_.each(HANDLERS, function(h) {

@@ -32,4 +31,9 @@ if (args[h]) {

});
}
}
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady,
setHandlers: setHandlers
});
///////////////////////////////////////

@@ -36,0 +40,0 @@ ////////// private functions //////////

@@ -1,3 +0,8 @@

$.w.setText("Press a button to see something happen");
function onReady(args) {
$.w.setText("Press a button to see something happen");
$.index.open();
}
$.index.open();
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady
});

@@ -0,24 +1,26 @@

function onReady(args) {
// add listeners for widget buttons
$.a.addEventListener('click',function(){
$.t.text = "You clicked A";
});
$.b.addEventListener('click',function(){
$.t.text = "You clicked B";
});
$.a.addEventListener('click',function(){
$.t.text = "You clicked A";
});
$.c.addEventListener('click',function(){
$.t.text = "You clicked C";
});
}
$.b.addEventListener('click',function(){
$.t.text = "You clicked B";
});
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady,
$.c.addEventListener('click',function(){
$.t.text = "You clicked C";
// custom functions for public interface
setText: function(text) {
$.t.text = text;
},
getText: function() {
return $.t.text;
}
});
// anything defined against the export will be provided as methods/properties against the widgets variable
$.setText = function(text){
$.t.text = text;
};
$.getText = function() {
return $.t.text;
}

@@ -1,13 +0,18 @@

var args = arguments[0] || {}; for (var k in args) { $.loading[k] = args[k]; }
function onReady(args) {
args || (args = {});
for (var k in args) {
$.loading[k] = args[k];
}
if (Ti.Platform.osname === 'mobileweb') {
$.loading.duration = 100;
}
$.loading.start();
if (Ti.Platform.osname === 'mobileweb') {
$.loading.duration = 100;
}
$.loading.start();
}
////////////////////////////////////////////////////////
////////// Exposed component object functions //////////
////////////////////////////////////////////////////////
$.setOpacity = function(opacity) {
$.loading.opacity = opacity;
};
module.exports = Alloy.getController('BaseController').extend({
onReady: onReady,
setOpacity: function(opacity) {
$.loading.opacity = opacity;
}
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc