<commit_before>(function ($, O2) {
    /**
     * @property bar.Ctrl
     */
    O2.createClass('bar.Ctrl', {
        $nbCarte : null,
        $diviser : null,
        $reset: null,
        $login: null,
        $glass: null,
        // $algoSelector : null,
        oView : null,
        __construct : function(oView) {
            var self = this;
            if (!oView) { return; }
            this.oView = oView;
            this.$contentWrapper = $('#contentWrapper');
            // Reset
            this.$reset = $('#resetBtn')
                .on('click', function() {
                    var holdForm = self._serializeForm();
                    self.$contentWrapper[0].reset();
                    self.$contentWrapper.trigger('change');
                    self.$contentWrapper.find('input').trigger('change');
                    Materializer.toast({
                        toast : {
                            message : 'La commande a été vidée'
                        },
                        btn : [
                            {
                                label: 'Annuler',
                                color: 'red',
                                click: function() {
                                    self.$contentWrapper.deserializeObject(holdForm);
                                }
                            }
                        ]
                    });
                });
            this.$nbCarte = $('#nbCarte');
            // this.$algoSelector = $('#algoSelector');
            this.$restore = $('#restoreBtn')
                .on('click', function() {
                    var oHistory = bar.helper.storage.import();
                    delete oHistory.tmp;
                    oView.showHistory(oHistory);
                });
            this.$diviser = $('#diviserBtn')
                .on('click', function() {
                    var val = +self.$nbCarte.val();
                    // var algo = self.$algoSelector.val();
                    var oCommande = self._serializeForm();
                    oCommande = new bar.Commande(oCommande);
                    oView.showFacture(oCommande, val);
                });
            this.$login = $('#loginBtn')
                .on('click', function() {
                    var $modalContent = $('
');
                    if (bar.store.login) {
                        // Modify
                        $('<form class="col s12 active">
' +
                            '

' +
                            '
<input id="m-username" name="username" value="'+ bar.store.login.username +'" type="text">Username
' +
                            '
<input id="m-password" name="password" value="" type="password">Password (vide = pas de modification)
' +
                            '
<input id="m-label" name="label" value="'+ bar.store.login.label +'" type="text">Label
' +
                            '
<input id="m-password2" value="" type="password">Confirmez password
' +
                            '<input class="hide" type="submit" />' +
                            '
</form>')
                            .on('submit', function (e) {
                                e.preventDefault();
                                var $this = $(this);
                                var data = $this.serializeObject();
                                if ($this.find("#m-password2").val() !== data.password) {
                                    Materialize.toast('Les mots de passe ne sont pas identique',2000);
                                    return;
                                }
                                data.id = bar.store.login.id;
                                if (!data.password) {
                                    delete data.password;
                                }
                                self.flushProfile(data)
                                    .done(function () {
                                        Materialize.toast('Votre profil à été mis à jour', 2000);
                                        self.oView.makeUserAddons();
                                        $modal.modal('close');
                                    });
                            })
                            .appendTo($modalContent)
                            .find('#logoutBtn')
                                .on('click', function() {
                                    Materializer.ajax(bar.config.API_URL + 'logout')
                                        .done(function () {
                                            bar.store.login = null;
                                            Materialize.toast('Vous êtes déconnecté', 2000);
                                            $modal.modal('close');
                                        });
                                });
                    } else {
                        var $tabsWrapper = $('
').appendTo($modalContent);

                        // Login
                        $('
Login
').appendTo($tabsWrapper);
                        $('<form id="log" class="col s12">
' +
                            '
<input id="l-username" name="username" type="text">Login
' +
                            '
<input id="l-password" name="password" type="password">Password
' +
                            '<input class="hide" type="submit" />' +
                            '
</form>')
                            .on('submit', function (e) {
                                e.preventDefault();
                                var data = $(this).serializeArray();
                                Materializer.ajax({
                                    url: bar.config.API_URL + 'login',
                                    method: 'POST',
                                    data: data
                                })
                                    .done(function (data) {
                                        bar.store.login = bar.store.users[data.id];
                                        Materialize.toast('Bonjour ' + data.label, 2000);
                                        $modal.modal('close');
                                    });
                            })
                            .appendTo($modalContent);

                        // Register
                        $('
S\'enregistrer
').appendTo($tabsWrapper);
                        $('<form id="register" class="col s12">
' +
                            '
<input id="r-username" name="username" type="text">Login
' +
                            '
<input id="r-password" name="password"  type="password">Password
' +
                            '<input class="hide" type="submit" />' +
                            '
</form>')
                            .on('submit', function (e) {
                                e.preventDefault();
                                var data = $(this).serializeObject();
                                if (data.username) {
                                    data.label = data.username;
                                }
                                self.flushProfile(data)
                                    .done(function (data) {
                                        Materialize.toast('Bienvenue ' + data.label, 2000);
                                        self.oView.makeUserAddons();
                                        $modal.modal('close');
                                    });
                            })
                            .appendTo($modalContent);
                    }
                    var $modal = Materializer.createModal({
                        content: $modalContent,
                        type: 'bottom-sheet with-tabs',
                        footer: {
                            "Ok" : {
                                callback: function($m, $b) {
                                    $b.on('click', function() {
                                        $m.find('form.active').trigger('submit');
                                    });
                                }
                            }
                        }
                    });
                });
            $('.help').on('click', function(e) {
                e.preventDefault();
                self.discover();
            });
            var favTimeout = null;
            this.$contentWrapper.on('change', function() {
                var oForm = self._serializeForm();
                if (oForm.cmd) {
                    oForm.cmd = oForm.cmd.filter(bar.helper.filter.empty);
                    if (!oForm.cmd.length) {
                        delete oForm.cmd;
                    }
                }
                var fav = [];
                if (oForm.fav) {
                    fav = oForm.fav;
                    delete oForm.fav;
                }
                if (bar.store.login) {
                    if (favTimeout) {
                        clearTimeout(favTimeout);
                    }
                    favTimeout = setTimeout(function () {
                        if (JSON.stringify(bar.store.login.pref) !== JSON.stringify(fav.map(function (v) { return +v; }))) {
                            self.flushProfile({
                                id: bar.store.login.id,
                                pref: fav.map(function (v) {
                                    return {"id": v};
                                })
                            }).done(function () {
                                Materialize.toast('Vos favoris ont été persistés', 2000);
                                self.oView.makeUserAddons();
                            });
                        }
                    }, 2000);
                }
                if ($.isEmptyObject(oForm)) {
                    self.$diviser.removeClass('scale-in').addClass('scale-out');
                    self.$reset.removeClass('scale-in').addClass('scale-out');

                    self.$restore.removeClass('scale-out').addClass('scale-in');

                    bar.helper.storage.export({'tmp': null });
                } else {
                    self.$diviser.removeClass('scale-out').addClass('scale-in');
                    self.$reset.removeClass('scale-out').addClass('scale-in');

                    self.$restore.removeClass('scale-in').addClass('scale-out');

                    bar.helper.storage.export({'tmp': self._serializeForm() });
                }
            });

            this.init();
        },
        init: function () {
            var self = this;
            Materializer.ajax(bar.config.API_URL)
                .done(function (data) {
                    bar.store = data;
                    Materializer.ajax(bar.config.API_URL +'login')
                        .done(function (data) {
                            if (data) {
                                bar.store.login = bar.store.users[data.id];
                                $.extend(bar.store.login, data);
                                Materialize.toast('Bonjour '+ data.label, 2000);
                            }
                        })
                        .always(function () {
                            self.oView.showHome();
                            self.oView.makeUserAddons();

                            $('input[type="number"]')
                                .on('click', function() {
                                    this.select();
                                })
                                .on('change', function() {
                                    var $this = $(this);
                                    if (+$this.val() < 0) {
                                        Materialize.toast('Le bar ne fait pas crédit !', 2000);
                                        $this.val(0);
                                    }
                                    var $cBody = $this.closest('.collapsible-body');
                                    var tot = $cBody.find('input[type="number"]').serializeArray().reduce(function(a, v) {
                                        return a + (+v.value);
                                    }, 0);
                                    $cBody.siblings('.collapsible-header').find('.badge').text(tot ? tot:'');
                                });
                            $('select').material_select();

                            var oStorage = bar.helper.storage.import();
                            if (oStorage) {
                                if (oStorage.tmp) {
                                    self.$contentWrapper.deserializeObject(oStorage.tmp);
                                    Materialize.toast('Commande temporaire restaurée', 2000);
                                }
                            } else {
                                this.discover();
                            }
                            self.$contentWrapper.materializeLayout();
                            $('.splash').addClass('disappear');
                        });
                });
            this.$glass = $('#glass').one('click', function() {
                self.easterEgg();
            });
        },
        flushProfile: function(data) {
            if ($.isPlainObject(data)) {
                var url;
                if (data.id) {
                    url = bar.config.API_URL + 'user';
                } else {
                    url = bar.config.API_URL + 'register';
                }
                return Materializer.ajax({
                    url: url,
                    method: 'POST',
                    data: JSON.stringify(data),
                    contentType: 'application/json'
                })
                    .done(function (data) {
                        var target = bar.store.users[data.id];
                        if (target) {
                            $.extend(target, data);
                        } else {
                            bar.store.users[data.id] = bar.store.login = data;
                        }
                    });
            }
            return null;
        },
        _serializeForm : function() {
            return this.$contentWrapper.serializeObject();
        },
        discover: function() {
            var id;
            if (this.$diviser.hasClass('scale-in')) {
                id = 'diviser';
            } else {
                id = 'restore';
            }
            $('.tap-target[data-activates="'+ id +'"]').tapTarget('open');
        },
        easterEgg: function() {
            var self = this;
            var $glass = this.$glass;
            var gameOver = false;
            var start = null;
            var alpha = 0;
            var facteurAcceleration = 1;
            var cssLeft = $glass.css('left');
            var left = $glass.offset().left;
            var borneMin = -250;
            var borneMax = window.innerWidth;
            window.addEventListener('devicemotion', function(e) {
                alpha = - e.accelerationIncludingGravity.x * facteurAcceleration;
            });

            function moveGlass(timestamp) {
                if (start === null) start = timestamp;
                if (left < borneMin || borneMax < left) {
                    gameOver = true;
                }
                if (timestamp - start >= facteurAcceleration * 5000) {
                    facteurAcceleration++;
                }
                if (!gameOver) {
                    left = left + Math.round(alpha);
                    $glass.css('left', left);
                    requestAnimationFrame(moveGlass);
                } else {
                    Materialize.toast('Score : '+ parseInt(timestamp - start) / 1000 +'s', 2000);
                    start = null;
                    left = $glass.css('left', cssLeft).offset().left;
                    gameOver = false;
                    facteurAcceleration = 1;
                    $glass.one('click', function() {
                        requestAnimationFrame(moveGlass);
                    })
                }
            }
            requestAnimationFrame(moveGlass);
        }
    });
})(jQuery, O2);<commit_msg>Petit easter egg ;-)<commit_after>(function ($, O2) {
    /**
     * @property bar.Ctrl
     */
    O2.createClass('bar.Ctrl', {
        $nbCarte : null,
        $diviser : null,
        $reset: null,
        $login: null,
        $glass: null,
        // $algoSelector : null,
        oView : null,
        __construct : function(oView) {
            var self = this;
            if (!oView) { return; }
            this.oView = oView;
            this.$contentWrapper = $('#contentWrapper');
            // Reset
            this.$reset = $('#resetBtn')
                .on('click', function() {
                    var holdForm = self._serializeForm();
                    self.$contentWrapper[0].reset();
                    self.$contentWrapper.trigger('change');
                    self.$contentWrapper.find('input').trigger('change');
                    Materializer.toast({
                        toast : {
                            message : 'La commande a été vidée'
                        },
                        btn : [
                            {
                                label: 'Annuler',
                                color: 'red',
                                click: function() {
                                    self.$contentWrapper.deserializeObject(holdForm);
                                }
                            }
                        ]
                    });
                });
            this.$nbCarte = $('#nbCarte');
            // this.$algoSelector = $('#algoSelector');
            this.$restore = $('#restoreBtn')
                .on('click', function() {
                    var oHistory = bar.helper.storage.import();
                    delete oHistory.tmp;
                    oView.showHistory(oHistory);
                });
            this.$diviser = $('#diviserBtn')
                .on('click', function() {
                    var val = +self.$nbCarte.val();
                    // var algo = self.$algoSelector.val();
                    var oCommande = self._serializeForm();
                    oCommande = new bar.Commande(oCommande);
                    oView.showFacture(oCommande, val);
                });
            this.$login = $('#loginBtn')
                .on('click', function() {
                    var $modalContent = $('
');
                    if (bar.store.login) {
                        // Modify
                        $('<form class="col s12 active">
' +
                            '

' +
                            '
<input id="m-username" name="username" value="'+ bar.store.login.username +'" type="text">Username
' +
                            '
<input id="m-password" name="password" value="" type="password">Password (vide = pas de modification)
' +
                            '
<input id="m-label" name="label" value="'+ bar.store.login.label +'" type="text">Label
' +
                            '
<input id="m-password2" value="" type="password">Confirmez password
' +
                            '<input class="hide" type="submit" />' +
                            '
</form>')
                            .on('submit', function (e) {
                                e.preventDefault();
                                var $this = $(this);
                                var data = $this.serializeObject();
                                if ($this.find("#m-password2").val() !== data.password) {
                                    Materialize.toast('Les mots de passe ne sont pas identique',2000);
                                    return;
                                }
                                data.id = bar.store.login.id;
                                if (!data.password) {
                                    delete data.password;
                                }
                                self.flushProfile(data)
                                    .done(function () {
                                        Materialize.toast('Votre profil à été mis à jour', 2000);
                                        self.oView.makeUserAddons();
                                        $modal.modal('close');
                                    });
                            })
                            .appendTo($modalContent)
                            .find('#logoutBtn')
                                .on('click', function() {
                                    Materializer.ajax(bar.config.API_URL + 'logout')
                                        .done(function () {
                                            bar.store.login = null;
                                            Materialize.toast('Vous êtes déconnecté', 2000);
                                            $modal.modal('close');
                                        });
                                });
                    } else {
                        var $tabsWrapper = $('
').appendTo($modalContent);

                        // Login
                        $('
Login
').appendTo($tabsWrapper);
                        $('<form id="log" class="col s12">
' +
                            '
<input id="l-username" name="username" type="text">Login
' +
                            '
<input id="l-password" name="password" type="password">Password
' +
                            '<input class="hide" type="submit" />' +
                            '
</form>')
                            .on('submit', function (e) {
                                e.preventDefault();
                                var data = $(this).serializeArray();
                                Materializer.ajax({
                                    url: bar.config.API_URL + 'login',
                                    method: 'POST',
                                    data: data
                                })
                                    .done(function (data) {
                                        bar.store.login = bar.store.users[data.id];
                                        $.extend(bar.store.login, data);
                                        Materialize.toast('Bonjour ' + data.label, 2000);
                                        $modal.modal('close');
                                    });
                            })
                            .appendTo($modalContent);

                        // Register
                        $('
S\'enregistrer
').appendTo($tabsWrapper);
                        $('<form id="register" class="col s12">
' +
                            '
<input id="r-username" name="username" type="text">Login
' +
                            '
<input id="r-password" name="password"  type="password">Password
' +
                            '<input class="hide" type="submit" />' +
                            '
</form>')
                            .on('submit', function (e) {
                                e.preventDefault();
                                var data = $(this).serializeObject();
                                if (data.username) {
                                    data.label = data.username;
                                }
                                self.flushProfile(data)
                                    .done(function (data) {
                                        Materialize.toast('Bienvenue ' + data.label, 2000);
                                        self.oView.makeUserAddons();
                                        $modal.modal('close');
                                    });
                            })
                            .appendTo($modalContent);
                    }
                    var $modal = Materializer.createModal({
                        content: $modalContent,
                        type: 'bottom-sheet with-tabs',
                        footer: {
                            "Ok" : {
                                callback: function($m, $b) {
                                    $b.on('click', function() {
                                        $m.find('form.active').trigger('submit');
                                    });
                                }
                            }
                        }
                    });
                });
            $('.help').on('click', function(e) {
                e.preventDefault();
                self.discover();
            });
            var favTimeout = null;
            this.$contentWrapper.on('change', function() {
                var oForm = self._serializeForm();
                if (oForm.cmd) {
                    oForm.cmd = oForm.cmd.filter(bar.helper.filter.empty);
                    if (!oForm.cmd.length) {
                        delete oForm.cmd;
                    }
                }
                var fav = [];
                if (oForm.fav) {
                    fav = oForm.fav;
                    delete oForm.fav;
                }
                if (bar.store.login) {
                    if (favTimeout) {
                        clearTimeout(favTimeout);
                    }
                    favTimeout = setTimeout(function () {
                        if (JSON.stringify(bar.store.login.pref) !== JSON.stringify(fav.map(function (v) { return +v; }))) {
                            self.flushProfile({
                                id: bar.store.login.id,
                                pref: fav.map(function (v) {
                                    return {"id": v};
                                })
                            }).done(function () {
                                Materialize.toast('Vos favoris ont été persistés', 2000);
                                self.oView.makeUserAddons();
                            });
                        }
                    }, 2000);
                }
                if ($.isEmptyObject(oForm)) {
                    self.$diviser.removeClass('scale-in').addClass('scale-out');
                    self.$reset.removeClass('scale-in').addClass('scale-out');

                    self.$restore.removeClass('scale-out').addClass('scale-in');

                    bar.helper.storage.export({'tmp': null });
                } else {
                    self.$diviser.removeClass('scale-out').addClass('scale-in');
                    self.$reset.removeClass('scale-out').addClass('scale-in');

                    self.$restore.removeClass('scale-in').addClass('scale-out');

                    bar.helper.storage.export({'tmp': self._serializeForm() });
                }
            });

            this.init();
        },
        init: function () {
            var self = this;
            Materializer.ajax(bar.config.API_URL)
                .done(function (data) {
                    bar.store = data;
                    Materializer.ajax(bar.config.API_URL +'login')
                        .done(function (data) {
                            if (data) {
                                bar.store.login = bar.store.users[data.id];
                                $.extend(bar.store.login, data);
                                Materialize.toast('Bonjour '+ data.label, 2000);
                            }
                        })
                        .always(function () {
                            self.oView.showHome();
                            self.oView.makeUserAddons();

                            $('input[type="number"]')
                                .on('click', function() {
                                    this.select();
                                })
                                .on('change', function() {
                                    var $this = $(this);
                                    if (+$this.val() < 0) {
                                        Materialize.toast('Le bar ne fait pas crédit !', 2000);
                                        $this.val(0);
                                    }
                                    var $cBody = $this.closest('.collapsible-body');
                                    var tot = $cBody.find('input[type="number"]').serializeArray().reduce(function(a, v) {
                                        return a + (+v.value);
                                    }, 0);
                                    $cBody.siblings('.collapsible-header').find('.badge').text(tot ? tot:'');
                                });
                            $('select').material_select();

                            var oStorage = bar.helper.storage.import();
                            if (oStorage) {
                                if (oStorage.tmp) {
                                    self.$contentWrapper.deserializeObject(oStorage.tmp);
                                    Materialize.toast('Commande temporaire restaurée', 2000);
                                }
                            } else {
                                this.discover();
                            }
                            self.$contentWrapper.materializeLayout();
                            $('.splash').addClass('disappear');
                        });
                });
            this.$glass = $('#glass').one('click', function() {
                self.easterEgg();
            });
        },
        flushProfile: function(data) {
            if ($.isPlainObject(data)) {
                var url;
                if (data.id) {
                    url = bar.config.API_URL + 'user';
                } else {
                    url = bar.config.API_URL + 'register';
                }
                return Materializer.ajax({
                    url: url,
                    method: 'POST',
                    data: JSON.stringify(data),
                    contentType: 'application/json'
                })
                    .done(function (data) {
                        var target = bar.store.users[data.id];
                        if (target) {
                            $.extend(target, data);
                        } else {
                            bar.store.users[data.id] = bar.store.login = data;
                        }
                    });
            }
            return null;
        },
        _serializeForm : function() {
            return this.$contentWrapper.serializeObject();
        },
        discover: function() {
            var id;
            if (this.$diviser.hasClass('scale-in')) {
                id = 'diviser';
            } else {
                id = 'restore';
            }
            $('.tap-target[data-activates="'+ id +'"]').tapTarget('open');
        },
        easterEgg: function() {
            var self = this;
            var $glass = this.$glass;
            var gameOver = false;
            var start = null;
            var alpha = 0;
            var facteurAcceleration = 1;
            var cssLeft = $glass.css('left');
            var left = $glass.offset().left;
            var borneMin = -250;
            var borneMax = window.innerWidth;
            window.addEventListener('deviceorientation', function(e) {
                alpha = e.gamma * facteurAcceleration;
            });

            function moveGlass(timestamp) {
                if (start === null) start = timestamp;
                if (left < borneMin || borneMax < left) {
                    gameOver = true;
                }
                if (timestamp - start >= facteurAcceleration * 5000) {
                    facteurAcceleration++;
                }
                if (!gameOver) {
                    left = left + Math.round(alpha);
                    $glass.css('left', left);
                    requestAnimationFrame(moveGlass);
                } else {
                    Materialize.toast('Score : '+ parseInt(timestamp - start) / 1000 +'s', 2000);
                    start = null;
                    left = $glass.css('left', cssLeft).offset().left;
                    gameOver = false;
                    facteurAcceleration = 1;
                    $glass.one('click', function() {
                        requestAnimationFrame(moveGlass);
                    })
                }
            }
            requestAnimationFrame(moveGlass);
        }
    });
})(jQuery, O2);<|endoftext|>


<commit_before>'use strict';
/*===========================
Framework 7
===========================*/
window.Framework7 = function (params) {

    // App
    var app = this;

    // Anim Frame
    app._animFrame = function (callback) {
        if (window.requestAnimationFrame) return window.requestAnimationFrame(callback);
        else if (window.webkitRequestAnimationFrame) return window.webkitRequestAnimationFrame(callback);
        else if (window.mozRequestAnimationFrame) return window.mozRequestAnimationFrame(callback);
        else {
            return window.setTimeout(callback, 1000 / 60);
        }
    };

    // Default Parameters
    app.params = {
        cache: true,
        cacheDuration: 1000 * 60 * 10, // Ten minutes
        preloadPreviousPage: true,
        // Push State
        pushState: false,
        // Fast clicks
        fastClicks : true,
        // Animate Nav Back Icon
        animateNavBackIcon: false,
        // Swipe Back
        swipeBackPage: true,
        swipeBackPageThreshold: 0,
        swipeBackPageActiveArea: 30,
        swipeBackPageBoxShadow: true,
        // Ajax
        ajaxLinks: false, // or CSS selector
        // Pull To Refresh
        pullToRefresh: true,
        // Swipeout
        swipeout: true,
        swipeoutNoFollow: false,
        // Smart Select Back link template
        smartSelectBackTemplate: '
Back
',
        // Panels
        swipePanel: false, // or 'left' or 'right'
        swipePanelNoFollow: false,
        swipePanelThreshold: 0,
        panelsCloseByOutside: true,
        panelsVisibleZIndex: 6000,
        // Modals
        modalTemplate: '
' +
                            '
' +
                                '{{if title}}
{{title}}
{{/if title}}' +
                                '
{{text}}
' +
                                '{{afterText}}' +
                            '
' +
                            '
{{buttons}}
' +
                        '
',
        modalActionsTemplate: '
{{buttons}}
',
        modalButtonOk: 'OK',
        modalButtonCancel: 'Cancel',
        modalTitle: 'Framework7',
        modalCloseByOutside: false,
        modalActionsCloseByOutside: true,
        modalPopupCloseByOutside: true,
        modalPreloaderTitle: 'Loading... ',
        // Auto init
        init: true,
        // Name space
        viewClass: 'view',
        viewMainClass: 'view-main',
        viewsClass: 'views',
    };

    // Extend defaults with parameters
    for (var param in params) {
        app.params[param] = params[param];
    }

    // Expose DOM lib
    app.$ = $;

    // Touch events
    app.touchEvents = {
        start: $.supportTouch ? 'touchstart' : 'mousedown',
        move: $.supportTouch ? 'touchmove' : 'mousemove',
        end: $.supportTouch ? 'touchend' : 'mouseup'
    };

    // Link to local storage
    app.ls = localStorage;
    <commit_msg>"sliding" class on smart select template<commit_after>'use strict';
/*===========================
Framework 7
===========================*/
window.Framework7 = function (params) {

    // App
    var app = this;

    // Anim Frame
    app._animFrame = function (callback) {
        if (window.requestAnimationFrame) return window.requestAnimationFrame(callback);
        else if (window.webkitRequestAnimationFrame) return window.webkitRequestAnimationFrame(callback);
        else if (window.mozRequestAnimationFrame) return window.mozRequestAnimationFrame(callback);
        else {
            return window.setTimeout(callback, 1000 / 60);
        }
    };

    // Default Parameters
    app.params = {
        cache: true,
        cacheDuration: 1000 * 60 * 10, // Ten minutes
        preloadPreviousPage: true,
        // Push State
        pushState: false,
        // Fast clicks
        fastClicks : true,
        // Animate Nav Back Icon
        animateNavBackIcon: false,
        // Swipe Back
        swipeBackPage: true,
        swipeBackPageThreshold: 0,
        swipeBackPageActiveArea: 30,
        swipeBackPageBoxShadow: true,
        // Ajax
        ajaxLinks: false, // or CSS selector
        // Pull To Refresh
        pullToRefresh: true,
        // Swipeout
        swipeout: true,
        swipeoutNoFollow: false,
        // Smart Select Back link template
        smartSelectBackTemplate: '
Back
',
        // Panels
        swipePanel: false, // or 'left' or 'right'
        swipePanelNoFollow: false,
        swipePanelThreshold: 0,
        panelsCloseByOutside: true,
        panelsVisibleZIndex: 6000,
        // Modals
        modalTemplate: '
' +
                            '
' +
                                '{{if title}}
{{title}}
{{/if title}}' +
                                '
{{text}}
' +
                                '{{afterText}}' +
                            '
' +
                            '
{{buttons}}
' +
                        '
',
        modalActionsTemplate: '
{{buttons}}
',
        modalButtonOk: 'OK',
        modalButtonCancel: 'Cancel',
        modalTitle: 'Framework7',
        modalCloseByOutside: false,
        modalActionsCloseByOutside: true,
        modalPopupCloseByOutside: true,
        modalPreloaderTitle: 'Loading... ',
        // Auto init
        init: true,
        // Name space
        viewClass: 'view',
        viewMainClass: 'view-main',
        viewsClass: 'views',
    };

    // Extend defaults with parameters
    for (var param in params) {
        app.params[param] = params[param];
    }

    // Expose DOM lib
    app.$ = $;

    // Touch events
    app.touchEvents = {
        start: $.supportTouch ? 'touchstart' : 'mousedown',
        move: $.supportTouch ? 'touchmove' : 'mousemove',
        end: $.supportTouch ? 'touchend' : 'mouseup'
    };

    // Link to local storage
    app.ls = localStorage;
    <|endoftext|>


<commit_before>    start: function (e) {
      var target = e.target;

      if ($(target).is('img')) {
        this.target = target;
        this.show();
      }
    },

    click: function (e) {
      var $target = $(e.target);
      var action = $target.data('action');
      var image = this.image;

      switch (action) {
        case 'mix':
          if (this.isPlayed) {
            this.stop();
          } else {
            if (this.options.inline) {
              if (this.isFulled) {
                this.exit();
              } else {
                this.full();
              }
            } else {
              this.hide();
            }
          }

          break;

        case 'view':
          this.view($target.data('index'));
          break;

        case 'zoom-in':
          this.zoom(0.1, true);
          break;

        case 'zoom-out':
          this.zoom(-0.1, true);
          break;

        case 'one-to-one':
          this.toggle();
          break;

        case 'reset':
          this.reset();
          break;

        case 'prev':
          this.prev();
          break;

        case 'play':
          this.play();
          break;

        case 'next':
          this.next();
          break;

        case 'rotate-left':
          this.rotate(-90);
          break;

        case 'rotate-right':
          this.rotate(90);
          break;

        case 'flip-horizontal':
          this.scaleX(-image.scaleX || -1);
          break;

        case 'flip-vertical':
          this.scaleY(-image.scaleY || -1);
          break;

        default:
          if (this.isPlayed) {
            this.stop();
          }
      }
    },

    load: function () {
      var options = this.options;
      var viewer = this.viewer;
      var $image = this.$image;

      if (this.timeout) {
        clearTimeout(this.timeout);
        this.timeout = false;
      }

      $image.removeClass(CLASS_INVISIBLE).css('cssText', (
        'width:0;' +
        'height:0;' +
        'margin-left:' + viewer.width / 2 + 'px;' +
        'margin-top:' + viewer.height / 2 + 'px;' +
        'max-width:none!important;' +
        'visibility:visible;'
      ));

      this.initImage($.proxy(function () {
        $image.
          toggleClass(CLASS_TRANSITION, options.transition).
          toggleClass(CLASS_MOVE, options.movable);

        this.renderImage($.proxy(function () {
          this.isViewed = true;
          this.trigger(EVENT_VIEWED);
        }, this));
      }, this));
    },

    loadImage: function (e) {
      var image = e.target;
      var $image = $(image);
      var $parent = $image.parent();
      var parentWidth = $parent.width();
      var parentHeight = $parent.height();
      var filled = e.data && e.data.filled;

      getImageSize(image, function (naturalWidth, naturalHeight) {
        var aspectRatio = naturalWidth / naturalHeight;
        var width = parentWidth;
        var height = parentHeight;

        if (parentHeight * aspectRatio > parentWidth) {
          if (filled) {
            width = parentHeight * aspectRatio;
          } else {
            height = parentWidth / aspectRatio;
          }
        } else {
          if (filled) {
            height = parentWidth / aspectRatio;
          } else {
            width = parentHeight * aspectRatio;
          }
        }

        $image.css({
          width: width,
          height: height,
          marginLeft: (parentWidth - width) / 2,
          marginTop: (parentHeight - height) / 2
        });
      });
    },

    resize: function () {
      this.initContainer();
      this.initViewer();
      this.renderViewer();
      this.renderList();

      if (this.isViewed) {
        this.initImage($.proxy(function () {
          this.renderImage();
        }, this));
      }

      if (this.isPlayed) {
        this.$player.
          find(SELECTOR_IMG).
          one(EVENT_LOAD, $.proxy(this.loadImage, this)).
          trigger(EVENT_LOAD);
      }
    },

    wheel: function (event) {
      var e = event.originalEvent || event;
      var ratio = num(this.options.zoomRatio) || 0.1;
      var delta = 1;

      if (!this.isViewed) {
        return;
      }

      event.preventDefault();

      // Limit wheel speed to prevent zoom too fast
      if (this.wheeling) {
        return;
      }

      this.wheeling = true;

      setTimeout($.proxy(function () {
        this.wheeling = false;
      }, this), 50);

      if (e.deltaY) {
        delta = e.deltaY > 0 ? 1 : -1;
      } else if (e.wheelDelta) {
        delta = -e.wheelDelta / 120;
      } else if (e.detail) {
        delta = e.detail > 0 ? 1 : -1;
      }

      this.zoom(-delta * ratio, true, event);
    },

    keydown: function (e) {
      var options = this.options;
      var which = e.which;

      if (!this.isFulled || !options.keyboard) {
        return;
      }

      switch (which) {

        // (Key: Esc)
        case 27:
          if (this.isPlayed) {
            this.stop();
          } else {
            if (options.inline) {
              if (this.isFulled) {
                this.exit();
              }
            } else {
              this.hide();
            }
          }

          break;

        // (Key: Space)
        case 32:
          if (this.isPlayed) {
            this.stop();
          }

          break;

        // View previous (Key: ←)
        case 37:
          this.prev();
          break;

        // Zoom in (Key: ↑)
        case 38:

          // Prevent scroll on Firefox
          e.preventDefault();

          this.zoom(options.zoomRatio, true);
          break;

        // View next (Key: →)
        case 39:
          this.next();
          break;

        // Zoom out (Key: ↓)
        case 40:

          // Prevent scroll on Firefox
          e.preventDefault();

          this.zoom(-options.zoomRatio, true);
          break;

        // Zoom out to initial size (Key: Ctrl + 0)
        case 48:
          // Go to next

        // Zoom in to natural size (Key: Ctrl + 1)
        case 49:
          if (e.ctrlKey || e.shiftKey) {
            e.preventDefault();
            this.toggle();
          }

          break;

        // No default
      }
    },

    mousedown: function (event) {
      var options = this.options;
      var originalEvent = event.originalEvent;
      var touches = originalEvent && originalEvent.touches;
      var e = event;
      var action = options.movable ? 'move' : false;
      var touchesLength;

      if (!this.isViewed || this.transitioning) {
        return;
      }

      if (touches) {
        touchesLength = touches.length;

        if (touchesLength > 1) {
          if (options.zoomable && touchesLength === 2) {
            e = touches[1];
            this.startX2 = e.pageX;
            this.startY2 = e.pageY;
            action = 'zoom';
          } else {
            return;
          }
        } else {
          if (this.isSwitchable()) {
            action = 'switch';
          }
        }

        e = touches[0];
      }

      if (action) {
        this.action = action;

        // IE8  has `event.pageX/Y`, but not `event.originalEvent.pageX/Y`
        // IE10 has `event.originalEvent.pageX/Y`, but not `event.pageX/Y`
        this.startX = e.pageX || originalEvent && originalEvent.pageX;
        this.startY = e.pageY || originalEvent && originalEvent.pageY;
      }
    },

    mousemove: function (event) {
      var options = this.options;
      var action = this.action;
      var $image = this.$image;
      var originalEvent = event.originalEvent;
      var touches = originalEvent && originalEvent.touches;
      var e = event;
      var touchesLength;

      if (!this.isViewed) {
        return;
      }

      if (touches) {
        touchesLength = touches.length;

        if (touchesLength > 1) {
          if (options.zoomable && touchesLength === 2) {
            e = touches[1];
            this.endX2 = e.pageX;
            this.endY2 = e.pageY;
          } else {
            return;
          }
        }

        e = touches[0];
      }

      if (action) {
        event.preventDefault();

        if (action === 'move' && options.transition && $image.hasClass(CLASS_TRANSITION)) {
          $image.removeClass(CLASS_TRANSITION);
        }

        this.endX = e.pageX || originalEvent && originalEvent.pageX;
        this.endY = e.pageY || originalEvent && originalEvent.pageY;

        this.change(event);
      }
    },

    mouseup: function (event) {
      var action = this.action;

      if (action) {
        if (action === 'move' && this.options.transition) {
          this.$image.addClass(CLASS_TRANSITION);
        }

        this.action = false;
      }
    },
<commit_msg>fix error when close before loaded<commit_after>    start: function (e) {
      var target = e.target;

      if ($(target).is('img')) {
        this.target = target;
        this.show();
      }
    },

    click: function (e) {
      var $target = $(e.target);
      var action = $target.data('action');
      var image = this.image;

      switch (action) {
        case 'mix':
          if (this.isPlayed) {
            this.stop();
          } else {
            if (this.options.inline) {
              if (this.isFulled) {
                this.exit();
              } else {
                this.full();
              }
            } else {
              this.hide();
            }
          }

          break;

        case 'view':
          this.view($target.data('index'));
          break;

        case 'zoom-in':
          this.zoom(0.1, true);
          break;

        case 'zoom-out':
          this.zoom(-0.1, true);
          break;

        case 'one-to-one':
          this.toggle();
          break;

        case 'reset':
          this.reset();
          break;

        case 'prev':
          this.prev();
          break;

        case 'play':
          this.play();
          break;

        case 'next':
          this.next();
          break;

        case 'rotate-left':
          this.rotate(-90);
          break;

        case 'rotate-right':
          this.rotate(90);
          break;

        case 'flip-horizontal':
          this.scaleX(-image.scaleX || -1);
          break;

        case 'flip-vertical':
          this.scaleY(-image.scaleY || -1);
          break;

        default:
          if (this.isPlayed) {
            this.stop();
          }
      }
    },

    load: function () {
      var options = this.options;
      var viewer = this.viewer;
      var $image = this.$image;

      if (this.timeout) {
        clearTimeout(this.timeout);
        this.timeout = false;
      }

      if (!$image) {
        return;
      }

      $image.removeClass(CLASS_INVISIBLE).css('cssText', (
        'width:0;' +
        'height:0;' +
        'margin-left:' + viewer.width / 2 + 'px;' +
        'margin-top:' + viewer.height / 2 + 'px;' +
        'max-width:none!important;' +
        'visibility:visible;'
      ));

      this.initImage($.proxy(function () {
        $image.
          toggleClass(CLASS_TRANSITION, options.transition).
          toggleClass(CLASS_MOVE, options.movable);

        this.renderImage($.proxy(function () {
          this.isViewed = true;
          this.trigger(EVENT_VIEWED);
        }, this));
      }, this));
    },

    loadImage: function (e) {
      var image = e.target;
      var $image = $(image);
      var $parent = $image.parent();
      var parentWidth = $parent.width();
      var parentHeight = $parent.height();
      var filled = e.data && e.data.filled;

      getImageSize(image, function (naturalWidth, naturalHeight) {
        var aspectRatio = naturalWidth / naturalHeight;
        var width = parentWidth;
        var height = parentHeight;

        if (parentHeight * aspectRatio > parentWidth) {
          if (filled) {
            width = parentHeight * aspectRatio;
          } else {
            height = parentWidth / aspectRatio;
          }
        } else {
          if (filled) {
            height = parentWidth / aspectRatio;
          } else {
            width = parentHeight * aspectRatio;
          }
        }

        $image.css({
          width: width,
          height: height,
          marginLeft: (parentWidth - width) / 2,
          marginTop: (parentHeight - height) / 2
        });
      });
    },

    resize: function () {
      this.initContainer();
      this.initViewer();
      this.renderViewer();
      this.renderList();

      if (this.isViewed) {
        this.initImage($.proxy(function () {
          this.renderImage();
        }, this));
      }

      if (this.isPlayed) {
        this.$player.
          find(SELECTOR_IMG).
          one(EVENT_LOAD, $.proxy(this.loadImage, this)).
          trigger(EVENT_LOAD);
      }
    },

    wheel: function (event) {
      var e = event.originalEvent || event;
      var ratio = num(this.options.zoomRatio) || 0.1;
      var delta = 1;

      if (!this.isViewed) {
        return;
      }

      event.preventDefault();

      // Limit wheel speed to prevent zoom too fast
      if (this.wheeling) {
        return;
      }

      this.wheeling = true;

      setTimeout($.proxy(function () {
        this.wheeling = false;
      }, this), 50);

      if (e.deltaY) {
        delta = e.deltaY > 0 ? 1 : -1;
      } else if (e.wheelDelta) {
        delta = -e.wheelDelta / 120;
      } else if (e.detail) {
        delta = e.detail > 0 ? 1 : -1;
      }

      this.zoom(-delta * ratio, true, event);
    },

    keydown: function (e) {
      var options = this.options;
      var which = e.which;

      if (!this.isFulled || !options.keyboard) {
        return;
      }

      switch (which) {

        // (Key: Esc)
        case 27:
          if (this.isPlayed) {
            this.stop();
          } else {
            if (options.inline) {
              if (this.isFulled) {
                this.exit();
              }
            } else {
              this.hide();
            }
          }

          break;

        // (Key: Space)
        case 32:
          if (this.isPlayed) {
            this.stop();
          }

          break;

        // View previous (Key: ←)
        case 37:
          this.prev();
          break;

        // Zoom in (Key: ↑)
        case 38:

          // Prevent scroll on Firefox
          e.preventDefault();

          this.zoom(options.zoomRatio, true);
          break;

        // View next (Key: →)
        case 39:
          this.next();
          break;

        // Zoom out (Key: ↓)
        case 40:

          // Prevent scroll on Firefox
          e.preventDefault();

          this.zoom(-options.zoomRatio, true);
          break;

        // Zoom out to initial size (Key: Ctrl + 0)
        case 48:
          // Go to next

        // Zoom in to natural size (Key: Ctrl + 1)
        case 49:
          if (e.ctrlKey || e.shiftKey) {
            e.preventDefault();
            this.toggle();
          }

          break;

        // No default
      }
    },

    mousedown: function (event) {
      var options = this.options;
      var originalEvent = event.originalEvent;
      var touches = originalEvent && originalEvent.touches;
      var e = event;
      var action = options.movable ? 'move' : false;
      var touchesLength;

      if (!this.isViewed || this.transitioning) {
        return;
      }

      if (touches) {
        touchesLength = touches.length;

        if (touchesLength > 1) {
          if (options.zoomable && touchesLength === 2) {
            e = touches[1];
            this.startX2 = e.pageX;
            this.startY2 = e.pageY;
            action = 'zoom';
          } else {
            return;
          }
        } else {
          if (this.isSwitchable()) {
            action = 'switch';
          }
        }

        e = touches[0];
      }

      if (action) {
        this.action = action;

        // IE8  has `event.pageX/Y`, but not `event.originalEvent.pageX/Y`
        // IE10 has `event.originalEvent.pageX/Y`, but not `event.pageX/Y`
        this.startX = e.pageX || originalEvent && originalEvent.pageX;
        this.startY = e.pageY || originalEvent && originalEvent.pageY;
      }
    },

    mousemove: function (event) {
      var options = this.options;
      var action = this.action;
      var $image = this.$image;
      var originalEvent = event.originalEvent;
      var touches = originalEvent && originalEvent.touches;
      var e = event;
      var touchesLength;

      if (!this.isViewed) {
        return;
      }

      if (touches) {
        touchesLength = touches.length;

        if (touchesLength > 1) {
          if (options.zoomable && touchesLength === 2) {
            e = touches[1];
            this.endX2 = e.pageX;
            this.endY2 = e.pageY;
          } else {
            return;
          }
        }

        e = touches[0];
      }

      if (action) {
        event.preventDefault();

        if (action === 'move' && options.transition && $image.hasClass(CLASS_TRANSITION)) {
          $image.removeClass(CLASS_TRANSITION);
        }

        this.endX = e.pageX || originalEvent && originalEvent.pageX;
        this.endY = e.pageY || originalEvent && originalEvent.pageY;

        this.change(event);
      }
    },

    mouseup: function (event) {
      var action = this.action;

      if (action) {
        if (action === 'move' && this.options.transition) {
          this.$image.addClass(CLASS_TRANSITION);
        }

        this.action = false;
      }
    },
<|endoftext|>


<commit_before>//Copyright ©2011-2012 Memba® Sarl. All rights reserved.
/*jslint browser:true*/
/*jshint browser:true*/

(function ($, undefined) {

    "use strict";

    var fn = Function,
        global = fn('return this')(),
        kendo = global.kendo,
        Widget = kendo.ui.Widget,
        kidoju = global.kidoju,
        constants = kidoju.constants;

    /*******************************************************************************************
     * Page widget
     *
     * Drag and drop is extensively explained at:
     * http://www.html5rocks.com/en/tutorials/dnd/basics/
     * http://www.html5laboratory.com/drag-and-drop.php
     * http://stackoverflow.com/questions/11529788/html-5-drag-events
     * http://stackoverflow.com/questions/5500615/internet-explorer-9-drag-and-drop-dnd
     * http://nettutsplus.s3.amazonaws.com/64_html5dragdrop/demo/index.html
     * http://github.com/guillaumebort/jquery-ndd
     *******************************************************************************************/

    /**
     * @class Page Widget (kendoPage)
     */
    var Page = Widget.extend({

        /**
         * Initializes the widget
         * @param element
         * @param options
         */
        init: function (element, options) {
            var that = this;
            options = options || {};
            Widget.fn.init.call(that, element, options);
            if(options.toolbox) { //we have designated a toolbox
                if ($(options.toolbox).data('kendoToolbox') instanceof Widget) { //the toolbox is ready
                    that._toolbox = $(options.toolbox).data('kendoToolbox');
                } else {  //the toolbox is not ready yet, wait for it
                    $(options.toolbox).on('toolboxready', function(e){
                        that._toolbox = $(options.toolbox).data('kendoToolbox');
                    });
                }
            }
            that._dataSource();
            that._layout();
        },

        /**
         * Widget options
         */
        options: {
            name: "Page",
            dataSource: null, //and not source (exception to the data-X parsing)
            mode: constants.MODE_THUMBNAIL, //MODE_DESIGN, MODE_SOLUTION, ...
            scale: 1,
            toolbox: null //this is the DOM id of the toolbox widget
            //editor: null //this is the DOM id of the property editor widget (CAREFUL! pop-up window as OK + Cancel button, side panel does not)
            //contextmenu: null //we might also want to designate the context menu
        },

        /**
         * Mode defines the operating mode of the Page Widget
         * @param value
         * @return {*}
         */
        mode: function (value) {
            var that = this;
            if (value) {
                if($.type(value) !== constants.STRING) {
                    throw new TypeError();
                }
                if ((constants.MODE_DESIGN + constants.MODE_SOLUTION + constants.MODE_PLAY + constants.MODE_CORRECTION).indexOf(value) < 0 ) {
                    value = constants.MODE_THUMBNAIL;
                }
                if(that.options.mode !== value) {
                    that.options.mode = value;
                    that.refresh();
                }
                //return;
            }
            else {
                return that.options.mode;
            }
        },

        /**
         * Scale the widget
         * @param value
         * @return {*}
         */
        scale: function (value) {
            var that = this;
            if (value) {
                if($.type(value) !== constants.NUMBER || value <=0) {
                    throw new TypeError();
                }
                if(that.options.scale !== value) {
                    $(that.element).scale(value);
                    that.options.scale = value;
                }
                //return;
            }
            else {
                return that.options.scale;
            }
        },

        /**
         * Private variables
         */
        //This is the active widget
        _currentWidget: null,
        //We currently need _currentTransform because dataTransfer.getData
        //returns an empty string when called in a dragover event handler in IE
        //dataTransfer.getData only seems to work in a drop event handler in IE
        _currentTransform: null,
        //The connected toolbox
        _toolbox: null,

        /**
         * Binds the widget to the change event of the data source
         * @private
         */
        _dataSource: function () {
            var that = this;
            if (that.options.dataSource) {
                if (that._refreshHandler) {
                    that.options.dataSource.unbind(constants.CHANGE, that._refreshHandler);
                }
                else {
                    that._refreshHandler = $.proxy(that.refresh, that);
                }
                // bind to the change event to refresh the widget
                that.options.dataSource.bind(constants.CHANGE, that._refreshHandler);
            }
        },

        /**
         * Sets the dataSource
         * @param dataSource
         */
        setDataSource: function(dataSource) {
            // set the internal datasource equal to the one passed in by MVVM
            this.options.dataSource = dataSource;
            // rebuild the datasource if necessary, or just reassign
            this._dataSource();
        },

        /**
         * Builds the widget layout
         * @private
         */
        _layout: function () {

            var that = this;

            that._clear();
            $(that.element)
                .addClass('k-widget kj-page')
                .css('position', 'relative'); //!important

            /*
             if (that.options.dataSource) {
             type = that.options.dataSource.get(that.options.type);
             text = that.options.dataSource.get(that.options.text);
             } else {
             type = that.type();
             text = that.text();
             }
             */

            $(that.element)
                .on(constants.CLICK, function(e) {
                    that._currentWidget = null;
                    that._hideHandles();
                    that._hideContextMenu();
                    var tool = that._toolbox.getTool();
                    if (that._toolbox instanceof Widget &&  tool instanceof kidoju.Tool && tool.id !== constants.TOOL_SELECT) {
                        that._addWidget(tool, {left: e.offsetX, top: e.offsetY});
                    }
                    that._toolbox.reset();
                    e.preventDefault();
                    e.stopPropagation();
                });

        },

        /**
         * Refreshes the widget as the dataSource changes
         */
        refresh: function(e) {
            var that = this;
            if (!e) {  //force a full refresh
                that._layout();
            } else {
                //Changes to the dataSource affect the databound fields
                if(($.type(e.field) === constants.STRING) && ((that.options.text.indexOf(e.field) > -1) || (that.options.type.indexOf(e.field) > -1))) {
                    that._layout();
                }
            }
        },

        /**
         *
         * @param tool
         * @param position
         * @param properties
         * @private
         */
        _addWidget: function(tool, position, properties) {
            var that = this;
            if ((tool instanceof kidoju.Tool) && $.isFunction(tool.draw)) {
                position = $.extend({top: 10, left: 10, width: 200, height: 100}, position);
                var widget = $(kendo.format(
                    '

',
                    kendo.guid(),
                    tool.id,
                    position.top,
                    position.left,
                    position.width,
                    position.height
                ));
                tool.draw(widget);
                var find = that.element.find('.kj-widget');
                if (find.length > 0) {
                    find.last().after(widget);
                } else {
                    $(that.element).prepend(widget);
                }
                widget
                    .on(constants.CLICK, function(e) {
                        if(that._currentWidget) {
                            that._enableEdit(that._currentWidget, false);
                            that._hideHandles();
                        }
                        var targetWidget = $(e.target).closest('.kj-widget').get();
                        if (targetWidget !== that._currentWidget) {
                            that._currentWidget = targetWidget;
                            that._prepareContextMenu();
                        }
                        that._prepareHandles();
                        that._showHandles();
                        e.preventDefault();
                        e.stopPropagation();
                    })
                    .on(constants.DBLCLICK, function(e){
                        var widget = $(e.target).closest('.kj-widget');
                        that._enableEdit(that._currentWidget, true);
                    })
                    .on('blur', function(e) {
                        that._enableEdit(that._currentWidget, false);
                        kendo.logToConsole('blur from ' + e.target.toString());
                    })
                    .on('focusout', function(e) {
                        that._enableEdit(that._currentWidget, false);
                        kendo.logToConsole('focusout from ' + e.target.toString());
                    });
                widget.trigger(constants.CLICK);
            }
        },

        _removeWidget: function(widget) {
            var that = this;
            //TODO: call destroy on Tool
            //widget.find('*').off();
            //widget.off();

        },

        /**
         *
         * @param widget
         * @param enabled
         * @private
         */
        _enableEdit: function (widget, enabled) {
            var that = this;
            if (that._toolbox instanceof Widget && $.isFunction(that._toolbox.getTool)) {
                var tool = that._toolbox.getTool($(widget).attr('data-tool'));
                if($.isFunction(tool.edit)) {
                    tool.edit(widget, that.options.mode, enabled);
                }
            }
        },

        /**
         * Prepare handles for the active widget
         * @private
         */
        _prepareHandles: function() {
            var that = this;
            if($(that.element).find('.kj-handler').length === 0) {
                $(that.element)
                    .append('

')
                    .on(constants.DRAGENTER, function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                    })
                    .on(constants.DRAGOVER, function (e) {
                        //TODO check the bounds of container
                        //TODO: snap to grid and to angles option
                        if (that._currentTransform.type === 'translate') {
                            $(that._currentWidget)
                                .css('left', Math.round(that._currentTransform.offset.x + e.originalEvent.clientX) + 'px')
                                .css('top', Math.round(that._currentTransform.offset.y + e.originalEvent.clientY) + 'px');
                            $(that.element).find('.kj-handler')
                                .css('top', $(that._currentWidget).css('top'))
                                .css('left', $(that._currentWidget).css('left'));
                        } else if (that._currentTransform.type === 'scale') {
                            $(that._currentWidget)
                                .css('width', Math.round(that._currentTransform.offset.x + e.originalEvent.clientX) + 'px')
                                .css('height', Math.round(that._currentTransform.offset.y + e.originalEvent.clientY) + 'px');
                            $(that.element).find('.kj-handler')
                                .css('width', $(that._currentWidget).css('width'))
                                .css('height', $(that._currentWidget).css('height'));
                        } else if (that._currentTransform.type === 'rotate') {
                            var angle = Math.round(that._currentTransform.currentAngle - that._currentTransform.offsetAngle + Math.atan2(e.originalEvent.clientY - that._currentTransform.origin.y, e.originalEvent.clientX - that._currentTransform.origin.x)*(180/Math.PI));
                            $(that._currentWidget)
                                .css('transform', 'rotate(' + angle + 'deg)');  //TODO: css vendor prefixes  + modulo?
                            $(that.element).find('.kj-handler')
                                .css('transform', $(that._currentWidget).css('transform'));
                            /*
                             $('#console').html(
                             'originX: ' + that._currentTransform.origin.x + '
' +
                             'originY: ' + that._currentTransform.origin.y + '
' +
                             'angle: ' + angle + '
'
                             );
                             */
                        }
                        e.preventDefault();
                        e.stopPropagation();
                    })
                    .on(constants.DROP, function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                    });
                $(that.element).find('.kj-handler')
                    .append('')
                    .append('')
                    .append('')
                    .append('')
                    .css('position', 'absolute')
                    .css('display', 'none');
                $(that.element).find('.kj-handler .kj-drag-button')
                    .prop(constants.DRAGGABLE, true)
                    .on(constants.DRAGSTART, function(e){
                        that._currentTransform = {
                            type: 'translate',
                            offset: {
                                x: $(that._currentWidget).position().left - e.originalEvent.clientX,
                                y: $(that._currentWidget).position().top - e.originalEvent.clientY
                            }};
                    });
                $(that.element).find('.kj-handler .kj-resize-button')
                    .prop(constants.DRAGGABLE, true)
                    .on(constants.DRAGSTART, function(e){
                        that._currentTransform = {
                            type: 'scale',
                            offset: {
                                x: $(that._currentWidget).width()- e.originalEvent.clientX,
                                y: $(that._currentWidget).height() - e.originalEvent.clientY
                            }};
                    });
                $(that.element).find('.kj-handler .kj-rotate-button')
                    .prop(constants.DRAGGABLE, true)
                    .on(constants.DRAGSTART, function(e){
                        var cssTransform = $(that._currentWidget).css('transform'),
                            pos1 = cssTransform.indexOf('('),
                            pos2 = cssTransform.indexOf(')'),
                            currentAngle = 0;
                        if (pos1 > 0) {
                            var matrix = cssTransform.substr(pos1 + 1, pos2-pos1-1).split(','),
                            //This is the angle of rotation of the widget before rotating it further
                            //TODO: http://css-tricks.com/get-value-of-css-rotation-through-javascript/
                                currentAngle = Math.atan2(matrix[1], matrix[0]);
                        }
                        //This is the center of the widget being rotated
                        var originX = Math.round($(that._currentWidget).position().left + ($(that._currentWidget).width()*Math.abs(Math.cos(currentAngle)) + $(that._currentWidget).height()*Math.abs(Math.sin(currentAngle)))/2),
                            originY = Math.round($(that._currentWidget).position().top + ($(that._currentWidget).width()*Math.abs(Math.sin(currentAngle)) + $(that._currentWidget).height()*Math.abs(Math.cos(currentAngle)))/2);
                        that._currentTransform = {
                            type:'rotate',
                            origin: {   //This is the center of the widget being rotated
                                //we need origin set only once in dragstart otherwise (in dragover) the values change slightly as we are rotating and the rotation flickers
                                x: originX,
                                y: originY
                            },
                            currentAngle: currentAngle * (180/Math.PI), //in degrees
                            //The offset angle takes into account the position of the handle that drives the rotation
                            offsetAngle: Math.atan2(e.originalEvent.clientY - originY, e.originalEvent.clientX - originX) * (180/Math.PI) //in degrees
                        };
                    });
                $(that.element).find('.kj-handler .kj-menu-button')
                    .on(constants.CLICK, function(e) {
                        that._showContextMenu(e.clientX - e.offsetX + 40, e.clientY - e.offsetY + 40);
                        e.preventDefault();
                        e.stopPropagation();
                    });
            }
        },

        /**
         * Show handles on a widget created by a tool from the toolbox
         * @private
         */
        _showHandles: function(){
            var that = this;
            if (!that._currentWidget) {
                return;
            }
            $(that.element).find('.kj-handler')
                .css('top', $(that._currentWidget).css('top'))
                .css('left', $(that._currentWidget).css('left'))
                .css('width', $(that._currentWidget).css('width'))
                .css('height', $(that._currentWidget).css('height'))
                .css('padding', '30px')
                .css('margin', '-30px')
                .css('transform', $(that._currentWidget).css('transform'))//TODO: CSS vendor prefixes
                .css('display', 'block');
        },

        /**
         * Hide handles
         * @private
         */
        _hideHandles: function(){
            var that = this;
            $(that.element).find('.kj-handler')
                .css('display', 'none');
        },

        /**
         * Prepare context menu for active widget
         * @private
         */
        _prepareContextMenu: function() {
            var that = this;
            if (!that._currentWidget) {
                return;
            }
            //Even though we append a context menu to the page element
            //the contextual menu plugin (kendo labs) removes it to place it in the document
            //so that it cannot be found withing the page element
            if ($(document).find('.kj-context-menu').length === 0) {
                $(that.element).append('

');
            }
            var menu = $(document).find('.kj-context-menu').first();
            if (menu.data('kendoExtContextMenu') instanceof kendo.ui.Menu){
                menu.data('kendoExtContextMenu').destroy();
            }
            menu.kendoExtContextMenu({
                width: "175px",
                items: [
                    {
                        text: "Add Item",
                        iconCss: "k-add"
                    },
                    {
                        text: "Rename Category",
                        iconCss: "k-edit"
                    },
                    {
                        separator: true
                    },
                    {
                        text: "Delete Category",
                        iconCss: "k-delete"
                    }
                ],
                itemSelect: function (e) {
                    var msg = kendo.format('You selected: "{0}" on "{1}"',
                        $(e.item).text().trim(),
                        $(e.target).text());
                    window.alert(msg);
                }
            });
        },

        /**
         * Show context menu for active widget
         * @param x top of the element containing the menu
         * @param y left of the element containing the menu
         * @private
         */
        _showContextMenu: function(x, y) {
            //var that = this;
            //if (!that._currentWidget) {
            //    return;
            //}
            var find = $(document).find('.kj-context-menu');
            if (find.length > 0 && find.first().data('kendoExtContextMenu') instanceof kendo.ui.Menu) {
                find.first().data('kendoExtContextMenu').show(x, y);
            }
        },

        /**
         * Hide context menu for active widget
         * @private
         */
        _hideContextMenu: function() {
            var find = $(document).find('.kj-context-menu');
            if (find.length > 0 && find.first().data('kendoExtContextMenu') instanceof kendo.ui.Menu) {
                find.first().data('kendoExtContextMenu').hide();
            }
        },

        /**
         * Clears the DOM from modifications made by the widget
         * @private
         */
        _clear: function() {
            var that = this;
            //unbind kendo
            //kendo.unbind($(that.element));
            //unbind all other events
            $(that.element).find('*').off();
            $(that.element).off();
            //remove descendants
            $(that.element).empty();
            //remove element classes
            $(that.element).removeClass('k-widget kj-page');
        },

        /**
         * Destroys the widget including bounds to the data source
         */
        destroy: function () {
            var that = this;
            that._clear();
            if (that.options.dataSource) {
                if (that._refreshHandler) {
                    that.options.dataSource.unbind(constants.CHANGE, that._refreshHandler);
                }
            }
        }

    });

    kendo.ui.plugin(Page);

}(jQuery));
<commit_msg>Initial Setup<commit_after><|endoftext|>


<commit_before>angular.module('pdf')
  .controller('PdfCtrl', [
    '$scope',
    '$element',
    '$attrs',
    'pdfDelegate',
    '$log',
    '$q',
  function($scope, $element, $attrs, pdfDelegate, $log, $q) {

    // Register the instance!
    var deregisterInstance = pdfDelegate._registerInstance(this, $attrs.delegateHandle);
    // De-Register on destory!
    $scope.$on('$destroy', deregisterInstance);

    var self = this;

    var url = $scope.$eval($attrs.url);
    var headers = $scope.$eval($attrs.headers);
    var pdfDoc;
    $scope.pageCount = 0;
    var currentPage = 1;
    var angle = 0;
    var scale = $attrs.scale ? $attrs.scale : 1;
    var canvas = $element.find('canvas')[0];
    var ctx = canvas.getContext('2d');

    var renderPage = function(num) {
      if (!angular.isNumber(num)) {
        num = parseInt(num);
      }
      if (!isFinite(num) || num <= 0 || num > $scope.pageCount) {
        return;
      }

      pdfDoc
        .getPage(num)
        .then(function(page) {
          var viewport = page.getViewport(scale);
          canvas.height = viewport.height;
          canvas.width = viewport.width;

          var renderContext = {
            canvasContext: ctx,
            viewport: viewport
          };

          page.render(renderContext);
        });
    };

    var transform = function() {
      canvas.style.webkitTransform = 'rotate('+ angle + 'deg)';
      canvas.style.MozTransform = 'rotate('+ angle + 'deg)';
      canvas.style.msTransform = 'rotate('+ angle + 'deg)';
      canvas.style.OTransform = 'rotate('+ angle + 'deg)';
      canvas.style.transform = 'rotate('+ angle + 'deg)';
    };

    self.prev = function() {
      if (currentPage <= 1)
        return;
      currentPage = parseInt(currentPage, 10) - 1;
      renderPage(currentPage);
    };

    self.next = function() {
      if (currentPage >= pdfDoc.numPages)
        return;
      currentPage = parseInt(currentPage, 10) + 1;
      renderPage(currentPage);
    };

    self.zoomIn = function(amount) {
      amount = amount || 0.2;
      scale = parseFloat(scale) + amount;
      renderPage(currentPage);
      return scale;
    };

    self.zoomOut = function(amount) {
      amount = amount || 0.2;
      scale = parseFloat(scale) - amount;
      scale = (scale > 0) ? scale : 0.1;
      renderPage(currentPage);
      return scale;
    };

    self.zoomTo = function(zoomToScale) {
      zoomToScale = (zoomToScale) ? zoomToScale : 1.0;
      scale = parseFloat(zoomToScale);
      renderPage(currentPage);
      return scale;
    };

    self.rotate = function() {
      if (angle === 0) {
        angle = 90;
      } else if (angle === 90) {
        angle = 180;
      } else if (angle === 180) {
        angle = 270;
      } else {
        angle = 0
      }
      transform();
    };

    self.getPageCount = function() {
      return $scope.pageCount;
    };

    self.getCurrentPage = function () {
      return currentPage;
    };

    self.goToPage = function(newVal) {
      if (pdfDoc !== null && !angular.isUndefined(pdfDoc)) {
        currentPage = newVal;
        renderPage(newVal);
      }
    };

    self.load = function(_url) {
      if (_url) {
        url = _url;
      }

      var docInitParams = {};

      if (typeof url === 'string') {
        docInitParams.url = url;
      } else {
        // use Uint8Array or request like `{data: new Uint8Array()}`.  See pdf.js for more details.
        docInitParams.data = url;
      }

      if (headers) {
        docInitParams.httpHeaders = headers;
      }

      return PDFJS
        .getDocument(docInitParams)
        .then(function (_pdfDoc) {

          pdfDoc = _pdfDoc;
          $scope.$apply(function() {
            $scope.pageCount = _pdfDoc.numPages;
            renderPage(1);
          });
        }, function(error) {
            $log.error(error);
            return $q.reject(error);
        })
    };

    if(url) self.load();
}]);
<commit_msg>Fixed a bug in PdfCtrl<commit_after>angular.module('pdf')
  .controller('PdfCtrl', [
    '$scope',
    '$element',
    '$attrs',
    'pdfDelegate',
    '$log',
    '$q',
  function($scope, $element, $attrs, pdfDelegate, $log, $q) {

    // Register the instance!
    var deregisterInstance = pdfDelegate._registerInstance(this, $attrs.delegateHandle);
    // De-Register on destory!
    $scope.$on('$destroy', deregisterInstance);

    var self = this;

    var url = $scope.$eval($attrs.url);
    var headers = $scope.$eval($attrs.headers);
    var pdfDoc;
    $scope.pageCount = 0;
    var currentPage = 1;
    var angle = 0;
    var scale = $attrs.scale ? $attrs.scale : 1;
    var canvas = $element.find('canvas')[0];
    var ctx = canvas.getContext('2d');

    var renderPage = function(num) {
      if (!angular.isNumber(num)) {
        num = parseInt(num);
      }
      if (!isFinite(num) || num <= 0 || num > $scope.pageCount || pdfDoc === null || angular.isUndefined(pdfDoc)) {
        return;
      }

      pdfDoc
        .getPage(num)
        .then(function(page) {
          var viewport = page.getViewport(scale);
          canvas.height = viewport.height;
          canvas.width = viewport.width;

          var renderContext = {
            canvasContext: ctx,
            viewport: viewport
          };

          page.render(renderContext);
        });
    };

    var transform = function() {
      canvas.style.webkitTransform = 'rotate('+ angle + 'deg)';
      canvas.style.MozTransform = 'rotate('+ angle + 'deg)';
      canvas.style.msTransform = 'rotate('+ angle + 'deg)';
      canvas.style.OTransform = 'rotate('+ angle + 'deg)';
      canvas.style.transform = 'rotate('+ angle + 'deg)';
    };

    self.prev = function() {
      if (currentPage <= 1)
        return;
      currentPage = parseInt(currentPage, 10) - 1;
      renderPage(currentPage);
    };

    self.next = function() {
      if (currentPage >= pdfDoc.numPages)
        return;
      currentPage = parseInt(currentPage, 10) + 1;
      renderPage(currentPage);
    };

    self.zoomIn = function(amount) {
      amount = amount || 0.2;
      scale = parseFloat(scale) + amount;
      renderPage(currentPage);
      return scale;
    };

    self.zoomOut = function(amount) {
      amount = amount || 0.2;
      scale = parseFloat(scale) - amount;
      scale = (scale > 0) ? scale : 0.1;
      renderPage(currentPage);
      return scale;
    };

    self.zoomTo = function(zoomToScale) {
      zoomToScale = (zoomToScale) ? zoomToScale : 1.0;
      scale = parseFloat(zoomToScale);
      renderPage(currentPage);
      return scale;
    };

    self.rotate = function() {
      if (angle === 0) {
        angle = 90;
      } else if (angle === 90) {
        angle = 180;
      } else if (angle === 180) {
        angle = 270;
      } else {
        angle = 0
      }
      transform();
    };

    self.getPageCount = function() {
      return $scope.pageCount;
    };

    self.getCurrentPage = function () {
      return currentPage;
    };

    self.goToPage = function(newVal) {
      if (pdfDoc !== null && !angular.isUndefined(pdfDoc)) {
        currentPage = newVal;
        renderPage(newVal);
      }
    };

    self.load = function(_url) {
      if (_url) {
        url = _url;
      }

      var docInitParams = {};

      if (typeof url === 'string') {
        docInitParams.url = url;
      } else {
        // use Uint8Array or request like `{data: new Uint8Array()}`.  See pdf.js for more details.
        docInitParams.data = url;
      }

      if (headers) {
        docInitParams.httpHeaders = headers;
      }

      return PDFJS
        .getDocument(docInitParams)
        .then(function (_pdfDoc) {

          pdfDoc = _pdfDoc;
          $scope.$apply(function() {
            $scope.pageCount = _pdfDoc.numPages;
            renderPage(1);
          });
        }, function(error) {
            $log.error(error);
            return $q.reject(error);
        })
    };

    if(url) self.load();
}]);
<|endoftext|>


<commit_before>"use strict";
define(['jquery'], function($){
    /*
        scanData has 'current' field for sure,
        and may also have 'prev', next fields.
    */
    var scanData = $.parseJSON($('#scanData').text());
    /*
        We add scanData.fields, which will contain an array of ordered
        Fields included in scanData:
    */
    scanData.fields = [];
    ['prev','current','next'].forEach(function(f){
        if(f in scanData){
            scanData.fields.push(f);
        }
    });
    /*
        We always preload images:
    */
    var proms = [];
    scanData.fields.forEach(function(key){
        var scan = scanData[key]
          , def  = $.Deferred()
          , img  = new Image();
        //Handling promise for this scan:
        img.onload = function(){ def.resolve(); };
        proms.push(def.promise());
        //We exchange scan.img from String to Image:
        img.src = scan.img;
        scan.img = img;
    });
    /* Adding scanData.whenLoaded: */
    var def = $.Deferred();
    $.when.apply($, proms).done(function(){
        def.resolve();
    });
    scanData.whenLoaded = function(func){
        def.done(func);
    };
    /*
        scanData now has a structure like this:
        {
            ['prev','current','next']: {
                    urn: String,
                    img: Image,
                    aois: ?
                },
            fields: [String], ordered subset of {'prev','current','next'},
            whenLoaded: function(callback) //Adds a callback to be called when images are loaded.
        }
    */
    return scanData;
});
<commit_msg>Add initial comment to scanData.js<commit_after>"use strict";
/**
    This module is concerned with presenting a single point to access data about scans and their AOIs
    as it is presented by singleFile.php
*/
define(['jquery'], function($){
    /*
        scanData has 'current' field for sure,
        and may also have 'prev', next fields.
    */
    var scanData = $.parseJSON($('#scanData').text());
    /*
        We add scanData.fields, which will contain an array of ordered
        Fields included in scanData:
    */
    scanData.fields = [];
    ['prev','current','next'].forEach(function(f){
        if(f in scanData){
            scanData.fields.push(f);
        }
    });
    /*
        We always preload images:
    */
    var proms = [];
    scanData.fields.forEach(function(key){
        var scan = scanData[key]
          , def  = $.Deferred()
          , img  = new Image();
        //Handling promise for this scan:
        img.onload = function(){ def.resolve(); };
        proms.push(def.promise());
        //We exchange scan.img from String to Image:
        img.src = scan.img;
        scan.img = img;
    });
    /* Adding scanData.whenLoaded: */
    var def = $.Deferred();
    $.when.apply($, proms).done(function(){
        def.resolve();
    });
    scanData.whenLoaded = function(func){
        def.done(func);
    };
    /*
        scanData now has a structure like this:
        {
            ['prev','current','next']: {
                    urn: String,
                    img: Image,
                    aois: ?
                },
            fields: [String], ordered subset of {'prev','current','next'},
            whenLoaded: function(callback) //Adds a callback to be called when images are loaded.
        }
    */
    return scanData;
});
<|endoftext|>