foam-framework
Version:
MVC metaprogramming framework
1,045 lines (970 loc) • 33.7 kB
JavaScript
/**
* @license
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
CLASS({
package: 'foam.apps.quickbug.model',
name: 'QProject',
tableProperties: [
'projectName',
'baseURL'
],
requires: [
'Binding',
'foam.dao.CachingDAO',
'foam.dao.EasyDAO',
'foam.dao.IDBDAO',
'foam.dao.LazyCacheDAO',
'foam.dao.ContextualizingDAO',
'MDAO',
'PersistentContext',
'foam.util.Timer',
'foam.apps.quickbug.dao.IssueRestDAO',
'foam.apps.quickbug.dao.QIssueCommentNetworkDAO',
'foam.apps.quickbug.dao.QIssueCommentUpdateDAO',
'foam.apps.quickbug.dao.SyncManager',
'foam.apps.quickbug.model.DefaultQuery',
'foam.apps.quickbug.model.LabelArrayProperty',
'foam.apps.quickbug.model.LabelStringEnumProperty',
'foam.apps.quickbug.model.LabelStringProperty',
'foam.apps.quickbug.model.QIssueComment',
'foam.apps.quickbug.model.QIssueCommentUpdate',
'foam.apps.quickbug.model.QIssueLabel',
'foam.apps.quickbug.model.QIssueStatus',
'foam.apps.quickbug.model.imported.Issue',
'foam.apps.quickbug.model.imported.IssuePerson',
'foam.apps.quickbug.model.LabelCompleter',
'foam.apps.quickbug.model.PersonCompleter',
'foam.apps.quickbug.model.StatusCompleter',
'foam.core.dao.MigrationRule',
'foam.lib.bookmarks.Bookmark',
'foam.core.dao.WhenIdleDAO',
'foam.metrics.Metric',
'foam.ui.CSSImageBooleanView'
],
exports: [
'IssueCommentDAO as qIssueCommentDAO',
'IssueCommentDAO as QIssueCommentDAO',
'StatusDAO as issueStatusDAO',
'StatusDAO as StatusDAO',
'LabelDAO as issueLabelDAO',
'LabelDAO as LabelDAO',
'PersonDAO as issuePersonDAO',
'PersonDAO as PersonDAO',
'openPredicate',
'QueryParser'
],
imports: [
'metricDAO'
],
properties: [
{
name: 'qbug',
},
{
name: 'project',
},
{
name: 'baseURL',
defaultValue: 'https://code.google.com/p/'
},
{
name: 'projectName',
scope: 'project',
defaultValueFn: function() { return this.project.name; }
},
{
name: 'summary',
scope: 'project',
defaultValueFn: function() { return this.project.summary; }
},
{
name: 'user',
scope: 'qbug',
defaultValueFn: function() { return this.qbug.user; }
},
{
name: 'openPredicate',
lazyFactory: function() {
var ss = this.project.issuesConfig.statuses;
var os = [];
for ( var i = 0 ; i < ss.length ; i++ ) {
var s = ss[i];
if ( ! s.meansOpen ) os.push(s.status);
}
return '-status=' + os.join(',');
}
},
{
name: 'LabelDAO',
help: 'DAO of known labels.',
factory: function() {
var dao = this.MDAO.create({model: this.QIssueLabel});
this.project.issuesConfig && this.project.issuesConfig.labels.select(dao);
return dao;
}
},
{
name: 'StatusDAO',
help: 'DAO of known statuses.',
factory: function() {
var dao = this.MDAO.create({model: this.QIssueStatus});
this.project.issuesConfig && this.project.issuesConfig.statuses.select(dao);
return dao;
}
},
{
name: 'PersonDAO',
help: 'DAO of known people.',
factory: function() {
var dao = this.MDAO.create({ model: this.IssuePerson });
this.project.members.select(dao);
return dao;
}
},
{
name: 'IssueMDAO',
lazyFactory: function() {
var dao = this.MDAO.create({model: this.QIssueModel}, this.Y);
var auto = this.X.AutoIndex.create(dao, this.Y);
auto.addIndex(this.QIssueModel.STATUS);
dao.addRawIndex(auto);
return dao;
}
},
{
name: 'IssueIDBDAO',
lazyFactory: function() {
return this.EasyDAO.create({
model: this.QIssueModel,
name: this.projectName + '_' + this.QIssueModel.plural,
migrationRules: [
this.MigrationRule.create({
modelName: 'QIssue',
version: 120,
migration: function(ret, dao) {
console.log("Migrating to ", this.version);
dao.removeAll()(ret);
}
})
]
});
},
transient: true
},
{
name: 'IssueCachingDAO',
lazyFactory: function() {
console.log('Creating IssueCachingDAO.');
return this.CachingDAO.create({cache: this.IssueMDAO, src: this.IssueIDBDAO}, this.Y);
},
transient: true
},
{
name: 'IssueCommentNetworkDAO',
lazyFactory: function() {
return this.LazyCacheDAO.create({
model: this.QIssueComment,
cacheOnSelect: true,
cache: this.IDBDAO.create({
model: this.QIssueComment,
name: this.projectName + '_' + this.QIssueComment.plural,
useSimpleSerialization: false }).addIndex(this.QIssueComment.ISSUE_ID),
delegate: this.QIssueCommentNetworkDAO.create({
model: this.QIssueComment,
url: 'https://www.googleapis.com/projecthosting/v2/projects/' + this.projectName + '/issues',
})
});
}
},
{
model_: 'foam.core.types.DAOProperty',
name: 'IssueCommentDAO',
factory: function() {
return this.WhenIdleDAO.create({
delegate: this.QIssueCommentUpdateDAO.create({
delegate: this.IssueCommentNetworkDAO
})
});
}
},
{
name: 'IssueNetworkDAO',
lazyFactory: function() {
return this.IssueRestDAO.create({
url: 'https://www.googleapis.com/projecthosting/v2/projects/' + this.projectName + '/issues',
IssueCommentDAO: this.IssueCommentNetworkDAO,
model: this.QIssueModel,
batchSize: 500
});
},
postSet: function(_, v) {
this.IssueCommentDAO.delegate.IssueNetworkDAO = v;
},
transient: true
},
{
name: 'IssueDAO',
lazyFactory: function() {
return this.ContextualizingDAO.create({
delegate: this.IssueCachingDAO
});
},
transient: true
},
{
name: 'bookmarkDAO',
lazyFactory: function() {
var newDAO = this.EasyDAO.create({
model: this.Bookmark,
name: this.projectName + '_' + this.Bookmark.plural,
cache: true,
guid: true,
daoType: 'SYNC'
}).orderBy(this.Bookmark.ID);
// Migrate bookmarks from old DAO to new SyncStorage.
// TODO: Remove this code after a couple versions when all data has been translated.
var oldDAO = this.EasyDAO.create({
model: this.Bookmark,
name: this.projectName + '_' + this.Bookmark.plural,
cache: true
});
oldDAO.select({put: function(bookmark) {
bookmark.id = '';
newDAO.put(bookmark);
}})(function() {
oldDAO.removeAll();
});
return newDAO;
},
transient: true
},
{
mode_: 'IntProperty',
name: 'issueCount'
},
{
name: 'url',
defaultValueFn: function() { return this.baseURL + this.projectName; }
},
{
name: 'timer',
factory: function() { return this.Timer.create(); },
transient: true
},
{
name: 'persistentContext',
lazyFactory: function() {
return this.PersistentContext.create({
dao: this.IDBDAO.create({
model: this.Binding,
name: 'QProject-' + this.projectName + '-Bindings'
}),
predicate: NOT_TRANSIENT,
context: this
});
}
},
{
name: 'syncManager'
},
{
name: 'syncManagerFuture',
factory: function() { return afuture(); }
},
{
name: 'defaultSortChoices',
lazyFactory: function() {
return [
[ DESC(this.QIssueModel.MODIFIED), 'Last modified' ],
[ this.QIssueModel.PRI, 'Priority' ],
[ DESC(this.QIssueModel.ID), 'Issue ID' ]
];
}
},
{
name: 'defaultFilterChoices',
factory: function() {
var open = 'status=Accepted,Assigned,Available,New,Started,Unconfirmed,Untriaged';
return [
// ['', 'ALL ISSUES'],
[open, 'OPEN ISSUES'],
[open + ' is:starred', 'STARRED'],
[open + ' owner=me', 'OWNED BY ME']
// [open + ' reporter=me', 'Open and reported by me'],
// [open + ' commentby:me', 'Open and comment by me'],
// ['status=New', 'New issues'],
// ['status=Fixed,Done', 'Issues to verify']
];
}
},
{
name: 'QIssueModel',
factory: function() {
var labelToProperty = {
App: 'app',
Type: 'type',
Milestone: 'm',
Mstone: 'm',
M: 'm',
Cr: 'cr',
Iteration: 'iteration',
Week: 'week',
ReleaseBlock: 'releaseBlock',
OS: 'OS',
MovedFrom: 'movedFrom',
Pri: 'pri',
Priority: 'priority'
};
var propertyLabels_ = {};
function isPropertyLabel(l) {
if ( l in propertyLabels_ ) return propertyLabels_[l];
var keyValue = l.match(/([^\-]*)\-(.*)/) || l.match(/(\D*)(.*)/);
if ( keyValue ) {
var key = labelToProperty[keyValue[1]];
var value = keyValue[2];
if ( key ) {
var kv = [key, value.intern()];
propertyLabels_[l] = kv;
return kv;
}
}
return propertyLabels_[l] = false;
}
var model = Model.create({
extends: 'foam.apps.quickbug.model.imported.Issue',
name: 'QIssue',
requires: [
'foam.ui.CSSImageBooleanView',
],
tableProperties: [
'starred',
'id',
// 'app',
'priority',
'm',
'iteration',
'releaseBlock',
'cr',
'status',
'owner',
'summary',
'OS',
'modified'
],
ids: ['id'],
properties: [
{
model_: 'IntProperty',
name: 'id',
shortName: 'i',
label: 'ID',
required: true,
tableWidth: '48px',
tableFormatter: function(value, row, table) {
var id = table.nextID();
table.on('mouseover', function(e) {
table.browser.preview(e, value);
}, id);
return '<div id="' + id + '">' + value + '</div>';
}
},
{
name: 'labels',
shortName: 'l',
aliases: ['label'],
type: 'String',
view: 'foam.apps.quickbug.ui.QIssueLabelsView',
autocompleter: 'foam.apps.quickbug.model.LabelCompleter',
tableFormatter: function(a, row) {
var s = '';
for ( var i = 0 ; i < a.length ; i++ ) {
if ( ! isPropertyLabel(a[i]) ) {
s += ' <span class="label">' + a[i] + '</span>';
}
}
return s;
},
preSet: function(_, a) {
for ( var i = 0; i < a.length; i++ ) a[i] = a[i].intern();
return a.sort();
},
postSet: function(_, a) {
// Reset all label properties to initial values.
var newValues = {};
// Create initial values
var properties = this.model_.getRuntimeProperties();
for ( var i = 0 ; i < properties.length ; i++ ) {
var p = properties[i];
if ( p.name_ === 'LabelArrayProperty' ) {
newValues[p.name] = [];
} else if ( p.name_ === 'LabelStringProperty' ) {
newValues[p.name] = '';
}
}
// Add values from new list
for ( var i = 0 ; i < a.length ; i++ ) {
var kv = isPropertyLabel(a[i]);
if ( kv ) {
// Cleanup 'movedFrom' labels
if ( kv[0] === 'movedFrom' ) {
kv[1] = typeof kv[1] === 'string' ? parseInt(kv[1].charAt(0) === 'M' ? kv[1].substring(1) : kv[1]) : kv[1];
}
if ( Array.isArray(newValues[kv[0]]) ) {
newValues[kv[0]] = newValues[kv[0]].binaryInsert(kv[1]);
} else {
newValues[kv[0]] = kv[1];
}
}
}
// Set new values back to object, but only if they've changed
for ( var key in newValues ) {
var value = newValues[key];
if ( this[key].compareTo(value) ) this[key] = value;
}
}
},
{
name: 'author',
preSet: function(_, a) { return a.intern(); },
aliases: ['reporter']
},
{
model_: 'foam.apps.quickbug.model.LabelStringEnumProperty',
name: 'priority',
tableLabel: 'Priority',
tableWidth: '60px',
compareProperty: function(p1, p2) {
var priorities = ['Low', 'Medium', 'High', 'Critical'];
var i1 = priorities.indexOf(p1);
var i2 = priorities.indexOf(p2);
if ( i1 < 0 && i2 < 0 ) {
// Neither is a proper priority - return normal string order.
return p1 === p2 ? 0 : p1 < p2 ? -1 : 1;
} else if ( i1 < 0 ) {
return 1; // Nonstandard come after standard priorities
} else if ( i2 < 0 ) {
return -1; // Likewise.
} else {
var r = i2 - i1;
return r === 0 ? 0 : r < 0 ? -1 : 1;
}
},
choices: ['Low', 'Medium', 'High', 'Critical'],
},
{
model_: 'foam.apps.quickbug.model.LabelStringEnumProperty',
name: 'pri',
tableLabel: 'Pri',
tableWidth: '60px',
compareProperty: function(p1, p2) {
if ( p1.length === 0 && p2.length != 0 ) return 1;
else if ( p2.length === 0 && p1.length != 0 ) return -1;
return p1.compareTo(p2);
},
choices: [
['0', 'Priority 0 -- Critical'],
['1', 'Priority 1 -- High'],
['2', 'Priority 2 -- Medium'],
['3', 'Priority 3 -- Low']
]
},
{
model_: 'StringProperty',
name: 'metaPriority',
compareProperty: (this.projectName == "chromium") ?
(function(p1, p2) {
if ( p1.length === 0 && p2.length != 0 ) return 1;
else if ( p2.length === 0 && p1.length != 0 ) return -1;
return p1.compareTo(p2);
}) : (function(p1, p2) {
var priorities = ['Low', 'Medium', 'High', 'Critical'];
var i1 = priorities.indexOf(p1);
var i2 = priorities.indexOf(p2);
if ( i1 < 0 && i2 < 0 ) {
// Neither is a proper priority - return normal string order.
return p1 === p2 ? 0 : p1 < p2 ? -1 : 1;
} else if ( i1 < 0 ) {
return 1; // Nonstandard come after standard priorities
} else if ( i2 < 0 ) {
return -1; // Likewise.
} else {
var r = i2 - i1;
return r === 0 ? 0 : r < 0 ? -1 : 1;
}
}),
getter: (this.projectName == "chromium") ?
(function() { return this.pri; }) :
(function() { return this.priority; }),
setter: (this.projectName == "chromium") ?
(function(value) { this.pri = value; }) :
(function(value) { this.priority = value; })
},
{
model_: 'foam.apps.quickbug.model.LabelArrayProperty',
name: 'app',
tableWidth: '70px'
},
{
model_: 'foam.apps.quickbug.model.LabelArrayProperty',
name: 'type',
tableWidth: '70px'
},
{
model_: 'foam.apps.quickbug.model.LabelArrayProperty',
name: 'm',
label: 'Milestone',
aliases: ['mstone', 'milestone'],
tableLabel: 'M',
tableWidth: '70px'
},
{
model_: 'foam.apps.quickbug.model.LabelArrayProperty',
name: 'iteration',
shortName: 'it',
aliases: ['iter'],
tableWidth: '69px'
},
{
model_: 'foam.apps.quickbug.model.LabelArrayProperty',
name: 'week',
tableWidth: '69px'
},
{
model_: 'foam.apps.quickbug.model.LabelArrayProperty',
name: 'releaseBlock',
shortName: 'rb',
aliases: ['rBlock', 'release'],
type: 'String',
tableWidth: '103px',
defaultValue: ''
},
{
model_: 'foam.apps.quickbug.model.LabelArrayProperty',
name: 'cr',
shortName: 'c',
aliases: ['cat', 'cr'],
label: 'Cr',
tableWidth: '87px',
},
{
model_: 'StringProperty',
name: 'status',
shortName: 's',
aliases: ['stat'],
type: 'String',
preSet: function(_, s) { return s.capitalize(); },
tableWidth: '58px',
autocompleter: 'foam.apps.quickbug.model.StatusCompleter',
defaultValue: ''
},
{
model_: 'StringArrayProperty',
name: 'cc',
autocompleter: 'foam.apps.quickbug.model.PersonCompleter',
displayWidth: 70
},
{
name: 'owner',
shortName: 'o',
tableWidth: '181px',
type: 'String',
autocompleter: 'foam.apps.quickbug.model.PersonCompleter',
preSet: function(_, a) { return a.intern(); }
},
{
name: 'summary',
shortName: 'su',
label: 'Summary',
type: 'String',
tableWidth: '350px',
displayWidth: 70,
// tableWidth: '100%'
tableFormatter: function(value, row, tableView) {
return tableView.strToHTML(value);
}
},
{
name: 'description',
displayHeight: 20,
displayWidth: 70
},
{
name: 'summaryPlusLabels',
label: 'Summary + Labels',
tableLabel: 'Summary + Labels',
type: 'String',
tableWidth: '100%',
tableFormatter: function(value, row, tableView) {
return tableView.strToHTML(row.summary) +
value.model_.LABELS.tableFormatter(row.labels, row);
}
},
{
model_: 'foam.apps.quickbug.model.LabelArrayProperty',
name: 'OS',
tableWidth: '61px',
type: 'String'
},
{
model_: 'BooleanProperty',
name: 'blocked',
tableWidth: '20px',
getter: function() { return !! this.blockedOn.length; }
},
{
model_: 'DateTimeProperty',
name: 'modified',
shortName: 'mod',
mode: 'read-write',
required: true,
tableWidth: '100px',
factory: function() { return new Date(); }
},
{
name: 'updated',
hidden: true,
setter: function(v) { this.modified = v; }
},
{
model_: 'BooleanProperty',
name: 'starred',
tableLabel: '',
tableWidth: '18px',
tableFormatter: function(val, obj, tableView) {
var view = obj.CSSImageBooleanView.create({
className: 'star-image',
data: obj.starred
});
view.data$.addListener(function() {
var tmp = obj.clone();
tmp.starred = view.data;
tableView.browser.IssueDAO.put(tmp);
});
tableView.addChild(view);
return view.toHTML();
},
view: { factory_: 'foam.ui.CSSImageBooleanView', className: 'star-image' },
help: 'Whether the authenticated user has starred this issue.'
},
{
model_: 'IntProperty',
name: 'stars',
tableWidth: '20px',
help: 'Number of stars this issue has.',
compareProperty: function(o2, o1) {
return o1 === o2 ? 0 : o1 > o2 ? 1 : -1;
}
},
{
model_: 'foam.apps.quickbug.model.LabelArrayProperty',
name: 'movedFrom',
tableWidth: '100px'
},
{
name: 'movedTo',
preSet: function(_, v) {
// TODO: looks like we're getting bad values, investigate and fix
/*
if ( v.length ) console.log('movedTo: ', v);
return v;
*/
return [];
}
},
{
model_: 'StringProperty',
name: 'content',
displayHeight: 4
}
],
methods: {
replaceLabels: function(label, values) {
var prefix = label + '-';
var labels = this.labels.filter(function(l) { return ! l.startsWith(prefix); });
if ( Array.isArray(values) ) {
for ( var i = 0 ; i < values.length ; i++ ) {
labels.binaryInsert(label + '-' + values[i]);
}
} else {
labels.binaryInsert(label + '-' + values);
}
if ( this.labels.compareTo(labels) ) this.labels = labels;
},
isOpen: function() {
return !! ({
'New': true,
'Accepted': true,
'Started': true,
'Untriaged': true
}[this.status]);
},
writeActions: function(other, out) {
var diff = this.diff(other);
delete diff.starred;
if ( Object.keys(diff).length == 0 ) return;
delete diff.stars;
function convertArray(key) {
if ( ! diff[key] ) {
diff[key] = [];
return;
}
var delta = diff[key].added;
for ( var i = 0; i < diff[key].removed.length; i++ )
delta.push("-" + diff[key].removed[i]);
diff[key] = delta;
}
convertArray('blockedOn');
convertArray('blocking');
convertArray('cc');
convertArray('labels');
convertArray('m');
convertArray('iteration');
convertArray('week');
var empty = true;
for ( var key in diff ) {
if ( ! Array.isArray(diff[key]) || diff[key].length > 0 ){
empty = false;
break;
}
}
if ( empty ) return;
var comment = this.X.lookup('foam.apps.quickbug.model.QIssueComment').create({
issueId: this.id,
content: other.content,
updates: this.X.lookup('foam.apps.quickbug.model.QIssueCommentUpdate').create(diff)
}, this.Y);
out(comment);
},
newComment: function() {
return this.X.lookup('foam.apps.quickbug.model.QIssueComment').create({
issueId: this.id,
updates: this.X.lookup('foam.apps.quickbug.model.QIssueCommentUpdate').create({
labels: this.labels.clone(),
owner: this.owner,
blockedOn: this.blockedOn.clone(),
blocking: this.blocking.clone(),
cc: this.cc.clone(),
mergedInto: this.mergedInto,
status: this.status,
summary: this.summary
})
}, this.Y)
}
},
relationships: [
{
name: 'comments',
label: 'Comments on this issue.',
relatedModel: 'foam.apps.quickbug.model.QIssueComment',
relatedProperty: 'issueId'
}
]
});
model.getPrototype();
model.getRuntimeProperties().forEach(function(p) {
if ( ! p["tableFormatter"] ) {
p["tableFormatter"] = function(v) {
return v || '----';
};
}
});
model.LABELS.toMQL = function() { return 'label'; };
model.AUTHOR.toMQL = function() { return 'reporter'; };
return model;
},
postSet: function(_, m) {
this.X.registerModel(m);
}
},
{
name: 'QueryParser',
factory: function() {
var parser = {
X: this.Y,
__proto__: QueryParserFactory(this.QIssueModel),
isOpen: literal_ic('is:open'),
stars: seq(literal_ic('stars:'), sym('number')),
labelMatch: seq(sym('fieldname'), alt(':', '='), sym('valueList')),
summary: str(plus(notChar(' ')))
}.addActions({
isOpen: function(v) {
return this.X.QueryParser.parseString(this.X.openPredicate);
},
stars: function(v) {
return GTE({
f: function(i) { return i.stars; },
partialEval: function() {return this;},
toSQL: function() { return 'stars > ' + v[1]; },
toMQL: function() { return 'stars > ' + v[1]; }
}, v[1]);
},
labelMatch: function(v) {
var a = [];
for ( var i = 2 ; i < v.length ; i++ ) {
a.push(v[0] + '-' + v[i]);
}
return IN(this.X.QIssue.LABELS, a).partialEval();
/*
var or = OR();
var values = v[2];
for ( var i = 0 ; i < values.length ; i++ ) {
or.args.push(CONTAINS_IC(QIssue.LABELS, v[0] + '-' + values[i]));
}
return or;
*/
},
summary: function(v) {
return this.X.lookup('foam.apps.quickbug.model.DefaultQuery').create({arg1: v});
}
});
parser.expr = alt(
sym('isOpen'),
parser.export('expr'),
sym('stars'),
sym('labelMatch'),
sym('summary')
);
return parser;
}
}
],
listeners: [
{
model_: 'Method',
name: 'onDAOUpdate',
isMerged: 16,
code: function() {
this.IssueMDAO.select(COUNT())(function (c) { this.issueCount = c.count; }.bind(this));
var self = this;
this.IssueMDAO.select(GROUP_BY(this.QIssueModel.CC, COUNT()))(function(g) {
Object.keys(g.groups).forEach(function(key) {
self.PersonDAO.find(key, { error: function() {
self.PersonDAO.put(self.IssuePerson.create({ name: key }));
}});
});
});
}
}
],
methods: {
init: function(args) {
this.SUPER(args);
if ( this.projectName !== 'chromium' ) {
this.defaultSortChoices = [
[ DESC(this.QIssueModel.MODIFIED), 'Last modified' ],
[ this.QIssueModel.PRIORITY, 'Priority' ],
[ DESC(this.QIssueModel.ID), 'Issue ID' ]
];
}
if ( ! this.X.DontSyncProjectData ) {
this.IssueDAO.listen(this.onDAOUpdate);
this.persistentContext.bindObject('syncManager', this.SyncManager.xbind({
syncInterval: 60*5,
batchSize: 500,
}), {
queryParser: this.QueryParser,
srcDAO: this.IssueNetworkDAO,
dstDAO: this.IssueCachingDAO,
modifiedProperty: this.QIssueModel.MODIFIED
}, 2)(function(manager) {
this.syncManager = manager;
this.syncManagerFuture.set(manager);
manager.start();
}.bind(this));
}
},
/** Open a Browser in a Window for a Chome Packaged App. **/
launchBrowser: function(opt_url) {
var self = this;
chrome.app.window.create('empty.html', {width: 1000, height: 800}, function(w) {
w.contentWindow.onload = function() {
var window = self.window = w.contentWindow;
self.X.arequire('foam.apps.quickbug.ui.ChromeAppBrowser')(
function (model) {
$addWindow(window);
var Y = self.Y.subWindow(window, 'Browser Window');
var b = model.create({project: self}, Y);
Y.touchManager = Y.foam.input.touch.TouchManager.create({}, Y);
window.document.body.outerHTML = b.toHTML()
b.initHTML();
if ( opt_url ) b.maybeSetLegacyUrl(opt_url);
w.focus();
self.metricDAO.put(self.Metric.create({
name: 'browserLaunched'
}));
});
};
w.onClosed.addListener(function() {
$removeWindow(window);
});
});
},
/** Create a Browser for use in a hosted app. **/
createBrowser: function(window) {
var b = this.X.Browser.create({project: this, window: window}, this.Y);
window.browser = b;
return b;
},
launchSync: function() {
var self = this;
this.syncManagerFuture.get((function(syncManager) {
chrome.app.window.create('empty.html', {width: 600, height: 600}, function(w) {
var window = w.contentWindow;
w.contentWindow.onload = function() {
$addWindow(window);
var Y = self.Y.subWindow(window, 'Sync Config')
var b = Y.DetailView.create({
model: Y.SyncManager,
title: '<img style="vertical-align:bottom;" src="images/refresh.png"> Sync Config: ' + self.projectName,
data: syncManager,
showActions: true });
window.document.body.innerHTML = '<div>' + b.toHTML() + '</div>';
b.initHTML();
var extrax = window.outerWidth - window.innerWidth + 16;
var extray = window.outerHeight - window.innerHeight + 16;
window.resizeTo(
window.document.body.firstChild.firstChild.firstChild.offsetWidth + extrax,
window.document.body.firstChild.offsetHeight + extray);
window.resizeTo(
window.document.body.firstChild.firstChild.firstChild.offsetWidth + extrax,
window.document.body.firstChild.offsetHeight + extray);
w.focus();
};
w.onClosed.addListener(function() {
$removeWindow(window);
});
});
}).bind(this));
},
launchConfigProjects: function() {
var self = this;
chrome.app.window.create('empty.html', {width: 430, height: 440}, function(w) {
var window = w.contentWindow;
w.contentWindow.onload = function() {
$addWindow(window);
var view = ConfigureProjectsView.create({ model: QUser });
view.data = self.user;
window.document.body.innerHTML = view.toHTML();
view.initHTML();
w.focus();
};
w.onClosed.addListener(function() {
$removeWindow(window);
});
});
}
},
});