<commit_before>// app initialization
window.App = Ember.Application.create({
    LOG_TRANSITIONS: true
});

// adapter initialization
App.ApplicationAdapter = DS.EmbeddedAdapter.extend({
    // set namespace to api.php in same subdirectory
    namespace: 'api.php?'
});

// serializer initialization
App.ApplicationSerializer = DS.EmbeddedSerializer.extend();

// adding support for attribut data-option-id to input fields
Ember.TextField.reopen({
    attributeBindings: ['data-option']
});

// decrypt / encrypt computed property helper
Ember.computed.encrypted = function(encryptedField) {
    return Ember.computed(encryptedField, function(key, decryptedValue) {
        var encryptKey = this.get('encryptKey'), encryptedValue;

        // check if encryptKey is set
        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;
            }
        }

        //setter
        if (arguments.length === 2) {
            encryptedValue = Ember.isNone(decryptedValue) ? null : String( sjcl.encrypt( encryptKey , decryptedValue) );
            this.set(encryptedField, encryptedValue);
        }

        try {
            encryptedValue = this.get(encryptedField);
            decryptedValue = sjcl.decrypt( encryptKey , encryptedValue);
        } catch (e) {
            console.log('Error on decrypting. Perhaps a wrong encryption key?');
            decryptedValue = '';
        }
        return Ember.isNone(encryptedValue) ? null : String( decryptedValue );
    });
};

/*
 * models
 */

// poll model
App.Poll = DS.Model.extend({
    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'),
    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({
    encryptedTitle : DS.attr('string'),
    title : Ember.computed.encrypted('encryptedTitle')
});

// user model
// used by poll model
App.User = DS.Model.extend({
    poll : DS.belongsTo('poll', {async: true}),
    encryptedName : DS.attr('string'),
    name : Ember.computed.encrypted('encryptedName'),
    selections : DS.hasMany('selection', {async: true}),
    creationDate : DS.attr('date')
});

// selection model
// used by user model
App.Selection = DS.Model.extend({
    encryptedValue : DS.attr('string'),
    value : Ember.computed.encrypted('encryptedValue')
});

App.Types = [
   Ember.Object.create({
        id : "FindADate",
        label : "Find a date"
   }),
   Ember.Object.create({
        id : "MakeAPoll",
        label : "Make a poll"
   })
];

/*
 * Serializer
 */
App.PollSerializer = App.ApplicationSerializer.extend({
    attrs: {
        options: {embedded: 'always'},
        users: {embedded: 'load'}
    }
});

App.UserSerializer = App.ApplicationSerializer.extend({
    attrs: {
        selections: {embedded: 'always'}
    }
});

/*
 * 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(){
        // 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
        return this.store.createRecord('poll', {
            encryptKey : encryptionKey,
            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') === null) {
            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') === null) {
            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');
        }
    }
});

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;
        });
    }
});

/*
 * controller
 */
App.CreateIndexController = Ember.ObjectController.extend({
   actions: {
       save: function(){
           // redirect to CreateMeta
           this.transitionToRoute('create.meta');
       }
   }
});

App.CreateMetaController = Ember.ObjectController.extend({
   actions: {
       save: function(){
           // redirect to CreateOptions
           this.transitionToRoute('create.options');
       }
   }
});

App.CreateOptionsController = Ember.ObjectController.extend({
    actions: {
        addOptions: function(options) {
            var self = this;

            // delete old options in model
            this.get('model.options').clear();

            // iterate over array of options and push them to poll
            options.forEach(function(option){
                // check if option has title and if it is unique
                if( /\S/.test(option.title)) {
                    // create newOption
                    var newOption = self.store.createRecord('option', {
                        encryptKey : self.get('model.encryptKey'),
                        title : option.title
                    });

                    // assign it to poll
                    self.get('model.options').then(function(model){
                        model.pushObject(newOption);
                    });
                }
            });

            this.send('save');
        },

        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(model){
                // redirect to new poll
                self.transitionToRoute('poll', model, {queryParams: {encryptionKey: self.get('encryptKey')}});
            });
        }
    }
});

App.PollController = Ember.ObjectController.extend({
    queryParams: ['encryptionKey'],
    encryptionKey: 'nicht definiert',

    actions: {
        saveNewUser: function(user){
            var self = this;

            console.log(user);

            // create new user record in store
            var newUser = this.store.createRecord('user', {
                encryptKey: this.get('model.encryptKey'),
                name: user.name,
                creationDate: new Date(),
                poll: this.get('model'),
                selections: user.selections
            });

            // create new selection record in store and assign it to the new user
            var newSelections = [];
            user.selections.forEach(function(selection){
                // create new selection record in store
                var newSelection = self.store.createRecord('selection', {
                    encryptKey: self.get('model.encryptKey'),
                    value: selection.value
                });

                // 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);
                    });
                });
            });
        }
    },

    updateEncryptionKey: function() {
        // check if they really differ to prevent unnecessary reload of data
        if (this.get('encryptKey') !== this.get('encryptionKey')) {
            // update encryptKey
            this.set('encryptKey', this.get('encryptionKey'));
            // reload content to recalculate computed properties
            this.get('content').reload();
        }
    }.observes('encryptionKey')
});

/*
 * views
 */
App.CreateOptionsView = Ember.View.extend({
    title: '',
    newOptions: [],

    actions: {
        moreOptions: function(){
            // create new Option
            this.get('newOptions').pushObject({title: ''});
       },

       saveOptions: function(){
            var options = this.get('newOptions');

            this.get('controller').send('addOptions', options);
       }
    },

    // set newOptions to existing options or to default
    willInsertElement: function() {
        var newOptions = Ember.A();

        if ( this.get('controller.model.options.length') > 0 ) {
            // existing options
            this.get('controller.model.options').forEach(function(option){
                newOptions.pushObject({title: option.get('title')});
            });
        }
        else {
            // default
            for(i = 0; i < 2; i++) {
                newOptions.pushObject({title: ''});
            }
        }
        this.set('newOptions', newOptions);
    }
});

App.PollView = Ember.View.extend({
    newUserName: 'name',
    newUserSelections: [],

    actions: {
        addNewUser: function(){
            console.log(this.get('newUserName'));
            var newUser = {
                name: this.get('newUserName'),
                selections: this.get('newUserSelections')
            };

            this.get('controller').send('saveNewUser', newUser);
        }
    },

    // generate selection array for new user
    willInsertElement: function(){
        var newUserSelections = Ember.A(),
            self = this;
        this.get('controller.model.options').then(function(options){
            options.forEach(function(){
                newUserSelections.pushObject({value: ''});
            });
            self.set('newUserSelections', newUserSelections);
        });
    }
});<commit_msg>fix error in last commit<commit_after>// app initialization
window.App = Ember.Application.create({
    LOG_TRANSITIONS: true
});

// adapter initialization
App.ApplicationAdapter = DS.EmbeddedAdapter.extend({
    // set namespace to api.php in same subdirectory
    namespace: 'api.php?'
});

// serializer initialization
App.ApplicationSerializer = DS.EmbeddedSerializer.extend();

// adding support for attribut data-option-id to input fields
Ember.TextField.reopen({
    attributeBindings: ['data-option']
});

// decrypt / encrypt computed property helper
Ember.computed.encrypted = function(encryptedField) {
    return Ember.computed(encryptedField, function(key, decryptedValue) {
        var encryptKey = this.get('encryptKey'), encryptedValue;

        // check if encryptKey is set
        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;
            }
        }

        //setter
        if (arguments.length === 2) {
            encryptedValue = Ember.isNone(decryptedValue) ? null : String( sjcl.encrypt( encryptKey , decryptedValue) );
            this.set(encryptedField, encryptedValue);
        }

        try {
            encryptedValue = this.get(encryptedField);
            decryptedValue = sjcl.decrypt( encryptKey , encryptedValue);
        } catch (e) {
            console.log('Error on decrypting. Perhaps a wrong encryption key?');
            decryptedValue = '';
        }
        return Ember.isNone(encryptedValue) ? null : String( decryptedValue );
    });
};

/*
 * models
 */

// poll model
App.Poll = DS.Model.extend({
    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'),
    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({
    encryptedTitle : DS.attr('string'),
    title : Ember.computed.encrypted('encryptedTitle')
});

// user model
// used by poll model
App.User = DS.Model.extend({
    poll : DS.belongsTo('poll', {async: true}),
    encryptedName : DS.attr('string'),
    name : Ember.computed.encrypted('encryptedName'),
    selections : DS.hasMany('selection', {async: true}),
    creationDate : DS.attr('date')
});

// selection model
// used by user model
App.Selection = DS.Model.extend({
    encryptedValue : DS.attr('string'),
    value : Ember.computed.encrypted('encryptedValue')
});

App.Types = [
   Ember.Object.create({
        id : "FindADate",
        label : "Find a date"
   }),
   Ember.Object.create({
        id : "MakeAPoll",
        label : "Make a poll"
   })
];

/*
 * Serializer
 */
App.PollSerializer = App.ApplicationSerializer.extend({
    attrs: {
        options: {embedded: 'always'},
        users: {embedded: 'load'}
    }
});

App.UserSerializer = App.ApplicationSerializer.extend({
    attrs: {
        selections: {embedded: 'always'}
    }
});

/*
 * 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(){
        // 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
        return this.store.createRecord('poll', {
            encryptKey : encryptionKey,
            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') === null) {
            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') === null) {
            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');
        }
    }
});

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;
        });
    }
});

/*
 * controller
 */
App.CreateIndexController = Ember.ObjectController.extend({
   actions: {
       save: function(){
           // redirect to CreateMeta
           this.transitionToRoute('create.meta');
       }
   }
});

App.CreateMetaController = Ember.ObjectController.extend({
   actions: {
       save: function(){
           // redirect to CreateOptions
           this.transitionToRoute('create.options');
       }
   }
});

App.CreateOptionsController = Ember.ObjectController.extend({
    actions: {
        addOptions: function(options) {
            var self = this;

            // delete old options in model
            this.get('model.options').clear();

            // iterate over array of options and push them to poll
            options.forEach(function(option){
                // check if option has title and if it is unique
                if( /\S/.test(option.title)) {
                    // create newOption
                    var newOption = self.store.createRecord('option', {
                        encryptKey : self.get('model.encryptKey'),
                        title : option.title
                    });

                    // assign it to poll
                    self.get('model.options').then(function(model){
                        model.pushObject(newOption);
                    });
                }
            });

            this.send('save');
        },

        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(model){
                // redirect to new poll
                self.transitionToRoute('poll', model, {queryParams: {encryptionKey: self.get('encryptKey')}});
            });
        }
    }
});

App.PollController = Ember.ObjectController.extend({
    queryParams: ['encryptionKey'],
    encryptionKey: 'nicht definiert',

    actions: {
        saveNewUser: function(user){
            var self = this;

            console.log(user);

            // create new user record in store
            var newUser = this.store.createRecord('user', {
                encryptKey: this.get('model.encryptKey'),
                name: user.name,
                creationDate: new Date(),
                poll: this.get('model')
            });

            // create new selection record in store and assign it to the new user
            var newSelections = [];
            user.selections.forEach(function(selection){
                // create new selection record in store
                var newSelection = self.store.createRecord('selection', {
                    encryptKey: self.get('model.encryptKey'),
                    value: selection.value
                });

                // 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);
                    });
                });
            });
        }
    },

    updateEncryptionKey: function() {
        // check if they really differ to prevent unnecessary reload of data
        if (this.get('encryptKey') !== this.get('encryptionKey')) {
            // update encryptKey
            this.set('encryptKey', this.get('encryptionKey'));
            // reload content to recalculate computed properties
            this.get('content').reload();
        }
    }.observes('encryptionKey')
});

/*
 * views
 */
App.CreateOptionsView = Ember.View.extend({
    title: '',
    newOptions: [],

    actions: {
        moreOptions: function(){
            // create new Option
            this.get('newOptions').pushObject({title: ''});
       },

       saveOptions: function(){
            var options = this.get('newOptions');

            this.get('controller').send('addOptions', options);
       }
    },

    // set newOptions to existing options or to default
    willInsertElement: function() {
        var newOptions = Ember.A();

        if ( this.get('controller.model.options.length') > 0 ) {
            // existing options
            this.get('controller.model.options').forEach(function(option){
                newOptions.pushObject({title: option.get('title')});
            });
        }
        else {
            // default
            for(i = 0; i < 2; i++) {
                newOptions.pushObject({title: ''});
            }
        }
        this.set('newOptions', newOptions);
    }
});

App.PollView = Ember.View.extend({
    newUserName: 'name',
    newUserSelections: [],

    actions: {
        addNewUser: function(){
            console.log(this.get('newUserName'));
            var newUser = {
                name: this.get('newUserName'),
                selections: this.get('newUserSelections')
            };

            this.get('controller').send('saveNewUser', newUser);
        }
    },

    // generate selection array for new user
    willInsertElement: function(){
        var newUserSelections = Ember.A(),
            self = this;
        this.get('controller.model.options').then(function(options){
            options.forEach(function(){
                newUserSelections.pushObject({value: ''});
            });
            self.set('newUserSelections', newUserSelections);
        });
    }
});<|endoftext|>


<commit_before>// app initialization
Ember.MODEL_FACTORY_INJECTIONS = true;

window.App = Ember.Application.create({
    LOG_TRANSITIONS: true,

    ready: function(){
        this.register('encryption:current', App.Encryption, {singleton: true});
        this.inject('controller:poll', 'encryption', 'encryption:current');
        this.inject('route:create', 'encryption', 'encryption:current');
        this.inject('model', 'encryption', 'encryption:current');
    }
});

// adapter initialization
App.ApplicationAdapter = DS.EmbeddedAdapter.extend({
    // set namespace to api.php in same subdirectory
    namespace: window.location.pathname
            // remove index.html if it's there
            .replace(/index.html$/, '')
            // remove leading and trailing slash
            .replace(/\/$/, '')
            // add api.php
            .concat('/api.php?')
            // remove leading slash
            .replace(/^\//g, '')
});

// serializer initialization
App.ApplicationSerializer = DS.EmbeddedSerializer.extend();

// adding support for attribut data-option-id to input fields
Ember.TextField.reopen({
    attributeBindings: ['data-option']
});

// decrypt / encrypt computed property helper
Ember.computed.encrypted = function(encryptedField, dataType) {
    return Ember.computed(encryptedField, function(key, decryptedValue) {
        var encryptKey = this.get('encryption.key'),
            encryptedValue;

        // check if encryptKey is set
        if (typeof encryptKey === 'undefined') {
            return;
        }

        // setter
        if (arguments.length === 2) {
            var decryptedJSON = JSON.stringify(decryptedValue);

            encryptedValue = Ember.isNone(decryptedValue) ? null : String(sjcl.encrypt(encryptKey , decryptedJSON));
            this.set(encryptedField, encryptedValue);
        }

        // get value of field to decrypt
        encryptedJSON = this.get(encryptedField);

        // check if encryptedField is defined and not null
        if (typeof encryptedJSON === 'undefined' ||
                encryptedJSON === null) {
            return null;
        }

        // try to decrypt value
        try {
            decryptedJSON = sjcl.decrypt(encryptKey, encryptedJSON);
            decryptedValue = JSON.parse(decryptedJSON);
        } catch (e) {
            console.log('Error on decrypting ' + encryptedField);
            console.log(e);
            console.log('Perhaps a wrong encryption key?');
            decryptedValue = '';
        }

        switch (dataType) {
            case 'array':
                return Ember.isNone(decryptedValue) ? null : decryptedValue;
                break;

            case 'date':
                return Ember.isNone(decryptedValue) ? null : Date(decryptedValue);
                break;

            case 'string':
                return Ember.isNone(decryptedValue) ? null : String(decryptedValue);
                break;
        }
    });
};

/*
 * models
 */

// poll model
App.Poll = DS.Model.extend({
    encryptedTitle : DS.attr('string'),
    title : Ember.computed.encrypted('encryptedTitle', 'string'),
    encryptedDescription : DS.attr('string'),
    description: Ember.computed.encrypted('encryptedDescription', 'string'),
    encryptedPollType : DS.attr('string'),
    pollType : Ember.computed.encrypted('encryptedPollType', 'string'),
    encryptedAnswerType: DS.attr('string'),
    answerType : Ember.computed.encrypted('encryptedAnswerType', 'string'),
    encryptedAnswers : DS.attr('string'),
    answers : Ember.computed.encrypted('encryptedAnswers', 'array'),
    encryptedOptions : DS.attr('string'),
    options : Ember.computed.encrypted('encryptedOptions', 'array'),
    users : DS.hasMany('user', {async: true}),
    encryptedCreationDate : DS.attr('string'),
    creationDate : Ember.computed.encrypted('encryptedCreationDate', 'date')
});

// user model
// used by poll model
App.User = DS.Model.extend({
    poll : DS.belongsTo('poll', {async: true}),
    encryptedName : DS.attr('string'),
    name : Ember.computed.encrypted('encryptedName', 'string'),
    selections : DS.hasMany('selection', {async: true}),
    encryptedCreationDate : DS.attr('string'),
    creationDate : Ember.computed.encrypted('encryptedCreationDate', 'date')
});

// selection model
// used by user model
App.Selection = DS.Model.extend({
    encryptedValue : DS.attr('string'),
    value : Ember.computed.encrypted('encryptedValue', 'string')
});

App.Encryption = Ember.Object.extend({
    key : '',
    isSet: false
});

App.PollTypes = [
   Ember.Object.create({
        id : "FindADate",
        label : "Find a date"
   }),
   Ember.Object.create({
        id : "MakeAPoll",
        label : "Make a poll"
   })
];

App.AnswerTypes = [
    Ember.Object.create({
        id : "YesNo",
        label : "yes, no",
        answers : [
                {label: "yes"},
                {label: "no"}
            ]
    }),
    Ember.Object.create({
        id : "YesNoMaybe",
        label : "yes, no, maybe",
        answers : [
                {label: "yes"},
                {label: "no"},
                {label: "maybe"}
            ]
    }),
    Ember.Object.create({
        id : "FreeText",
        label : "free text",
        answers : []
    })
];

/*
 * Serializer
 */
App.PollSerializer = App.ApplicationSerializer.extend({
    attrs: {
        users: {embedded: 'load'}
    }
});

App.UserSerializer = App.ApplicationSerializer.extend({
    attrs: {
        selections: {embedded: 'always'}
    }
});

/*
 * 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({
    beforeModel: function(){
        // 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);

        // set encryption key
        this.set('encryption.key', encryptionKey);
    },

    model: function(){
        // create empty poll
        return this.store.createRecord('poll', {
            creationDate : new Date(),
            options : [{title: ''}, {title: ''}]
        });
    }
});

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 poll type is not set
    afterModel: function(create){
        if (create.get('pollType') === null) {
            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') === null) {
            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');
        }
    }
});

App.PollRoute = Ember.Route.extend({
    model: function(params){
        return this.store.find('poll', params.poll_id).then(function(poll) {
            return poll;
        });
    }
});

/*
 * controller
 */
App.CreateIndexController = Ember.ObjectController.extend({
   actions: {
       save: function(){
           // redirect to CreateMeta
           this.transitionToRoute('create.meta');
       }
   }
});

App.CreateMetaController = Ember.ObjectController.extend({
   actions: {
       save: function(){
           // redirect to CreateOptions
           this.transitionToRoute('create.options');
       }
   }
});

App.CreateOptionsController = Ember.ObjectController.extend({
    actions: {
        saveOptions: function() {
            var options = this.get('model.options'),
                newOptions = [];

            // remove options without value
            options.forEach(function(option) {
                if (option.title !== '') {
                     newOptions.pushObject(option);
                }
            });

            // set updated options
						//
            // we have to hardly set new options even if they wasn't changed to
						// trigger computed property; push on array doesn't trigger computed
						// property to recalculate
            this.set('model.options', newOptions);

            // tricker save action
            this.send('save');
        },

        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(model){
                // reload as workaround for bug: duplicated records after save
                model.reload().then(function(model){
                   // redirect to new poll
                   self.transitionToRoute('poll', model, {queryParams: {encryptionKey: self.get('encryption.key')}});
                });
            });
        }
    },

    updateAnswers: function(){
        var selectedAnswer = this.get('model.answerType'),
            answers = [];

        if (selectedAnswer !== null) {
            for (var i=0; i<App.AnswerTypes.length; i++) {
                if (App.AnswerTypes[i].id === selectedAnswer) {
                    answers = App.AnswerTypes[i].answers;
                }
            }

            this.set('answers', answers);
        }
    }.observes('answerType')
});

App.PollController = Ember.ObjectController.extend({
    queryParams: ['encryptionKey'],
    encryptionKey: '',

    actions: {
        saveNewUser: function(user){
            var self = this;

            // create new user record in store
            var newUser = this.store.createRecord('user', {
                name: user.name,
                creationDate: new Date(),
                poll: this.get('model')
            });

            // create new selection record in store and assign it to the new user
            var newSelections = [];
            user.selections.forEach(function(selection){
                // create new selection record in store
                var newSelection = self.store.createRecord('selection', {
                    value: selection.value
                });

                // 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);
                    });
                    // reload as workaround for bug: duplicated records after save
                    self.get('model').reload();
                });
            });
        }
    },

    isFreeText: function() {
        var answerType = this.get('answerType');
        if (answerType === 'FreeText') {
            return true;
        }
        else {
            return false;
        }
    }.property('answerType'),

    updateEncryptionKey: function() {
        // update encryption key
        this.set('encryption.key', this.get('encryptionKey'));

        // reload content to recalculate computed properties
        // if encryption key was set before
        if (this.get('encryption.isSet') === true) {
            this.get('content').reload();
        }

        this.set('encryption.isSet', true);
    }.observes('encryptionKey')
});

/*
 * views
 */
App.CreateOptionsView = Ember.View.extend({
    title: '',

    actions: {
        moreOptions: function(){
            // create new Option
            this.get('controller.model.options').pushObject({title: ''});
       }
    }
});

App.PollView = Ember.View.extend({
    newUserName: '',
    newUserSelections: [],

    actions: {
        addNewUser: function(){
            var newUser = {
                name: this.get('newUserName'),
                selections: this.get('newUserSelections')
            };

            this.get('controller').send('saveNewUser', newUser);

            // clear input fields
            this.set('newUserName', '');
            this.get('newUserSelections').forEach(function(selection){
                selection.set('value', '');
            });
        }
    },

    // generate selection array for new user
    willInsertElement: function(){
        var newUserSelections = Ember.A(),
            self = this,
            options = this.get('controller.model.options');

        options.forEach(function(){
            newSelection = Ember.Object.create({value: ''});
            newUserSelections.pushObject(newSelection);
        });
        self.set('newUserSelections', newUserSelections);
    }
});<commit_msg>change selections to encrypted array<commit_after>// app initialization
Ember.MODEL_FACTORY_INJECTIONS = true;

window.App = Ember.Application.create({
    LOG_TRANSITIONS: true,

    ready: function(){
        this.register('encryption:current', App.Encryption, {singleton: true});
        this.inject('controller:poll', 'encryption', 'encryption:current');
        this.inject('route:create', 'encryption', 'encryption:current');
        this.inject('model', 'encryption', 'encryption:current');
    }
});

// adapter initialization
App.ApplicationAdapter = DS.EmbeddedAdapter.extend({
    // set namespace to api.php in same subdirectory
    namespace: window.location.pathname
            // remove index.html if it's there
            .replace(/index.html$/, '')
            // remove leading and trailing slash
            .replace(/\/$/, '')
            // add api.php
            .concat('/api.php?')
            // remove leading slash
            .replace(/^\//g, '')
});

// serializer initialization
App.ApplicationSerializer = DS.EmbeddedSerializer.extend();

// adding support for attribut data-option-id to input fields
Ember.TextField.reopen({
    attributeBindings: ['data-option']
});

// decrypt / encrypt computed property helper
Ember.computed.encrypted = function(encryptedField, dataType) {
    return Ember.computed(encryptedField, function(key, decryptedValue) {
        var encryptKey = this.get('encryption.key'),
            encryptedValue;

        // check if encryptKey is set
        if (typeof encryptKey === 'undefined') {
            return;
        }

        // setter
        if (arguments.length === 2) {
            var decryptedJSON = JSON.stringify(decryptedValue);

            encryptedValue = Ember.isNone(decryptedValue) ? null : String(sjcl.encrypt(encryptKey , decryptedJSON));
            this.set(encryptedField, encryptedValue);
        }

        // get value of field to decrypt
        encryptedJSON = this.get(encryptedField);

        // check if encryptedField is defined and not null
        if (typeof encryptedJSON === 'undefined' ||
                encryptedJSON === null) {
            return null;
        }

        // try to decrypt value
        try {
            decryptedJSON = sjcl.decrypt(encryptKey, encryptedJSON);
            decryptedValue = JSON.parse(decryptedJSON);
        } catch (e) {
            console.log('Error on decrypting ' + encryptedField);
            console.log(e);
            console.log('Perhaps a wrong encryption key?');
            decryptedValue = '';
        }

        switch (dataType) {
            case 'array':
                return Ember.isNone(decryptedValue) ? null : decryptedValue;
                break;

            case 'date':
                return Ember.isNone(decryptedValue) ? null : Date(decryptedValue);
                break;

            case 'string':
                return Ember.isNone(decryptedValue) ? null : String(decryptedValue);
                break;
        }
    });
};

/*
 * models
 */

// poll model
App.Poll = DS.Model.extend({
    encryptedTitle : DS.attr('string'),
    title : Ember.computed.encrypted('encryptedTitle', 'string'),
    encryptedDescription : DS.attr('string'),
    description: Ember.computed.encrypted('encryptedDescription', 'string'),
    encryptedPollType : DS.attr('string'),
    pollType : Ember.computed.encrypted('encryptedPollType', 'string'),
    encryptedAnswerType: DS.attr('string'),
    answerType : Ember.computed.encrypted('encryptedAnswerType', 'string'),
    encryptedAnswers : DS.attr('string'),
    answers : Ember.computed.encrypted('encryptedAnswers', 'array'),
    encryptedOptions : DS.attr('string'),
    options : Ember.computed.encrypted('encryptedOptions', 'array'),
    users : DS.hasMany('user', {async: true}),
    encryptedCreationDate : DS.attr('string'),
    creationDate : Ember.computed.encrypted('encryptedCreationDate', 'date')
});

// user model
// used by poll model
App.User = DS.Model.extend({
    poll : DS.belongsTo('poll', {async: true}),
    encryptedName : DS.attr('string'),
    name : Ember.computed.encrypted('encryptedName', 'string'),
    encryptedSelections : DS.attr('string'),
    selections : Ember.computed.encrypted('encryptedSelections', 'array'),
    encryptedCreationDate : DS.attr('string'),
    creationDate : Ember.computed.encrypted('encryptedCreationDate', 'date')
});

App.Encryption = Ember.Object.extend({
    key : '',
    isSet: false
});

App.PollTypes = [
   Ember.Object.create({
        id : "FindADate",
        label : "Find a date"
   }),
   Ember.Object.create({
        id : "MakeAPoll",
        label : "Make a poll"
   })
];

App.AnswerTypes = [
    Ember.Object.create({
        id : "YesNo",
        label : "yes, no",
        answers : [
                {label: "yes"},
                {label: "no"}
            ]
    }),
    Ember.Object.create({
        id : "YesNoMaybe",
        label : "yes, no, maybe",
        answers : [
                {label: "yes"},
                {label: "no"},
                {label: "maybe"}
            ]
    }),
    Ember.Object.create({
        id : "FreeText",
        label : "free text",
        answers : []
    })
];

/*
 * Serializer
 */
App.PollSerializer = App.ApplicationSerializer.extend({
    attrs: {
        users: {embedded: 'load'}
    }
});

/*
 * 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({
    beforeModel: function(){
        // 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);

        // set encryption key
        this.set('encryption.key', encryptionKey);
    },

    model: function(){
        // create empty poll
        return this.store.createRecord('poll', {
            creationDate : new Date(),
            options : [{title: ''}, {title: ''}]
        });
    }
});

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 poll type is not set
    afterModel: function(create){
        if (create.get('pollType') === null) {
            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') === null) {
            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');
        }
    }
});

App.PollRoute = Ember.Route.extend({
    model: function(params){
        return this.store.find('poll', params.poll_id).then(function(poll) {
            return poll;
        });
    }
});

/*
 * controller
 */
App.CreateIndexController = Ember.ObjectController.extend({
   actions: {
       save: function(){
           // redirect to CreateMeta
           this.transitionToRoute('create.meta');
       }
   }
});

App.CreateMetaController = Ember.ObjectController.extend({
   actions: {
       save: function(){
           // redirect to CreateOptions
           this.transitionToRoute('create.options');
       }
   }
});

App.CreateOptionsController = Ember.ObjectController.extend({
    actions: {
        saveOptions: function() {
            var options = this.get('model.options'),
                newOptions = [];

            // remove options without value
            options.forEach(function(option) {
                if (option.title !== '') {
                     newOptions.pushObject(option);
                }
            });

            // set updated options
						//
            // we have to hardly set new options even if they wasn't changed to
						// trigger computed property; push on array doesn't trigger computed
						// property to recalculate
            this.set('model.options', newOptions);

            // tricker save action
            this.send('save');
        },

        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(model){
                // reload as workaround for bug: duplicated records after save
                model.reload().then(function(model){
                   // redirect to new poll
                   self.transitionToRoute('poll', model, {queryParams: {encryptionKey: self.get('encryption.key')}});
                });
            });
        }
    },

    updateAnswers: function(){
        var selectedAnswer = this.get('model.answerType'),
            answers = [];

        if (selectedAnswer !== null) {
            for (var i=0; i<App.AnswerTypes.length; i++) {
                if (App.AnswerTypes[i].id === selectedAnswer) {
                    answers = App.AnswerTypes[i].answers;
                }
            }

            this.set('answers', answers);
        }
    }.observes('answerType')
});

App.PollController = Ember.ObjectController.extend({
    queryParams: ['encryptionKey'],
    encryptionKey: '',

    actions: {
        saveNewUser: function(user){
            var self = this;

            console.log(user);

            // create new user record in store
            var newUser = this.store.createRecord('user', {
                name: user.name,
                creationDate: new Date(),
                poll: this.get('model'),
                selections: user.selections
            });

            // save new user
            newUser.save().then(function(){
                self.get('model.users').then(function(users){
                    // assign new user to poll
                    users.pushObject(newUser);
                });
                // reload as workaround for bug: duplicated records after save
                self.get('model').reload();
            });
        }
    },

    isFreeText: function() {
        var answerType = this.get('answerType');
        if (answerType === 'FreeText') {
            return true;
        }
        else {
            return false;
        }
    }.property('answerType'),

    updateEncryptionKey: function() {
        // update encryption key
        this.set('encryption.key', this.get('encryptionKey'));

        // reload content to recalculate computed properties
        // if encryption key was set before
        if (this.get('encryption.isSet') === true) {
            this.get('content').reload();
        }

        this.set('encryption.isSet', true);
    }.observes('encryptionKey')
});

/*
 * views
 */
App.CreateOptionsView = Ember.View.extend({
    title: '',

    actions: {
        moreOptions: function(){
            // create new Option
            this.get('controller.model.options').pushObject({title: ''});
       }
    }
});

App.PollView = Ember.View.extend({
    newUserName: '',
    newUserSelections: [],

    actions: {
        addNewUser: function(){
            var newUser = {
                name: this.get('newUserName'),
                selections: this.get('newUserSelections')
            };

            this.get('controller').send('saveNewUser', newUser);

            // clear input fields
            this.set('newUserName', '');
            this.get('newUserSelections').forEach(function(selection){
                selection.set('value', '');
            });
        }
    },

    // generate selection array for new user
    willInsertElement: function(){
        var newUserSelections = Ember.A(),
            self = this,
            options = this.get('controller.model.options');

        options.forEach(function(){
            newSelection = Ember.Object.create({value: ''});
            newUserSelections.pushObject(newSelection);
        });
        self.set('newUserSelections', newUserSelections);
    }
});<|endoftext|>


<commit_before>/*
//  default.js
//  Digital Signage
//
//  Created by Micah Bucy on 1/11/2016.
//  Copyright © 2016 Micah Bucy. All rights reserved.
//
//  The MIT License (MIT)
//  This file is subject to the terms and conditions defined in LICENSE.md
*/
(function () {
    "use strict";

    var alert = function (message, callback) {
        vex.defaultOptions.className = "vex-theme-os";
        if (typeof callback === 'function') {
            vex.dialog.alert({ message: message, callback: callback });
        }
        else {
            vex.dialog.alert(message);
        }
    };
    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;
    var ViewManagement = Windows.UI.ViewManagement;
    var FullScreenSystemOverlayMode = ViewManagement.FullScreenSystemOverlayMode;
    var ApplicationView = ViewManagement.ApplicationView;
    var cursorPositionX = 0;
    var cursorPositionY = 0;
    var initializing = true;
    var slideshowLoader = [];
    var slideshow = [];
    var countdowns = [];
    var currentSlide = 0;
    var loadedJSON = "";
    var mouseTimer;
    var updateTimer;
    var countdownTimer;
    var timer;
    var loading = false;
    var updateReady = false;
    var Item = WinJS.Class.define(
	    function (uri, type, filename, localUri) {
	        this.uri = uri;
	        this.type = type;
	        this.filename = filename;
	        this.localUri = localUri;
	        this.status = 0;
	    },
        {
            generateItemHTML: function () {
                var $item;
                if (this.type == "image") {
                    $item = $("<img src='" + this.localUri + "' />");
                }
                if (this.type == "video") {
                    $item = $("<video src='" + this.localUri + "'></video>");
                }
                return $item;
            }
        },
        {}
	);
    var Countdown = WinJS.Class.define(
        function (day, hour, minute, duration) {
            this.day = day;
            this.hour = hour;
            this.minute = minute;
            this.duration = duration;
        },
        {},
        {}
    );

    app.downloadItem = function (item) {
        var filename = item.filename;
        if (updateTimer == undefined) {
            console.log("updateTimer is undefined, aborting download of " + filename);
            return;
        }
        Windows.Storage.ApplicationData.current.localFolder.createFileAsync(filename).done(function (file) {
            var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
            var download = downloader.createDownload(item.uri, file).startAsync().done(function (file) {
                item.status = 1;
            });
        });
    };

    app.loadItem = function (item) {
        var filename = item.filename;
        if (updateTimer == undefined) {
            console.log("updateTimer is undefined, aborting loading " + filename);
            return;
        }
        if (item.status == 1) {
            console.log(filename + " already exists, skipping download.");
            return;
        }
        var backgroundDownloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
        Windows.Storage.ApplicationData.current.localFolder.tryGetItemAsync(filename).done(function (file) {
            if (file !== null) {
                file.deleteAsync().done(function () {
                    app.downloadItem(item);
                });
            }
            else {
                app.downloadItem(item);
            }
        });
    };

    app.loadNextSlide = function () {
        if (initializing || slideshow.length == 0) {
            currentSlide = 0;
            timer = setTimeout(app.loadNextSlide, 5000);
            return;
        }
        var $slideshow = $("#slideshow");
        var item;
        if (updateReady) {
            app.reloadSlideshow();
        }
        item = slideshow[currentSlide];
        currentSlide = (currentSlide + 1) % slideshow.length;
        var $item = item.generateItemHTML();
        $slideshow.append($item);
        if (item.type == "video") {
            $item.on("ended", function () {
                app.loadNextSlide();
            });
            app.scaleToFill($item);
            $item[0].play();
            $item[0].pause();
        }
        $item.transition({ opacity: 1 }, 1000, "linear", function () {
            if ($slideshow.children().length > 1) {
                $slideshow.children().first().remove();
            }
            if (item.type == "image") {
                timer = setTimeout(app.loadNextSlide, 5000);
            }
            else {
                $item[0].play();
            }
        });
    };

    app.scaleToFill = function($video) {
        var videoRatio = 16/9;
        var tagRatio = $video.width() / $video.height();
        if (videoRatio < tagRatio) {
            $video.css('transform','scaleX(' + tagRatio / videoRatio  + ')');
        }
        else if (tagRatio < videoRatio) {
            $video.css('transform', 'scaleY(' + videoRatio / tagRatio + ')');
        }
    };

    app.reloadSlideshow = function () {
        if (updateTimer == undefined) {
            console.log("updateTimer is undefined, not reloading show");
            return;
        }
        slideshow = slideshowLoader;
        slideshowLoader = [];
        currentSlide = 0;
        if (initializing) {
            initializing = false;
            app.loadNextSlide();
        }
        loading = false;
        updateReady = false;
    };

    app.checkLoadStatus = function () {
        var finished = true;
        $.each(slideshowLoader, function () {
            if (this.status == 0) {
                finished = false;
                return false;
            }
        });
        if (!finished) {
            setTimeout(app.checkLoadStatus, 100);
        }
        else {
            var appData = Windows.Storage.ApplicationData.current;
            var localFolder = appData.localFolder;
            var currentLoader = slideshowLoader;
            localFolder.getFilesAsync().done(function (files) {
                files.forEach(function forEachFile(file) {
                    var filename = file.name;
                    if (filename == "json.txt") {
                        return;
                    }
                    var remove = true;
                    $.each(currentLoader, function () {
                        if (filename == this.filename) {
                            remove = false;
                            return false;
                        }
                    });
                    if (remove) {
                        file.deleteAsync().done(function () {
                            console.log("removed " + filename);
                        });
                    }
                });
            });
            if (initializing) {
                console.log("Initializing");
                app.reloadSlideshow();
            }
            else {
                console.log("Update is ready.");
                updateReady = true;
            }
        }
    };

    app.writeJSON = function (text, json) {
        var appData = Windows.Storage.ApplicationData.current;
        var localFolder = appData.localFolder;
        localFolder.createFileAsync("json.txt", Windows.Storage.CreationCollisionOption.replaceExisting).then(function (file) {
            if (file !== null) {
                Windows.Storage.FileIO.writeTextAsync(file, text).done(function () {
                    loadedJSON = text;
                    app.loadCountdowns(json);
                    app.loadItems(json);
                });
            }
        });
    };

    app.readJSON = function () {
        var applicationData = Windows.Storage.ApplicationData.current;
        var localFolder = applicationData.localFolder;
        Windows.Storage.ApplicationData.current.localFolder.tryGetItemAsync("json.txt").done(function (file) {
            Windows.Storage.FileIO.readTextAsync(file).done(function (text) {
                try {
                    var data = JSON.parse(text);
                    loadedJSON = text;
                    app.loadCountdowns(data);
                    app.loadItems(data);
                } catch (Exception) {
                    alert("Cached json is corrupt.");
                }
            });
        }, function (error) {
            alert("Offline and no cache.");
        });
    };

    app.loadItems = function (data) {
        $.each(data.items, function () {
            if (updateTimer == undefined) {
                console.log("updateTimer is undefined, aborting current loading of items.");
                return false;
            }
            var path;
            var url = this.url;
            var filename = url.substring(url.lastIndexOf('/') + 1);
            var server_md5sum = this.md5sum;
            var uri;
            try {
                uri = new Windows.Foundation.Uri(url);
            }
            catch (Exception) {
                console.log("malformed url");
                return;
            }
            if (uri.schemeName != "https") {
                console.log("url must be using https");
                return;
            }
            var path = Windows.Storage.ApplicationData.current.localFolder.path + "\\" + filename;
            var item = new Item(uri, this.type, filename, path);
            slideshowLoader.push(item);
            var length = slideshowLoader.length
            Windows.Storage.ApplicationData.current.localFolder.tryGetItemAsync(filename).done(function (file) {
                if (updateTimer == undefined) {
                    console.log("updateTimer is undefined, no need to load items.");
                    return;
                }
                var item = slideshowLoader[length - 1];
                if (file !== null) {
                    var hashProvider = Windows.Security.Cryptography.Core.HashAlgorithmProvider.openAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.md5);
                    Windows.Storage.FileIO.readBufferAsync(file).then(
                        function (buffer) {
                            if (updateTimer == undefined) {
                                console.log("updateTimer is undefined, no need to verify existing item.");
                                return;
                            }
                            var outputBuffer = hashProvider.hashData(buffer);
                            var md5sum = Windows.Security.Cryptography.CryptographicBuffer.encodeToHexString(outputBuffer);
                            if (md5sum != server_md5sum) {
                                app.loadItem(item);
                            }
                            else {
                                item.status = 1;
                                app.loadItem(item);
                            }
                        }
                    );
                }
                else {
                    app.loadItem(item);
                }
            });
        });
        if (updateTimer == undefined) {
            console.log("updateTimer is undefined, no need to check current load status.");
            return;
        }
        setTimeout(app.checkLoadStatus, 100);
    };

    app.loadCountdowns = function (data) {
        countdowns = [];
        if (data.hasOwnProperty("countdowns")) {
            $.each(data.countdowns, function () {
                var countdown = new Countdown(this.day, this.hour, this.minute, this.duration);
                countdowns.push(countdown);
            });
            if (countdownTimer == undefined) {
                countdownTimer = setInterval(app.updateCountdown, 100);
            }
        }
    }

    app.ToggleFullscreen = function () {
        var view = ApplicationView.getForCurrentView();
        if (!view.isFullScreen) {
            view.tryEnterFullScreenMode();
        }
        else {
            view.exitFullScreenMode();
        }
    };

    app.toHHMMSS = function (value) {
        var sec_num = parseInt(value, 10); // don't forget the second param
        var hoursInt = Math.floor(sec_num / 3600);
        var minutes = Math.floor((sec_num - (hoursInt * 3600)) / 60);
        var seconds = sec_num - (hoursInt * 3600) - (minutes * 60);
        var hours;

        if (hoursInt < 10) { hours = "0" + hoursInt + ":"; }
        else { hoursInt = hoursInt + ":"; }
        if (hoursInt < 1) { hours = ""; }
        if (minutes < 10) { minutes = "0" + minutes; }
        if (seconds < 10) { seconds = "0" + seconds; }
        var time = hours + minutes + ':' + seconds;
        return time;
    };

    app.updateCountdown = function () {
        var now = new Date();
        // javascript day of week starts at 0 instead of 1
        var day = now.getDay() + 1;
        var seconds = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();
        var hide = true;
        var $countdown = $("#countdown");
        $.each(countdowns, function () {
            var countdown = this;
            if (day != countdown.day) {
                return true;
            }
            var countdownSeconds = countdown.hour * 3600 + countdown.minute * 60;
            var difference = countdownSeconds - seconds;
            var duration = countdown.duration * 60;
            if (difference > 0 && difference < duration) {
                hide = false;
                $countdown.html(app.toHHMMSS(difference));
                return false;
            }
        });
        if (hide) {
            $countdown.hide();
        }
        else {
            $countdown.show();
        }
    };

    app.loadJSON = function (url) {
        var uri;
        try {
            uri = new Windows.Foundation.Uri(url);
        }
        catch (Exception) {
            alert("url is malformed", function (value) {
                $("#addressBox").focus();
            });
            return;
        }
        if (uri.schemeName != "https") {
            alert("only https is supported", function (value) {
                $("#addressBox").focus();
            });
            return;
        }
        var httpClient = new Windows.Web.Http.HttpClient();
        httpClient.defaultRequestHeaders.userAgent.parseAdd("Digital Signage");
        httpClient.getStringAsync(uri).then(
            function (response) {
                try {
                    var json = JSON.parse(response);
                    $("#form").hide();
                    if (updateTimer == undefined) {
                        console.log("Setting updateTimer.");
                        updateTimer = setInterval(app.loadJSON, 30000, url);
                    }
                }
                catch (e) {
                    alert("Could not parse response as JSON", function (value) {
                        $("#form").show();
                        $("#addressBox").focus();
                    });
                    return;
                }
                var appData = Windows.Storage.ApplicationData.current.localSettings;
                appData.values["url"] = url;
                if (loadedJSON == "") {
                    return app.writeJSON(response, json);
                }
                if (!initializing && loadedJSON == response) {
                    console.log("No changes.");
                    loading = false;
                    return;
                }
                console.log("loading changes");
                app.writeJSON(response, json);
            },
            function (error) {
                if (loadedJSON == "") {
                    app.readJSON();
                }
                else {
                    loading = false;
                }
            }
        );
    };

    app.hideCursor = function () {
        $("body").addClass("hideCursor");
    };

    app.reset = function () {
        console.log("Resetting app");
        initializing = true;
        updateTimer = clearInterval(updateTimer);
        if (countdownTimer != undefined) {
            countdownTimer = clearInterval(countdownTimer);
        }
        $("#countdown").hide();
        $("#slideshow").children().each(function () {
            $(this).remove();
        });
        $("#form").show();
        $("#addressBox").focus();
    };

    app.loadAddress = function () {
        if (timer != undefined) {
            clearTimeout(timer);
        }
        app.loadJSON($("#addressBox")[0].value);
    };

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            var view = ApplicationView.getForCurrentView();
            if (!view.isFullScreen) {
                view.tryEnterFullScreenMode();
            }
            var appData = Windows.Storage.ApplicationData.current.localSettings;
            $("#countdown").hide();
            $("#goButton").on("click", function(e) {
                app.loadAddress();
            });
            $("#addressBox").on("keydown", function (e) {
                if (e.keyCode == 13) {
                    e.preventDefault();
                    app.loadAddress();
                }
            });
            if (appData.values["url"]) {
                var url = appData.values["url"];
                $("#addressBox").val(url);
                app.loadAddress();
            }

            $("body").on("keyup", function (e) {
                switch (e.keyCode) {
                    case 122: {
                        app.ToggleFullscreen();
                    }
                    case 76: {
                        if (e.ctrlKey) {
                            app.reset();
                        }
                    }
                }
            });
            $(window).on("resize", function (e) {
                $("video").each(function () {
                    app.scaleToFill($(this));
                });
            });
            mouseTimer = setTimeout(app.hideCursor, 5000);
            $("body").on("mousemove", function (e) {
                if (e.pageX != cursorPositionX || e.pageY != cursorPositionY) {
                    cursorPositionX = e.pageX;
                    cursorPositionY = e.pageY;
                    if (mouseTimer != undefined) {
                        mouseTimer = clearTimeout(mouseTimer);
                    }
                    mouseTimer = setTimeout(app.hideCursor, 5000);
                    $(this).removeClass("hideCursor");
                }
            });
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
    };

    app.start();
})();<commit_msg>check for existing load process<commit_after>/*
//  default.js
//  Digital Signage
//
//  Created by Micah Bucy on 1/11/2016.
//  Copyright © 2016 Micah Bucy. All rights reserved.
//
//  The MIT License (MIT)
//  This file is subject to the terms and conditions defined in LICENSE.md
*/
(function () {
    "use strict";

    var alert = function (message, callback) {
        vex.defaultOptions.className = "vex-theme-os";
        if (typeof callback === 'function') {
            vex.dialog.alert({ message: message, callback: callback });
        }
        else {
            vex.dialog.alert(message);
        }
    };
    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;
    var ViewManagement = Windows.UI.ViewManagement;
    var FullScreenSystemOverlayMode = ViewManagement.FullScreenSystemOverlayMode;
    var ApplicationView = ViewManagement.ApplicationView;
    var cursorPositionX = 0;
    var cursorPositionY = 0;
    var initializing = true;
    var slideshowLoader = [];
    var slideshow = [];
    var countdowns = [];
    var currentSlide = 0;
    var loadedJSON = "";
    var mouseTimer;
    var updateTimer;
    var countdownTimer;
    var timer;
    var loading = false;
    var updateReady = false;
    var Item = WinJS.Class.define(
	    function (uri, type, filename, localUri) {
	        this.uri = uri;
	        this.type = type;
	        this.filename = filename;
	        this.localUri = localUri;
	        this.status = 0;
	    },
        {
            generateItemHTML: function () {
                var $item;
                if (this.type == "image") {
                    $item = $("<img src='" + this.localUri + "' />");
                }
                if (this.type == "video") {
                    $item = $("<video src='" + this.localUri + "'></video>");
                }
                return $item;
            }
        },
        {}
	);
    var Countdown = WinJS.Class.define(
        function (day, hour, minute, duration) {
            this.day = day;
            this.hour = hour;
            this.minute = minute;
            this.duration = duration;
        },
        {},
        {}
    );

    app.downloadItem = function (item) {
        var filename = item.filename;
        if (updateTimer == undefined) {
            console.log("updateTimer is undefined, aborting download of " + filename);
            return;
        }
        Windows.Storage.ApplicationData.current.localFolder.createFileAsync(filename).done(function (file) {
            var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
            var download = downloader.createDownload(item.uri, file).startAsync().done(function (file) {
                item.status = 1;
            });
        });
    };

    app.loadItem = function (item) {
        var filename = item.filename;
        if (updateTimer == undefined) {
            console.log("updateTimer is undefined, aborting loading " + filename);
            return;
        }
        if (item.status == 1) {
            console.log(filename + " already exists, skipping download.");
            return;
        }
        var backgroundDownloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
        Windows.Storage.ApplicationData.current.localFolder.tryGetItemAsync(filename).done(function (file) {
            if (file !== null) {
                file.deleteAsync().done(function () {
                    app.downloadItem(item);
                });
            }
            else {
                app.downloadItem(item);
            }
        });
    };

    app.loadNextSlide = function () {
        if (initializing || slideshow.length == 0) {
            currentSlide = 0;
            timer = setTimeout(app.loadNextSlide, 5000);
            return;
        }
        var $slideshow = $("#slideshow");
        var item;
        if (updateReady) {
            app.reloadSlideshow();
        }
        item = slideshow[currentSlide];
        currentSlide = (currentSlide + 1) % slideshow.length;
        var $item = item.generateItemHTML();
        $slideshow.append($item);
        if (item.type == "video") {
            $item.on("ended", function () {
                app.loadNextSlide();
            });
            app.scaleToFill($item);
            $item[0].play();
            $item[0].pause();
        }
        $item.transition({ opacity: 1 }, 1000, "linear", function () {
            if ($slideshow.children().length > 1) {
                $slideshow.children().first().remove();
            }
            if (item.type == "image") {
                timer = setTimeout(app.loadNextSlide, 5000);
            }
            else {
                $item[0].play();
            }
        });
    };

    app.scaleToFill = function($video) {
        var videoRatio = 16/9;
        var tagRatio = $video.width() / $video.height();
        if (videoRatio < tagRatio) {
            $video.css('transform','scaleX(' + tagRatio / videoRatio  + ')');
        }
        else if (tagRatio < videoRatio) {
            $video.css('transform', 'scaleY(' + videoRatio / tagRatio + ')');
        }
    };

    app.reloadSlideshow = function () {
        if (updateTimer == undefined) {
            console.log("updateTimer is undefined, not reloading show");
            return;
        }
        slideshow = slideshowLoader;
        slideshowLoader = [];
        currentSlide = 0;
        if (initializing) {
            initializing = false;
            app.loadNextSlide();
        }
        loading = false;
        updateReady = false;
    };

    app.checkLoadStatus = function () {
        var finished = true;
        $.each(slideshowLoader, function () {
            if (this.status == 0) {
                finished = false;
                return false;
            }
        });
        if (!finished) {
            setTimeout(app.checkLoadStatus, 100);
        }
        else {
            var appData = Windows.Storage.ApplicationData.current;
            var localFolder = appData.localFolder;
            var currentLoader = slideshowLoader;
            localFolder.getFilesAsync().done(function (files) {
                files.forEach(function forEachFile(file) {
                    var filename = file.name;
                    if (filename == "json.txt") {
                        return;
                    }
                    var remove = true;
                    $.each(currentLoader, function () {
                        if (filename == this.filename) {
                            remove = false;
                            return false;
                        }
                    });
                    if (remove) {
                        file.deleteAsync().done(function () {
                            console.log("removed " + filename);
                        });
                    }
                });
            });
            if (initializing) {
                console.log("Initializing");
                app.reloadSlideshow();
            }
            else {
                console.log("Update is ready.");
                updateReady = true;
            }
        }
    };

    app.writeJSON = function (text, json) {
        var appData = Windows.Storage.ApplicationData.current;
        var localFolder = appData.localFolder;
        localFolder.createFileAsync("json.txt", Windows.Storage.CreationCollisionOption.replaceExisting).then(function (file) {
            if (file !== null) {
                Windows.Storage.FileIO.writeTextAsync(file, text).done(function () {
                    loadedJSON = text;
                    app.loadCountdowns(json);
                    app.loadItems(json);
                });
            }
        });
    };

    app.readJSON = function () {
        var applicationData = Windows.Storage.ApplicationData.current;
        var localFolder = applicationData.localFolder;
        Windows.Storage.ApplicationData.current.localFolder.tryGetItemAsync("json.txt").done(function (file) {
            Windows.Storage.FileIO.readTextAsync(file).done(function (text) {
                try {
                    var data = JSON.parse(text);
                    loadedJSON = text;
                    app.loadCountdowns(data);
                    app.loadItems(data);
                } catch (Exception) {
                    alert("Cached json is corrupt.");
                }
            });
        }, function (error) {
            alert("Offline and no cache.");
        });
    };

    app.loadItems = function (data) {
        $.each(data.items, function () {
            if (updateTimer == undefined) {
                console.log("updateTimer is undefined, aborting current loading of items.");
                return false;
            }
            var path;
            var url = this.url;
            var filename = url.substring(url.lastIndexOf('/') + 1);
            var server_md5sum = this.md5sum;
            var uri;
            try {
                uri = new Windows.Foundation.Uri(url);
            }
            catch (Exception) {
                console.log("malformed url");
                return;
            }
            if (uri.schemeName != "https") {
                console.log("url must be using https");
                return;
            }
            var path = Windows.Storage.ApplicationData.current.localFolder.path + "\\" + filename;
            var item = new Item(uri, this.type, filename, path);
            slideshowLoader.push(item);
            var length = slideshowLoader.length
            Windows.Storage.ApplicationData.current.localFolder.tryGetItemAsync(filename).done(function (file) {
                if (updateTimer == undefined) {
                    console.log("updateTimer is undefined, no need to load items.");
                    return;
                }
                var item = slideshowLoader[length - 1];
                if (file !== null) {
                    var hashProvider = Windows.Security.Cryptography.Core.HashAlgorithmProvider.openAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.md5);
                    Windows.Storage.FileIO.readBufferAsync(file).then(
                        function (buffer) {
                            if (updateTimer == undefined) {
                                console.log("updateTimer is undefined, no need to verify existing item.");
                                return;
                            }
                            var outputBuffer = hashProvider.hashData(buffer);
                            var md5sum = Windows.Security.Cryptography.CryptographicBuffer.encodeToHexString(outputBuffer);
                            if (md5sum != server_md5sum) {
                                app.loadItem(item);
                            }
                            else {
                                item.status = 1;
                                app.loadItem(item);
                            }
                        }
                    );
                }
                else {
                    app.loadItem(item);
                }
            });
        });
        if (updateTimer == undefined) {
            console.log("updateTimer is undefined, no need to check current load status.");
            return;
        }
        setTimeout(app.checkLoadStatus, 100);
    };

    app.loadCountdowns = function (data) {
        countdowns = [];
        if (data.hasOwnProperty("countdowns")) {
            $.each(data.countdowns, function () {
                var countdown = new Countdown(this.day, this.hour, this.minute, this.duration);
                countdowns.push(countdown);
            });
            if (countdownTimer == undefined) {
                countdownTimer = setInterval(app.updateCountdown, 100);
            }
        }
    }

    app.ToggleFullscreen = function () {
        var view = ApplicationView.getForCurrentView();
        if (!view.isFullScreen) {
            view.tryEnterFullScreenMode();
        }
        else {
            view.exitFullScreenMode();
        }
    };

    app.toHHMMSS = function (value) {
        var sec_num = parseInt(value, 10); // don't forget the second param
        var hoursInt = Math.floor(sec_num / 3600);
        var minutes = Math.floor((sec_num - (hoursInt * 3600)) / 60);
        var seconds = sec_num - (hoursInt * 3600) - (minutes * 60);
        var hours;

        if (hoursInt < 10) { hours = "0" + hoursInt + ":"; }
        else { hoursInt = hoursInt + ":"; }
        if (hoursInt < 1) { hours = ""; }
        if (minutes < 10) { minutes = "0" + minutes; }
        if (seconds < 10) { seconds = "0" + seconds; }
        var time = hours + minutes + ':' + seconds;
        return time;
    };

    app.updateCountdown = function () {
        var now = new Date();
        // javascript day of week starts at 0 instead of 1
        var day = now.getDay() + 1;
        var seconds = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();
        var hide = true;
        var $countdown = $("#countdown");
        $.each(countdowns, function () {
            var countdown = this;
            if (day != countdown.day) {
                return true;
            }
            var countdownSeconds = countdown.hour * 3600 + countdown.minute * 60;
            var difference = countdownSeconds - seconds;
            var duration = countdown.duration * 60;
            if (difference > 0 && difference < duration) {
                hide = false;
                $countdown.html(app.toHHMMSS(difference));
                return false;
            }
        });
        if (hide) {
            $countdown.hide();
        }
        else {
            $countdown.show();
        }
    };

    app.loadJSON = function (url) {
        // check if still processing the last load request and return if so
        if (loading) {
            return;
        }
        loading = true;
        var uri;
        try {
            uri = new Windows.Foundation.Uri(url);
        }
        catch (Exception) {
            alert("url is malformed", function (value) {
                $("#addressBox").focus();
            });
            return;
        }
        if (uri.schemeName != "https") {
            alert("only https is supported", function (value) {
                $("#addressBox").focus();
            });
            return;
        }
        var httpClient = new Windows.Web.Http.HttpClient();
        httpClient.defaultRequestHeaders.userAgent.parseAdd("Digital Signage");
        httpClient.getStringAsync(uri).then(
            function (response) {
                try {
                    var json = JSON.parse(response);
                    $("#form").hide();
                    if (updateTimer == undefined) {
                        console.log("Setting updateTimer.");
                        updateTimer = setInterval(app.loadJSON, 30000, url);
                    }
                }
                catch (e) {
                    alert("Could not parse response as JSON", function (value) {
                        $("#form").show();
                        $("#addressBox").focus();
                    });
                    return;
                }
                var appData = Windows.Storage.ApplicationData.current.localSettings;
                appData.values["url"] = url;
                if (loadedJSON == "") {
                    return app.writeJSON(response, json);
                }
                if (!initializing && loadedJSON == response) {
                    console.log("No changes.");
                    loading = false;
                    return;
                }
                console.log("loading changes");
                app.writeJSON(response, json);
            },
            function (error) {
                if (loadedJSON == "") {
                    app.readJSON();
                }
                else {
                    loading = false;
                }
            }
        );
    };

    app.hideCursor = function () {
        $("body").addClass("hideCursor");
    };

    app.reset = function () {
        console.log("Resetting app");
        initializing = true;
        loading = false;
        updateTimer = clearInterval(updateTimer);
        if (countdownTimer != undefined) {
            countdownTimer = clearInterval(countdownTimer);
        }
        $("#countdown").hide();
        $("#slideshow").children().each(function () {
            $(this).remove();
        });
        $("#form").show();
        $("#addressBox").focus();
    };

    app.loadAddress = function () {
        if (timer != undefined) {
            clearTimeout(timer);
        }
        app.loadJSON($("#addressBox")[0].value);
    };

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            var view = ApplicationView.getForCurrentView();
            if (!view.isFullScreen) {
                view.tryEnterFullScreenMode();
            }
            var appData = Windows.Storage.ApplicationData.current.localSettings;
            $("#countdown").hide();
            $("#goButton").on("click", function(e) {
                app.loadAddress();
            });
            $("#addressBox").on("keydown", function (e) {
                if (e.keyCode == 13) {
                    e.preventDefault();
                    app.loadAddress();
                }
            });
            if (appData.values["url"]) {
                var url = appData.values["url"];
                $("#addressBox").val(url);
                app.loadAddress();
            }

            $("body").on("keyup", function (e) {
                switch (e.keyCode) {
                    case 122: {
                        app.ToggleFullscreen();
                    }
                    case 76: {
                        if (e.ctrlKey) {
                            app.reset();
                        }
                    }
                }
            });
            $(window).on("resize", function (e) {
                $("video").each(function () {
                    app.scaleToFill($(this));
                });
            });
            mouseTimer = setTimeout(app.hideCursor, 5000);
            $("body").on("mousemove", function (e) {
                if (e.pageX != cursorPositionX || e.pageY != cursorPositionY) {
                    cursorPositionX = e.pageX;
                    cursorPositionY = e.pageY;
                    if (mouseTimer != undefined) {
                        mouseTimer = clearTimeout(mouseTimer);
                    }
                    mouseTimer = setTimeout(app.hideCursor, 5000);
                    $(this).removeClass("hideCursor");
                }
            });
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
    };

    app.start();
})();<|endoftext|>