2013-10-22 11:16:08 +02:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<meta charset="utf-8">
|
2013-11-01 00:56:51 +01:00
|
|
|
<title>Croodle</title>
|
2013-10-22 11:16:08 +02:00
|
|
|
</head>
|
|
|
|
<body>
|
2013-12-30 17:01:24 +01:00
|
|
|
<!--
|
|
|
|
TEMPLATES
|
|
|
|
-->
|
|
|
|
|
|
|
|
<!-- application template -->
|
|
|
|
<script type="text/x-handlebars">
|
|
|
|
<div class="main">
|
|
|
|
<h1>Croodle</h1>
|
|
|
|
{{outlet}}
|
|
|
|
</div>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<!-- poll template -->
|
|
|
|
<script type="text/x-handlebars" id="poll">
|
|
|
|
<h2>title</h2>
|
|
|
|
<p>{{title}}</p>
|
|
|
|
|
|
|
|
<h2>description</h2>
|
|
|
|
<p>{{description}}</p>
|
|
|
|
|
|
|
|
<h2>type</h2>
|
|
|
|
<p>{{type}}</p>
|
|
|
|
|
|
|
|
<h2>options and user</h2>
|
|
|
|
<table>
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<td>user</td>
|
|
|
|
{{#each option in options}}
|
|
|
|
<td>{{option.title}}</td>
|
|
|
|
{{/each}}
|
|
|
|
<td> </td>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
|
|
|
|
<tbody>
|
|
|
|
{{#each user in users}}
|
|
|
|
<tr>
|
|
|
|
<td>{{user.name}}</td>
|
2014-01-29 15:32:27 +01:00
|
|
|
{{#each selection in user.selections}}
|
2013-12-30 17:01:24 +01:00
|
|
|
<td>{{selection.value}}</td>
|
|
|
|
{{/each}}
|
|
|
|
<td> </td>
|
|
|
|
</tr>
|
|
|
|
{{/each}}
|
|
|
|
|
|
|
|
<tr class='newUser'>
|
|
|
|
<td>{{input value=newUserName}}</td>
|
|
|
|
{{#each option in options}}
|
2014-01-07 16:07:42 +01:00
|
|
|
<td>{{input class="newUserSelection" data-option=option.id}}</td>
|
2013-12-30 17:01:24 +01:00
|
|
|
{{/each}}
|
|
|
|
<td><button {{action "save"}}> ok </button></td>
|
|
|
|
</tr>
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
|
|
|
|
<h2>creationDate</h2>
|
|
|
|
<p>{{creationDate}}</p>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<!-- create templates -->
|
|
|
|
<script type="text/x-handlebars" id="create">
|
|
|
|
{{outlet}}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-handlebars" id="create/index">
|
|
|
|
<p>
|
|
|
|
type:<br/>
|
|
|
|
{{view Ember.Select
|
|
|
|
contentBinding="App.Types"
|
|
|
|
optionValuePath="content.id"
|
|
|
|
optionLabelPath="content.label"
|
|
|
|
valueBinding="type"}}
|
|
|
|
</p>
|
|
|
|
<p><button {{action "save"}}> ok </button></p>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-handlebars" id="create/meta">
|
|
|
|
<p>title:<br/>{{input value=title}}</p>
|
|
|
|
<p>description:<br/>{{input value=description}}</p>
|
|
|
|
<p><button {{action "save"}}> ok </button></p>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-handlebars" id="create/options">
|
|
|
|
<p>options<br/>
|
|
|
|
{{#each option in options}}
|
|
|
|
{{option.title}}<br/>
|
|
|
|
{{/each}}
|
|
|
|
</p>
|
|
|
|
<p>{{input value=newOptionTitle}} <button {{action "addOption"}}> add option </button></p>
|
|
|
|
<p><button {{action "save"}}> ok </button></p>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-handlebars" id="create/settings">
|
|
|
|
<p>settings</p>
|
|
|
|
<p><button {{action "save"}}> ok </button></p>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<!-- DEPEDENCIES -->
|
2014-02-01 04:04:34 +01:00
|
|
|
<script type="text/javascript">
|
|
|
|
// enable ember query-params-new feature
|
|
|
|
window.ENV = {FEATURES: {'query-params-new': true}};
|
|
|
|
</script>
|
|
|
|
|
2014-01-31 15:00:47 +01:00
|
|
|
<script src="lib/sjcl.js"></script>
|
2013-12-30 17:01:24 +01:00
|
|
|
<script src="lib/jquery-2.0.3.js"></script>
|
|
|
|
<script src="lib/handlebars-v1.2.0.js"></script>
|
2014-01-23 11:55:16 +01:00
|
|
|
<script src="lib/ember.js"></script>
|
2013-12-30 17:01:24 +01:00
|
|
|
<script src="lib/ember-data.js"></script>
|
2014-01-31 15:00:47 +01:00
|
|
|
<script src="lib/embedded-adapter.js"></script>
|
2013-12-30 17:01:24 +01:00
|
|
|
|
|
|
|
<!-- EMBER APP CODE -->
|
|
|
|
<script type="text/javascript">
|
|
|
|
// app initialization
|
|
|
|
window.App = Ember.Application.create({
|
|
|
|
LOG_TRANSITIONS: true
|
|
|
|
});
|
|
|
|
|
|
|
|
// adapter initialization
|
2014-01-28 00:19:08 +01:00
|
|
|
App.ApplicationAdapter = DS.EmbeddedAdapter.extend({
|
2014-01-06 19:56:32 +01:00
|
|
|
// set namespace to api.php in same subdirectory
|
|
|
|
namespace: 'api.php?'
|
|
|
|
});
|
2014-01-28 00:19:08 +01:00
|
|
|
|
2014-01-28 02:05:14 +01:00
|
|
|
// serializer initialization
|
|
|
|
App.ApplicationSerializer = DS.EmbeddedSerializer.extend();
|
2013-12-30 17:01:24 +01:00
|
|
|
|
2014-01-07 16:07:42 +01:00
|
|
|
// adding support for attribut data-option-id to input fields
|
|
|
|
Ember.TextField.reopen({
|
|
|
|
attributeBindings: ['data-option']
|
|
|
|
});
|
|
|
|
|
2014-02-01 08:14:44 +01:00
|
|
|
//
|
|
|
|
Ember.computed.encrypted = function(encryptedField) {
|
|
|
|
return Ember.computed(encryptedField, function(key, decryptedValue) {
|
|
|
|
var encryptKey = this.get('encryptKey'), encryptedValue;
|
|
|
|
|
2014-02-01 22:08:47 +01:00
|
|
|
// check if encryptKey is set
|
2014-02-01 21:59:58 +01:00
|
|
|
if (typeof encryptKey === 'undefined') {
|
|
|
|
console.log("encryption key is not set for: " + this.toString() + " " + encryptedField);
|
|
|
|
|
|
|
|
// dirty workaround for model of embedded records
|
|
|
|
console.log("using dirty workaround")
|
|
|
|
encryptKey = App.__container__.lookup("controller:poll").get('encryptionKey');
|
|
|
|
if (typeof encryptKey === 'undefined') {
|
|
|
|
console.log("dirty workaround failed also");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-01 08:14:44 +01:00
|
|
|
//setter
|
|
|
|
if (arguments.length == 2) {
|
|
|
|
encryptedValue = Ember.isNone(decryptedValue) ? null : String( sjcl.encrypt( encryptKey , decryptedValue) );
|
|
|
|
this.set(encryptedField, encryptedValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
encryptedValue = this.get(encryptedField);
|
|
|
|
return Ember.isNone(encryptedValue) ? null : String( sjcl.decrypt( encryptKey , encryptedValue) );
|
|
|
|
});
|
|
|
|
};
|
2014-01-31 15:00:47 +01:00
|
|
|
|
2013-12-30 17:01:24 +01:00
|
|
|
/*
|
|
|
|
* models
|
|
|
|
*/
|
|
|
|
|
|
|
|
// poll model
|
|
|
|
App.Poll = DS.Model.extend({
|
2014-02-01 08:14:44 +01:00
|
|
|
encryptedTitle : DS.attr('string'),
|
|
|
|
title : Ember.computed.encrypted('encryptedTitle'),
|
|
|
|
encryptedDescription : DS.attr('string'),
|
|
|
|
description: Ember.computed.encrypted('encryptedDescription'),
|
|
|
|
encryptedType : DS.attr('string'),
|
|
|
|
type : Ember.computed.encrypted('encryptedType'),
|
2013-12-30 17:01:24 +01:00
|
|
|
options : DS.hasMany('option', {async: true}),
|
|
|
|
users : DS.hasMany('user', {async: true}),
|
|
|
|
creationDate : DS.attr('date')
|
|
|
|
});
|
|
|
|
|
|
|
|
// option model
|
|
|
|
// used by poll model
|
|
|
|
App.Option = DS.Model.extend({
|
2014-01-06 19:56:32 +01:00
|
|
|
poll : DS.belongsTo('poll', {async: true}),
|
2014-02-01 08:14:44 +01:00
|
|
|
encryptedTitle : DS.attr('string'),
|
|
|
|
title : Ember.computed.encrypted('encryptedTitle'),
|
2013-12-30 17:01:24 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
// user model
|
|
|
|
// used by poll model
|
|
|
|
App.User = DS.Model.extend({
|
2014-01-07 16:07:42 +01:00
|
|
|
poll : DS.belongsTo('poll', {async: true}),
|
2014-02-01 22:08:47 +01:00
|
|
|
encryptedName : DS.attr('string'),
|
2014-02-01 08:14:44 +01:00
|
|
|
name : Ember.computed.encrypted('encryptedName'),
|
2014-01-07 16:07:42 +01:00
|
|
|
selections : DS.hasMany('selection', {async: true}),
|
2013-12-30 17:01:24 +01:00
|
|
|
creationDate : DS.attr('date')
|
|
|
|
});
|
|
|
|
|
|
|
|
// selection model
|
|
|
|
// used by user model
|
|
|
|
App.Selection = DS.Model.extend({
|
2014-01-07 16:07:42 +01:00
|
|
|
// option : DS.belongsTo('option'),
|
|
|
|
user : DS.belongsTo('user', {async: true}),
|
2014-02-01 08:14:44 +01:00
|
|
|
encryptedValue : DS.attr('string'),
|
|
|
|
value : Ember.computed.encrypted('encryptedValue')
|
2013-12-30 17:01:24 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
App.Types = [
|
|
|
|
Ember.Object.create({
|
|
|
|
id : "FindADate",
|
|
|
|
label : "Find a date"
|
|
|
|
}),
|
|
|
|
Ember.Object.create({
|
|
|
|
id : "MakeAPoll",
|
|
|
|
label : "Make a poll"
|
|
|
|
})
|
|
|
|
];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* routes
|
|
|
|
*/
|
|
|
|
|
|
|
|
// defining routes of app
|
|
|
|
App.Router.map(function(){
|
|
|
|
this.route('poll', { path: '/poll/:poll_id' });
|
|
|
|
this.resource('create', function(){
|
|
|
|
this.route('meta');
|
|
|
|
this.route('options');
|
|
|
|
this.route('settings');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
App.CreateRoute = Ember.Route.extend({
|
|
|
|
model: function(){
|
2014-02-01 08:14:44 +01:00
|
|
|
// generate encryptionKey
|
|
|
|
var encryptionKeyLength = 40;
|
|
|
|
var encryptionKeyChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
|
|
|
|
|
|
var encryptionKey = '';
|
|
|
|
var list = encryptionKeyChars.split('');
|
|
|
|
var len = list.length, i = 0;
|
|
|
|
do {
|
|
|
|
i++;
|
|
|
|
var index = Math.floor(Math.random() * len);
|
|
|
|
encryptionKey += list[index]
|
|
|
|
} while(i < encryptionKeyLength);
|
|
|
|
|
|
|
|
// create empty poll
|
2013-12-30 17:01:24 +01:00
|
|
|
return this.store.createRecord('poll', {
|
2014-02-01 08:14:44 +01:00
|
|
|
encryptKey : encryptionKey,
|
2013-12-30 17:01:24 +01:00
|
|
|
creationDate : new Date()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
App.CreateIndexRoute = Ember.Route.extend({
|
|
|
|
model: function(){
|
|
|
|
return this.modelFor('create');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
App.CreateMetaRoute = Ember.Route.extend({
|
|
|
|
model: function(){
|
|
|
|
return this.modelFor('create');
|
|
|
|
},
|
|
|
|
|
|
|
|
// redirect to create/index if type is not set
|
|
|
|
afterModel: function(create){
|
|
|
|
if (create.get('type') === undefined) {
|
|
|
|
this.transitionTo('create.index');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
App.CreateOptionsRoute = Ember.Route.extend({
|
|
|
|
model: function(){
|
|
|
|
return this.modelFor('create');
|
|
|
|
},
|
|
|
|
|
|
|
|
// redirect to create/meta if title is not set
|
|
|
|
afterModel: function(create){
|
|
|
|
if (create.get('title') === undefined) {
|
|
|
|
this.transitionTo('create.meta');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
App.CreateSettingsRoute = Ember.Route.extend({
|
|
|
|
model: function(){
|
|
|
|
return this.modelFor('create');
|
|
|
|
},
|
|
|
|
|
|
|
|
// redirect to create/options if less then two options are defined
|
|
|
|
afterModel: function(create){
|
|
|
|
if (create.get('options.length') < 2) {
|
|
|
|
this.transitionTo('create.options');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2014-02-01 08:14:44 +01:00
|
|
|
App.PollRoute = Ember.Route.extend({
|
|
|
|
model: function(params){
|
|
|
|
return this.store.find('poll', params.poll_id).then(function(poll) {
|
|
|
|
poll.set('encryptKey', params.encryptionKey);
|
|
|
|
return poll;
|
|
|
|
});
|
2013-12-30 17:01:24 +01:00
|
|
|
}
|
2014-02-01 08:14:44 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
/*
|
|
|
|
* controller
|
|
|
|
*/
|
|
|
|
App.CreateIndexController = Ember.ObjectController.extend({
|
|
|
|
actions: {
|
|
|
|
save: function(){
|
|
|
|
// redirect to CreateMeta
|
|
|
|
this.transitionToRoute('create.meta');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2014-01-07 16:07:42 +01:00
|
|
|
|
2014-02-01 08:14:44 +01:00
|
|
|
App.CreateMetaController = Ember.ObjectController.extend({
|
|
|
|
actions: {
|
|
|
|
save: function(){
|
|
|
|
// redirect to CreateOptions
|
|
|
|
this.transitionToRoute('create.options');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2014-01-07 16:07:42 +01:00
|
|
|
|
2014-02-01 08:14:44 +01:00
|
|
|
App.CreateOptionsController = Ember.ObjectController.extend({
|
|
|
|
actions: {
|
|
|
|
addOption: function(){
|
|
|
|
// create new option
|
|
|
|
var newOptionId = this.get('model.options.length') + 1,
|
|
|
|
newOption = this.store.createRecord('option', {
|
|
|
|
encryptKey : this.get('model.encryptKey'),
|
|
|
|
id : newOptionId,
|
|
|
|
title : this.get('newOptionTitle')
|
|
|
|
});
|
|
|
|
|
|
|
|
// assign it to poll
|
|
|
|
this.get('model.options').pushObject(newOption);
|
|
|
|
|
|
|
|
// clear newOptionTitle input field
|
|
|
|
this.set('newOptionTitle', '');
|
|
|
|
},
|
|
|
|
|
|
|
|
save: function(){
|
|
|
|
// redirect to CreateSettings
|
|
|
|
this.transitionToRoute('create.settings');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
App.CreateSettingsController = Ember.ObjectController.extend({
|
|
|
|
actions: {
|
|
|
|
save: function(){
|
|
|
|
// save poll
|
|
|
|
var self = this;
|
|
|
|
this.get('model').save().then(function(){
|
|
|
|
// redirect to new poll
|
|
|
|
self.transitionToRoute('poll', self.get('model'), {queryParams: {encryptionKey: self.get('encryptKey')}});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
App.PollController = Ember.ObjectController.extend({
|
|
|
|
queryParams: ['encryptionKey'],
|
|
|
|
encryptionKey: 'nicht definiert',
|
|
|
|
|
|
|
|
actions: {
|
|
|
|
save: function(){
|
|
|
|
// create new user record in store
|
|
|
|
var newUser = this.store.createRecord('user', {
|
|
|
|
encryptKey : this.get('model.encryptKey'),
|
|
|
|
name : this.get('newUserName'),
|
|
|
|
creationDate : new Date(),
|
|
|
|
poll : this.get('model')
|
|
|
|
});
|
|
|
|
|
|
|
|
// create new selection record in store and assign it to the new user
|
|
|
|
var self = this,
|
|
|
|
newSelections = [];
|
|
|
|
$('.newUserSelection').each(function(){
|
|
|
|
// generate a new selection id
|
|
|
|
var newSelectionId = function(){
|
|
|
|
// ToDo: check if id already exists
|
|
|
|
return newId = Math.floor(Math.random()*(100000)+1);
|
|
|
|
};
|
2013-12-30 17:01:24 +01:00
|
|
|
|
2014-02-01 08:14:44 +01:00
|
|
|
// create new selection record in store
|
|
|
|
var newSelection = self.store.createRecord('selection', {
|
|
|
|
encryptKey : self.get('model.encryptKey'),
|
|
|
|
id : newSelectionId(),
|
|
|
|
value : $(this).val()
|
|
|
|
});
|
|
|
|
|
|
|
|
// store new selections in an array
|
|
|
|
newSelections.push(newSelection);
|
|
|
|
});
|
|
|
|
|
|
|
|
newUser.get('selections').then(function(selections){
|
|
|
|
// map over all new selections and assign them to user
|
|
|
|
$.each(newSelections, function(){
|
|
|
|
selections.pushObject(this);
|
|
|
|
});
|
|
|
|
|
|
|
|
// save new user
|
|
|
|
newUser.save().then(function(){
|
|
|
|
self.get('model.users').then(function(users){
|
|
|
|
// assign new user to poll
|
|
|
|
users.pushObject(newUser);
|
|
|
|
});
|
|
|
|
|
|
|
|
// empty newUser form after user is saved
|
|
|
|
self.set('newUserName', '');
|
|
|
|
$('.newUserSelection').val('');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
updateEncryptionKey: function() {
|
|
|
|
this.set('encryptKey', this.get('encryptionKey'));
|
|
|
|
this.get('content').reload();
|
|
|
|
}.observes('encryptionKey')
|
|
|
|
});
|
|
|
|
|
|
|
|
/*
|
|
|
|
* views
|
|
|
|
*/
|
2014-01-28 00:19:08 +01:00
|
|
|
App.PollSerializer = App.ApplicationSerializer.extend({
|
2013-12-30 17:01:24 +01:00
|
|
|
attrs: {
|
2014-01-28 02:05:14 +01:00
|
|
|
options: {embedded: 'always'},
|
|
|
|
users: {embedded: 'load'}
|
2014-01-07 16:07:42 +01:00
|
|
|
}
|
|
|
|
});
|
2014-02-01 08:14:44 +01:00
|
|
|
|
2014-01-28 00:19:08 +01:00
|
|
|
App.UserSerializer = App.ApplicationSerializer.extend({
|
2014-01-07 16:07:42 +01:00
|
|
|
attrs: {
|
|
|
|
selections: {embedded: 'always'}
|
2013-12-30 17:01:24 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
</script>
|
2013-10-22 11:16:08 +02:00
|
|
|
</body>
|
|
|
|
</html>
|