Promises (first look)

Thread dropdown
Small fixes
This commit is contained in:
RainLoop Team 2015-03-14 03:10:00 +04:00
parent dd41d30f9b
commit c23ba31e17
61 changed files with 12442 additions and 130 deletions

View file

@ -421,6 +421,12 @@
'MailServerError': 901, 'MailServerError': 901,
'ClientViewError': 902, 'ClientViewError': 902,
'InvalidInputArgument': 903, 'InvalidInputArgument': 903,
'AjaxFalse': 950,
'AjaxAbort': 951,
'AjaxParse': 952,
'AjaxTimeout': 953,
'UnknownNotification': 999, 'UnknownNotification': 999,
'UnknownError': 999 'UnknownError': 999
}; };

View file

@ -134,9 +134,6 @@
'allowedContent': true, 'allowedContent': true,
'extraAllowedContent': true, 'extraAllowedContent': true,
'forceEnterMode': true,
'autoParagraph': false,
'fillEmptyBlocks': false, 'fillEmptyBlocks': false,
'ignoreEmptyParagraph': true, 'ignoreEmptyParagraph': true,

View file

@ -613,7 +613,7 @@
*/ */
Utils.microtime = function () Utils.microtime = function ()
{ {
return (new Date()).getTime(); return (new window.Date()).getTime();
}; };
/** /**
@ -848,7 +848,7 @@
}, },
convertBlockquote = function (sText) { convertBlockquote = function (sText) {
sText = splitPlainText($.trim(sText)); sText = Utils.trim(sText);
sText = '> ' + sText.replace(/\n/gm, '\n> '); sText = '> ' + sText.replace(/\n/gm, '\n> ');
return sText.replace(/(^|\n)([> ]+)/gm, function () { return sText.replace(/(^|\n)([> ]+)/gm, function () {
return (arguments && 2 < arguments.length) ? arguments[1] + $.trim(arguments[2].replace(/[\s]/g, '')) + ' ' : ''; return (arguments && 2 < arguments.length) ? arguments[1] + $.trim(arguments[2].replace(/[\s]/g, '')) + ' ' : '';
@ -920,8 +920,10 @@
.replace(/&amp;/gi, '&') .replace(/&amp;/gi, '&')
; ;
sText = splitPlainText(Utils.trim(sText));
iPos = 0; iPos = 0;
iLimit = 100; iLimit = 800;
while (0 < iLimit) while (0 < iLimit)
{ {

View file

@ -0,0 +1,172 @@
(function () {
'use strict';
var
_ = require('_'),
$ = require('$'),
Q = require('Q'),
Consts = require('Common/Consts'),
Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
Links = require('Common/Links'),
Settings = require('Storage/Settings')
;
/**
* @constructor
*/
function AbstractAjaxPromises()
{
this.oRequests = {};
}
AbstractAjaxPromises.prototype.func = function (fFunc)
{
fFunc();
return this;
};
AbstractAjaxPromises.prototype.fastPromise = function (mData)
{
var oDeferred = Q.defer();
oDeferred.resolve(mData);
return oDeferred.promise;
};
AbstractAjaxPromises.prototype.abort = function (sAction, bClearOnly)
{
if (this.oRequests[sAction])
{
if (!bClearOnly && this.oRequests[sAction].abort)
{
this.oRequests[sAction].__aborted = true;
this.oRequests[sAction].abort();
}
this.oRequests[sAction] = null;
delete this.oRequests[sAction];
}
return this;
};
AbstractAjaxPromises.prototype.ajaxRequest = function (sAction, bPost, iTimeOut, oParameters, sAdditionalGetString, fTrigger)
{
var
oH = null,
self = this,
iStart = Utils.microtime(),
oDeferred = Q.defer()
;
iTimeOut = Utils.isNormal(iTimeOut) ? iTimeOut : Consts.Defaults.DefaultAjaxTimeout;
sAdditionalGetString = Utils.isUnd(sAdditionalGetString) ? '' : Utils.pString(sAdditionalGetString);
if (bPost)
{
oParameters['XToken'] = Settings.settingsGet('Token');
}
if (fTrigger)
{
fTrigger(true);
}
oH = $.ajax({
'type': bPost ? 'POST' : 'GET',
'url': Links.ajax(sAdditionalGetString),
'async': true,
'dataType': 'json',
'data': bPost ? (oParameters || {}) : {},
'timeout': iTimeOut,
'global': true
}).always(function (oData, sTextStatus) {
var bCached = false;
if (oData && oData['Time'])
{
bCached = Utils.pInt(oData['Time']) > Utils.microtime() - iStart;
}
if ('success' === sTextStatus)
{
if (oData && oData.Result && sAction === oData.Action)
{
oData.Result.__cached__ = bCached;
oDeferred.resolve(oData.Result);
}
else if (oData && oData.Action)
{
oDeferred.reject(oData.ErrorCode ? oData.ErrorCode : Enums.Notification.AjaxFalse);
}
else
{
oDeferred.reject(Enums.Notification.AjaxParse);
}
}
else if ('timeout' === sTextStatus)
{
oDeferred.reject(Enums.Notification.AjaxTimeout);
}
else if ('abort' === sTextStatus)
{
if (!oData || !oData.__aborted)
{
oDeferred.reject(Enums.Notification.AjaxAbort);
}
}
else
{
oDeferred.reject(Enums.Notification.AjaxParse);
}
if (self.oRequests[sAction])
{
self.oRequests[sAction] = null;
delete self.oRequests[sAction];
}
if (fTrigger)
{
fTrigger(false);
}
});
if (oH)
{
if (this.oRequests[sAction])
{
this.oRequests[sAction] = null;
delete this.oRequests[sAction];
}
this.oRequests[sAction] = oH;
}
return oDeferred.promise;
};
AbstractAjaxPromises.prototype.getRequest = function (sAction, fTrigger, sAdditionalGetString, iTimeOut)
{
sAdditionalGetString = Utils.isUnd(sAdditionalGetString) ? '' : Utils.pString(sAdditionalGetString);
sAdditionalGetString = sAction + '/' + sAdditionalGetString;
return this.ajaxRequest(sAction, false, iTimeOut, null, sAdditionalGetString, fTrigger);
};
AbstractAjaxPromises.prototype.postRequest = function (sAction, fTrigger, oParameters, iTimeOut)
{
oParameters = oParameters || {};
oParameters['Action'] = sAction;
return this.ajaxRequest(sAction, true, iTimeOut, oParameters, '', fTrigger);
};
module.exports = AbstractAjaxPromises;
}());

58
dev/Promises/User/Ajax.js Normal file
View file

@ -0,0 +1,58 @@
(function () {
'use strict';
var
_ = require('_'),
ko = require('ko'),
AbstractAjaxPromises = require('Promises/AbstractAjax'),
MessageModel = require('Model/Message')
;
/**
* @constructor
* @extends AbstractAjaxPromises
*/
function PromisesUserAjax()
{
AbstractAjaxPromises.call(this);
this.messageListSimple.loading = ko.observable(false).extend({'rateLimit': 1});
this.messageListSimple.hash = '';
this.messageListSimple.cache = null;
}
PromisesUserAjax.prototype.messageListSimple = function (sFolder, aUids)
{
var self = this, sHash = sFolder + '~' + aUids.join('/');
if (sHash === this.messageListSimple.hash && this.messageListSimple.cache)
{
return this.fastPromise(this.messageListSimple.cache);
}
return this.abort('MessageListSimple')
.postRequest('MessageListSimple', this.messageListSimple.loading, {
'Folder': sFolder,
'Uids': aUids
}).then(function (aData) {
var aResult = _.compact(_.map(aData, function (aItem) {
return MessageModel.newInstanceFromJson(aItem);
}));
self.messageListSimple.hash = sHash;
self.messageListSimple.cache = aResult;
return aResult;
})
;
};
_.extend(PromisesUserAjax.prototype, AbstractAjaxPromises.prototype);
module.exports = new PromisesUserAjax();
}());

View file

@ -24,7 +24,7 @@
* @constructor * @constructor
* @extends AbstractRemoteStorage * @extends AbstractRemoteStorage
*/ */
function RemoteUserStorage() function RemoteUserAjax()
{ {
AbstractAjaxRemote.call(this); AbstractAjaxRemote.call(this);
@ -33,12 +33,12 @@
this.sSubSubQuery = '&ss=/'; this.sSubSubQuery = '&ss=/';
} }
_.extend(RemoteUserStorage.prototype, AbstractAjaxRemote.prototype); _.extend(RemoteUserAjax.prototype, AbstractAjaxRemote.prototype);
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.folders = function (fCallback) RemoteUserAjax.prototype.folders = function (fCallback)
{ {
this.defaultRequest(fCallback, 'Folders', { this.defaultRequest(fCallback, 'Folders', {
'SentFolder': Settings.settingsGet('SentFolder'), 'SentFolder': Settings.settingsGet('SentFolder'),
@ -59,7 +59,7 @@
* @param {string=} sAdditionalCode * @param {string=} sAdditionalCode
* @param {boolean=} bAdditionalCodeSignMe * @param {boolean=} bAdditionalCodeSignMe
*/ */
RemoteUserStorage.prototype.login = function (fCallback, sEmail, sLogin, sPassword, bSignMe, sLanguage, sAdditionalCode, bAdditionalCodeSignMe) RemoteUserAjax.prototype.login = function (fCallback, sEmail, sLogin, sPassword, bSignMe, sLanguage, sAdditionalCode, bAdditionalCodeSignMe)
{ {
this.defaultRequest(fCallback, 'Login', { this.defaultRequest(fCallback, 'Login', {
'Email': sEmail, 'Email': sEmail,
@ -75,7 +75,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.getTwoFactor = function (fCallback) RemoteUserAjax.prototype.getTwoFactor = function (fCallback)
{ {
this.defaultRequest(fCallback, 'GetTwoFactorInfo'); this.defaultRequest(fCallback, 'GetTwoFactorInfo');
}; };
@ -83,7 +83,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.createTwoFactor = function (fCallback) RemoteUserAjax.prototype.createTwoFactor = function (fCallback)
{ {
this.defaultRequest(fCallback, 'CreateTwoFactorSecret'); this.defaultRequest(fCallback, 'CreateTwoFactorSecret');
}; };
@ -91,7 +91,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.clearTwoFactor = function (fCallback) RemoteUserAjax.prototype.clearTwoFactor = function (fCallback)
{ {
this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); this.defaultRequest(fCallback, 'ClearTwoFactorInfo');
}; };
@ -99,7 +99,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.showTwoFactorSecret = function (fCallback) RemoteUserAjax.prototype.showTwoFactorSecret = function (fCallback)
{ {
this.defaultRequest(fCallback, 'ShowTwoFactorSecret'); this.defaultRequest(fCallback, 'ShowTwoFactorSecret');
}; };
@ -108,7 +108,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {string} sCode * @param {string} sCode
*/ */
RemoteUserStorage.prototype.testTwoFactor = function (fCallback, sCode) RemoteUserAjax.prototype.testTwoFactor = function (fCallback, sCode)
{ {
this.defaultRequest(fCallback, 'TestTwoFactorInfo', { this.defaultRequest(fCallback, 'TestTwoFactorInfo', {
'Code': sCode 'Code': sCode
@ -119,7 +119,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {boolean} bEnable * @param {boolean} bEnable
*/ */
RemoteUserStorage.prototype.enableTwoFactor = function (fCallback, bEnable) RemoteUserAjax.prototype.enableTwoFactor = function (fCallback, bEnable)
{ {
this.defaultRequest(fCallback, 'EnableTwoFactor', { this.defaultRequest(fCallback, 'EnableTwoFactor', {
'Enable': bEnable ? '1' : '0' 'Enable': bEnable ? '1' : '0'
@ -129,7 +129,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.clearTwoFactorInfo = function (fCallback) RemoteUserAjax.prototype.clearTwoFactorInfo = function (fCallback)
{ {
this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); this.defaultRequest(fCallback, 'ClearTwoFactorInfo');
}; };
@ -137,7 +137,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.contactsSync = function (fCallback) RemoteUserAjax.prototype.contactsSync = function (fCallback)
{ {
this.defaultRequest(fCallback, 'ContactsSync', null, Consts.Defaults.ContactsSyncAjaxTimeout); this.defaultRequest(fCallback, 'ContactsSync', null, Consts.Defaults.ContactsSyncAjaxTimeout);
}; };
@ -149,7 +149,7 @@
* @param {string} sUser * @param {string} sUser
* @param {string} sPassword * @param {string} sPassword
*/ */
RemoteUserStorage.prototype.saveContactsSyncData = function (fCallback, bEnable, sUrl, sUser, sPassword) RemoteUserAjax.prototype.saveContactsSyncData = function (fCallback, bEnable, sUrl, sUser, sPassword)
{ {
this.defaultRequest(fCallback, 'SaveContactsSyncData', { this.defaultRequest(fCallback, 'SaveContactsSyncData', {
'Enable': bEnable ? '1' : '0', 'Enable': bEnable ? '1' : '0',
@ -165,7 +165,7 @@
* @param {string} sPassword * @param {string} sPassword
* @param {boolean=} bNew * @param {boolean=} bNew
*/ */
RemoteUserStorage.prototype.accountSetup = function (fCallback, sEmail, sPassword, bNew) RemoteUserAjax.prototype.accountSetup = function (fCallback, sEmail, sPassword, bNew)
{ {
bNew = Utils.isUnd(bNew) ? true : !!bNew; bNew = Utils.isUnd(bNew) ? true : !!bNew;
@ -180,7 +180,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {string} sEmailToDelete * @param {string} sEmailToDelete
*/ */
RemoteUserStorage.prototype.accountDelete = function (fCallback, sEmailToDelete) RemoteUserAjax.prototype.accountDelete = function (fCallback, sEmailToDelete)
{ {
this.defaultRequest(fCallback, 'AccountDelete', { this.defaultRequest(fCallback, 'AccountDelete', {
'EmailToDelete': sEmailToDelete 'EmailToDelete': sEmailToDelete
@ -192,7 +192,7 @@
* @param {Array} aAccounts * @param {Array} aAccounts
* @param {Array} aIdentities * @param {Array} aIdentities
*/ */
RemoteUserStorage.prototype.accountsAndIdentitiesSortOrder = function (fCallback, aAccounts, aIdentities) RemoteUserAjax.prototype.accountsAndIdentitiesSortOrder = function (fCallback, aAccounts, aIdentities)
{ {
this.defaultRequest(fCallback, 'AccountsAndIdentitiesSortOrder', { this.defaultRequest(fCallback, 'AccountsAndIdentitiesSortOrder', {
'Accounts': aAccounts, 'Accounts': aAccounts,
@ -210,7 +210,7 @@
* @param {string} sSignature * @param {string} sSignature
* @param {boolean} bSignatureInsertBefore * @param {boolean} bSignatureInsertBefore
*/ */
RemoteUserStorage.prototype.identityUpdate = function (fCallback, sId, sEmail, sName, sReplyTo, sBcc, RemoteUserAjax.prototype.identityUpdate = function (fCallback, sId, sEmail, sName, sReplyTo, sBcc,
sSignature, bSignatureInsertBefore) sSignature, bSignatureInsertBefore)
{ {
this.defaultRequest(fCallback, 'IdentityUpdate', { this.defaultRequest(fCallback, 'IdentityUpdate', {
@ -228,7 +228,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {string} sIdToDelete * @param {string} sIdToDelete
*/ */
RemoteUserStorage.prototype.identityDelete = function (fCallback, sIdToDelete) RemoteUserAjax.prototype.identityDelete = function (fCallback, sIdToDelete)
{ {
this.defaultRequest(fCallback, 'IdentityDelete', { this.defaultRequest(fCallback, 'IdentityDelete', {
'IdToDelete': sIdToDelete 'IdToDelete': sIdToDelete
@ -238,7 +238,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.accountsAndIdentities = function (fCallback) RemoteUserAjax.prototype.accountsAndIdentities = function (fCallback)
{ {
this.defaultRequest(fCallback, 'AccountsAndIdentities'); this.defaultRequest(fCallback, 'AccountsAndIdentities');
}; };
@ -246,7 +246,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.accountsCounts = function (fCallback) RemoteUserAjax.prototype.accountsCounts = function (fCallback)
{ {
this.defaultRequest(fCallback, 'AccountsCounts'); this.defaultRequest(fCallback, 'AccountsCounts');
}; };
@ -254,7 +254,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.filtersSave = function (fCallback, RemoteUserAjax.prototype.filtersSave = function (fCallback,
aFilters, sRaw, bRawIsActive) aFilters, sRaw, bRawIsActive)
{ {
this.defaultRequest(fCallback, 'FiltersSave', { this.defaultRequest(fCallback, 'FiltersSave', {
@ -269,7 +269,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.filtersGet = function (fCallback) RemoteUserAjax.prototype.filtersGet = function (fCallback)
{ {
this.defaultRequest(fCallback, 'Filters', {}); this.defaultRequest(fCallback, 'Filters', {});
}; };
@ -277,7 +277,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.templates = function (fCallback) RemoteUserAjax.prototype.templates = function (fCallback)
{ {
this.defaultRequest(fCallback, 'Templates', {}); this.defaultRequest(fCallback, 'Templates', {});
}; };
@ -285,7 +285,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.templateGetById = function (fCallback, sID) RemoteUserAjax.prototype.templateGetById = function (fCallback, sID)
{ {
this.defaultRequest(fCallback, 'TemplateGetByID', { this.defaultRequest(fCallback, 'TemplateGetByID', {
'ID': sID 'ID': sID
@ -295,7 +295,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.templateDelete = function (fCallback, sID) RemoteUserAjax.prototype.templateDelete = function (fCallback, sID)
{ {
this.defaultRequest(fCallback, 'TemplateDelete', { this.defaultRequest(fCallback, 'TemplateDelete', {
'IdToDelete': sID 'IdToDelete': sID
@ -305,7 +305,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.templateSetup = function (fCallback, sID, sName, sBody) RemoteUserAjax.prototype.templateSetup = function (fCallback, sID, sName, sBody)
{ {
this.defaultRequest(fCallback, 'TemplateSetup', { this.defaultRequest(fCallback, 'TemplateSetup', {
'ID': sID, 'ID': sID,
@ -319,7 +319,7 @@
* @param {string} sFolderFullNameRaw * @param {string} sFolderFullNameRaw
* @param {Array} aUids * @param {Array} aUids
*/ */
RemoteUserStorage.prototype.messageListSimple = function (fCallback, sFolderFullNameRaw, aUids) RemoteUserAjax.prototype.messageListSimple = function (fCallback, sFolderFullNameRaw, aUids)
{ {
return this.defaultRequest(fCallback, 'MessageListSimple', { return this.defaultRequest(fCallback, 'MessageListSimple', {
'Folder': Utils.pString(sFolderFullNameRaw), 'Folder': Utils.pString(sFolderFullNameRaw),
@ -335,7 +335,7 @@
* @param {string=} sSearch = '' * @param {string=} sSearch = ''
* @param {boolean=} bSilent = false * @param {boolean=} bSilent = false
*/ */
RemoteUserStorage.prototype.messageList = function (fCallback, sFolderFullNameRaw, iOffset, iLimit, sSearch, bSilent) RemoteUserAjax.prototype.messageList = function (fCallback, sFolderFullNameRaw, iOffset, iLimit, sSearch, bSilent)
{ {
sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw);
@ -381,7 +381,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {Array} aDownloads * @param {Array} aDownloads
*/ */
RemoteUserStorage.prototype.messageUploadAttachments = function (fCallback, aDownloads) RemoteUserAjax.prototype.messageUploadAttachments = function (fCallback, aDownloads)
{ {
this.defaultRequest(fCallback, 'MessageUploadAttachments', { this.defaultRequest(fCallback, 'MessageUploadAttachments', {
'Attachments': aDownloads 'Attachments': aDownloads
@ -394,7 +394,7 @@
* @param {number} iUid * @param {number} iUid
* @return {boolean} * @return {boolean}
*/ */
RemoteUserStorage.prototype.message = function (fCallback, sFolderFullNameRaw, iUid) RemoteUserAjax.prototype.message = function (fCallback, sFolderFullNameRaw, iUid)
{ {
sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw);
iUid = Utils.pInt(iUid); iUid = Utils.pInt(iUid);
@ -421,7 +421,7 @@
* @param {number} iUid * @param {number} iUid
* @return {boolean} * @return {boolean}
*/ */
RemoteUserStorage.prototype.messageThreadsFromCache = function (fCallback, sFolderFullNameRaw, iUid) RemoteUserAjax.prototype.messageThreadsFromCache = function (fCallback, sFolderFullNameRaw, iUid)
{ {
sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw);
iUid = Utils.pInt(iUid); iUid = Utils.pInt(iUid);
@ -448,7 +448,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {Array} aExternals * @param {Array} aExternals
*/ */
RemoteUserStorage.prototype.composeUploadExternals = function (fCallback, aExternals) RemoteUserAjax.prototype.composeUploadExternals = function (fCallback, aExternals)
{ {
this.defaultRequest(fCallback, 'ComposeUploadExternals', { this.defaultRequest(fCallback, 'ComposeUploadExternals', {
'Externals': aExternals 'Externals': aExternals
@ -460,7 +460,7 @@
* @param {string} sUrl * @param {string} sUrl
* @param {string} sAccessToken * @param {string} sAccessToken
*/ */
RemoteUserStorage.prototype.composeUploadDrive = function (fCallback, sUrl, sAccessToken) RemoteUserAjax.prototype.composeUploadDrive = function (fCallback, sUrl, sAccessToken)
{ {
this.defaultRequest(fCallback, 'ComposeUploadDrive', { this.defaultRequest(fCallback, 'ComposeUploadDrive', {
'AccessToken': sAccessToken, 'AccessToken': sAccessToken,
@ -473,7 +473,7 @@
* @param {string} sFolder * @param {string} sFolder
* @param {Array=} aList = [] * @param {Array=} aList = []
*/ */
RemoteUserStorage.prototype.folderInformation = function (fCallback, sFolder, aList) RemoteUserAjax.prototype.folderInformation = function (fCallback, sFolder, aList)
{ {
var var
bRequest = true, bRequest = true,
@ -524,7 +524,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {Array} aFolders * @param {Array} aFolders
*/ */
RemoteUserStorage.prototype.folderInformationMultiply = function (fCallback, aFolders) RemoteUserAjax.prototype.folderInformationMultiply = function (fCallback, aFolders)
{ {
this.defaultRequest(fCallback, 'FolderInformationMultiply', { this.defaultRequest(fCallback, 'FolderInformationMultiply', {
'Folders': aFolders 'Folders': aFolders
@ -534,7 +534,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.logout = function (fCallback) RemoteUserAjax.prototype.logout = function (fCallback)
{ {
this.defaultRequest(fCallback, 'Logout'); this.defaultRequest(fCallback, 'Logout');
}; };
@ -545,7 +545,7 @@
* @param {Array} aUids * @param {Array} aUids
* @param {boolean} bSetFlagged * @param {boolean} bSetFlagged
*/ */
RemoteUserStorage.prototype.messageSetFlagged = function (fCallback, sFolderFullNameRaw, aUids, bSetFlagged) RemoteUserAjax.prototype.messageSetFlagged = function (fCallback, sFolderFullNameRaw, aUids, bSetFlagged)
{ {
this.defaultRequest(fCallback, 'MessageSetFlagged', { this.defaultRequest(fCallback, 'MessageSetFlagged', {
'Folder': sFolderFullNameRaw, 'Folder': sFolderFullNameRaw,
@ -560,7 +560,7 @@
* @param {Array} aUids * @param {Array} aUids
* @param {boolean} bSetSeen * @param {boolean} bSetSeen
*/ */
RemoteUserStorage.prototype.messageSetSeen = function (fCallback, sFolderFullNameRaw, aUids, bSetSeen) RemoteUserAjax.prototype.messageSetSeen = function (fCallback, sFolderFullNameRaw, aUids, bSetSeen)
{ {
this.defaultRequest(fCallback, 'MessageSetSeen', { this.defaultRequest(fCallback, 'MessageSetSeen', {
'Folder': sFolderFullNameRaw, 'Folder': sFolderFullNameRaw,
@ -574,7 +574,7 @@
* @param {string} sFolderFullNameRaw * @param {string} sFolderFullNameRaw
* @param {boolean} bSetSeen * @param {boolean} bSetSeen
*/ */
RemoteUserStorage.prototype.messageSetSeenToAll = function (fCallback, sFolderFullNameRaw, bSetSeen) RemoteUserAjax.prototype.messageSetSeenToAll = function (fCallback, sFolderFullNameRaw, bSetSeen)
{ {
this.defaultRequest(fCallback, 'MessageSetSeenToAll', { this.defaultRequest(fCallback, 'MessageSetSeenToAll', {
'Folder': sFolderFullNameRaw, 'Folder': sFolderFullNameRaw,
@ -600,7 +600,7 @@
* @param {string} sReferences * @param {string} sReferences
* @param {boolean} bMarkAsImportant * @param {boolean} bMarkAsImportant
*/ */
RemoteUserStorage.prototype.saveMessage = function (fCallback, sIdentityID, sMessageFolder, sMessageUid, sDraftFolder, RemoteUserAjax.prototype.saveMessage = function (fCallback, sIdentityID, sMessageFolder, sMessageUid, sDraftFolder,
sTo, sCc, sBcc, sReplyTo, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, bMarkAsImportant) sTo, sCc, sBcc, sReplyTo, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, bMarkAsImportant)
{ {
this.defaultRequest(fCallback, 'SaveMessage', { this.defaultRequest(fCallback, 'SaveMessage', {
@ -632,7 +632,7 @@
* @param {string} sSubject * @param {string} sSubject
* @param {string} sText * @param {string} sText
*/ */
RemoteUserStorage.prototype.sendReadReceiptMessage = function (fCallback, sMessageFolder, sMessageUid, sReadReceipt, sSubject, sText) RemoteUserAjax.prototype.sendReadReceiptMessage = function (fCallback, sMessageFolder, sMessageUid, sReadReceipt, sSubject, sText)
{ {
this.defaultRequest(fCallback, 'SendReadReceiptMessage', { this.defaultRequest(fCallback, 'SendReadReceiptMessage', {
'MessageFolder': sMessageFolder, 'MessageFolder': sMessageFolder,
@ -664,7 +664,7 @@
* @param {boolean} bRequestReadReceipt * @param {boolean} bRequestReadReceipt
* @param {boolean} bMarkAsImportant * @param {boolean} bMarkAsImportant
*/ */
RemoteUserStorage.prototype.sendMessage = function (fCallback, sIdentityID, sMessageFolder, sMessageUid, sSentFolder, RemoteUserAjax.prototype.sendMessage = function (fCallback, sIdentityID, sMessageFolder, sMessageUid, sSentFolder,
sTo, sCc, sBcc, sReplyTo, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, sTo, sCc, sBcc, sReplyTo, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences,
bRequestDsn, bRequestReadReceipt, bMarkAsImportant) bRequestDsn, bRequestReadReceipt, bMarkAsImportant)
{ {
@ -694,7 +694,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {Object} oData * @param {Object} oData
*/ */
RemoteUserStorage.prototype.saveSystemFolders = function (fCallback, oData) RemoteUserAjax.prototype.saveSystemFolders = function (fCallback, oData)
{ {
this.defaultRequest(fCallback, 'SystemFoldersUpdate', oData); this.defaultRequest(fCallback, 'SystemFoldersUpdate', oData);
}; };
@ -703,7 +703,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {Object} oData * @param {Object} oData
*/ */
RemoteUserStorage.prototype.saveSettings = function (fCallback, oData) RemoteUserAjax.prototype.saveSettings = function (fCallback, oData)
{ {
this.defaultRequest(fCallback, 'SettingsUpdate', oData); this.defaultRequest(fCallback, 'SettingsUpdate', oData);
}; };
@ -713,7 +713,7 @@
* @param {string} sPrevPassword * @param {string} sPrevPassword
* @param {string} sNewPassword * @param {string} sNewPassword
*/ */
RemoteUserStorage.prototype.changePassword = function (fCallback, sPrevPassword, sNewPassword) RemoteUserAjax.prototype.changePassword = function (fCallback, sPrevPassword, sNewPassword)
{ {
this.defaultRequest(fCallback, 'ChangePassword', { this.defaultRequest(fCallback, 'ChangePassword', {
'PrevPassword': sPrevPassword, 'PrevPassword': sPrevPassword,
@ -726,7 +726,7 @@
* @param {string} sNewFolderName * @param {string} sNewFolderName
* @param {string} sParentName * @param {string} sParentName
*/ */
RemoteUserStorage.prototype.folderCreate = function (fCallback, sNewFolderName, sParentName) RemoteUserAjax.prototype.folderCreate = function (fCallback, sNewFolderName, sParentName)
{ {
this.defaultRequest(fCallback, 'FolderCreate', { this.defaultRequest(fCallback, 'FolderCreate', {
'Folder': sNewFolderName, 'Folder': sNewFolderName,
@ -738,7 +738,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {string} sFolderFullNameRaw * @param {string} sFolderFullNameRaw
*/ */
RemoteUserStorage.prototype.folderDelete = function (fCallback, sFolderFullNameRaw) RemoteUserAjax.prototype.folderDelete = function (fCallback, sFolderFullNameRaw)
{ {
this.defaultRequest(fCallback, 'FolderDelete', { this.defaultRequest(fCallback, 'FolderDelete', {
'Folder': sFolderFullNameRaw 'Folder': sFolderFullNameRaw
@ -750,7 +750,7 @@
* @param {string} sPrevFolderFullNameRaw * @param {string} sPrevFolderFullNameRaw
* @param {string} sNewFolderName * @param {string} sNewFolderName
*/ */
RemoteUserStorage.prototype.folderRename = function (fCallback, sPrevFolderFullNameRaw, sNewFolderName) RemoteUserAjax.prototype.folderRename = function (fCallback, sPrevFolderFullNameRaw, sNewFolderName)
{ {
this.defaultRequest(fCallback, 'FolderRename', { this.defaultRequest(fCallback, 'FolderRename', {
'Folder': sPrevFolderFullNameRaw, 'Folder': sPrevFolderFullNameRaw,
@ -762,7 +762,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {string} sFolderFullNameRaw * @param {string} sFolderFullNameRaw
*/ */
RemoteUserStorage.prototype.folderClear = function (fCallback, sFolderFullNameRaw) RemoteUserAjax.prototype.folderClear = function (fCallback, sFolderFullNameRaw)
{ {
this.defaultRequest(fCallback, 'FolderClear', { this.defaultRequest(fCallback, 'FolderClear', {
'Folder': sFolderFullNameRaw 'Folder': sFolderFullNameRaw
@ -774,7 +774,7 @@
* @param {string} sFolderFullNameRaw * @param {string} sFolderFullNameRaw
* @param {boolean} bSubscribe * @param {boolean} bSubscribe
*/ */
RemoteUserStorage.prototype.folderSetSubscribe = function (fCallback, sFolderFullNameRaw, bSubscribe) RemoteUserAjax.prototype.folderSetSubscribe = function (fCallback, sFolderFullNameRaw, bSubscribe)
{ {
this.defaultRequest(fCallback, 'FolderSubscribe', { this.defaultRequest(fCallback, 'FolderSubscribe', {
'Folder': sFolderFullNameRaw, 'Folder': sFolderFullNameRaw,
@ -789,7 +789,7 @@
* @param {Array} aUids * @param {Array} aUids
* @param {string=} sLearning * @param {string=} sLearning
*/ */
RemoteUserStorage.prototype.messagesMove = function (fCallback, sFolder, sToFolder, aUids, sLearning) RemoteUserAjax.prototype.messagesMove = function (fCallback, sFolder, sToFolder, aUids, sLearning)
{ {
this.defaultRequest(fCallback, 'MessageMove', { this.defaultRequest(fCallback, 'MessageMove', {
'FromFolder': sFolder, 'FromFolder': sFolder,
@ -805,7 +805,7 @@
* @param {string} sToFolder * @param {string} sToFolder
* @param {Array} aUids * @param {Array} aUids
*/ */
RemoteUserStorage.prototype.messagesCopy = function (fCallback, sFolder, sToFolder, aUids) RemoteUserAjax.prototype.messagesCopy = function (fCallback, sFolder, sToFolder, aUids)
{ {
this.defaultRequest(fCallback, 'MessageCopy', { this.defaultRequest(fCallback, 'MessageCopy', {
'FromFolder': sFolder, 'FromFolder': sFolder,
@ -819,7 +819,7 @@
* @param {string} sFolder * @param {string} sFolder
* @param {Array} aUids * @param {Array} aUids
*/ */
RemoteUserStorage.prototype.messagesDelete = function (fCallback, sFolder, aUids) RemoteUserAjax.prototype.messagesDelete = function (fCallback, sFolder, aUids)
{ {
this.defaultRequest(fCallback, 'MessageDelete', { this.defaultRequest(fCallback, 'MessageDelete', {
'Folder': sFolder, 'Folder': sFolder,
@ -830,7 +830,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.appDelayStart = function (fCallback) RemoteUserAjax.prototype.appDelayStart = function (fCallback)
{ {
this.defaultRequest(fCallback, 'AppDelayStart'); this.defaultRequest(fCallback, 'AppDelayStart');
}; };
@ -838,7 +838,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.quota = function (fCallback) RemoteUserAjax.prototype.quota = function (fCallback)
{ {
this.defaultRequest(fCallback, 'Quota'); this.defaultRequest(fCallback, 'Quota');
}; };
@ -849,7 +849,7 @@
* @param {number} iLimit * @param {number} iLimit
* @param {string} sSearch * @param {string} sSearch
*/ */
RemoteUserStorage.prototype.contacts = function (fCallback, iOffset, iLimit, sSearch) RemoteUserAjax.prototype.contacts = function (fCallback, iOffset, iLimit, sSearch)
{ {
this.defaultRequest(fCallback, 'Contacts', { this.defaultRequest(fCallback, 'Contacts', {
'Offset': iOffset, 'Offset': iOffset,
@ -864,7 +864,7 @@
* @param {string} sUid * @param {string} sUid
* @param {Array} aProperties * @param {Array} aProperties
*/ */
RemoteUserStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, aProperties) RemoteUserAjax.prototype.contactSave = function (fCallback, sRequestUid, sUid, aProperties)
{ {
this.defaultRequest(fCallback, 'ContactSave', { this.defaultRequest(fCallback, 'ContactSave', {
'RequestUid': sRequestUid, 'RequestUid': sRequestUid,
@ -877,7 +877,7 @@
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {Array} aUids * @param {Array} aUids
*/ */
RemoteUserStorage.prototype.contactsDelete = function (fCallback, aUids) RemoteUserAjax.prototype.contactsDelete = function (fCallback, aUids)
{ {
this.defaultRequest(fCallback, 'ContactsDelete', { this.defaultRequest(fCallback, 'ContactsDelete', {
'Uids': aUids.join(',') 'Uids': aUids.join(',')
@ -889,7 +889,7 @@
* @param {string} sQuery * @param {string} sQuery
* @param {number} iPage * @param {number} iPage
*/ */
RemoteUserStorage.prototype.suggestions = function (fCallback, sQuery, iPage) RemoteUserAjax.prototype.suggestions = function (fCallback, sQuery, iPage)
{ {
this.defaultRequest(fCallback, 'Suggestions', { this.defaultRequest(fCallback, 'Suggestions', {
'Query': sQuery, 'Query': sQuery,
@ -900,7 +900,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.clearUserBackground = function (fCallback) RemoteUserAjax.prototype.clearUserBackground = function (fCallback)
{ {
this.defaultRequest(fCallback, 'ClearUserBackground'); this.defaultRequest(fCallback, 'ClearUserBackground');
}; };
@ -908,7 +908,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.facebookUser = function (fCallback) RemoteUserAjax.prototype.facebookUser = function (fCallback)
{ {
this.defaultRequest(fCallback, 'SocialFacebookUserInformation'); this.defaultRequest(fCallback, 'SocialFacebookUserInformation');
}; };
@ -916,7 +916,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.facebookDisconnect = function (fCallback) RemoteUserAjax.prototype.facebookDisconnect = function (fCallback)
{ {
this.defaultRequest(fCallback, 'SocialFacebookDisconnect'); this.defaultRequest(fCallback, 'SocialFacebookDisconnect');
}; };
@ -924,7 +924,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.twitterUser = function (fCallback) RemoteUserAjax.prototype.twitterUser = function (fCallback)
{ {
this.defaultRequest(fCallback, 'SocialTwitterUserInformation'); this.defaultRequest(fCallback, 'SocialTwitterUserInformation');
}; };
@ -932,7 +932,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.twitterDisconnect = function (fCallback) RemoteUserAjax.prototype.twitterDisconnect = function (fCallback)
{ {
this.defaultRequest(fCallback, 'SocialTwitterDisconnect'); this.defaultRequest(fCallback, 'SocialTwitterDisconnect');
}; };
@ -940,7 +940,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.googleUser = function (fCallback) RemoteUserAjax.prototype.googleUser = function (fCallback)
{ {
this.defaultRequest(fCallback, 'SocialGoogleUserInformation'); this.defaultRequest(fCallback, 'SocialGoogleUserInformation');
}; };
@ -948,7 +948,7 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.googleDisconnect = function (fCallback) RemoteUserAjax.prototype.googleDisconnect = function (fCallback)
{ {
this.defaultRequest(fCallback, 'SocialGoogleDisconnect'); this.defaultRequest(fCallback, 'SocialGoogleDisconnect');
}; };
@ -956,11 +956,11 @@
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
RemoteUserStorage.prototype.socialUsers = function (fCallback) RemoteUserAjax.prototype.socialUsers = function (fCallback)
{ {
this.defaultRequest(fCallback, 'SocialUsers'); this.defaultRequest(fCallback, 'SocialUsers');
}; };
module.exports = new RemoteUserStorage(); module.exports = new RemoteUserAjax();
}()); }());

View file

@ -364,6 +364,20 @@ html.rl-no-preview-pane {
border-radius: @rlLowBorderRadius; border-radius: @rlLowBorderRadius;
border-color: darken(@rlMainDarkColor, 5%); border-color: darken(@rlMainDarkColor, 5%);
} }
.thread-list {
.e-link {
padding: 3px 5px 3px 10px;
overflow: hidden;
text-overflow: ellipsis;
}
.hread-date {
font-size: 13px;
color: #999;
}
}
} }
html.rl-no-preview-pane .messageView { html.rl-no-preview-pane .messageView {

View file

@ -504,6 +504,8 @@
this.driveCallback = _.bind(this.driveCallback, this); this.driveCallback = _.bind(this.driveCallback, this);
this.onMessageUploadAttachments = _.bind(this.onMessageUploadAttachments, this);
this.bDisabeCloseOnEsc = true; this.bDisabeCloseOnEsc = true;
this.sDefaultKeyScope = Enums.KeyState.Compose; this.sDefaultKeyScope = Enums.KeyState.Compose;
@ -1228,37 +1230,7 @@
aDownloads = this.getAttachmentsDownloadsForUpload(); aDownloads = this.getAttachmentsDownloadsForUpload();
if (Utils.isNonEmptyArray(aDownloads)) if (Utils.isNonEmptyArray(aDownloads))
{ {
Remote.messageUploadAttachments(function (sResult, oData) { Remote.messageUploadAttachments(this.onMessageUploadAttachments, aDownloads);
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
{
var
oAttachment = null,
sTempName = ''
;
if (!self.viewModelVisibility())
{
for (sTempName in oData.Result)
{
if (oData.Result.hasOwnProperty(sTempName))
{
oAttachment = self.getAttachmentById(oData.Result[sTempName]);
if (oAttachment)
{
oAttachment.tempName(sTempName);
oAttachment.waiting(false).uploading(false).complete(true);
}
}
}
}
}
else
{
self.setMessageAttachmentFailedDownloadText();
}
}, aDownloads);
} }
if (oIdentity) if (oIdentity)
@ -1269,6 +1241,37 @@
this.resizerTrigger(); this.resizerTrigger();
}; };
ComposePopupView.prototype.onMessageUploadAttachments = function (sResult, oData)
{
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
{
var
oAttachment = null,
sTempName = ''
;
if (!this.viewModelVisibility())
{
for (sTempName in oData.Result)
{
if (oData.Result.hasOwnProperty(sTempName))
{
oAttachment = this.getAttachmentById(oData.Result[sTempName]);
if (oAttachment)
{
oAttachment.tempName(sTempName);
oAttachment.waiting(false).uploading(false).complete(true);
}
}
}
}
}
else
{
this.setMessageAttachmentFailedDownloadText();
}
};
ComposePopupView.prototype.setFocusInPopup = function () ComposePopupView.prototype.setFocusInPopup = function ()
{ {
if (!Globals.bMobileDevice) if (!Globals.bMobileDevice)

View file

@ -29,6 +29,8 @@
Local = require('Storage/Client'), Local = require('Storage/Client'),
Remote = require('Remote/User/Ajax'), Remote = require('Remote/User/Ajax'),
Promises = require('Promises/User/Ajax'),
kn = require('Knoin/Knoin'), kn = require('Knoin/Knoin'),
AbstractView = require('Knoin/AbstractView') AbstractView = require('Knoin/AbstractView')
; ;
@ -73,6 +75,8 @@
this.fullScreenMode = MessageStore.messageFullScreenMode; this.fullScreenMode = MessageStore.messageFullScreenMode;
this.messageListOfThreadsLoading = Promises.messageListSimple.loading;
this.lastReplyAction_ = ko.observable(''); this.lastReplyAction_ = ko.observable('');
this.lastReplyAction = ko.computed({ this.lastReplyAction = ko.computed({
read: this.lastReplyAction_, read: this.lastReplyAction_,
@ -205,9 +209,11 @@
// THREADS // THREADS
this.viewThreads = ko.observableArray([]); this.viewThreads = ko.observableArray([]);
this.viewThreadMessages = ko.observableArray([]);
this.viewThreads.trigger = ko.observable(false); this.viewThreads.trigger = ko.observable(false);
this.viewThreadMessages = ko.observableArray([]);
this.viewThreadMessages.hash = '';
MessageStore.messageLastThreadUidsData.subscribe(function (oData) { MessageStore.messageLastThreadUidsData.subscribe(function (oData) {
if (oData && oData['Uids']) if (oData && oData['Uids'])
{ {
@ -290,14 +296,39 @@
}, this.viewThreadsControlForwardAllow); }, this.viewThreadsControlForwardAllow);
this.threadListCommand = Utils.createCommand(this, function () { this.threadListCommand = Utils.createCommand(this, function () {
var aList = [], aStatus = this.viewThreads.status();
var
self = this,
sFolder = this.viewFolder,
sUid = this.viewUid,
aUids = this.viewThreads(),
aStatus = this.viewThreads.status()
;
if (aStatus && aStatus[0]) if (aStatus && aStatus[0])
{ {
this.viewThreadMessages(aList); self.viewThreadMessages([]);
// window.console.log(aStatus); Promises.messageListSimple(sFolder, aUids).then(function (aList) {
_.each(aList, function (oItem) {
if (oItem && oItem.uid)
{
oItem.selected(sUid === oItem.uid);
}
});
self.viewThreadMessages(aList);
}, function (iErrorCode) {
window.alert(Translator.getNotification(iErrorCode));
});
} }
}, function () { }, function () {
return !this.messageLoadingThrottle(); return !this.messageLoadingThrottle() &&
!this.messageListOfThreadsLoading();
}); });
// PGP // PGP
@ -675,6 +706,13 @@
oEvent.stopPropagation(); oEvent.stopPropagation();
} }
}) })
.on('click', '.thread-list .thread-list-message', function () {
var oMessage = ko.dataFor(this);
if (oMessage && oMessage.folderFullNameRaw && oMessage.uid)
{
self.openThreadMessage(oMessage.uid);
}
})
.on('click', '.attachmentsPlace .attachmentItem .attachmentNameParent', function () { .on('click', '.attachmentsPlace .attachmentItem .attachmentNameParent', function () {
var var

View file

@ -168,6 +168,7 @@ cfg.paths.js = {
'vendors/ssm/ssm.min.js', 'vendors/ssm/ssm.min.js',
'vendors/jua/jua.min.js', 'vendors/jua/jua.min.js',
'vendors/buzz/buzz.min.js', 'vendors/buzz/buzz.min.js',
'vendors/Q/q.js',
'vendors/Autolinker/Autolinker.min.js', 'vendors/Autolinker/Autolinker.min.js',
'vendors/photoswipe/photoswipe.min.js', 'vendors/photoswipe/photoswipe.min.js',
'vendors/photoswipe/photoswipe-ui-default.min.js', 'vendors/photoswipe/photoswipe-ui-default.min.js',

View file

@ -2,7 +2,7 @@
"name": "RainLoop", "name": "RainLoop",
"title": "RainLoop Webmail", "title": "RainLoop Webmail",
"version": "1.8.2", "version": "1.8.2",
"release": "284", "release": "287",
"description": "Simple, modern & fast web-based email client", "description": "Simple, modern & fast web-based email client",
"homepage": "http://rainloop.net", "homepage": "http://rainloop.net",
"main": "gulpfile.js", "main": "gulpfile.js",

View file

@ -2217,6 +2217,16 @@ END;
)); ));
} }
/**
* @param string $sIp
*
* @return bool
*/
public static function ValidateIP($sIp)
{
return !empty($sIp) && $sIp === @\filter_var($sIp, FILTER_VALIDATE_IP);
}
/** /**
* @return \Net_IDNA2 * @return \Net_IDNA2
*/ */

View file

@ -154,6 +154,26 @@ class MailClient
return $this->oImapClient->IsLoggined(); return $this->oImapClient->IsLoggined();
} }
/**
* @return string
*/
private function getEnvelopeOrHeadersRequestStringForSimpleList()
{
return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array(
\MailSo\Mime\Enumerations\Header::RETURN_PATH,
\MailSo\Mime\Enumerations\Header::RECEIVED,
\MailSo\Mime\Enumerations\Header::MIME_VERSION,
\MailSo\Mime\Enumerations\Header::FROM_,
\MailSo\Mime\Enumerations\Header::TO_,
\MailSo\Mime\Enumerations\Header::CC,
\MailSo\Mime\Enumerations\Header::SENDER,
\MailSo\Mime\Enumerations\Header::REPLY_TO,
\MailSo\Mime\Enumerations\Header::DATE,
\MailSo\Mime\Enumerations\Header::SUBJECT,
\MailSo\Mime\Enumerations\Header::CONTENT_TYPE
), true);
}
/** /**
* @return string * @return string
*/ */
@ -1622,11 +1642,12 @@ class MailClient
* @param \MailSo\Mail\MessageCollection &$oMessageCollection * @param \MailSo\Mail\MessageCollection &$oMessageCollection
* @param array $aRequestIndexOrUids * @param array $aRequestIndexOrUids
* @param bool $bIndexAsUid * @param bool $bIndexAsUid
* @param bool $bSimple = false
* *
* @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception
*/ */
public function MessageListByRequestIndexOrUids(&$oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid) public function MessageListByRequestIndexOrUids(&$oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid, $bSimple = false)
{ {
if (\is_array($aRequestIndexOrUids) && 0 < \count($aRequestIndexOrUids)) if (\is_array($aRequestIndexOrUids) && 0 < \count($aRequestIndexOrUids))
{ {
@ -1637,7 +1658,8 @@ class MailClient
\MailSo\Imap\Enumerations\FetchType::INTERNALDATE, \MailSo\Imap\Enumerations\FetchType::INTERNALDATE,
\MailSo\Imap\Enumerations\FetchType::FLAGS, \MailSo\Imap\Enumerations\FetchType::FLAGS,
\MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE, \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE,
$this->getEnvelopeOrHeadersRequestString() $bSimple ? $this->getEnvelopeOrHeadersRequestStringForSimpleList() :
$this->getEnvelopeOrHeadersRequestString()
), \MailSo\Base\Utils::PrepearFetchSequence($aRequestIndexOrUids), $bIndexAsUid); ), \MailSo\Base\Utils::PrepearFetchSequence($aRequestIndexOrUids), $bIndexAsUid);
if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse))
@ -1862,6 +1884,33 @@ class MailClient
return \array_map('trim', $aResult); return \array_map('trim', $aResult);
} }
/**
* @param string $sFolderName
* @param array $aUids
*
* @return \MailSo\Mail\MessageCollection
*
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
*/
public function MessageListSimple($sFolderName, $aUids)
{
if (0 === \strlen($sFolderName) || !\MailSo\Base\Validator::NotEmptyArray($aUids))
{
throw new \MailSo\Base\Exceptions\InvalidArgumentException();
}
$this->oImapClient->FolderExamine($sFolderName);
$oMessageCollection = \MailSo\Mail\MessageCollection::NewInstance();
$oMessageCollection->FolderName = $sFolderName;
$this->MessageListByRequestIndexOrUids($oMessageCollection, $aUids, true, true);
return $oMessageCollection->GetAsArray();
}
/** /**
* @param string $sFolderName * @param string $sFolderName
* @param int $iOffset = 0 * @param int $iOffset = 0

View file

@ -1520,7 +1520,8 @@ class Actions
$aResult['AllowDropboxSocial'] = (bool) $oConfig->Get('social', 'dropbox_enable', false); $aResult['AllowDropboxSocial'] = (bool) $oConfig->Get('social', 'dropbox_enable', false);
$aResult['DropboxApiKey'] = (string) $oConfig->Get('social', 'dropbox_api_key', ''); $aResult['DropboxApiKey'] = (string) $oConfig->Get('social', 'dropbox_api_key', '');
$aResult['SubscriptionEnabled'] = \MailSo\Base\Utils::ValidateDomain($aResult['AdminDomain']); $aResult['SubscriptionEnabled'] = \MailSo\Base\Utils::ValidateDomain($aResult['AdminDomain']) ||
\MailSo\Base\Utils::ValidateIP($aResult['AdminDomain']);
$aResult['WeakPassword'] = $oConfig->ValidatePassword('12345'); $aResult['WeakPassword'] = $oConfig->ValidatePassword('12345');
$aResult['CoreAccess'] = $this->rainLoopCoreAccess(); $aResult['CoreAccess'] = $this->rainLoopCoreAccess();
@ -5478,6 +5479,40 @@ class Actions
return $this->DefaultResponse(__FUNCTION__, $oMessageList); return $this->DefaultResponse(__FUNCTION__, $oMessageList);
} }
/**
* @return array
*
* @throws \MailSo\Base\Exceptions\Exception
*/
public function DoMessageListSimple()
{
// \sleep(2);
// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList);
$sFolder = $this->GetActionParam('Folder', '');
$aUids = $this->GetActionParam('Uids', null);
if (0 === \strlen($sFolder) || !\is_array($aUids))
{
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
}
$this->initMailClientConnection();
$aMessageList = array();
try
{
$aMessageList = $this->MailClient()->MessageListSimple($sFolder, $aUids);
}
catch (\Exception $oException)
{
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList, $oException);
}
return $this->DefaultResponse(__FUNCTION__, $aMessageList);
}
/** /**
* @param \RainLoop\Model\Account $oAccount * @param \RainLoop\Model\Account $oAccount
* @param bool $bWithDraftInfo = true * @param bool $bWithDraftInfo = true

View file

@ -186,26 +186,30 @@
<a class="btn btn-thin" data-tooltip-placement="bottom" data-bind="command: threadForwardCommand"> <a class="btn btn-thin" data-tooltip-placement="bottom" data-bind="command: threadForwardCommand">
<i class="icon-left-middle"></i> <i class="icon-left-middle"></i>
</a> </a>
<a class="btn btn-thin btn-dark-disabled-border dropdown-toggle" id="thread-list-view-dropdown-id" data-toggle="dropdown" <a class="btn btn-dark-disabled-border dropdown-toggle" id="thread-list-view-dropdown-id" data-toggle="dropdown"
href="#" tabindex="-1" data-tooltip-placement="bottom"> href="#" tabindex="-1" data-tooltip-placement="bottom" data-bind="command: threadListCommand">
<!--href="#" tabindex="-1" data-tooltip-placement="bottom" data-bind="command: threadListCommand">--> <i class="icon-list"
<i class="icon-list"></i> data-bind="css: {'icon-list': !messageListOfThreadsLoading(), 'icon-spinner animated': messageListOfThreadsLoading()}"></i>
<!--<b data-bind="text: viewThreadsControlDesc"></b>-->
</a> </a>
<a class="btn btn-thin" data-tooltip-placement="bottom" data-bind="command: threadBackCommand"> <a class="btn btn-thin" data-tooltip-placement="bottom" data-bind="command: threadBackCommand">
<i class="icon-right-middle"></i> <i class="icon-right-middle"></i>
</a> </a>
<!-- <ul class="dropdown-menu g-ui-menu" role="menu" aria-labelledby="thread-list-view-dropdown-id" <ul class="dropdown-menu g-ui-menu thread-list" role="menu" aria-labelledby="thread-list-view-dropdown-id"
style="min-width: 400px; max-width: 400px; width: 400px;"> style="min-width: 400px; max-width: 400px; width: 400px;">
<li class="e-item" role="presentation"> <div data-bind="visible: messageListOfThreadsLoading" style="text-align: center; padding: 10px">
<a class="e-link menuitem" href="#" tabindex="-1"> <i class="icon-spinner animated" />
<span class="thread-from">test@rainloop.de</span> </div >
<span class="thread-date">05/20</span> <div data-bind="foreach: viewThreadMessages, visible: !messageListOfThreadsLoading()">
<br /> <li class="e-item thread-list-message" role="presentation" data-bind="css: {'selected': selected}">
<span class="thread-subject">Re: thread</span> <a class="e-link menuitem" href="#" tabindex="-1">
</a> <span class="thread-from" data-bind="text: senderEmailsString"></span>
</li> <span class="hread-date pull-right" data-moment-format="SHORT" data-bind="moment: dateTimeStampInUTC"></span>
</ul>--> <br />
<span class="thread-subject" data-bind="text: subject"></span>
</a>
</li>
</div>
</ul>
</div> </div>
</nobr> </nobr>
</div> </div>

View file

@ -19,7 +19,7 @@
<!-- ko foreach: accounts --> <!-- ko foreach: accounts -->
<li class="e-item" role="presentation"> <li class="e-item" role="presentation">
<a class="e-link menuitem account-item" href="#" data-bind="click: $root.accountClick, <a class="e-link menuitem account-item" href="#" data-bind="click: $root.accountClick,
attr: {'href': changeAccountLink()}, css: {current: $root.accountEmail() === email}"> attr: {'href': changeAccountLink()}, css: {'current': $root.accountEmail() === email}">
<!-- <b class="pull-right counter" data-bind="visible: 0 < count()"> <!-- <b class="pull-right counter" data-bind="visible: 0 < count()">
<span data-bind="text: count, visible: 100 > count()"></span> <span data-bind="text: count, visible: 100 > count()"></span>
<span data-bind="visible: 99 < count()">99+</span> <span data-bind="visible: 99 < count()">99+</span>

1
vendors/Q/.coverignore vendored Normal file
View file

@ -0,0 +1 @@
spec/

14
vendors/Q/.gitignore vendored Normal file
View file

@ -0,0 +1,14 @@
node_modules
npm-debug.log
CHANGES.html
README.html
.tmp
q.min.js
.coverage_data/
.coverage_debug/
cover_html/
# IntelliJ IDEA project files
.idea
*.iml

27
vendors/Q/.jshintrc vendored Normal file
View file

@ -0,0 +1,27 @@
{
"browser": true,
"node": true,
"curly": true,
"eqeqeq": true,
"es3": true,
"newcap": false,
"noarg": true,
"nonew": true,
"quotmark": "double",
"strict": true,
"trailing": true,
"undef": true,
"unused": true,
"globals": {
"self": false,
"bootstrap": false,
"cajaVM": false,
"define": false,
"ReturnValue": false,
"ses": false,
"setImmediate": false,
"Q": true
}
}

2
vendors/Q/.mailmap vendored Normal file
View file

@ -0,0 +1,2 @@
Domenic Denicola <domenic@domenicdenicola.com>
Kris Kowal <kris.kowal@cixar.com>

5
vendors/Q/.travis.yml vendored Normal file
View file

@ -0,0 +1,5 @@
language: node_js
node_js:
- "0.10"
script:
npm run lint && npm test

762
vendors/Q/CHANGES.md vendored Normal file
View file

@ -0,0 +1,762 @@
<!-- vim:ts=4:sts=4:sw=4:et:tw=70 -->
## 1.1.2
- Removed extraneous files from the npm package by using the "files"
whitelist in package.json instead of the .npmignore blacklist.
(@anton-rudeshko)
## 1.1.1
- Fix a pair of regressions in bootstrapping, one which precluded
WebWorker support, and another that precluded support in
``<script>`` usage outright. #607
## 1.1.0
- Adds support for enabling long stack traces in node.js by setting
environment variable `Q_DEBUG=1`.
- Introduces the `tap` method to promises, which will see a value
pass through without alteration.
- Use instanceof to recognize own promise instances as opposed to
thenables.
- Construct timeout errors with `code === ETIMEDOUT` (Kornel Lesiński)
- More descriminant CommonJS module environment detection.
- Dropped continuous integration for Node.js 0.6 and 0.8 because of
changes to npm that preclude the use of new `^` version predicate
operator in any transitive dependency.
- Users can now override `Q.nextTick`.
## 1.0.1
- Adds support for `Q.Promise`, which implements common usage of the
ES6 `Promise` constructor and its methods. `Promise` does not have
a valid promise constructor and a proper implementation awaits
version 2 of Q.
- Removes the console stopgap for a promise inspector. This no longer
works with any degree of reliability.
- Fixes support for content security policies that forbid eval. Now
using the `StopIteration` global to distinguish SpiderMonkey
generators from ES6 generators, assuming that they will never
coexist.
## 1.0.0
:cake: This is all but a re-release of version 0.9, which has settled
into a gentle maintenance mode and rightly deserves an official 1.0.
An ambitious 2.0 release is already around the corner, but 0.9/1.0
have been distributed far and wide and demand long term support.
- Q will now attempt to post a debug message in browsers regardless
of whether window.Touch is defined. Chrome at least now has this
property regardless of whether touch is supported by the underlying
hardware.
- Remove deprecation warning from `promise.valueOf`. The function is
called by the browser in various ways so there is no way to
distinguish usage that should be migrated from usage that cannot be
altered.
## 0.9.7
- :warning: `q.min.js` is no longer checked-in. It is however still
created by Grunt and NPM.
- Fixes a bug that inhibited `Q.async` with implementations of the new
ES6 generators.
- Fixes a bug with `nextTick` affecting Safari 6.0.5 the first time a
page loads when an `iframe` is involved.
- Introduces `passByCopy`, `join`, and `race`.
- Shows stack traces or error messages on the console, instead of
`Error` objects.
- Elimintates wrapper methods for improved performance.
- `Q.all` now propagates progress notifications of the form you might
expect of ES6 iterations, `{value, index}` where the `value` is the
progress notification from the promise at `index`.
## 0.9.6
- Fixes a bug in recognizing the difference between compatible Q
promises, and Q promises from before the implementation of "inspect".
The latter are now coerced.
- Fixes an infinite asynchronous coercion cycle introduced by former
solution, in two independently sufficient ways. 1.) All promises
returned by makePromise now implement "inspect", albeit a default
that reports that the promise has an "unknown" state. 2.) The
implementation of "then/when" is now in "then" instead of "when", so
that the responsibility to "coerce" the given promise rests solely in
the "when" method and the "then" method may assume that "this" is a
promise of the right type.
- Refactors `nextTick` to use an unrolled microtask within Q regardless
of how new ticks a requested. #316 @rkatic
## 0.9.5
- Introduces `inspect` for getting the state of a promise as
`{state: "fulfilled" | "rejected" | "pending", value | reason}`.
- Introduces `allSettled` which produces an array of promises states
for the input promises once they have all "settled". This is in
accordance with a discussion on Promises/A+ that "settled" refers to
a promise that is "fulfilled" or "rejected". "resolved" refers to a
deferred promise that has been "resolved" to another promise,
"sealing its fate" to the fate of the successor promise.
- Long stack traces are now off by default. Set `Q.longStackSupport`
to true to enable long stack traces.
- Long stack traces can now follow the entire asynchronous history of a
promise, not just a single jump.
- Introduces `spawn` for an immediately invoked asychronous generator.
@jlongster
- Support for *experimental* synonyms `mapply`, `mcall`, `nmapply`,
`nmcall` for method invocation.
## 0.9.4
- `isPromise` and `isPromiseAlike` now always returns a boolean
(even for falsy values). #284 @lfac-pt
- Support for ES6 Generators in `async` #288 @andywingo
- Clear duplicate promise rejections from dispatch methods #238 @SLaks
- Unhandled rejection API #296 @domenic
`stopUnhandledRejectionTracking`, `getUnhandledReasons`,
`resetUnhandledRejections`.
## 0.9.3
- Add the ability to give `Q.timeout`'s errors a custom error message. #270
@jgrenon
- Fix Q's call-stack busting behavior in Node.js 0.10, by switching from
`process.nextTick` to `setImmediate`. #254 #259
- Fix Q's behavior when used with the Mocha test runner in the browser, since
Mocha introduces a fake `process` global without a `nextTick` property. #267
- Fix some, but not all, cases wherein Q would give false positives in its
unhandled rejection detection (#252). A fix for other cases (#238) is
hopefully coming soon.
- Made `Q.promise` throw early if given a non-function.
## 0.9.2
- Pass through progress notifications when using `timeout`. #229 @omares
- Pass through progress notifications when using `delay`.
- Fix `nbind` to actually bind the `thisArg`. #232 @davidpadbury
## 0.9.1
- Made the AMD detection compatible with the RequireJS optimizer's `namespace`
option. #225 @terinjokes
- Fix side effects from `valueOf`, and thus from `isFulfilled`, `isRejected`,
and `isPending`. #226 @benjamn
## 0.9.0
This release removes many layers of deprecated methods and brings Q closer to
alignment with Mark Millers TC39 [strawman][] for concurrency. At the same
time, it fixes many bugs and adds a few features around error handling. Finally,
it comes with an updated and comprehensive [API Reference][].
[strawman]: http://wiki.ecmascript.org/doku.php?id=strawman:concurrency
[API Reference]: https://github.com/kriskowal/q/wiki/API-Reference
### API Cleanup
The following deprecated or undocumented methods have been removed.
Their replacements are listed here:
<table>
<thead>
<tr>
<th>0.8.x method</th>
<th>0.9 replacement</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Q.ref</code></td>
<td><code>Q</code></td>
</tr>
<tr>
<td><code>call</code>, <code>apply</code>, <code>bind</code> (*)</td>
<td><code>fcall</code>/<code>invoke</code>, <code>fapply</code>/<code>post</code>, <code>fbind</code></td>
</tr>
<tr>
<td><code>ncall</code>, <code>napply</code> (*)</td>
<td><code>nfcall</code>/<code>ninvoke</code>, <code>nfapply</code>/<code>npost</code></td>
</tr>
<tr>
<td><code>end</code></td>
<td><code>done</code></td>
</tr>
<tr>
<td><code>put</code></td>
<td><code>set</code></td>
</tr>
<tr>
<td><code>node</code></td>
<td><code>nbind</code></td>
</tr>
<tr>
<td><code>nend</code></td>
<td><code>nodeify</code></td>
</tr>
<tr>
<td><code>isResolved</code></td>
<td><code>isPending</code></td>
</tr>
<tr>
<td><code>deferred.node</code></td>
<td><code>deferred.makeNodeResolver</code></td>
</tr>
<tr>
<td><code>Method</code>, <code>sender</code></td>
<td><code>dispatcher</code></td>
</tr>
<tr>
<td><code>send</code></td>
<td><code>dispatch</code></td>
</tr>
<tr>
<td><code>view</code>, <code>viewInfo</code></td>
<td>(none)</td>
</tr>
</tbody>
</table>
(*) Use of ``thisp`` is discouraged. For calling methods, use ``post`` or
``invoke``.
### Alignment with the Concurrency Strawman
- Q now exports a `Q(value)` function, an alias for `resolve`.
`Q.call`, `Q.apply`, and `Q.bind` were removed to make room for the
same methods on the function prototype.
- `invoke` has been aliased to `send` in all its forms.
- `post` with no method name acts like `fapply`.
### Error Handling
- Long stack traces can be turned off by setting `Q.stackJumpLimit` to zero.
In the future, this property will be used to fine tune how many stack jumps
are retained in long stack traces; for now, anything nonzero is treated as
one (since Q only tracks one stack jump at the moment, see #144). #168
- In Node.js, if there are unhandled rejections when the process exits, they
are output to the console. #115
### Other
- `delete` and `set` (née `put`) no longer have a fulfillment value.
- Q promises are no longer frozen, which
[helps with performance](http://code.google.com/p/v8/issues/detail?id=1858).
- `thenReject` is now included, as a counterpart to `thenResolve`.
- The included browser `nextTick` shim is now faster. #195 @rkatic.
### Bug Fixes
- Q now works in Internet Explorer 10. #186 @ForbesLindesay
- `fbind` no longer hard-binds the returned function's `this` to `undefined`.
#202
- `Q.reject` no longer leaks memory. #148
- `npost` with no arguments now works. #207
- `allResolved` now works with non-Q promises ("thenables"). #179
- `keys` behavior is now correct even in browsers without native
`Object.keys`. #192 @rkatic
- `isRejected` and the `exception` property now work correctly if the
rejection reason is falsy. #198
### Internals and Advanced
- The internal interface for a promise now uses
`dispatchPromise(resolve, op, operands)` instead of `sendPromise(op,
resolve, ...operands)`, which reduces the cases where Q needs to do
argument slicing.
- The internal protocol uses different operands. "put" is now "set".
"del" is now "delete". "view" and "viewInfo" have been removed.
- `Q.fulfill` has been added. It is distinct from `Q.resolve` in that
it does not pass promises through, nor coerces promises from other
systems. The promise becomes the fulfillment value. This is only
recommended for use when trying to fulfill a promise with an object that has
a `then` function that is at the same time not a promise.
## 0.8.12
- Treat foreign promises as unresolved in `Q.isFulfilled`; this lets `Q.all`
work on arrays containing foreign promises. #154
- Fix minor incompliances with the [Promises/A+ spec][] and [test suite][]. #157
#158
[Promises/A+ spec]: http://promises-aplus.github.com/promises-spec/
[test suite]: https://github.com/promises-aplus/promises-tests
## 0.8.11
- Added ``nfcall``, ``nfapply``, and ``nfbind`` as ``thisp``-less versions of
``ncall``, ``napply``, and ``nbind``. The latter are now deprecated. #142
- Long stack traces no longer cause linearly-growing memory usage when chaining
promises together. #111
- Inspecting ``error.stack`` in a rejection handler will now give a long stack
trace. #103
- Fixed ``Q.timeout`` to clear its timeout handle when the promise is rejected;
previously, it kept the event loop alive until the timeout period expired.
#145 @dfilatov
- Added `q/queue` module, which exports an infinite promise queue
constructor.
## 0.8.10
- Added ``done`` as a replacement for ``end``, taking the usual fulfillment,
rejection, and progress handlers. It's essentially equivalent to
``then(f, r, p).end()``.
- Added ``Q.onerror``, a settable error trap that you can use to get full stack
traces for uncaught errors. #94
- Added ``thenResolve`` as a shortcut for returning a constant value once a
promise is fulfilled. #108 @ForbesLindesay
- Various tweaks to progress notification, including propagation and
transformation of progress values and only forwarding a single progress
object.
- Renamed ``nend`` to ``nodeify``. It no longer returns an always-fulfilled
promise when a Node callback is passed.
- ``deferred.resolve`` and ``deferred.reject`` no longer (sometimes) return
``deferred.promise``.
- Fixed stack traces getting mangled if they hit ``end`` twice. #116 #121 @ef4
- Fixed ``ninvoke`` and ``npost`` to work on promises for objects with Node
methods. #134
- Fixed accidental coercion of objects with nontrivial ``valueOf`` methods,
like ``Date``s, by the promise's ``valueOf`` method. #135
- Fixed ``spread`` not calling the passed rejection handler if given a rejected
promise.
## 0.8.9
- Added ``nend``
- Added preliminary progress notification support, via
``promise.then(onFulfilled, onRejected, onProgress)``,
``promise.progress(onProgress)``, and ``deferred.notify(...progressData)``.
- Made ``put`` and ``del`` return the object acted upon for easier chaining.
#84
- Fixed coercion cycles with cooperating promises. #106
## 0.8.7
- Support [Montage Require](http://github.com/kriskowal/mr)
## 0.8.6
- Fixed ``npost`` and ``ninvoke`` to pass the correct ``thisp``. #74
- Fixed various cases involving unorthodox rejection reasons. #73 #90
@ef4
- Fixed double-resolving of misbehaved custom promises. #75
- Sped up ``Q.all`` for arrays contain already-resolved promises or scalar
values. @ForbesLindesay
- Made stack trace filtering work when concatenating assets. #93 @ef4
- Added warnings for deprecated methods. @ForbesLindesay
- Added ``.npmignore`` file so that dependent packages get a slimmer
``node_modules`` directory.
## 0.8.5
- Added preliminary support for long traces (@domenic)
- Added ``fapply``, ``fcall``, ``fbind`` for non-thisp
promised function calls.
- Added ``return`` for async generators, where generators
are implemented.
- Rejected promises now have an "exception" property. If an object
isRejected(object), then object.valueOf().exception will
be the wrapped error.
- Added Jasmine specifications
- Support Internet Explorers 79 (with multiple bug fixes @domenic)
- Support Firefox 12
- Support Safari 5.1.5
- Support Chrome 18
## 0.8.4
- WARNING: ``promise.timeout`` is now rejected with an ``Error`` object
and the message now includes the duration of the timeout in
miliseconds. This doesn't constitute (in my opinion) a
backward-incompatibility since it is a change of an undocumented and
unspecified public behavior, but if you happened to depend on the
exception being a string, you will need to revise your code.
- Added ``deferred.makeNodeResolver()`` to replace the more cryptic
``deferred.node()`` method.
- Added experimental ``Q.promise(maker(resolve, reject))`` to make a
promise inside a callback, such that thrown exceptions in the
callback are converted and the resolver and rejecter are arguments.
This is a shorthand for making a deferred directly and inspired by
@gozalas stream constructor pattern and the Microsoft Windows Metro
Promise constructor interface.
- Added experimental ``Q.begin()`` that is intended to kick off chains
of ``.then`` so that each of these can be reordered without having to
edit the new and former first step.
## 0.8.3
- Added ``isFulfilled``, ``isRejected``, and ``isResolved``
to the promise prototype.
- Added ``allResolved`` for waiting for every promise to either be
fulfilled or rejected, without propagating an error. @utvara #53
- Added ``Q.bind`` as a method to transform functions that
return and throw into promise-returning functions. See
[an example](https://gist.github.com/1782808). @domenic
- Renamed ``node`` export to ``nbind``, and added ``napply`` to
complete the set. ``node`` remains as deprecated. @domenic #58
- Renamed ``Method`` export to ``sender``. ``Method``
remains as deprecated and will be removed in the next
major version since I expect it has very little usage.
- Added browser console message indicating a live list of
unhandled errors.
- Added support for ``msSetImmediate`` (IE10) or ``setImmediate``
(available via [polyfill](https://github.com/NobleJS/setImmediate))
as a browser-side ``nextTick`` implementation. #44 #50 #59
- Stopped using the event-queue dependency, which was in place for
Narwhal support: now directly using ``process.nextTick``.
- WARNING: EXPERIMENTAL: added ``finally`` alias for ``fin``, ``catch``
alias for ``fail``, ``try`` alias for ``call``, and ``delete`` alias
for ``del``. These properties are enquoted in the library for
cross-browser compatibility, but may be used as property names in
modern engines.
## 0.8.2
- Deprecated ``ref`` in favor of ``resolve`` as recommended by
@domenic.
- Update event-queue dependency.
## 0.8.1
- Fixed Opera bug. #35 @cadorn
- Fixed ``Q.all([])`` #32 @domenic
## 0.8.0
- WARNING: ``enqueue`` removed. Use ``nextTick`` instead.
This is more consistent with NodeJS and (subjectively)
more explicit and intuitive.
- WARNING: ``def`` removed. Use ``master`` instead. The
term ``def`` was too confusing to new users.
- WARNING: ``spy`` removed in favor of ``fin``.
- WARNING: ``wait`` removed. Do ``all(args).get(0)`` instead.
- WARNING: ``join`` removed. Do ``all(args).spread(callback)`` instead.
- WARNING: Removed the ``Q`` function module.exports alias
for ``Q.ref``. It conflicts with ``Q.apply`` in weird
ways, making it uncallable.
- Revised ``delay`` so that it accepts both ``(value,
timeout)`` and ``(timeout)`` variations based on
arguments length.
- Added ``ref().spread(cb(...args))``, a variant of
``then`` that spreads an array across multiple arguments.
Useful with ``all()``.
- Added ``defer().node()`` Node callback generator. The
callback accepts ``(error, value)`` or ``(error,
...values)``. For multiple value arguments, the
fulfillment value is an array, useful in conjunction with
``spread``.
- Added ``node`` and ``ncall``, both with the signature
``(fun, thisp_opt, ...args)``. The former is a decorator
and the latter calls immediately. ``node`` optional
binds and partially applies. ``ncall`` can bind and pass
arguments.
## 0.7.2
- Fixed thenable promise assimilation.
## 0.7.1
- Stopped shimming ``Array.prototype.reduce``. The
enumerable property has bad side-effects. Libraries that
depend on this (for example, QQ) will need to be revised.
## 0.7.0 - BACKWARD INCOMPATIBILITY
- WARNING: Removed ``report`` and ``asap``
- WARNING: The ``callback`` argument of the ``fin``
function no longer receives any arguments. Thus, it can
be used to call functions that should not receive
arguments on resolution. Use ``when``, ``then``, or
``fail`` if you need a value.
- IMPORTANT: Fixed a bug in the use of ``MessageChannel``
for ``nextTick``.
- Renamed ``enqueue`` to ``nextTick``.
- Added experimental ``view`` and ``viewInfo`` for creating
views of promises either when or before they're
fulfilled.
- Shims are now externally applied so subsequent scripts or
dependees can use them.
- Improved minification results.
- Improved readability.
## 0.6.0 - BACKWARD INCOMPATIBILITY
- WARNING: In practice, the implementation of ``spy`` and
the name ``fin`` were useful. I've removed the old
``fin`` implementation and renamed/aliased ``spy``.
- The "q" module now exports its ``ref`` function as a "Q"
constructor, with module systems that support exports
assignment including NodeJS, RequireJS, and when used as
a ``<script>`` tag. Notably, strictly compliant CommonJS
does not support this, but UncommonJS does.
- Added ``async`` decorator for generators that use yield
to "trampoline" promises. In engines that support
generators (SpiderMonkey), this will greatly reduce the
need for nested callbacks.
- Made ``when`` chainable.
- Made ``all`` chainable.
## 0.5.3
- Added ``all`` and refactored ``join`` and ``wait`` to use
it. All of these will now reject at the earliest
rejection.
## 0.5.2
- Minor improvement to ``spy``; now waits for resolution of
callback promise.
## 0.5.1
- Made most Q API methods chainable on promise objects, and
turned the previous promise-methods of ``join``,
``wait``, and ``report`` into Q API methods.
- Added ``apply`` and ``call`` to the Q API, and ``apply``
as a promise handler.
- Added ``fail``, ``fin``, and ``spy`` to Q and the promise
prototype for convenience when observing rejection,
fulfillment and rejection, or just observing without
affecting the resolution.
- Renamed ``def`` (although ``def`` remains shimmed until
the next major release) to ``master``.
- Switched to using ``MessageChannel`` for next tick task
enqueue in browsers that support it.
## 0.5.0 - MINOR BACKWARD INCOMPATIBILITY
- Exceptions are no longer reported when consumed.
- Removed ``error`` from the API. Since exceptions are
getting consumed, throwing them in an errback causes the
exception to silently disappear. Use ``end``.
- Added ``end`` as both an API method and a promise-chain
ending method. It causes propagated rejections to be
thrown, which allows Node to write stack traces and
emit ``uncaughtException`` events, and browsers to
likewise emit ``onerror`` and log to the console.
- Added ``join`` and ``wait`` as promise chain functions,
so you can wait for variadic promises, returning your own
promise back, or join variadic promises, resolving with a
callback that receives variadic fulfillment values.
## 0.4.4
- ``end`` no longer returns a promise. It is the end of the
promise chain.
- Stopped reporting thrown exceptions in ``when`` callbacks
and errbacks. These must be explicitly reported through
``.end()``, ``.then(null, Q.error)``, or some other
mechanism.
- Added ``report`` as an API method, which can be used as
an errback to report and propagate an error.
- Added ``report`` as a promise-chain method, so an error
can be reported if it passes such a gate.
## 0.4.3
- Fixed ``<script>`` support that regressed with 0.4.2
because of "use strict" in the module system
multi-plexer.
## 0.4.2
- Added support for RequireJS (jburke)
## 0.4.1
- Added an "end" method to the promise prototype,
as a shorthand for waiting for the promise to
be resolved gracefully, and failing to do so,
to dump an error message.
## 0.4.0 - BACKWARD INCOMPATIBLE*
- *Removed the utility modules. NPM and Node no longer
expose any module except the main module. These have
been moved and merged into the "qq" package.
- *In a non-CommonJS browser, q.js can be used as a script.
It now creates a Q global variable.
- Fixed thenable assimilation.
- Fixed some issues with asap, when it resolves to
undefined, or throws an exception.
## 0.3.0 - BACKWARD-INCOMPATIBLE
- The `post` method has been reverted to its original
signature, as provided in Tyler Close's `ref_send` API.
That is, `post` accepts two arguments, the second of
which is an arbitrary object, but usually invocation
arguments as an `Array`. To provide variadic arguments
to `post`, there is a new `invoke` function that posts
the variadic arguments to the value given in the first
argument.
- The `defined` method has been moved from `q` to `q/util`
since it gets no use in practice but is still
theoretically useful.
- The `Promise` constructor has been renamed to
`makePromise` to be consistent with the convention that
functions that do not require the `new` keyword to be
used as constructors have camelCase names.
- The `isResolved` function has been renamed to
`isFulfilled`. There is a new `isResolved` function that
indicates whether a value is not a promise or, if it is a
promise, whether it has been either fulfilled or
rejected. The code has been revised to reflect this
nuance in terminology.
## 0.2.10
- Added `join` to `"q/util"` for variadically joining
multiple promises.
## 0.2.9
- The future-compatible `invoke` method has been added,
to replace `post`, since `post` will become backward-
incompatible in the next major release.
- Exceptions thrown in the callbacks of a `when` call are
now emitted to Node's `"uncaughtException"` `process`
event in addition to being returned as a rejection reason.
## 0.2.8
- Exceptions thrown in the callbacks of a `when` call
are now consumed, warned, and transformed into
rejections of the promise returned by `when`.
## 0.2.7
- Fixed a minor bug in thenable assimilation, regressed
because of the change in the forwarding protocol.
- Fixed behavior of "q/util" `deep` method on dates and
other primitives. Github issue #11.
## 0.2.6
- Thenables (objects with a "then" method) are accepted
and provided, bringing this implementation of Q
into conformance with Promises/A, B, and D.
- Added `makePromise`, to replace the `Promise` function
eventually.
- Rejections are now also duck-typed. A rejection is a
promise with a valueOf method that returns a rejection
descriptor. A rejection descriptor has a
"promiseRejected" property equal to "true" and a
"reason" property corresponding to the rejection reason.
- Altered the `makePromise` API such that the `fallback`
method no longer receives a superfluous `resolved` method
after the `operator`. The fallback method is responsible
only for returning a resolution. This breaks an
undocumented API, so third-party API's depending on the
previous undocumented behavior may break.
## 0.2.5
- Changed promises into a duck-type such that multiple
instances of the Q module can exchange promise objects.
A promise is now defined as "an object that implements the
`promiseSend(op, resolved, ...)` method and `valueOf`".
- Exceptions in promises are now captured and returned
as rejections.
## 0.2.4
- Fixed bug in `ref` that prevented `del` messages from
being received (gozala)
- Fixed a conflict with FireFox 4; constructor property
is now read-only.
## 0.2.3
- Added `keys` message to promises and to the promise API.
## 0.2.2
- Added boilerplate to `q/queue` and `q/util`.
- Fixed missing dependency to `q/queue`.
## 0.2.1
- The `resolve` and `reject` methods of `defer` objects now
return the resolution promise for convenience.
- Added `q/util`, which provides `step`, `delay`, `shallow`,
`deep`, and three reduction orders.
- Added `q/queue` module for a promise `Queue`.
- Added `q-comm` to the list of compatible libraries.
- Deprecated `defined` from `q`, with intent to move it to
`q/util`.
## 0.2.0 - BACKWARD INCOMPATIBLE
- Changed post(ref, name, args) to variadic
post(ref, name, ...args). BACKWARD INCOMPATIBLE
- Added a def(value) method to annotate an object as being
necessarily a local value that cannot be serialized, such
that inter-process/worker/vat promise communication
libraries will send messages to it, but never send it
back.
- Added a send(value, op, ...args) method to the public API, for
forwarding messages to a value or promise in a future turn.
## 0.1.9
- Added isRejected() for testing whether a value is a rejected
promise. isResolved() retains the behavior of stating
that rejected promises are not resolved.
## 0.1.8
- Fixed isResolved(null) and isResolved(undefined) [issue #9]
- Fixed a problem with the Object.create shim
## 0.1.7
- shimmed ES5 Object.create in addition to Object.freeze
for compatibility on non-ES5 engines (gozala)
## 0.1.6
- Q.isResolved added
- promise.valueOf() now returns the value of resolved
and near values
- asap retried
- promises are frozen when possible
## 0.1.5
- fixed dependency list for Teleport (gozala)
- all unit tests now pass (gozala)
## 0.1.4
- added support for Teleport as an engine (gozala)
- simplified and updated methods for getting internal
print and enqueue functions universally (gozala)
## 0.1.3
- fixed erroneous link to the q module in package.json
## 0.1.2
- restructured for overlay style package compatibility
## 0.1.0
- removed asap because it was broken, probably down to the
philosophy.
## 0.0.3
- removed q-util
- fixed asap so it returns a value if completed
## 0.0.2
- added q-util
## 0.0.1
- initial version

40
vendors/Q/CONTRIBUTING.md vendored Normal file
View file

@ -0,0 +1,40 @@
For pull requests:
- Be consistent with prevalent style and design decisions.
- Add a Jasmine spec to `specs/q-spec.js`.
- Use `npm test` to avoid regressions.
- Run tests in `q-spec/run.html` in as many supported browsers as you
can find the will to deal with.
- Do not build minified versions; we do this each release.
- If you would be so kind, add a note to `CHANGES.md` in an
appropriate section:
- `Next Major Version` if it introduces backward incompatibilities
to code in the wild using documented features.
- `Next Minor Version` if it adds a new feature.
- `Next Patch Version` if it fixes a bug.
For releases:
- Run `npm test`.
- Run tests in `q-spec/run.html` in a representative sample of every
browser under the sun.
- Run `npm run cover` and make sure you're happy with the results.
- Run `npm run minify` and be sure to commit the resulting `q.min.js`.
- Note the Gzipped size output by the previous command, and update
`README.md` if it has changed to 1 significant digit.
- Stash any local changes.
- Update `CHANGES.md` to reflect all changes in the differences
between `HEAD` and the previous tagged version. Give credit where
credit is due.
- Update `README.md` to address all new, non-experimental features.
- Update the API reference on the Wiki to reflect all non-experimental
features.
- Use `npm version major|minor|patch` to update `package.json`,
commit, and tag the new version.
- Use `npm publish` to send up a new release.
- Send an email to the q-continuum mailing list announcing the new
release and the notes from the change log. This helps folks
maintaining other package ecosystems.

16
vendors/Q/Gruntfile.js vendored Normal file
View file

@ -0,0 +1,16 @@
"use strict";
module.exports = function (grunt) {
grunt.loadNpmTasks("grunt-contrib-uglify");
grunt.initConfig({
uglify: {
"q.min.js": ["q.js"],
options: {
report: "gzip"
}
}
});
grunt.registerTask("default", ["uglify"]);
};

18
vendors/Q/LICENSE vendored Normal file
View file

@ -0,0 +1,18 @@
Copyright 20092014 Kristopher Michael Kowal. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

869
vendors/Q/README.md vendored Normal file
View file

@ -0,0 +1,869 @@
[![Build Status](https://secure.travis-ci.org/kriskowal/q.png?branch=master)](http://travis-ci.org/kriskowal/q)
<a href="http://promises-aplus.github.com/promises-spec">
<img src="http://kriskowal.github.io/q/q.png"
align="right" alt="Q logo" />
</a>
*This is Q version 1, from the `v1` branch in Git. This documentation applies to
the latest of both the version 1 and version 0.9 release trains. These releases
are stable. There will be no further releases of 0.9 after 0.9.7 which is nearly
equivalent to version 1.0.0. All further releases of `q@~1.0` will be backward
compatible. The version 2 release train introduces significant and
backward-incompatible changes and is experimental at this time.*
If a function cannot return a value or throw an exception without
blocking, it can return a promise instead. A promise is an object
that represents the return value or the thrown exception that the
function may eventually provide. A promise can also be used as a
proxy for a [remote object][Q-Connection] to overcome latency.
[Q-Connection]: https://github.com/kriskowal/q-connection
On the first pass, promises can mitigate the “[Pyramid of
Doom][POD]”: the situation where code marches to the right faster
than it marches forward.
[POD]: http://calculist.org/blog/2011/12/14/why-coroutines-wont-work-on-the-web/
```javascript
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});
```
With a promise library, you can flatten the pyramid.
```javascript
Q.fcall(promisedStep1)
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (value4) {
// Do something with value4
})
.catch(function (error) {
// Handle any error from all above steps
})
.done();
```
With this approach, you also get implicit error propagation, just like `try`,
`catch`, and `finally`. An error in `promisedStep1` will flow all the way to
the `catch` function, where its caught and handled. (Here `promisedStepN` is
a version of `stepN` that returns a promise.)
The callback approach is called an “inversion of control”.
A function that accepts a callback instead of a return value
is saying, “Dont call me, Ill call you.”. Promises
[un-invert][IOC] the inversion, cleanly separating the input
arguments from control flow arguments. This simplifies the
use and creation of APIs, particularly variadic,
rest and spread arguments.
[IOC]: http://www.slideshare.net/domenicdenicola/callbacks-promises-and-coroutines-oh-my-the-evolution-of-asynchronicity-in-javascript
## Getting Started
The Q module can be loaded as:
- A ``<script>`` tag (creating a ``Q`` global variable): ~2.5 KB minified and
gzipped.
- A Node.js and CommonJS module, available in [npm](https://npmjs.org/) as
the [q](https://npmjs.org/package/q) package
- An AMD module
- A [component](https://github.com/component/component) as ``microjs/q``
- Using [bower](http://bower.io/) as `q#1.0.1`
- Using [NuGet](http://nuget.org/) as [Q](https://nuget.org/packages/q)
Q can exchange promises with jQuery, Dojo, When.js, WinJS, and more.
## Resources
Our [wiki][] contains a number of useful resources, including:
- A method-by-method [Q API reference][reference].
- A growing [examples gallery][examples], showing how Q can be used to make
everything better. From XHR to database access to accessing the Flickr API,
Q is there for you.
- There are many libraries that produce and consume Q promises for everything
from file system/database access or RPC to templating. For a list of some of
the more popular ones, see [Libraries][].
- If you want materials that introduce the promise concept generally, and the
below tutorial isn't doing it for you, check out our collection of
[presentations, blog posts, and podcasts][resources].
- A guide for those [coming from jQuery's `$.Deferred`][jquery].
We'd also love to have you join the Q-Continuum [mailing list][].
[wiki]: https://github.com/kriskowal/q/wiki
[reference]: https://github.com/kriskowal/q/wiki/API-Reference
[examples]: https://github.com/kriskowal/q/wiki/Examples-Gallery
[Libraries]: https://github.com/kriskowal/q/wiki/Libraries
[resources]: https://github.com/kriskowal/q/wiki/General-Promise-Resources
[jquery]: https://github.com/kriskowal/q/wiki/Coming-from-jQuery
[mailing list]: https://groups.google.com/forum/#!forum/q-continuum
## Tutorial
Promises have a ``then`` method, which you can use to get the eventual
return value (fulfillment) or thrown exception (rejection).
```javascript
promiseMeSomething()
.then(function (value) {
}, function (reason) {
});
```
If ``promiseMeSomething`` returns a promise that gets fulfilled later
with a return value, the first function (the fulfillment handler) will be
called with the value. However, if the ``promiseMeSomething`` function
gets rejected later by a thrown exception, the second function (the
rejection handler) will be called with the exception.
Note that resolution of a promise is always asynchronous: that is, the
fulfillment or rejection handler will always be called in the next turn of the
event loop (i.e. `process.nextTick` in Node). This gives you a nice
guarantee when mentally tracing the flow of your code, namely that
``then`` will always return before either handler is executed.
In this tutorial, we begin with how to consume and work with promises. We'll
talk about how to create them, and thus create functions like
`promiseMeSomething` that return promises, [below](#the-beginning).
### Propagation
The ``then`` method returns a promise, which in this example, Im
assigning to ``outputPromise``.
```javascript
var outputPromise = getInputPromise()
.then(function (input) {
}, function (reason) {
});
```
The ``outputPromise`` variable becomes a new promise for the return
value of either handler. Since a function can only either return a
value or throw an exception, only one handler will ever be called and it
will be responsible for resolving ``outputPromise``.
- If you return a value in a handler, ``outputPromise`` will get
fulfilled.
- If you throw an exception in a handler, ``outputPromise`` will get
rejected.
- If you return a **promise** in a handler, ``outputPromise`` will
“become” that promise. Being able to become a new promise is useful
for managing delays, combining results, or recovering from errors.
If the ``getInputPromise()`` promise gets rejected and you omit the
rejection handler, the **error** will go to ``outputPromise``:
```javascript
var outputPromise = getInputPromise()
.then(function (value) {
});
```
If the input promise gets fulfilled and you omit the fulfillment handler, the
**value** will go to ``outputPromise``:
```javascript
var outputPromise = getInputPromise()
.then(null, function (error) {
});
```
Q promises provide a ``fail`` shorthand for ``then`` when you are only
interested in handling the error:
```javascript
var outputPromise = getInputPromise()
.fail(function (error) {
});
```
If you are writing JavaScript for modern engines only or using
CoffeeScript, you may use `catch` instead of `fail`.
Promises also have a ``fin`` function that is like a ``finally`` clause.
The final handler gets called, with no arguments, when the promise
returned by ``getInputPromise()`` either returns a value or throws an
error. The value returned or error thrown by ``getInputPromise()``
passes directly to ``outputPromise`` unless the final handler fails, and
may be delayed if the final handler returns a promise.
```javascript
var outputPromise = getInputPromise()
.fin(function () {
// close files, database connections, stop servers, conclude tests
});
```
- If the handler returns a value, the value is ignored
- If the handler throws an error, the error passes to ``outputPromise``
- If the handler returns a promise, ``outputPromise`` gets postponed. The
eventual value or error has the same effect as an immediate return
value or thrown error: a value would be ignored, an error would be
forwarded.
If you are writing JavaScript for modern engines only or using
CoffeeScript, you may use `finally` instead of `fin`.
### Chaining
There are two ways to chain promises. You can chain promises either
inside or outside handlers. The next two examples are equivalent.
```javascript
return getUsername()
.then(function (username) {
return getUser(username)
.then(function (user) {
// if we get here without an error,
// the value returned here
// or the exception thrown here
// resolves the promise returned
// by the first line
})
});
```
```javascript
return getUsername()
.then(function (username) {
return getUser(username);
})
.then(function (user) {
// if we get here without an error,
// the value returned here
// or the exception thrown here
// resolves the promise returned
// by the first line
});
```
The only difference is nesting. Its useful to nest handlers if you
need to capture multiple input values in your closure.
```javascript
function authenticate() {
return getUsername()
.then(function (username) {
return getUser(username);
})
// chained because we will not need the user name in the next event
.then(function (user) {
return getPassword()
// nested because we need both user and password next
.then(function (password) {
if (user.passwordHash !== hash(password)) {
throw new Error("Can't authenticate");
}
});
});
}
```
### Combination
You can turn an array of promises into a promise for the whole,
fulfilled array using ``all``.
```javascript
return Q.all([
eventualAdd(2, 2),
eventualAdd(10, 20)
]);
```
If you have a promise for an array, you can use ``spread`` as a
replacement for ``then``. The ``spread`` function “spreads” the
values over the arguments of the fulfillment handler. The rejection handler
will get called at the first sign of failure. That is, whichever of
the received promises fails first gets handled by the rejection handler.
```javascript
function eventualAdd(a, b) {
return Q.spread([a, b], function (a, b) {
return a + b;
})
}
```
But ``spread`` calls ``all`` initially, so you can skip it in chains.
```javascript
return getUsername()
.then(function (username) {
return [username, getUser(username)];
})
.spread(function (username, user) {
});
```
The ``all`` function returns a promise for an array of values. When this
promise is fulfilled, the array contains the fulfillment values of the original
promises, in the same order as those promises. If one of the given promises
is rejected, the returned promise is immediately rejected, not waiting for the
rest of the batch. If you want to wait for all of the promises to either be
fulfilled or rejected, you can use ``allSettled``.
```javascript
Q.allSettled(promises)
.then(function (results) {
results.forEach(function (result) {
if (result.state === "fulfilled") {
var value = result.value;
} else {
var reason = result.reason;
}
});
});
```
### Sequences
If you have a number of promise-producing functions that need
to be run sequentially, you can of course do so manually:
```javascript
return foo(initialVal).then(bar).then(baz).then(qux);
```
However, if you want to run a dynamically constructed sequence of
functions, you'll want something like this:
```javascript
var funcs = [foo, bar, baz, qux];
var result = Q(initialVal);
funcs.forEach(function (f) {
result = result.then(f);
});
return result;
```
You can make this slightly more compact using `reduce`:
```javascript
return funcs.reduce(function (soFar, f) {
return soFar.then(f);
}, Q(initialVal));
```
Or, you could use the ultra-compact version:
```javascript
return funcs.reduce(Q.when, Q(initialVal));
```
### Handling Errors
One sometimes-unintuive aspect of promises is that if you throw an
exception in the fulfillment handler, it will not be caught by the error
handler.
```javascript
return foo()
.then(function (value) {
throw new Error("Can't bar.");
}, function (error) {
// We only get here if "foo" fails
});
```
To see why this is, consider the parallel between promises and
``try``/``catch``. We are ``try``-ing to execute ``foo()``: the error
handler represents a ``catch`` for ``foo()``, while the fulfillment handler
represents code that happens *after* the ``try``/``catch`` block.
That code then needs its own ``try``/``catch`` block.
In terms of promises, this means chaining your rejection handler:
```javascript
return foo()
.then(function (value) {
throw new Error("Can't bar.");
})
.fail(function (error) {
// We get here with either foo's error or bar's error
});
```
### Progress Notification
It's possible for promises to report their progress, e.g. for tasks that take a
long time like a file upload. Not all promises will implement progress
notifications, but for those that do, you can consume the progress values using
a third parameter to ``then``:
```javascript
return uploadFile()
.then(function () {
// Success uploading the file
}, function (err) {
// There was an error, and we get the reason for error
}, function (progress) {
// We get notified of the upload's progress as it is executed
});
```
Like `fail`, Q also provides a shorthand for progress callbacks
called `progress`:
```javascript
return uploadFile().progress(function (progress) {
// We get notified of the upload's progress
});
```
### The End
When you get to the end of a chain of promises, you should either
return the last promise or end the chain. Since handlers catch
errors, its an unfortunate pattern that the exceptions can go
unobserved.
So, either return it,
```javascript
return foo()
.then(function () {
return "bar";
});
```
Or, end it.
```javascript
foo()
.then(function () {
return "bar";
})
.done();
```
Ending a promise chain makes sure that, if an error doesnt get
handled before the end, it will get rethrown and reported.
This is a stopgap. We are exploring ways to make unhandled errors
visible without any explicit handling.
### The Beginning
Everything above assumes you get a promise from somewhere else. This
is the common case. Every once in a while, you will need to create a
promise from scratch.
#### Using ``Q.fcall``
You can create a promise from a value using ``Q.fcall``. This returns a
promise for 10.
```javascript
return Q.fcall(function () {
return 10;
});
```
You can also use ``fcall`` to get a promise for an exception.
```javascript
return Q.fcall(function () {
throw new Error("Can't do it");
});
```
As the name implies, ``fcall`` can call functions, or even promised
functions. This uses the ``eventualAdd`` function above to add two
numbers.
```javascript
return Q.fcall(eventualAdd, 2, 2);
```
#### Using Deferreds
If you have to interface with asynchronous functions that are callback-based
instead of promise-based, Q provides a few shortcuts (like ``Q.nfcall`` and
friends). But much of the time, the solution will be to use *deferreds*.
```javascript
var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", function (error, text) {
if (error) {
deferred.reject(new Error(error));
} else {
deferred.resolve(text);
}
});
return deferred.promise;
```
Note that a deferred can be resolved with a value or a promise. The
``reject`` function is a shorthand for resolving with a rejected
promise.
```javascript
// this:
deferred.reject(new Error("Can't do it"));
// is shorthand for:
var rejection = Q.fcall(function () {
throw new Error("Can't do it");
});
deferred.resolve(rejection);
```
This is a simplified implementation of ``Q.delay``.
```javascript
function delay(ms) {
var deferred = Q.defer();
setTimeout(deferred.resolve, ms);
return deferred.promise;
}
```
This is a simplified implementation of ``Q.timeout``
```javascript
function timeout(promise, ms) {
var deferred = Q.defer();
Q.when(promise, deferred.resolve);
delay(ms).then(function () {
deferred.reject(new Error("Timed out"));
});
return deferred.promise;
}
```
Finally, you can send a progress notification to the promise with
``deferred.notify``.
For illustration, this is a wrapper for XML HTTP requests in the browser. Note
that a more [thorough][XHR] implementation would be in order in practice.
[XHR]: https://github.com/montagejs/mr/blob/71e8df99bb4f0584985accd6f2801ef3015b9763/browser.js#L29-L73
```javascript
function requestOkText(url) {
var request = new XMLHttpRequest();
var deferred = Q.defer();
request.open("GET", url, true);
request.onload = onload;
request.onerror = onerror;
request.onprogress = onprogress;
request.send();
function onload() {
if (request.status === 200) {
deferred.resolve(request.responseText);
} else {
deferred.reject(new Error("Status code was " + request.status));
}
}
function onerror() {
deferred.reject(new Error("Can't XHR " + JSON.stringify(url)));
}
function onprogress(event) {
deferred.notify(event.loaded / event.total);
}
return deferred.promise;
}
```
Below is an example of how to use this ``requestOkText`` function:
```javascript
requestOkText("http://localhost:3000")
.then(function (responseText) {
// If the HTTP response returns 200 OK, log the response text.
console.log(responseText);
}, function (error) {
// If there's an error or a non-200 status code, log the error.
console.error(error);
}, function (progress) {
// Log the progress as it comes in.
console.log("Request progress: " + Math.round(progress * 100) + "%");
});
```
#### Using `Q.Promise`
This is an alternative promise-creation API that has the same power as
the deferred concept, but without introducing another conceptual entity.
Rewriting the `requestOkText` example above using `Q.Promise`:
```javascript
function requestOkText(url) {
return Q.Promise(function(resolve, reject, notify) {
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.onload = onload;
request.onerror = onerror;
request.onprogress = onprogress;
request.send();
function onload() {
if (request.status === 200) {
resolve(request.responseText);
} else {
reject(new Error("Status code was " + request.status));
}
}
function onerror() {
reject(new Error("Can't XHR " + JSON.stringify(url)));
}
function onprogress(event) {
notify(event.loaded / event.total);
}
});
}
```
If `requestOkText` were to throw an exception, the returned promise would be
rejected with that thrown exception as the rejection reason.
### The Middle
If you are using a function that may return a promise, but just might
return a value if it doesnt need to defer, you can use the “static”
methods of the Q library.
The ``when`` function is the static equivalent for ``then``.
```javascript
return Q.when(valueOrPromise, function (value) {
}, function (error) {
});
```
All of the other methods on a promise have static analogs with the
same name.
The following are equivalent:
```javascript
return Q.all([a, b]);
```
```javascript
return Q.fcall(function () {
return [a, b];
})
.all();
```
When working with promises provided by other libraries, you should
convert it to a Q promise. Not all promise libraries make the same
guarantees as Q and certainly dont provide all of the same methods.
Most libraries only provide a partially functional ``then`` method.
This thankfully is all we need to turn them into vibrant Q promises.
```javascript
return Q($.ajax(...))
.then(function () {
});
```
If there is any chance that the promise you receive is not a Q promise
as provided by your library, you should wrap it using a Q function.
You can even use ``Q.invoke`` as a shorthand.
```javascript
return Q.invoke($, 'ajax', ...)
.then(function () {
});
```
### Over the Wire
A promise can serve as a proxy for another object, even a remote
object. There are methods that allow you to optimistically manipulate
properties or call functions. All of these interactions return
promises, so they can be chained.
```
direct manipulation using a promise as a proxy
-------------------------- -------------------------------
value.foo promise.get("foo")
value.foo = value promise.put("foo", value)
delete value.foo promise.del("foo")
value.foo(...args) promise.post("foo", [args])
value.foo(...args) promise.invoke("foo", ...args)
value(...args) promise.fapply([args])
value(...args) promise.fcall(...args)
```
If the promise is a proxy for a remote object, you can shave
round-trips by using these functions instead of ``then``. To take
advantage of promises for remote objects, check out [Q-Connection][].
[Q-Connection]: https://github.com/kriskowal/q-connection
Even in the case of non-remote objects, these methods can be used as
shorthand for particularly-simple fulfillment handlers. For example, you
can replace
```javascript
return Q.fcall(function () {
return [{ foo: "bar" }, { foo: "baz" }];
})
.then(function (value) {
return value[0].foo;
});
```
with
```javascript
return Q.fcall(function () {
return [{ foo: "bar" }, { foo: "baz" }];
})
.get(0)
.get("foo");
```
### Adapting Node
If you're working with functions that make use of the Node.js callback pattern,
where callbacks are in the form of `function(err, result)`, Q provides a few
useful utility functions for converting between them. The most straightforward
are probably `Q.nfcall` and `Q.nfapply` ("Node function call/apply") for calling
Node.js-style functions and getting back a promise:
```javascript
return Q.nfcall(FS.readFile, "foo.txt", "utf-8");
return Q.nfapply(FS.readFile, ["foo.txt", "utf-8"]);
```
If you are working with methods, instead of simple functions, you can easily
run in to the usual problems where passing a method to another function—like
`Q.nfcall`—"un-binds" the method from its owner. To avoid this, you can either
use `Function.prototype.bind` or some nice shortcut methods we provide:
```javascript
return Q.ninvoke(redisClient, "get", "user:1:id");
return Q.npost(redisClient, "get", ["user:1:id"]);
```
You can also create reusable wrappers with `Q.denodeify` or `Q.nbind`:
```javascript
var readFile = Q.denodeify(FS.readFile);
return readFile("foo.txt", "utf-8");
var redisClientGet = Q.nbind(redisClient.get, redisClient);
return redisClientGet("user:1:id");
```
Finally, if you're working with raw deferred objects, there is a
`makeNodeResolver` method on deferreds that can be handy:
```javascript
var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", deferred.makeNodeResolver());
return deferred.promise;
```
### Long Stack Traces
Q comes with optional support for “long stack traces,” wherein the `stack`
property of `Error` rejection reasons is rewritten to be traced along
asynchronous jumps instead of stopping at the most recent one. As an example:
```js
function theDepthsOfMyProgram() {
Q.delay(100).done(function explode() {
throw new Error("boo!");
});
}
theDepthsOfMyProgram();
```
usually would give a rather unhelpful stack trace looking something like
```
Error: boo!
at explode (/path/to/test.js:3:11)
at _fulfilled (/path/to/test.js:q:54)
at resolvedValue.promiseDispatch.done (/path/to/q.js:823:30)
at makePromise.promise.promiseDispatch (/path/to/q.js:496:13)
at pending (/path/to/q.js:397:39)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
```
But, if you turn this feature on by setting
```js
Q.longStackSupport = true;
```
then the above code gives a nice stack trace to the tune of
```
Error: boo!
at explode (/path/to/test.js:3:11)
From previous event:
at theDepthsOfMyProgram (/path/to/test.js:2:16)
at Object.<anonymous> (/path/to/test.js:7:1)
```
Note how you can see the function that triggered the async operation in the
stack trace! This is very helpful for debugging, as otherwise you end up getting
only the first line, plus a bunch of Q internals, with no sign of where the
operation started.
In node.js, this feature can also be enabled through the Q_DEBUG environment
variable:
```
Q_DEBUG=1 node server.js
```
This will enable long stack support in every instance of Q.
This feature does come with somewhat-serious performance and memory overhead,
however. If you're working with lots of promises, or trying to scale a server
to many users, you should probably keep it off. But in development, go for it!
## Tests
You can view the results of the Q test suite [in your browser][tests]!
[tests]: https://rawgithub.com/kriskowal/q/v1/spec/q-spec.html
## License
Copyright 20092014 Kristopher Michael Kowal
MIT License (enclosed)

18
vendors/Q/VERSIONS.md vendored Normal file
View file

@ -0,0 +1,18 @@
<!-- vim:ts=4:sts=4:sw=4:et:tw=60 -->
This library has the following policy about versions.
- Presently, all planned versions have a major version number of 0.
- The minor version number increases for every backward-incompatible
change to a documented behavior.
- The patch version number increases for every added feature,
backward-incompatible changes to undocumented features, and
bug-fixes.
Upon the release of a version 1.0.0, the strategy will be revised.
- The major version will increase for any backward-incompatible
changes.
- The minor version will increase for added features.
- The patch version will increase for bug-fixes.

View file

@ -0,0 +1,71 @@
"use strict";
var Q = require("../q");
var fs = require("fs");
suite("A single simple async operation", function () {
bench("with an immediately-fulfilled promise", function (done) {
Q().then(done);
});
bench("with direct setImmediate usage", function (done) {
setImmediate(done);
});
bench("with direct setTimeout(…, 0)", function (done) {
setTimeout(done, 0);
});
});
suite("A fs.readFile", function () {
var denodeified = Q.denodeify(fs.readFile);
set("iterations", 1000);
set("delay", 1000);
bench("directly, with callbacks", function (done) {
fs.readFile(__filename, done);
});
bench("with Q.nfcall", function (done) {
Q.nfcall(fs.readFile, __filename).then(done);
});
bench("with a Q.denodeify'ed version", function (done) {
denodeified(__filename).then(done);
});
bench("with manual usage of deferred.makeNodeResolver", function (done) {
var deferred = Q.defer();
fs.readFile(__filename, deferred.makeNodeResolver());
deferred.promise.then(done);
});
});
suite("1000 operations in parallel", function () {
function makeCounter(desiredCount, ultimateCallback) {
var soFar = 0;
return function () {
if (++soFar === desiredCount) {
ultimateCallback();
}
};
}
var numberOfOps = 1000;
bench("with immediately-fulfilled promises", function (done) {
var counter = makeCounter(numberOfOps, done);
for (var i = 0; i < numberOfOps; ++i) {
Q().then(counter);
}
});
bench("with direct setImmediate usage", function (done) {
var counter = makeCounter(numberOfOps, done);
for (var i = 0; i < numberOfOps; ++i) {
setImmediate(counter);
}
});
});

36
vendors/Q/benchmark/scenarios.js vendored Normal file
View file

@ -0,0 +1,36 @@
"use strict";
var Q = require("../q");
suite("Chaining", function () {
var numberToChain = 1000;
bench("Chaining many already-fulfilled promises together", function (done) {
var currentPromise = Q();
for (var i = 0; i < numberToChain; ++i) {
currentPromise = currentPromise.then(function () {
return Q();
});
}
currentPromise.then(done);
});
bench("Chaining and then fulfilling the end of the chain", function (done) {
var deferred = Q.defer();
var currentPromise = deferred.promise;
for (var i = 0; i < numberToChain; ++i) {
(function () {
var promiseToReturn = currentPromise;
currentPromise = Q().then(function () {
return promiseToReturn;
});
}());
}
currentPromise.then(done);
deferred.resolve();
});
});

1026
vendors/Q/design/README.js vendored Normal file

File diff suppressed because it is too large Load diff

22
vendors/Q/design/q0.js vendored Normal file
View file

@ -0,0 +1,22 @@
var defer = function () {
var pending = [], value;
return {
resolve: function (_value) {
value = _value;
for (var i = 0, ii = pending.length; i < ii; i++) {
var callback = pending[i];
callback(value);
}
pending = undefined;
},
then: function (callback) {
if (pending) {
pending.push(callback);
} else {
callback(value);
}
}
}
};

26
vendors/Q/design/q1.js vendored Normal file
View file

@ -0,0 +1,26 @@
var defer = function () {
var pending = [], value;
return {
resolve: function (_value) {
if (pending) {
value = _value;
for (var i = 0, ii = pending.length; i < ii; i++) {
var callback = pending[i];
callback(value);
}
pending = undefined;
} else {
throw new Error("A promise can only be resolved once.");
}
},
then: function (callback) {
if (pending) {
pending.push(callback);
} else {
callback(value);
}
}
}
};

33
vendors/Q/design/q2.js vendored Normal file
View file

@ -0,0 +1,33 @@
var Promise = function () {
};
var isPromise = function (value) {
return value instanceof Promise;
};
var defer = function () {
var pending = [], value;
var promise = new Promise();
promise.then = function (callback) {
if (pending) {
pending.push(callback);
} else {
callback(value);
}
};
return {
resolve: function (_value) {
if (pending) {
value = _value;
for (var i = 0, ii = pending.length; i < ii; i++) {
var callback = pending[i];
callback(value);
}
pending = undefined;
}
},
promise: promise
};
};

30
vendors/Q/design/q3.js vendored Normal file
View file

@ -0,0 +1,30 @@
var isPromise = function (value) {
return value && typeof value.then === "function";
};
var defer = function () {
var pending = [], value;
return {
resolve: function (_value) {
if (pending) {
value = _value;
for (var i = 0, ii = pending.length; i < ii; i++) {
var callback = pending[i];
callback(value);
}
pending = undefined;
}
},
promise: {
then: function (callback) {
if (pending) {
pending.push(callback);
} else {
callback(value);
}
}
}
};
};

48
vendors/Q/design/q4.js vendored Normal file
View file

@ -0,0 +1,48 @@
var isPromise = function (value) {
return value && typeof value.then === "function";
};
var defer = function () {
var pending = [], value;
return {
resolve: function (_value) {
if (pending) {
value = ref(_value); // values wrapped in a promise
for (var i = 0, ii = pending.length; i < ii; i++) {
var callback = pending[i];
value.then(callback); // then called instead
}
pending = undefined;
}
},
promise: {
then: function (_callback) {
var result = defer();
// callback is wrapped so that its return
// value is captured and used to resolve the promise
// that "then" returns
var callback = function (value) {
result.resolve(_callback(value));
};
if (pending) {
pending.push(callback);
} else {
value.then(callback);
}
return result.promise;
}
}
};
};
var ref = function (value) {
if (value && typeof value.then === "function")
return value;
return {
then: function (callback) {
return ref(callback(value));
}
};
};

56
vendors/Q/design/q5.js vendored Normal file
View file

@ -0,0 +1,56 @@
var isPromise = function (value) {
return value && typeof value.then === "function";
};
var defer = function () {
var pending = [], value;
return {
resolve: function (_value) {
if (pending) {
value = ref(_value);
for (var i = 0, ii = pending.length; i < ii; i++) {
// apply the pending arguments to "then"
value.then.apply(value, pending[i]);
}
pending = undefined;
}
},
promise: {
then: function (_callback, _errback) {
var result = defer();
var callback = function (value) {
result.resolve(_callback(value));
};
var errback = function (reason) {
result.resolve(_errback(reason));
};
if (pending) {
pending.push([callback, errback]);
} else {
value.then(callback, errback);
}
return result.promise;
}
}
};
};
var ref = function (value) {
if (value && typeof value.then === "function")
return value;
return {
then: function (callback) {
return ref(callback(value));
}
};
};
var reject = function (reason) {
return {
then: function (callback, errback) {
return ref(errback(reason));
}
};
};

64
vendors/Q/design/q6.js vendored Normal file
View file

@ -0,0 +1,64 @@
var isPromise = function (value) {
return value && typeof value.then === "function";
};
var defer = function () {
var pending = [], value;
return {
resolve: function (_value) {
if (pending) {
value = ref(_value);
for (var i = 0, ii = pending.length; i < ii; i++) {
value.then.apply(value, pending[i]);
}
pending = undefined;
}
},
promise: {
then: function (_callback, _errback) {
var result = defer();
// provide default callbacks and errbacks
_callback = _callback || function (value) {
// by default, forward fulfillment
return value;
};
_errback = _errback || function (reason) {
// by default, forward rejection
return reject(reason);
};
var callback = function (value) {
result.resolve(_callback(value));
};
var errback = function (reason) {
result.resolve(_errback(reason));
};
if (pending) {
pending.push([callback, errback]);
} else {
value.then(callback, errback);
}
return result.promise;
}
}
};
};
var ref = function (value) {
if (value && typeof value.then === "function")
return value;
return {
then: function (callback) {
return ref(callback(value));
}
};
};
var reject = function (reason) {
return {
then: function (callback, errback) {
return ref(errback(reason));
}
};
};

126
vendors/Q/design/q7.js vendored Normal file
View file

@ -0,0 +1,126 @@
var enqueue = function (callback) {
//process.nextTick(callback); // NodeJS
setTimeout(callback, 1); // Naïve browser solution
};
var isPromise = function (value) {
return value && typeof value.then === "function";
};
var defer = function () {
var pending = [], value;
return {
resolve: function (_value) {
if (pending) {
value = ref(_value);
for (var i = 0, ii = pending.length; i < ii; i++) {
// XXX
enqueue(function () {
value.then.apply(value, pending[i]);
});
}
pending = undefined;
}
},
promise: {
then: function (_callback, _errback) {
var result = defer();
_callback = _callback || function (value) {
return value;
};
_errback = _errback || function (reason) {
return reject(reason);
};
var callback = function (value) {
result.resolve(_callback(value));
};
var errback = function (reason) {
result.resolve(_errback(reason));
};
if (pending) {
pending.push([callback, errback]);
} else {
// XXX
enqueue(function () {
value.then(callback, errback);
});
}
return result.promise;
}
}
};
};
var ref = function (value) {
if (value && value.then)
return value;
return {
then: function (callback) {
var result = defer();
// XXX
enqueue(function () {
result.resolve(callback(value));
});
return result.promise;
}
};
};
var reject = function (reason) {
return {
then: function (callback, errback) {
var result = defer();
// XXX
enqueue(function () {
result.resolve(errback(reason));
});
return result.promise;
}
};
};
var when = function (value, _callback, _errback) {
var result = defer();
var done;
_callback = _callback || function (value) {
return value;
};
_errback = _errback || function (reason) {
return reject(reason);
};
// XXX
var callback = function (value) {
try {
return _callback(value);
} catch (reason) {
return reject(reason);
}
};
var errback = function (reason) {
try {
return _errback(reason);
} catch (reason) {
return reject(reason);
}
};
enqueue(function () {
ref(value).then(function (value) {
if (done)
return;
done = true;
result.resolve(ref(value).then(callback, errback));
}, function (reason) {
if (done)
return;
done = true;
result.resolve(errback(reason));
});
});
return result.promise;
};

21
vendors/Q/examples/all.js vendored Normal file
View file

@ -0,0 +1,21 @@
"use strict";
var Q = require("../q");
function eventually(value) {
return Q.delay(value, 1000);
}
Q.all([1, 2, 3].map(eventually))
.done(function (result) {
console.log(result);
});
Q.all([
eventually(10),
eventually(20)
])
.spread(function (x, y) {
console.log(x, y);
})
.done();

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>Q.async animation example</title>
<!--
Works in browsers that support ES6 geneartors, like Chromium 29 with
the --harmony flag.
Peter Hallam, Tom van Cutsem, Mark S. Miller, Dave Herman, Andy Wingo.
The animation example was taken from
<http://wiki.ecmascript.org/doku.php?id=strawman:deferred_functions>
-->
</head>
<body>
<div id="box" style="width: 20px; height: 20px; background-color: red;"></div>
<script src="../../q.js"></script>
<script>
(function () {
"use strict";
var deferredAnimate = Q.async(function* (element) {
for (var i = 0; i < 100; ++i) {
element.style.marginLeft = i + "px";
yield Q.delay(20);
}
});
Q.spawn(function* () {
yield deferredAnimate(document.getElementById("box"));
alert("Done!");
});
}());
</script>
</body>
</html>

View file

@ -0,0 +1,19 @@
"use strict";
var Q = require("../../q");
var generator = Q.async(function* () {
var ten = yield 10;
console.log(ten, 10);
var twenty = yield ten + 10;
console.log(twenty, 20);
var thirty = yield twenty + 10;
console.log(thirty, 30);
return thirty + 10;
});
generator().then(function (forty) {
console.log(forty, 40);
}, function (reason) {
console.log("reason", reason);
});

View file

@ -0,0 +1,21 @@
"use strict";
var Q = require("../../q");
var generator = Q.async(function* () {
try {
var ten = yield Q.reject(new Error("Rejected!"));
console.log("Should not get here 1");
} catch (exception) {
console.log("Should get here 1");
console.log(exception.message, "should be", "Rejected!");
throw new Error("Threw!");
}
});
generator().then(function () {
console.log("Should not get here 2");
}, function (reason) {
console.log("Should get here 2");
console.log(reason.message, "should be", "Threw!");
});

View file

@ -0,0 +1,21 @@
"use strict";
var Q = require("../../q");
function foo() {
return Q.delay(5, 1000);
}
function bar() {
return Q.delay(10, 1000);
}
Q.spawn(function* () {
var x = yield foo();
console.log(x);
var y = yield bar();
console.log(y);
console.log("result", x + y);
});

View file

@ -0,0 +1,42 @@
"use strict";
var Q = require("../../q");
// We get back blocking semantics: can use promises with `if`, `while`, `for`,
// etc.
var filter = Q.async(function* (promises, test) {
var results = [];
for (var i = 0; i < promises.length; i++) {
var val = yield promises[i];
if (test(val)) {
results.push(val);
}
}
return results;
});
var promises = [
Q.delay("a", 500),
Q.delay("d", 1000),
Q("l")
];
filter(promises, function (letter) {
return "f" > letter;
}).done(function (all) {
console.log(all); // [ "a", "d" ]
});
// we can use try and catch to handle rejected promises
var logRejections = Q.async(function* (work) {
try {
yield work;
console.log("Never end up here");
} catch (e) {
console.log("Caught:", e.message);
}
});
var rejection = Q.reject(new Error("Oh dear"));
logRejections(rejection); // Caught: Oh dear

View file

@ -0,0 +1,66 @@
:warning: Warning: The behavior described here is likely to be quickly
obseleted by developments in standardization and implementation. Tread with
care.
Q has an `async` function. This can be used to decorate a generator function
such that `yield` is effectively equivalent to `await` or `defer` syntax as
supported by languages like Go and C# 5.
Generator functions are presently on the standards track for ES6. As of July
2013, they are only fully supported by bleeding edge V8, which hasn't made it
out to a released Chromium yet but will probably be in Chromium 29. Even then,
they must be enabled from [chrome://flags](chrome://flags) as "Experimental
JavaScript features." SpiderMonkey (used in Firefox) includes an older style of
generators, but these are not supported by Q.
Here's an example of using generators by themselves, without any Q features:
```js
function* count() {
var i = 0;
while (true) {
yield i++;
}
}
var counter = count();
counter.next().value === 0;
counter.next().value === 1;
counter.next().value === 2;
```
`yield` can also return a value, if the `next` method of the generator is
called with a parameter:
```js
var buffer = (function* () {
var x;
while (true) {
x = yield x;
}
}());
buffer.next(1).value === undefined;
buffer.next("a").value === 1;
buffer.value(2).value === "a";
buffer.next().value === 2;
buffer.next().value === undefined;
buffer.next().value === undefined;
```
Inside functions wrapped with `Q.async`, we can use `yield` to wait for a
promise to settle:
```js
var eventualAdd = Q.async(function* (oneP, twoP) {
var one = yield oneP;
var two = yield twoP;
return one + two;
});
eventualAdd(eventualOne, eventualTwo).then(function (three) {
three === 3;
});
```
You can see more examples of how this works, as well as the `Q.spawn` function,
in the other files in this folder.

79
vendors/Q/package.json vendored Normal file
View file

@ -0,0 +1,79 @@
{
"name": "q",
"version": "1.1.2",
"description": "A library for promises (CommonJS/Promises/A,B,D)",
"homepage": "https://github.com/kriskowal/q",
"author": "Kris Kowal <kris@cixar.com> (https://github.com/kriskowal)",
"keywords": [
"q",
"promise",
"promises",
"promises-a",
"promises-aplus",
"deferred",
"future",
"async",
"flow control",
"fluent",
"browser",
"node"
],
"contributors": [
"Kris Kowal <kris@cixar.com> (https://github.com/kriskowal)",
"Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)",
"Domenic Denicola <domenic@domenicdenicola.com> (http://domenicdenicola.com)"
],
"bugs": {
"mail": "kris@cixar.com",
"url": "http://github.com/kriskowal/q/issues"
},
"license": {
"type": "MIT",
"url": "http://github.com/kriskowal/q/raw/master/LICENSE"
},
"main": "q.js",
"files": [
"LICENSE",
"q.js",
"queue.js"
],
"repository": {
"type": "git",
"url": "git://github.com/kriskowal/q.git"
},
"engines": {
"node": ">=0.6.0",
"teleport": ">=0.2.0"
},
"dependencies": {},
"devDependencies": {
"jshint": "~2.1.9",
"cover": "*",
"jasmine-node": "1.11.0",
"opener": "*",
"promises-aplus-tests": "1.x",
"grunt": "~0.4.1",
"grunt-cli": "~0.1.9",
"grunt-contrib-uglify": "~0.2.2",
"matcha": "~0.2.0"
},
"scripts": {
"test": "jasmine-node spec && promises-aplus-tests spec/aplus-adapter",
"test-browser": "opener spec/q-spec.html",
"benchmark": "matcha",
"lint": "jshint q.js",
"cover": "cover run node_modules/jasmine-node/bin/jasmine-node spec && cover report html && opener cover_html/index.html",
"minify": "grunt",
"prepublish": "grunt"
},
"overlay": {
"teleport": {
"dependencies": {
"system": ">=0.0.4"
}
}
},
"directories": {
"test": "./spec"
}
}

1937
vendors/Q/q.js vendored Normal file

File diff suppressed because it is too large Load diff

BIN
vendors/Q/q.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

114
vendors/Q/q.svg vendored Normal file
View file

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="157.5"
height="180"
id="svg2"
version="1.1"
inkscape:version="0.48.1 r9760"
sodipodi:docname="q.svg"
inkscape:export-filename="/home/kris/art/q.png"
inkscape:export-xdpi="51.200001"
inkscape:export-ydpi="51.200001">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2"
inkscape:cx="62.864072"
inkscape:cy="167.31214"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="in"
inkscape:window-width="1680"
inkscape:window-height="973"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-872.3622)">
<path
sodipodi:type="star"
style="fill:#f9df34;fill-opacity:1;stroke:none;opacity:1"
id="path3833"
sodipodi:sides="6"
sodipodi:cx="1118"
sodipodi:cy="456.36218"
sodipodi:r1="277.59683"
sodipodi:r2="240.40591"
sodipodi:arg1="0.52359878"
sodipodi:arg2="1.0471976"
inkscape:flatsided="true"
inkscape:rounded="0"
inkscape:randomized="0"
d="M 1358.4059,595.1606 1118,733.95901 877.59409,595.1606 l 0,-277.59683 L 1118,178.76535 1358.4059,317.56377 z"
transform="matrix(0.28609737,0,0,0.28609737,-241.10686,831.79819)" />
<path
inkscape:connector-curvature="0"
id="path3840"
d="m 23.150536,930.17141 c 0.02584,21.44054 0.05616,42.88112 0.0266,64.32167 18.544384,10.71192 37.074475,21.44862 55.599461,32.19412 18.524303,-10.7114 37.048573,-21.4227 55.572863,-32.13419 -0.0259,-21.44055 -0.0561,-42.88112 -0.0266,-64.32168 C 115.77802,919.52027 97.24878,908.78212 78.723431,898.0372 60.199152,908.74861 41.674869,919.46002 23.150565,930.17141 z m 55.792247,-8.92728 c 11.80936,6.85273 23.635797,13.68573 35.470907,20.49746 -0.004,13.75374 -0.009,27.50747 -0.0132,41.2612 -3.04307,1.75007 -6.08198,3.50751 -9.12033,5.26584 -6.092341,-10.55513 -12.176786,-21.11483 -18.260622,-31.67487 -5.796593,3.34635 -11.593186,6.69268 -17.389782,10.03903 6.083829,10.56004 12.168276,21.11974 18.260615,31.67487 -3.035798,1.77164 -6.093381,3.50564 -9.120329,5.29244 -11.883066,-6.88841 -23.778192,-13.75616 -35.676998,-20.61727 0.0022,-13.75374 0.0045,-27.50747 0.0066,-41.2612 11.884425,-6.85251 23.763957,-13.71376 35.630451,-20.59733 l 0.185407,0.10445 0.02732,0.0154 z"
style="fill:#b7a634;fill-opacity:1;stroke:#524839;stroke-width:5.37970828999999995;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;opacity:0.96" />
<path
style="fill:#f9df34;fill-opacity:1;stroke:#524839;stroke-width:5.54999999999999982;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 3.9712996,919.13021 c 0.034761,28.79449 0.07553,57.58902 0.035762,86.38349 24.9413394,14.3861 49.8634534,28.8054 74.7787004,43.2365 24.914328,-14.3853 49.828638,-28.7707 74.742938,-43.156 -0.0347,-28.79449 -0.0755,-57.58901 -0.0358,-86.38352 -24.942,-14.38487 -49.86297,-28.80613 -74.778703,-43.23647 -24.914303,14.38534 -49.828606,28.77067 -74.7429375,43.156 z M 79.00929,907.14095 c 15.883039,9.20316 31.78905,18.37981 47.70674,27.52793 -0.006,18.47116 -0.0123,36.94232 -0.0177,55.41348 -4.0928,2.35032 -8.17998,4.71056 -12.26643,7.07197 -8.19391,-14.17545 -16.377211,-28.35704 -24.559682,-42.5391 -7.796153,4.49411 -15.592307,8.98822 -23.38846,13.48234 8.182471,14.18206 16.365771,28.36365 24.559685,42.53913 -4.08301,2.3792 -8.195316,4.7081 -12.266424,7.1077 -15.982172,-9.2511 -31.980565,-18.47444 -47.983908,-27.68886 0.0029,-18.47116 0.006,-36.94232 0.0089,-55.41348 15.984003,-9.20286 31.961425,-18.41747 47.92131,-27.66204 l 0.249362,0.14026 0.03674,0.0207 z"
id="path2993"
inkscape:connector-curvature="0" />
<g
id="g4862"
transform="matrix(0.11775097,-0.06798356,0.06798356,0.11775097,5.1642661,919.0661)">
<path
style="fill:#524739"
inkscape:connector-curvature="0"
d="m 217.503,388.691 v 14.757 h -16.155 v 39.766 c 0,3.729 0.621,6.214 1.864,7.457 1.243,1.242 3.728,1.863 7.456,1.863 1.243,0 2.432,-0.051 3.573,-0.155 1.138,-0.102 2.226,-0.257 3.262,-0.466 V 469 c -1.864,0.311 -3.937,0.517 -6.213,0.621 -2.279,0.103 -4.505,0.155 -6.68,0.155 -3.417,0 -6.655,-0.232 -9.708,-0.698 -3.056,-0.467 -5.747,-1.372 -8.077,-2.719 -2.33,-1.345 -4.17,-3.262 -5.515,-5.747 -1.347,-2.485 -2.019,-5.748 -2.019,-9.786 v -47.378 h -13.359 v -14.757 h 13.359 v -24.077 h 22.058 v 24.077 h 16.154 z"
id="path4864" />
<path
style="fill:#524739"
inkscape:connector-curvature="0"
d="m 248.569,358.091 v 41.785 h 0.466 c 2.796,-4.66 6.369,-8.051 10.718,-10.175 4.349,-2.121 8.594,-3.185 12.737,-3.185 5.903,0 10.742,0.804 14.524,2.408 3.778,1.606 6.757,3.832 8.932,6.68 2.175,2.849 3.701,6.317 4.582,10.407 0.879,4.092 1.32,8.621 1.32,13.592 V 469 H 279.79 v -45.357 c 0,-6.627 -1.036,-11.573 -3.106,-14.835 -2.073,-3.262 -5.747,-4.894 -11.029,-4.894 -6.007,0 -10.356,1.787 -13.048,5.359 -2.694,3.573 -4.039,9.451 -4.039,17.631 V 469 H 226.51 V 358.091 h 22.059 z"
id="path4866" />
<path
style="fill:#524739"
inkscape:connector-curvature="0"
d="m 334.467,449.738 c 3.313,3.211 8.077,4.815 14.291,4.815 4.451,0 8.283,-1.111 11.495,-3.34 3.208,-2.226 5.177,-4.582 5.902,-7.067 h 19.417 c -3.106,9.631 -7.871,16.519 -14.291,20.659 -6.422,4.144 -14.188,6.214 -23.3,6.214 -6.318,0 -12.015,-1.01 -17.087,-3.029 -5.075,-2.02 -9.374,-4.893 -12.894,-8.621 -3.521,-3.728 -6.24,-8.18 -8.154,-13.358 -1.918,-5.178 -2.874,-10.874 -2.874,-17.087 0,-6.005 0.982,-11.597 2.951,-16.776 1.966,-5.177 4.762,-9.655 8.388,-13.437 3.624,-3.779 7.947,-6.757 12.971,-8.932 5.021,-2.175 10.587,-3.263 16.699,-3.263 6.834,0 12.788,1.32 17.863,3.962 5.072,2.641 9.242,6.188 12.504,10.64 3.263,4.454 5.617,9.529 7.068,15.224 1.449,5.696 1.966,11.649 1.553,17.863 H 329.03 c 0.311,7.146 2.121,12.325 5.437,15.533 z m 24.931,-42.251 c -2.641,-2.898 -6.655,-4.35 -12.039,-4.35 -3.521,0 -6.446,0.598 -8.776,1.786 -2.33,1.192 -4.193,2.668 -5.592,4.428 -1.398,1.762 -2.384,3.626 -2.951,5.592 -0.57,1.969 -0.908,3.728 -1.01,5.281 h 35.882 c -1.036,-5.591 -2.873,-9.836 -5.514,-12.737 z"
id="path4868" />
<path
style="fill:#524739"
inkscape:connector-curvature="0"
d="m 413.221,388.691 v 11.185 h 0.466 c 2.796,-4.66 6.42,-8.051 10.874,-10.175 4.451,-2.121 9.009,-3.185 13.669,-3.185 5.903,0 10.742,0.804 14.524,2.408 3.778,1.606 6.757,3.832 8.932,6.68 2.175,2.849 3.701,6.317 4.582,10.407 0.879,4.092 1.32,8.621 1.32,13.592 V 469 H 445.53 v -45.357 c 0,-6.627 -1.036,-11.573 -3.106,-14.835 -2.073,-3.262 -5.747,-4.894 -11.029,-4.894 -6.007,0 -10.356,1.787 -13.048,5.359 -2.694,3.573 -4.039,9.451 -4.039,17.631 V 469 H 392.25 v -80.309 h 20.971 z"
id="path4870" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.6 KiB

35
vendors/Q/queue.js vendored Normal file
View file

@ -0,0 +1,35 @@
var Q = require("./q");
module.exports = Queue;
function Queue() {
var ends = Q.defer();
var closed = Q.defer();
return {
put: function (value) {
var next = Q.defer();
ends.resolve({
head: value,
tail: next.promise
});
ends.resolve = next.resolve;
},
get: function () {
var result = ends.promise.get("head");
ends.promise = ends.promise.get("tail");
return result.fail(function (error) {
closed.resolve(error);
throw error;
});
},
closed: closed.promise,
close: function (error) {
error = error || new Error("Can't get value from closed queue");
var end = {head: Q.reject(error)};
end.tail = end;
ends.resolve(end);
return closed.promise;
}
};
}

26
vendors/Q/ref_send.md vendored Normal file
View file

@ -0,0 +1,26 @@
This API varies from Tyler Closes ref_send in the
following ways:
* Promises can be resolved to function values.
* Promises can be resolved to null or undefined.
* Promises are distinguishable from arbitrary functions.
* The promise API is abstracted with a Promise constructor
that accepts a descriptor that receives all of the
messages forwarded to that promise and handles the
common patterns for message receivers. The promise
constructor also takes optional fallback and valueOf
methods which handle the cases for missing handlers on
the descriptor (rejection by default) and the valueOf
call (which returns the promise itself by default)
* near(ref) has been changed to Promise.valueOf() in
keeping with JavaScript's existing Object.valueOf().
* post(promise, name, args) has been altered to a variadic
post(promise, name ...args)
* variadic arguments are used internally where
applicable. However, I have not altered the Q.post()
API to expand variadic arguments since Tyler Close
informed the CommonJS list that it would restrict
usage patterns for web_send, posting arbitrary JSON
objects as the "arguments" over HTTP.

15
vendors/Q/spec/aplus-adapter.js vendored Normal file
View file

@ -0,0 +1,15 @@
"use strict";
var Q = require("../q");
exports.fulfilled = Q.resolve;
exports.rejected = Q.reject;
exports.pending = function () {
var deferred = Q.defer();
return {
promise: deferred.promise,
fulfill: deferred.resolve,
reject: deferred.reject
};
};

View file

@ -0,0 +1,20 @@
Copyright (c) 2008-2011 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,616 @@
jasmine.HtmlReporterHelpers = {};
jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
} else {
if (child) {
el.appendChild(child);
}
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
};
jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
var results = child.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
return status;
};
jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
var parentDiv = this.dom.summary;
var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
var parent = child[parentSuite];
if (parent) {
if (typeof this.views.suites[parent.id] == 'undefined') {
this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
}
parentDiv = this.views.suites[parent.id].element;
}
parentDiv.appendChild(childElement);
};
jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
for(var fn in jasmine.HtmlReporterHelpers) {
ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
}
};
jasmine.HtmlReporter = function(_doc) {
var self = this;
var doc = _doc || window.document;
var reporterView;
var dom = {};
// Jasmine Reporter Public Interface
self.logRunningSpecs = false;
self.reportRunnerStarting = function(runner) {
var specs = runner.specs() || [];
if (specs.length == 0) {
return;
}
createReporterDom(runner.env.versionString());
doc.body.appendChild(dom.reporter);
reporterView = new jasmine.HtmlReporter.ReporterView(dom);
reporterView.addSpecs(specs, self.specFilter);
};
self.reportRunnerResults = function(runner) {
reporterView && reporterView.complete();
};
self.reportSuiteResults = function(suite) {
reporterView.suiteComplete(suite);
};
self.reportSpecStarting = function(spec) {
if (self.logRunningSpecs) {
self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
self.reportSpecResults = function(spec) {
reporterView.specComplete(spec);
};
self.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
self.specFilter = function(spec) {
if (!focusedSpecName()) {
return true;
}
return spec.getFullName().indexOf(focusedSpecName()) === 0;
};
return self;
function focusedSpecName() {
var specName;
(function memoizeFocusedSpec() {
if (specName) {
return;
}
var paramMap = [];
var params = doc.location.search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
specName = paramMap.spec;
})();
return specName;
}
function createReporterDom(version) {
dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
dom.banner = self.createDom('div', { className: 'banner' },
self.createDom('span', { className: 'title' }, "Jasmine "),
self.createDom('span', { className: 'version' }, version)),
dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
dom.alert = self.createDom('div', {className: 'alert'}),
dom.results = self.createDom('div', {className: 'results'},
dom.summary = self.createDom('div', { className: 'summary' }),
dom.details = self.createDom('div', { id: 'details' }))
);
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
this.startedAt = new Date();
this.runningSpecCount = 0;
this.completeSpecCount = 0;
this.passedCount = 0;
this.failedCount = 0;
this.skippedCount = 0;
this.createResultsMenu = function() {
this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
' | ',
this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
this.summaryMenuItem.onclick = function() {
dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
};
this.detailsMenuItem.onclick = function() {
showDetails();
};
};
this.addSpecs = function(specs, specFilter) {
this.totalSpecCount = specs.length;
this.views = {
specs: {},
suites: {}
};
for (var i = 0; i < specs.length; i++) {
var spec = specs[i];
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
if (specFilter(spec)) {
this.runningSpecCount++;
}
}
};
this.specComplete = function(spec) {
this.completeSpecCount++;
if (isUndefined(this.views.specs[spec.id])) {
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
}
var specView = this.views.specs[spec.id];
switch (specView.status()) {
case 'passed':
this.passedCount++;
break;
case 'failed':
this.failedCount++;
break;
case 'skipped':
this.skippedCount++;
break;
}
specView.refresh();
this.refresh();
};
this.suiteComplete = function(suite) {
var suiteView = this.views.suites[suite.id];
if (isUndefined(suiteView)) {
return;
}
suiteView.refresh();
};
this.refresh = function() {
if (isUndefined(this.resultsMenu)) {
this.createResultsMenu();
}
// currently running UI
if (isUndefined(this.runningAlert)) {
this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
dom.alert.appendChild(this.runningAlert);
}
this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
// skipped specs UI
if (isUndefined(this.skippedAlert)) {
this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
}
this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
if (this.skippedCount === 1 && isDefined(dom.alert)) {
dom.alert.appendChild(this.skippedAlert);
}
// passing specs UI
if (isUndefined(this.passedAlert)) {
this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
}
this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
// failing specs UI
if (isUndefined(this.failedAlert)) {
this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
}
this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
if (this.failedCount === 1 && isDefined(dom.alert)) {
dom.alert.appendChild(this.failedAlert);
dom.alert.appendChild(this.resultsMenu);
}
// summary info
this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
};
this.complete = function() {
dom.alert.removeChild(this.runningAlert);
this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
if (this.failedCount === 0) {
dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
} else {
showDetails();
}
dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
};
return this;
function showDetails() {
if (dom.reporter.className.search(/showDetails/) === -1) {
dom.reporter.className += " showDetails";
}
}
function isUndefined(obj) {
return typeof obj === 'undefined';
}
function isDefined(obj) {
return !isUndefined(obj);
}
function specPluralizedFor(count) {
var str = count + " spec";
if (count > 1) {
str += "s"
}
return str;
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
this.spec = spec;
this.dom = dom;
this.views = views;
this.symbol = this.createDom('li', { className: 'pending' });
this.dom.symbolSummary.appendChild(this.symbol);
this.summary = this.createDom('div', { className: 'specSummary' },
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
title: this.spec.getFullName()
}, this.spec.description)
);
this.detail = this.createDom('div', { className: 'specDetail' },
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
title: this.spec.getFullName()
}, this.spec.getFullName())
);
};
jasmine.HtmlReporter.SpecView.prototype.status = function() {
return this.getSpecStatus(this.spec);
};
jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
this.symbol.className = this.status();
switch (this.status()) {
case 'skipped':
break;
case 'passed':
this.appendSummaryToSuiteDiv();
break;
case 'failed':
this.appendSummaryToSuiteDiv();
this.appendFailureDetail();
break;
}
};
jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
this.summary.className += ' ' + this.status();
this.appendToSummary(this.spec, this.summary);
};
jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
this.detail.className += ' ' + this.status();
var resultItems = this.spec.results().getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
this.detail.appendChild(messagesDiv);
this.dom.details.appendChild(this.detail);
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
this.suite = suite;
this.dom = dom;
this.views = views;
this.element = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
);
this.appendToSummary(this.suite, this.element);
};
jasmine.HtmlReporter.SuiteView.prototype.status = function() {
return this.getSpecStatus(this.suite);
};
jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
this.element.className += " " + this.status();
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
/* @deprecated Use jasmine.HtmlReporter instead
*/
jasmine.TrivialReporter = function(doc) {
this.document = doc || document;
this.suiteDivs = {};
this.logRunningSpecs = false;
};
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
} else {
if (child) { el.appendChild(child); }
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
};
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
this.createDom('span', { className: 'title' }, "Jasmine"),
this.createDom('span', { className: 'version' }, runner.env.versionString())),
this.createDom('div', { className: 'options' },
"Show ",
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
)
),
this.runnerDiv = this.createDom('div', { className: 'runner running' },
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
);
this.document.body.appendChild(this.outerDiv);
var suites = runner.suites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
var suiteDiv = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
this.suiteDivs[suite.id] = suiteDiv;
var parentDiv = this.outerDiv;
if (suite.parentSuite) {
parentDiv = this.suiteDivs[suite.parentSuite.id];
}
parentDiv.appendChild(suiteDiv);
}
this.startedAt = new Date();
var self = this;
showPassed.onclick = function(evt) {
if (showPassed.checked) {
self.outerDiv.className += ' show-passed';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
}
};
showSkipped.onclick = function(evt) {
if (showSkipped.checked) {
self.outerDiv.className += ' show-skipped';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
}
};
};
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
var results = runner.results();
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
this.runnerDiv.setAttribute("class", className);
//do it twice for IE
this.runnerDiv.setAttribute("className", className);
var specs = runner.specs();
var specCount = 0;
for (var i = 0; i < specs.length; i++) {
if (this.specFilter(specs[i])) {
specCount++;
}
}
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
};
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
var results = suite.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.totalCount === 0) { // todo: change this to check results.skipped
status = 'skipped';
}
this.suiteDivs[suite.id].className += " " + status;
};
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
if (this.logRunningSpecs) {
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
var results = spec.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
var specDiv = this.createDom('div', { className: 'spec ' + status },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(spec.getFullName()),
title: spec.getFullName()
}, spec.description));
var resultItems = results.getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
specDiv.appendChild(messagesDiv);
}
this.suiteDivs[spec.suite.id].appendChild(specDiv);
};
jasmine.TrivialReporter.prototype.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
jasmine.TrivialReporter.prototype.getLocation = function() {
return this.document.location;
};
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
var paramMap = {};
var params = this.getLocation().search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
if (!paramMap.spec) {
return true;
}
return spec.getFullName().indexOf(paramMap.spec) === 0;
};

View file

@ -0,0 +1,81 @@
body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
#HTMLReporter a { text-decoration: none; }
#HTMLReporter a:hover { text-decoration: underline; }
#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
#HTMLReporter .version { color: #aaaaaa; }
#HTMLReporter .banner { margin-top: 14px; }
#HTMLReporter .duration { color: #aaaaaa; float: right; }
#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
#HTMLReporter .runningAlert { background-color: #666666; }
#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
#HTMLReporter .passingAlert { background-color: #a6b779; }
#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
#HTMLReporter .failingAlert { background-color: #cf867e; }
#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
#HTMLReporter .results { margin-top: 14px; }
#HTMLReporter #details { display: none; }
#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter.showDetails .summary { display: none; }
#HTMLReporter.showDetails #details { display: block; }
#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter .summary { margin-top: 14px; }
#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
#HTMLReporter .description + .suite { margin-top: 0; }
#HTMLReporter .suite { margin-top: 14px; }
#HTMLReporter .suite a { color: #333333; }
#HTMLReporter #details .specDetail { margin-bottom: 28px; }
#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
#HTMLReporter .resultMessage span.result { display: block; }
#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
#TrivialReporter .runner.running { background-color: yellow; }
#TrivialReporter .options { text-align: right; font-size: .8em; }
#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
#TrivialReporter .suite .suite { margin: 5px; }
#TrivialReporter .suite.passed { background-color: #dfd; }
#TrivialReporter .suite.failed { background-color: #fdd; }
#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
#TrivialReporter .spec.skipped { background-color: #bbb; }
#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
#TrivialReporter .passed { background-color: #cfc; display: none; }
#TrivialReporter .failed { background-color: #fbb; }
#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
#TrivialReporter .resultMessage .mismatch { color: black; }
#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }

File diff suppressed because it is too large Load diff

91
vendors/Q/spec/lib/jasmine-promise.js vendored Normal file
View file

@ -0,0 +1,91 @@
"use strict";
/**
* Modifies the way that individual specs are run to easily test async
* code with promises.
*
* A spec may return a promise. If it does, then the spec passes if and
* only if that promise is fulfilled within a very short period of time.
* If it is rejected, or if it isn't fulfilled quickly, the spec fails.
*
* In this way, we can use promise chaining to structure our asynchronous
* tests. Expectations all down the chain of promises are all checked and
* guaranteed to be run and resolved or the test fails.
*
* This is a big win over the runs() and watches() code that jasmine
* supports out of the box.
*/
jasmine.Block.prototype.execute = function (onComplete) {
var spec = this.spec;
try {
var result = this.func.call(spec, onComplete);
// It seems Jasmine likes to return the suite if you pass it anything.
// So make sure it's a promise first.
if (result && typeof result.then === "function") {
Q.timeout(result, 500).then(function () {
onComplete();
}, function (error) {
spec.fail(error);
onComplete();
});
} else if (this.func.length === 0) {
onComplete();
}
} catch (error) {
spec.fail(error);
onComplete();
}
};
/**
* Tests and documents the behavior of the above extension to jasmine.
*/
describe('jasmine-promise', function() {
it('passes if the deferred resolves immediately', function() {
var deferred = Q.defer();
deferred.resolve();
return deferred.promise;
});
it('passes if the deferred resolves after a short delay', function() {
var deferred = Q.defer();
setTimeout(function() {deferred.resolve();}, 100);
return deferred.promise;
});
it('lets specs that return nothing pass', function() {
});
it('lets specs that return non-promises pass', function() {
return {'some object': 'with values'};
});
it('works ok with specs that return crappy non-Q promises', function() {
return {
'then': function(callback) {
callback();
}
}
});
// These are expected to fail. Remove the x from xdescribe to test that.
xdescribe('failure cases (expected to fail)', function() {
it('fails if the deferred is rejected', function() {
var deferred = Q.defer();
deferred.reject();
return deferred.promise;
});
it('fails if the deferred takes too long to resolve', function() {
var deferred = Q.defer();
setTimeout(function() {deferred.resolve()}, 5 * 1000);
return deferred.promise;
});
it('fails if a returned crappy non-Q promise is rejected', function() {
return {
'then': function(_, callback) {callback()}
}
});
it('fails if a returned crappy promise is never resolved', function() {
return {
'then': function() {}
}
});
})
});

52
vendors/Q/spec/q-spec.html vendored Normal file
View file

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<title>Jasmine Spec Runner</title>
<meta charset="utf-8" />
<link rel="shortcut icon" type="image/png" href="lib/jasmine-1.2.0/jasmine_favicon.png" />
<link rel="stylesheet" href="lib/jasmine-1.2.0/jasmine.css" />
<script src="lib/jasmine-1.2.0/jasmine.js"></script>
<script src="lib/jasmine-1.2.0/jasmine-html.js"></script>
<script src="lib/jasmine-promise.js"></script>
<!-- include source files here... -->
<script src="../q.js"></script>
<!-- include spec files here... -->
<script src="q-spec.js"></script>
<script>
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function(spec) {
return htmlReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
</script>
</head>
<body>
</body>
</html>

2611
vendors/Q/spec/q-spec.js vendored Normal file

File diff suppressed because it is too large Load diff

180
vendors/Q/spec/queue-spec.js vendored Normal file
View file

@ -0,0 +1,180 @@
var Q = require("../q");
var Queue = require("../queue");
global.Q = Q;
require("./lib/jasmine-promise");
describe("queue", function () {
it("should enqueue then dequeue", function () {
var queue = Queue();
queue.put(1);
return queue.get().then(function (value) {
expect(value).toBe(1);
});
});
it("should dequeue then enqueue", function () {
var queue = Queue();
var promise = queue.get().then(function (value) {
expect(value).toBe(1);
});
queue.put(1);
return promise;
});
it("should stream", function () {
var queue = Queue();
Q.try(function () {
return Q.delay(20).then(function () {
queue.put(1);
})
})
.then(function () {
return Q.delay(20).then(function () {
queue.put(2);
})
})
.then(function () {
return Q.delay(20).then(function () {
queue.put(3);
})
})
.done();
return Q.try(function () {
return queue.get()
.then(function (value) {
expect(value).toBe(1);
});
})
.then(function () {
return queue.get()
.then(function (value) {
expect(value).toBe(2);
});
})
.then(function () {
return queue.get()
.then(function (value) {
expect(value).toBe(3);
});
})
});
it("should be order agnostic", function () {
var queue = Queue();
Q.try(function () {
return Q.delay(20).then(function () {
queue.put(1);
})
})
.then(function () {
return Q.delay(20).then(function () {
queue.put(2);
})
})
.then(function () {
return Q.delay(20).then(function () {
queue.put(3);
})
})
.done();
return Q.all([
queue.get()
.then(function (value) {
expect(value).toBe(1);
}),
queue.get()
.then(function (value) {
expect(value).toBe(2);
}),
queue.get()
.then(function (value) {
expect(value).toBe(3);
})
]);
});
it("should close", function () {
var queue = Queue();
Q.try(function () {
return Q.delay(20).then(function () {
queue.put(1);
})
})
.then(function () {
return Q.delay(20).then(function () {
queue.put(2);
})
})
.then(function () {
queue.close();
})
.done();
return Q.try(function () {
return queue.get()
.then(function (value) {
expect(value).toBe(1);
});
})
.then(function () {
return queue.get()
.then(function (value) {
expect(value).toBe(2);
});
})
.then(function () {
return queue.get()
.then(function (value) {
expect(false).toBe(true); // should not get here
});
})
.catch(function (error) {
expect(error.message).toBe("Can't get value from closed queue");
return queue.get();
})
.catch(function (error) {
expect(error.message).toBe("Can't get value from closed queue");
})
.then(function () {
return queue.closed;
})
.then(function (error) {
expect(error.message).toBe("Can't get value from closed queue");
})
});
it("should close with alternate error", function () {
var queue = Queue();
queue.close(new Error("Alternate reason"));
return Q.try(function () {
return queue.get();
})
.catch(function (error) {
expect(error.message).toBe("Alternate reason");
return queue.get();
})
.catch(function (error) {
expect(error.message).toBe("Alternate reason");
})
.then(function () {
return queue.closed;
})
.then(function (error) {
expect(error.message).toBe("Alternate reason");
})
});
});

View file

@ -43,6 +43,7 @@ module.exports = {
'ssm': 'window.ssm', 'ssm': 'window.ssm',
'key': 'window.key', 'key': 'window.key',
'_': 'window._', '_': 'window._',
'Q': 'window.Q',
'$': 'window.jQuery' '$': 'window.jQuery'
} }
}; };