Changeset 468
- Timestamp:
- 06/26/13 21:17:41 (12 years ago)
- Location:
- Dev/trunk
- Files:
-
- 1 added
- 1 deleted
- 11 edited
- 3 moved
Legend:
- Unmodified
- Added
- Removed
-
Dev/trunk/docs/TODO.md
r463 r468 2 2 ==== 3 3 4 * Drop separate development directory for more complicated build process. 5 - Generate files in-place (maybe even include in commit, although I hate that.) 6 Automatically update gitignore for generated files? 7 - Add header to files to make sure they are not edited as source files by accident. 8 - A smarter copy might also fix this, maybe we should implement our own copy. 9 - Can we do amd dependency checks? 10 - We should also lint the generated javascript, because coffee 11 doesn't catch accidental globals 4 12 * Have a generic page-wide note (rounded corner, close button thingy) 5 13 for notification (maybe completely replace the toaster?) … … 12 20 these must match the types returned by the actual widgets. Fix 13 21 this. 22 - Would be nicer if only newly dropped questions are in edit mode 23 and the ones that exist on load in view mode. 14 24 * Codes 15 25 - Details need to be figured out. Now we have a code in one place, … … 24 34 was disabled because the questions didn't pass anymore. 25 35 - use it server side (and maybe client side as well?) 36 * Editing 37 - Warn if leaving a page that has edits. 26 38 * Validate documents on the server before saving them. 27 39 * Implement authentication and later authorization. -
Dev/trunk/src/client/index.html
r466 r468 30 30 </div> 31 31 <div id="toaster" data-dojo-type="qed-client/app/Notifications"></div> 32 <div id="loginDialog" data-dojo-type="qed-client/ui/LoginDialog"></div>32 <div data-dojo-type="qed-client/ui/LoginDialogWrapper"></div> 33 33 </body> 34 34 </html> -
Dev/trunk/src/client/qed-client/index.js
r467 r468 7 7 "./store", 8 8 "./store/request", 9 "./ui/LoginDialogWrapper", 9 10 "./ui/MainMenu", 10 11 "dojo/_base/array", … … 12 13 "./stddeps", 13 14 "dojo/domReady!" 14 ], function(Content, Page, Router, routes, session, store, request, MainMenu, array, parser) { 15 ], function(Content, Page, Router, routes, session, store, 16 request, LoginDialogWrapper, MainMenu, array, parser) { 15 17 16 18 parser.parse(); … … 21 23 Router.register(route); 22 24 }); 25 Router.startup(); 23 26 24 session.restore().then(function(){ 25 Router.startup(); 26 }); 27 27 session.restore(); 28 28 29 }); -
Dev/trunk/src/client/qed-client/request.js
r464 r468 1 1 define([ 2 "./session", 2 3 "dojo/Deferred", 4 "dojo/on", 3 5 "dojo/request" 4 ], function( Deferred, request) {6 ], function(session, Deferred, on, request) { 5 7 6 var authenticated = true;8 var user = session.get(); 7 9 var queue = []; 8 10 11 on(session, 'change', function(newUser) { 12 user = newUser; 13 if ( user ) { 14 retry(); 15 } 16 }); 17 18 function retry() { 19 if (queue.length > 0) { 20 var item = queue.shift(); 21 console.log("Retry",item.url); 22 real_request(item); 23 } 24 } 25 26 function real_request(item) { 27 var req = request(item.url,item.options); 28 29 // forward successfull response 30 req.then(function(body){ 31 item.dfd.resolve(body); 32 }); 33 34 // handle unauthenticated and queued requests 35 req.response.then(function(response){ 36 retry(); 37 }, function(error) { 38 if ( error.response.status === 401 ) { 39 queue.unshift(item); 40 session.restore(); 41 } else { 42 item.dfd.reject(error); // this should be error body 43 // not, the request? 44 retry(); 45 } 46 }); 47 } 48 9 49 var _request = function(url, options) { 10 var dfd = new Deferred(); 11 if ( authenticated ) { 12 var req = request(url,options); 50 var item = { 51 url: url, 52 options: options, 53 dfd: new Deferred() 54 }; 55 // only do the request directly if we are authenticated and 56 // there are no earlier requests queued. 57 if ( user && queue.length === 0 ) { 58 console.log("Request",url); 59 real_request(item); 60 } else { 61 console.log("Push",url); 62 queue.push(item); 63 } 64 return item.dfd.promise; 65 }; 13 66 14 // forward successfull response15 req.then(function(data){16 dfd.resolve(data);17 });18 19 req.response.then(function(response){20 // if we are recovering, launch other requests21 }, function(error) {22 if ( error.response.status === 401 ) {23 queue.push({24 url: url,25 options: options,26 dfd: dfd27 });28 console.log("Retry goes here :)");29 } else {30 dfd.reject(error);31 }32 });33 } else {34 queue.push({35 url: url,36 options: options,37 dfd: dfd38 });39 }40 return dfd.promise;41 };42 67 return _request; 43 68 }); -
Dev/trunk/src/client/qed-client/session.coffee
r466 r468 7 7 Session = declare [Evented], 8 8 info: null 9 9 10 get: () -> 10 11 @info 12 11 13 restore: () -> 12 14 request '/api/login', … … 16 18 @_set res 17 19 , () => 18 @_set null 20 throw (@_set null) 21 19 22 login: (username, password) -> 20 23 request '/api/login', … … 27 30 @_set res 28 31 , () => 29 @_set null 32 throw (@_set null) 33 30 34 logout: () -> 31 35 request '/api/logout', 32 36 method: "POST" 33 37 handleAs: "json" 34 .then ( (res) =>35 console.log "Logged out"36 @_set null), () =>37 console.log "Error logging out"38 .then (res) => 39 @_set null 40 , () => 41 @_set null 38 42 39 43 _set: (newInfo) -> 40 @info = newInfo 41 @emit 'change', @info 42 @info 44 if (newInfo isnt @info) 45 @info = newInfo 46 @emit 'change', @info 47 @info 43 48 44 49 new Session() -
Dev/trunk/src/client/qed-client/stddeps.js
r466 r468 33 33 './model/widgets/SurveyWidget', 34 34 35 './ui/LoginDialog ',35 './ui/LoginDialogWrapper', 36 36 './ui/MainMenu', 37 37 './ui/MenuBarLink', -
Dev/trunk/src/client/qed-client/store.js
r466 r468 5 5 'dojox/json/schema', 6 6 './model/schema', 7 './request', 7 8 './store/CouchStore' 8 ],function(stamp,Cache,Memory,jsonSchema,schema, CouchStore){9 ],function(stamp,Cache,Memory,jsonSchema,schema,request,CouchStore){ 9 10 10 11 var couchStore = new CouchStore({ 11 target: 'api/data/' /*, 12 target: 'api/data/', 13 request: request /*, 12 14 validate: function(object) { 13 15 var result = jsonSchema.validate(object,schema); -
Dev/trunk/src/client/qed-client/store/CouchStore.js
r466 r468 28 28 _responseIdProperty: "id", 29 29 _responseRevProperty: "rev", 30 request: request, 30 31 constructor: function(options){ 31 32 declare.safeMixin(this, options); … … 39 40 info: function(){ 40 41 var dfd = new Deferred(); 41 request(this.target, {42 this.request(this.target, { 42 43 method: "GET", 43 44 handleAs: "json", … … 58 59 get: function(id){ 59 60 var dfd = new Deferred(); 60 request(this.target + encodeURIComponent(id), {61 this.request(this.target + encodeURIComponent(id), { 61 62 method: "GET", 62 63 handleAs: "json", … … 103 104 var id = options.id ? options.id : this.getIdentity(object); 104 105 var hasId = typeof id !== "undefined"; 105 request(hasId ? this.target + encodeURIComponent(id) : this.target, {106 this.request(hasId ? this.target + encodeURIComponent(id) : this.target, { 106 107 method: hasId ? "PUT" : "POST", 107 108 data: json.toJson(object), … … 129 130 remove: function(id,rev){ 130 131 var dfd = new Deferred(); 131 request(this.target + encodeURIComponent(id), {132 this.request(this.target + encodeURIComponent(id), { 132 133 method: "DELETE", 133 134 headers: { … … 243 244 } 244 245 245 request(this.target + query, {246 this.request(this.target + query, { 246 247 method: "GET", 247 248 handleAs: "json", -
Dev/trunk/src/client/qed-client/ui/LoginDialogWrapper.coffee
r466 r468 1 1 define [ 2 2 "../session", 3 "dijit/_WidgetBase", 4 "dijit/_TemplatedMixin", 3 5 "dijit/_WidgetsInTemplateMixin", 4 "dijit/Dialog", 5 "dijit/form/ValidationTextBox", 6 "dijit/registry", 6 7 "dojo/_base/declare", 7 8 "dojo/_base/event", 8 "dojo/ dom-construct",9 "dojo/ text!./templates/LoginDialog.html"10 ], (session, _WidgetsInTemplateMixin, Dialog, 11 ValidationTextBox, declare, event,12 domConstruct, template) ->13 declare [ Dialog,_WidgetsInTemplateMixin],9 "dojo/_base/lang", 10 "dojo/on", 11 "dojo/text!./templates/LoginDialogWrapper.html" 12 ], (session, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, 13 registry, declare, event, lang, _on, template) -> 14 declare [_WidgetBase,_TemplatedMixin,_WidgetsInTemplateMixin], 14 15 templateString: template 15 title: "Login to QED" 16 show: () -> 17 @loginForm.reset() 16 startup: () -> 17 if @_started then return 18 18 @inherited arguments 19 _on session, 'change', (lang.hitch @, @onUserChange) 20 @onUserChange session.get() 19 21 onLogin: (evt) -> 20 if @loginForm.validate 22 if @loginForm.validate() 21 23 value = @loginForm.get 'value' 22 24 session.login value.username, 23 25 value.password 24 .then (() => @hide()), 25 () => alert "Login failed!" 26 @hide() 26 .then () => 27 @loginDialog.hide() 28 , () => 29 alert "Login failed!" 27 30 event.stop evt if evt 28 31 false 29 onCancel: (evt) -> 30 @hide() 31 event.stop evt if evt 32 false 32 onUserChange: (user) -> 33 if user 34 @loginDialog.hide() 35 else 36 @loginDialog.show() -
Dev/trunk/src/client/qed-client/ui/SessionMenu.coffee
r466 r468 1 1 define [ 2 2 "../session", 3 "dijit/DropDownMenu", 4 "dijit/registry", 3 "./LoginDialogWrapper", 5 4 "dijit/MenuBarItem", 6 5 "dojo/_base/declare", 7 6 "dojo/_base/event", 8 7 "dojo/on" 9 ], (session, DropDownMenu, registry, MenuBarItem, declare, event, _on) ->8 ], (session, LoginDialogWrapper, MenuBarItem, declare, event, _on) -> 10 9 declare [MenuBarItem], 11 10 info: null 12 11 postCreate: () -> 13 @loginDialog = registry.byId 'loginDialog'14 console.error "Cannot find loginDialog" if not @loginDialog15 12 @set 'label', "Login" 16 13 startup: () -> … … 29 26 session.logout() 30 27 else 31 @loginDialog.show()28 LoginDialogWrapper.show() 32 29 event.stop evt if evt 33 30 false -
Dev/trunk/src/package.json
r464 r468 9 9 "passport-local": "~0.1.6", 10 10 "q": "~0.9.6", 11 " q-io": "~1.9.1"11 "request": "~2.21.0" 12 12 }, 13 13 "engines": { -
Dev/trunk/src/server/config/config-couchdb.js
r466 r468 1 var q = require('q') ;2 var request = require('../util/request'); 3 var _ = require('underscore'); 4 varutil = require('util');1 var q = require('q'), 2 request = require('../util/q-request'), 3 _ = require('underscore'), 4 util = require('util'); 5 5 6 6 var designDocs = require('./couchdb-design-docs'); … … 34 34 'accept': 'application/json' 35 35 }, 36 body: content36 body: JSON.stringify(content) 37 37 }; 38 return request(url,options); 38 //console.log('req',url,options); 39 return request(url,options).then(function(res){ 40 return JSON.parse(res); 41 }, function(err){ 42 return JSON.parse(err); 43 }); 39 44 } 40 45 … … 90 95 } 91 96 })); 92 }).then(function( ){97 }).then(function(results){ 93 98 console.log("Done!"); 94 99 },function(err){ -
Dev/trunk/src/server/heroku.js
r464 r468 3 3 4 4 var configCouch = require('./config/config-couchdb'); 5 6 console.log("Running on",couchDbURL); 5 7 6 8 configCouch(couchDbURL) -
Dev/trunk/src/server/util/q-request.js
r466 r468 1 var http = require('q-io/http'), 1 var q = require('q'), 2 request = require('request'), 2 3 url = require('url'), 3 4 _ = require('underscore'); 4 5 5 module.exports = function(url OrObject, options) {6 module.exports = function(url, options) { 6 7 8 var dfd = q.defer(); 9 dfd.response = q.defer(); 10 7 11 options = options 8 12 ? _.clone(options) 9 13 : {}; 10 options.url = _.isString(urlOrObject) 11 ? url.parse(urlOrObject) 12 : _.clone(urlOrObject); 14 options.uri = url || options.uri; 15 16 request(options,function(err,res,body){ 17 if ( err ) { 18 dfd.response.reject(err); 19 } else { 20 if ( res.statusCode >= 200 && res.statusCode < 300 ) { 21 dfd.resolve(body); 22 } else { 23 dfd.reject(body); 24 } 25 } 26 dfd.response.resolve(res); 27 }); 13 28 14 // wrap content into q-io thingy 15 if ( options.body ) { 16 options.body = { 17 forEach: function(callback) { 18 callback(JSON.stringify(options.body)); 19 } 20 }; 21 }; 29 return dfd.promise; 22 30 23 // add auth header since q-io doesn't support this24 if ( options.url.auth ) {25 options.headers.authorization = 'Basic '+(new Buffer(options.url.auth).toString("base64"));26 }27 28 // make request and collect results29 return http.request(options)30 .then(function(res){31 return res.body.read().then(function(content){32 return content.length > 0 ? JSON.parse(content) : null;33 });34 },function(res){35 return res.body.read().then(function(error){36 return error.length > 0 ? JSON.parse(error) : null;37 });38 });39 31 };
Note: See TracChangeset
for help on using the changeset viewer.