<commit_before>/* Set caret at end of text in given elem */
function setCaretAtEnd(elem) {
    var range;
    var caretPos = $(elem).val().length;

    if (elem.createTextRange) {
        range = elem.createTextRange();
        range.move('character', caretPos);
        range.select();
    } else {
        elem.focus();
        if (elem.selectionStart !== undefined) {
            elem.setSelectionRange(caretPos, caretPos);
        }
    }
}

if (typeof String.prototype.startsWith != 'function') {
    String.prototype.startsWith = function(str) {
        return this.substring(0, str.length) === str;
    }
}

if (typeof String.prototype.endsWith != 'function') {
    String.prototype.endsWith = function(str) {
        return this.substring(this.length - str.length, this.length ) === str;
    }
}

(function($, window, document, undefined){
    var truncatedFields;

    window.HLApp = {
        config: {
            phoneInputFields: 'input[name^="phone"]',
            countryPrefix: '+31',
            truncateFields: '.truncate',
            truncateToken: ' (…)',
            toastrPosition: 'toast-bottom-right',
            contactField: '#id_contact',
            quickContactField: '#id_case_quickbutton_contact',
            accountField: '#id_account',
            quickAccountField: '#id_case_quickbutton_account',
            contactJsonUrl: "/search/search/?type=accounts_account&contact="
        },

        init: function(config) {
            // Setup config
            var self = this;
            if ($.isPlainObject(config)) {
                $.extend(self.config, config);
            }

            self.initListeners();
            self.resetTruncateFields();
            self.initToastr();
            self.initDatePicker();
            self.initModalSpinner();
        },

        initListeners: function() {
            var self = this,
                cf = self.config;
            $('body')
                .on('blur', cf.phoneInputFields, function() {
                    // Format phonenumbers for every phone input field
                    self.formatPhoneNumber.call(self, this);
                })
                .on('change', cf.contactField, function() {
                    self.changedContact(cf.contactField, cf.accountField);
                })
                .on('change', cf.quickContactField, function() {
                    self.changedContact(cf.quickContactField, cf.quickAccountField);
                })
                .on('change', cf.accountField, function() {
                    self.changedAccount(cf.contactField, cf.accountField);
                })
                .on('change', cf.quickAccountField, function() {
                    self.changedAccount(cf.quickContactField, cf.quickAccountField);
                })
                .on('hidden.bs.modal', '.modal', function() {
                    // remove any results from other modals
                    $(this).find('[data-async-response]').html('');
                })
                .on('hide.bs.modal', '.modal', function() {
                    // remove focus from element that triggered modal
                    $(':focus').blur();
                })
                .on('click', '[data-source]', function(event) {
                    self.openModalWithRemoteContent.call(this, event);
                })
                .on('submit', 'form[data-async]', function(event) {
                    self.submitAjaxForm.call(self, this, event);
                })
                .on('shown.bs.tab', '[data-toggle="tab"]', function(e) {
                    // update address bar with target
                    // - this helps showing the correct tab immediately on page load after
                    // trying to post a form but receiving errors for instance
                    window.location.hash = e.target.hash;
                });

            $(window).on('resize', function() {
                self.truncateFields();
            });

            // submit forms with other elements
            $('[data-form-submit]').on('click', function(event) {
                $($(this).data('form-selector')).submit();
                event.preventDefault();
            });
        },

        formatPhoneNumber: function(phoneNumberInput) {
            // Format telephone number
            var $phoneNumberInput = $(phoneNumberInput);
            var phone = $phoneNumberInput.val();
            if (phone.match(/[a-z]|[A-Z]/)) {
                // if letters are found, skip formatting: it may not be a phone field after all
                return false;
            }

            phone = phone
                .replace("(0)","")
                .replace(/\s|\(|\-|\)|\.|x|:|\*/g, "")
                .replace(/^00/,"+");

            if (phone.length == 0) {
                return false;
            }

            if (!phone.startsWith('+')) {
                if (phone.startsWith('0')) {
                    phone = phone.substring(1);
                }
                phone = this.config.countryPrefix + phone;
            }

            if (phone.startsWith('+310')) {
                phone = '+31' + phone.substring(4);
            }
            $phoneNumberInput.val(phone);
        },

        setupTruncate: function() {
            truncatedFields = $(this.config.truncateFields);
        },

        truncateFields: function() {
            truncatedFields.truncate({
                token: this.config.truncateToken
            });
        },

        resetTruncateFields: function() {
            this.setupTruncate();
            this.truncateFields();
        },

        initToastr: function() {
            toastr.options = {
                closeButton: true,
                positionClass: this.config.toastrPosition
            };
        },

        initDatePicker: function() {
            $('body').removeClass('modal-open'); // fix bug when inline picker is used in modal
        },

        // Selects the Account belonging to a Contact when a Contact is selected.
        changedContact: function(idContact, idAccount) {
            var $contact = $(idContact),
                $account = $(idAccount),
                contactPk = $contact.val(),
                accountPk = $account.val();
            // Resets the Contact & Accounts if Contact clear is selected.
            if (contactPk == -1) {
                $contact.select2('data', null);
                $account.select2('data', null);
            } else if (contactPk && !accountPk) {
                // Contact is selected, and no Account is selected.
                var url = this.config.contactJsonUrl + contactPk;
                $.getJSON(url, function(data) {
                    if (data.hits.length) {
                        $account.select2('data', {'id': data.hits[0].id, 'text': data.hits[0].name});
                    } else {
                        $account.select2('data', null);
                    }
                });
            }
        },

        // Resets the Contact & Accounts if Account clear is selected.
        changedAccount: function(idContact, idAccount) {
            var $account = $(idAccount);
            if ($account.val() == -1) {
                $(idContact).select2('data', null);
                $account.select2('data', null);
            }
        },

        initModalSpinner: function() {
            // spinner template for bootstrap 3
            $.fn.modal.defaults.spinner = $.fn.modalmanager.defaults.spinner =
                '
' +
                '
' +
                '

' +
                '
' +
                '
';

            $.fn.modalmanager.defaults.resize = true;
        },

        openModalWithRemoteContent: function(event) {
            var $button = $(this);
            var modal = $($button.data('target'));

            // create the backdrop and wait for next modal to be triggered
            $('body').modalmanager('loading');

            setTimeout(function() {
                modal.load($button.data('source'), '', function() {
                    modal.modal();
                });
            }, 300);

            event.preventDefault();
        },

        updateModal: function(current, update) {
            var $current = $(current);
            var $update = $(update);
            if($current.find('.modal-header').length && $update.find('.modal-header').length) {
                $current.find('.modal-header').html($update.find('.modal-header').html());
            }
            if($current.find('.modal-body').length && $update.find('.modal-body').length) {
                $current.find('.modal-body').html($update.find('.modal-body').html());
            }
            if($current.find('.modal-footer').length && $update.find('.modal-footer').length) {
                $current.find('.modal-footer').html($update.find('.modal-footer').html());
            }

            // prettify checkboxes/radio buttons
            var inputs = $("input[type=checkbox]:not(.toggle), input[type=radio]:not(.toggle, .star)");
            if (inputs.size() > 0) {
                App.initUniform(inputs);
            }
        },

        submitAjaxForm: function(form, event) {
            var self = this;
            var $form = $(form);
            $form.ajaxStart(function() {
                $form.find('[type="submit"]').button('loading');
            }).ajaxStop(function() {
                setTimeout(function() {
                    $form.find('[type="submit"]').button('reset');
                }, 300);
            }).ajaxSubmit({
                success: function(response) {
                    if(response.clear_serialize) {
                        // clear serialized_form so certain modals don't show a popup when completed
                        $form.data('serialized_form', '');
                    }
                    if(response.error) {
                        if(response.html) {
                            self.updateModal($form, response.html);
                        }
                        // loads notifications if any
                        load_notifications();
                    } else if(response.redirect_url) {
                        location.reload(true);
                    } else {
                        if(response.html) {
                            self.updateModal($form, response.html);
                        } else {
                            // fool the "confirm prevent accidental close" popup from triggering
                            $form.data('serialized_form', $form.serialize());

                            $form.closest('.modal').modal('hide');
                        }
                        // loads notifications if any
                        load_notifications();
                    }
                    // Reset all Select2 options
                    HLSelect2.setupSelect2();
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    $form.find('[data-async-response]').html(jqXHR.responseText);
                    // loads notifications if any
                    load_notifications();
                    // Reset all Select2 options
                    HLSelect2.setupSelect2();
                }
            });
            event.preventDefault();
        },

        redirectTo: function(redirectUrl) {
            // go to redirectUrl, reload if redirectUrl is current
            // and/or if it contains an anchor reference
            var current = window.location.href;
            var index = current.indexOf(redirectUrl);

            window.location = redirectUrl;
            if(index == current.length - redirectUrl.length ||
                redirectUrl.indexOf('#') != -1) {
                window.location.reload(true);
            }
        },

        getCookie: function(name) {
            var value = "; " + document.cookie;
            var parts = value.split("; " + name + "=");
            if (parts.length == 2) return parts.pop().split(";").shift();
        },

        isSameOrigin: function(url) {
            // url could be relative or scheme relative or absolute
            var host = document.location.host; // host + port
            var protocol = document.location.protocol;
            var sr_origin = '//' + host;
            var origin = protocol + sr_origin;
            // Allow absolute or scheme relative URLs to same origin
            return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
                (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
                // or any other URL that isn't scheme relative or absolute i.e relative.
                !(/^(\/\/|http:|https:).*/.test(url));
        },

        safeMethod: function(method) {
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        },

        addCSRFHeader: function(jqXHR, settings) {
            if (!HLApp.safeMethod(settings.type) && HLApp.isSameOrigin(settings.url)) {
                jqXHR.setRequestHeader("X-CSRFToken", HLApp.getCookie('csrftoken'));
            }
        },

        getUrlParameter: function(sParam) {
            var sPageURL = window.location.search.substring(1);
            var sURLVariables = sPageURL.split('&');
            for (var i = 0; i < sURLVariables.length; i++)
            {
                var sParameterName = sURLVariables[i].split('=');
                if (sParameterName[0] == sParam)
                {
                    return decodeURIComponent(sParameterName[1]);
                }
            }
        }

    }
})(jQuery, window, document);
<commit_msg>1.5/2 LILY-500: Extend the search api for extended Contact search<commit_after>/* Set caret at end of text in given elem */
function setCaretAtEnd(elem) {
    var range;
    var caretPos = $(elem).val().length;

    if (elem.createTextRange) {
        range = elem.createTextRange();
        range.move('character', caretPos);
        range.select();
    } else {
        elem.focus();
        if (elem.selectionStart !== undefined) {
            elem.setSelectionRange(caretPos, caretPos);
        }
    }
}

if (typeof String.prototype.startsWith != 'function') {
    String.prototype.startsWith = function(str) {
        return this.substring(0, str.length) === str;
    }
}

if (typeof String.prototype.endsWith != 'function') {
    String.prototype.endsWith = function(str) {
        return this.substring(this.length - str.length, this.length ) === str;
    }
}

(function($, window, document, undefined){
    var truncatedFields;

    window.HLApp = {
        config: {
            phoneInputFields: 'input[name^="phone"]',
            countryPrefix: '+31',
            truncateFields: '.truncate',
            truncateToken: ' (…)',
            toastrPosition: 'toast-bottom-right',
            contactField: '#id_contact',
            quickContactField: '#id_case_quickbutton_contact',
            accountField: '#id_account',
            quickAccountField: '#id_case_quickbutton_account',
        },

        init: function(config) {
            // Setup config
            var self = this;
            if ($.isPlainObject(config)) {
                $.extend(self.config, config);
            }

            self.initListeners();
            self.resetTruncateFields();
            self.initToastr();
            self.initDatePicker();
            self.initModalSpinner();
        },

        initListeners: function() {
            var self = this,
                cf = self.config;
            $('body')
                .on('blur', cf.phoneInputFields, function() {
                    // Format phonenumbers for every phone input field
                    self.formatPhoneNumber.call(self, this);
                })
                .on('change', cf.contactField, function() {
                    self.changedContact(cf.contactField, cf.accountField);
                })
                .on('change', cf.quickContactField, function() {
                    self.changedContact(cf.quickContactField, cf.quickAccountField);
                })
                .on('change', cf.accountField, function() {
                    self.changedAccount(cf.contactField, cf.accountField);
                })
                .on('change', cf.quickAccountField, function() {
                    self.changedAccount(cf.quickContactField, cf.quickAccountField);
                })
                .on('hidden.bs.modal', '.modal', function() {
                    // remove any results from other modals
                    $(this).find('[data-async-response]').html('');
                })
                .on('hide.bs.modal', '.modal', function() {
                    // remove focus from element that triggered modal
                    $(':focus').blur();
                })
                .on('click', '[data-source]', function(event) {
                    self.openModalWithRemoteContent.call(this, event);
                })
                .on('submit', 'form[data-async]', function(event) {
                    self.submitAjaxForm.call(self, this, event);
                })
                .on('shown.bs.tab', '[data-toggle="tab"]', function(e) {
                    // update address bar with target
                    // - this helps showing the correct tab immediately on page load after
                    // trying to post a form but receiving errors for instance
                    window.location.hash = e.target.hash;
                });

            $(window).on('resize', function() {
                self.truncateFields();
            });

            // submit forms with other elements
            $('[data-form-submit]').on('click', function(event) {
                $($(this).data('form-selector')).submit();
                event.preventDefault();
            });
        },

        formatPhoneNumber: function(phoneNumberInput) {
            // Format telephone number
            var $phoneNumberInput = $(phoneNumberInput);
            var phone = $phoneNumberInput.val();
            if (phone.match(/[a-z]|[A-Z]/)) {
                // if letters are found, skip formatting: it may not be a phone field after all
                return false;
            }

            phone = phone
                .replace("(0)","")
                .replace(/\s|\(|\-|\)|\.|x|:|\*/g, "")
                .replace(/^00/,"+");

            if (phone.length == 0) {
                return false;
            }

            if (!phone.startsWith('+')) {
                if (phone.startsWith('0')) {
                    phone = phone.substring(1);
                }
                phone = this.config.countryPrefix + phone;
            }

            if (phone.startsWith('+310')) {
                phone = '+31' + phone.substring(4);
            }
            $phoneNumberInput.val(phone);
        },

        setupTruncate: function() {
            truncatedFields = $(this.config.truncateFields);
        },

        truncateFields: function() {
            truncatedFields.truncate({
                token: this.config.truncateToken
            });
        },

        resetTruncateFields: function() {
            this.setupTruncate();
            this.truncateFields();
        },

        initToastr: function() {
            toastr.options = {
                closeButton: true,
                positionClass: this.config.toastrPosition
            };
        },

        initDatePicker: function() {
            $('body').removeClass('modal-open'); // fix bug when inline picker is used in modal
        },

        // Selects the Account belonging to a Contact when a Contact is selected.
        changedContact: function(idContact, idAccount) {
            var $contact = $(idContact),
                $account = $(idAccount),
                contactPk = $contact.val(),
                accountPk = $account.val();
            // Resets the Contact & Accounts if Contact clear is selected.
            if (contactPk == -1) {
                $contact.select2('data', null);
                $account.select2('data', null);
            } else if (contactPk && !accountPk) {
                // Contact is selected, and no Account is selected.
                var url = this.config.contactJsonUrl + contactPk;
                $.getJSON(url, function(data) {
                    if (data.hits.length) {
                        $account.select2('data', {'id': data.hits[0].id, 'text': data.hits[0].name});
                    } else {
                        $account.select2('data', null);
                    }
                });
            }
        },

        // Resets the Contact & Accounts if Account clear is selected.
        changedAccount: function(idContact, idAccount) {
            var $account = $(idAccount);
            if ($account.val() == -1) {
                $(idContact).select2('data', null);
                $account.select2('data', null);
            }
        },

        initModalSpinner: function() {
            // spinner template for bootstrap 3
            $.fn.modal.defaults.spinner = $.fn.modalmanager.defaults.spinner =
                '
' +
                '
' +
                '

' +
                '
' +
                '
';

            $.fn.modalmanager.defaults.resize = true;
        },

        openModalWithRemoteContent: function(event) {
            var $button = $(this);
            var modal = $($button.data('target'));

            // create the backdrop and wait for next modal to be triggered
            $('body').modalmanager('loading');

            setTimeout(function() {
                modal.load($button.data('source'), '', function() {
                    modal.modal();
                });
            }, 300);

            event.preventDefault();
        },

        updateModal: function(current, update) {
            var $current = $(current);
            var $update = $(update);
            if($current.find('.modal-header').length && $update.find('.modal-header').length) {
                $current.find('.modal-header').html($update.find('.modal-header').html());
            }
            if($current.find('.modal-body').length && $update.find('.modal-body').length) {
                $current.find('.modal-body').html($update.find('.modal-body').html());
            }
            if($current.find('.modal-footer').length && $update.find('.modal-footer').length) {
                $current.find('.modal-footer').html($update.find('.modal-footer').html());
            }

            // prettify checkboxes/radio buttons
            var inputs = $("input[type=checkbox]:not(.toggle), input[type=radio]:not(.toggle, .star)");
            if (inputs.size() > 0) {
                App.initUniform(inputs);
            }
        },

        submitAjaxForm: function(form, event) {
            var self = this;
            var $form = $(form);
            $form.ajaxStart(function() {
                $form.find('[type="submit"]').button('loading');
            }).ajaxStop(function() {
                setTimeout(function() {
                    $form.find('[type="submit"]').button('reset');
                }, 300);
            }).ajaxSubmit({
                success: function(response) {
                    if(response.clear_serialize) {
                        // clear serialized_form so certain modals don't show a popup when completed
                        $form.data('serialized_form', '');
                    }
                    if(response.error) {
                        if(response.html) {
                            self.updateModal($form, response.html);
                        }
                        // loads notifications if any
                        load_notifications();
                    } else if(response.redirect_url) {
                        location.reload(true);
                    } else {
                        if(response.html) {
                            self.updateModal($form, response.html);
                        } else {
                            // fool the "confirm prevent accidental close" popup from triggering
                            $form.data('serialized_form', $form.serialize());

                            $form.closest('.modal').modal('hide');
                        }
                        // loads notifications if any
                        load_notifications();
                    }
                    // Reset all Select2 options
                    HLSelect2.setupSelect2();
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    $form.find('[data-async-response]').html(jqXHR.responseText);
                    // loads notifications if any
                    load_notifications();
                    // Reset all Select2 options
                    HLSelect2.setupSelect2();
                }
            });
            event.preventDefault();
        },

        redirectTo: function(redirectUrl) {
            // go to redirectUrl, reload if redirectUrl is current
            // and/or if it contains an anchor reference
            var current = window.location.href;
            var index = current.indexOf(redirectUrl);

            window.location = redirectUrl;
            if(index == current.length - redirectUrl.length ||
                redirectUrl.indexOf('#') != -1) {
                window.location.reload(true);
            }
        },

        getCookie: function(name) {
            var value = "; " + document.cookie;
            var parts = value.split("; " + name + "=");
            if (parts.length == 2) return parts.pop().split(";").shift();
        },

        isSameOrigin: function(url) {
            // url could be relative or scheme relative or absolute
            var host = document.location.host; // host + port
            var protocol = document.location.protocol;
            var sr_origin = '//' + host;
            var origin = protocol + sr_origin;
            // Allow absolute or scheme relative URLs to same origin
            return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
                (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
                // or any other URL that isn't scheme relative or absolute i.e relative.
                !(/^(\/\/|http:|https:).*/.test(url));
        },

        safeMethod: function(method) {
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        },

        addCSRFHeader: function(jqXHR, settings) {
            if (!HLApp.safeMethod(settings.type) && HLApp.isSameOrigin(settings.url)) {
                jqXHR.setRequestHeader("X-CSRFToken", HLApp.getCookie('csrftoken'));
            }
        },

        getUrlParameter: function(sParam) {
            var sPageURL = window.location.search.substring(1);
            var sURLVariables = sPageURL.split('&');
            for (var i = 0; i < sURLVariables.length; i++)
            {
                var sParameterName = sURLVariables[i].split('=');
                if (sParameterName[0] == sParam)
                {
                    return decodeURIComponent(sParameterName[1]);
                }
            }
        }

    }
})(jQuery, window, document);
<|endoftext|>


<commit_before>var albumApp = angular.module('albumApp', ['ui.bootstrap']);

/* Define an album metadata update service. */
albumApp.factory('AlbumMetaUpdateService', ['$http', function ($http, album_metadata) {
    return function (album_metadata) {
        console.log("in service with metadata.name, metadata.description: " + album_metadata.name + ", " + album_metadata.description);
        $http.put("albums/" + album_metadata.name, album_metadata)
            .success(function (data, status, headers, config) {
                console.log("put worked");
            })
            .error(function (data, status, headers, config) {
                console.log("put failed");
            });
    }
}]);

albumApp.controller('AlbumController', function ($scope, $http, $modal, $log) {

    $scope.image_names_by_album = [];

    $http.get("albums")
        .success(function (data, status, headers, config) {
            $scope.albums = data;
            for (var i = 0; i < $scope.albums.length; i++) {
                $scope.album_fetcher($scope.albums[i]);
            }
        })
        .error(function (data, status, headers, config) {
        });

    $scope.album_fetcher = function (album_metadata) {
        $http.get("albums/" + album_metadata.name + "/photos")
            .success(function (data, status, headers, config) {
                $scope.image_names_by_album[album_metadata.name] = data;
            })
            .error(function (data, status, headers, config) {
            });
    };

    $scope.open = function (album_number, image_name) {

        $http.get("photo/metadata/" + album_number + "/" + image_name)
            .success(function (data, status, headers, config) {
                $scope.openPhotoDetail(data);
            })
            .error(function (data, status, headers, config) {
                $log.info("Error getting metadata for " + image_name);
            });

        $scope.openPhotoDetail = function (photo_metadata) {
            var photoDetailModal = $modal.open({
                templateUrl: 'partials/photodetail.html',
                controller: PhotoDetailModalController,
                resolve: {
                    image_info: function () {
                        return {
                            album: album_number,
                            image_name: image_name,
                            caption: "",
                            exif: {
                                lat: photo_metadata.lat,
                                long: photo_metadata.lng,
                                original_date: photo_metadata.originalTime
                            }
                        };
                    }
                }
            });
            photoDetailModal.result.then(function () {
            }, function () {
            });
        };
    };

    var PhotoDetailModalController = function ($scope, $modalInstance, image_info) {
        $scope.image_info = image_info;
        $scope.show_edit = false;
        $scope.caption = $scope.image_info.caption;

        $scope.ok = function () {
            $modalInstance.close();
        };

        $scope.edit = function () {
            $scope.show_edit = true;
            console.log("edit clicked: " + $scope.image_info.album + ", " + $scope.image_info.image_name);
        };

        $scope.update_caption = function () {
            $scope.show_edit = false;
            console.log("update caption" + $scope.image_info.caption);
        };

        $scope.cancel = function () {
            $modalInstance.dismiss('cancel');
        };
    };

    $scope.change_album_description = function (name, description) {
        for (i = 0; i < $scope.albums.length; ++i) {
            if ($scope.albums[i].name == name) {
                $scope.albums[i] = {name: name, description: description};
            }
        }
    };

    $scope.album_metadata_edit = function (album_metadata) {
        var albumDescriptionModal = $modal.open({
            templateUrl: 'partials/albumdetail.html',
            controller: AlbumDetailModalController,
            resolve: {
                album_meta: function () {
                    return {
                        name: album_metadata.name,
                        description: album_metadata.description,

                        /* deprecated:  let the album meta service update albums[] to avoid this callback */
                        update_callback: $scope.change_album_description
                    };
                }
            }
        });

        albumDescriptionModal.result.then(function () {
        }, function () {
        });
    };

    var AlbumDetailModalController = function ($scope, $modalInstance, AlbumMetaUpdateService, album_meta) {
        $scope.album_meta = album_meta;
        $scope.description = album_meta.description;

        $scope.ok = function (description) {
            $modalInstance.close();
            $scope.album_meta.update_callback($scope.album_meta.name, description);
            AlbumMetaUpdateService({name: $scope.album_meta.name, description: description});
        };

        $scope.cancel = function () {
            $modalInstance.dismiss('cancel');
        };
    };
});<commit_msg>implement album update service<commit_after>var albumApp = angular.module('albumApp', ['ui.bootstrap']);

/* Define an album metadata update service. */
albumApp.factory('AlbumMetaUpdateService', ['$http', function ($http) {
    return {
        update: function (album_metadata) {
            console.log("in service with metadata.name, metadata.description: " + album_metadata.name + ", " + album_metadata.description);
            $http.put("albums/" + album_metadata.name, album_metadata)
                .success(function (data, status, headers, config) {
                    console.log("put worked: status=" + status);
                })
                .error(function (data, status, headers, config) {
                    console.log("put failed: status=" + status);
                });
        }}
}]);

albumApp.controller('AlbumController', function ($scope, $http, $modal, $log) {

    $scope.image_names_by_album = [];

    $http.get("albums")
        .success(function (data, status, headers, config) {
            $scope.albums = data;
            for (var i = 0; i < $scope.albums.length; i++) {
                $scope.album_fetcher($scope.albums[i]);
            }
        })
        .error(function (data, status, headers, config) {
        });

    $scope.album_fetcher = function (album_metadata) {
        $http.get("albums/" + album_metadata.name + "/photos")
            .success(function (data, status, headers, config) {
                $scope.image_names_by_album[album_metadata.name] = data;
            })
            .error(function (data, status, headers, config) {
            });
    };

    $scope.open = function (album_number, image_name) {

        $http.get("photo/metadata/" + album_number + "/" + image_name)
            .success(function (data, status, headers, config) {
                $scope.openPhotoDetail(data);
            })
            .error(function (data, status, headers, config) {
                $log.info("Error getting metadata for " + image_name);
            });

        $scope.openPhotoDetail = function (photo_metadata) {
            var photoDetailModal = $modal.open({
                templateUrl: 'partials/photodetail.html',
                controller: PhotoDetailModalController,
                resolve: {
                    image_info: function () {
                        return {
                            album: album_number,
                            image_name: image_name,
                            caption: "",
                            exif: {
                                lat: photo_metadata.lat,
                                long: photo_metadata.lng,
                                original_date: photo_metadata.originalTime
                            }
                        };
                    }
                }
            });
            photoDetailModal.result.then(function () {
            }, function () {
            });
        };
    };

    var PhotoDetailModalController = function ($scope, $modalInstance, image_info) {
        $scope.image_info = image_info;
        $scope.show_edit = false;
        $scope.caption = $scope.image_info.caption;

        $scope.ok = function () {
            $modalInstance.close();
        };

        $scope.edit = function () {
            $scope.show_edit = true;
            console.log("edit clicked: " + $scope.image_info.album + ", " + $scope.image_info.image_name);
        };

        $scope.update_caption = function () {
            $scope.show_edit = false;
            console.log("update caption" + $scope.image_info.caption);
        };

        $scope.cancel = function () {
            $modalInstance.dismiss('cancel');
        };
    };

    $scope.change_album_description = function (name, description) {
        for (i = 0; i < $scope.albums.length; ++i) {
            if ($scope.albums[i].name == name) {
                $scope.albums[i] = {name: name, description: description};
            }
        }
    };

    $scope.album_metadata_edit = function (album_metadata) {
        var albumDescriptionModal = $modal.open({
            templateUrl: 'partials/albumdetail.html',
            controller: AlbumDetailModalController,
            resolve: {
                album_meta: function () {
                    return {
                        name: album_metadata.name,
                        description: album_metadata.description,

                        /* deprecated:  let the album meta service update albums[] to avoid this callback */
                        update_callback: $scope.change_album_description
                    };
                }
            }
        });

        albumDescriptionModal.result.then(function () {
        }, function () {
        });
    };

    var AlbumDetailModalController = function ($scope, $modalInstance, AlbumMetaUpdateService, album_meta) {
        $scope.album_meta = album_meta;
        $scope.description = album_meta.description;

        $scope.ok = function (description) {
            $modalInstance.close();
            /* this callback is clunky.  can we not update albums here? */
            $scope.album_meta.update_callback($scope.album_meta.name, description);
            AlbumMetaUpdateService.update({name: $scope.album_meta.name, description: description});
        };

        $scope.cancel = function () {
            $modalInstance.dismiss('cancel');
        };
    };
});<|endoftext|>


<commit_before>// takes a post link and returns its comment url
function getCommentURL( linkToPost ) {
	var postCell,
		postRow,
		commentRow,
		commentLink,
		commentURL;

	postCell = linkToPost.parentNode;  // get table cell of link
	postRow = postCell.parentNode;	// get table row of link
	commentRow = postRow.nextElementSibling;  // go to next row (containing comment)

	// check if next row was found
	if( commentRow ) {
		commentLink = commentRow.querySelector("a:last-child");  // get the last link in that row
		// comments don't exist for "x is hiring" listings
		if ( commentLink )
			commentURL = commentLink.getAttribute("href");	// get the href attribute of comment link

		// return comment url
		return commentURL;
	}
}

function nodelistToArray( nodelist ) {
	var array = [];

	for (var i = 0; i < nodelist.length; i++ ) {
		var currentPost = nodelist[i];  // the node for the current post

		// Add node to array
		array.push( currentPost );
	}

	console.log(array);

	return array;
}

var linkList,
	linkArray;

// grab all links including "more" link and convert to array of objects
linkList = document.querySelectorAll( "td.title a" );
linkArray = nodelistToArray( linkList );

for (var i = 0; i <= linkArray.length; i++) {
	linkArray[i].addEventListener
};
<commit_msg>Lists all comments.<commit_after>// takes a post link and returns its comment url
function getCommentURL( linkToPost ) {
	var postCell,
		postRow,
		commentRow,
		commentLink,
		commentURL;

	postCell = linkToPost.parentNode;  // get table cell of link
	postRow = postCell.parentNode;	// get table row of link
	commentRow = postRow.nextElementSibling;  // go to next row (containing comment)

	// check if next row was found
	if( commentRow ) {
		commentLink = commentRow.querySelector("a:last-child");  // get the last link in that row
		// comments don't exist for "x is hiring" listings
		if ( commentLink )
			commentURL = commentLink.getAttribute("href");	// get the href attribute of comment link

		// return comment url
		return commentURL;
	}
}

// convert nodeList to array and get rid
function nodelistToArray( nodelist ) {
	var array = [];

	for (var i = 0; i < nodelist.length; i++ ) {
		var currentPost = nodelist[i];  // the node for the current post

		// Add node to array
		array.push( currentPost );
	}

	return array;
}

var linkList,
	linkArray,
	commentList = [];

// grab all links including "more" link and convert to array of objects
linkList = document.querySelectorAll( "td.title a" );
linkArray = nodelistToArray( linkList );

// use < to omit "more"
for (var i = 0; i < linkArray.length; i++) {
	var link 	= linkArray[i],
		comment = getCommentURL( link );

	if ( comment ) {
		console.log( comment );
	}
};
<|endoftext|>


<commit_before>function initCategoryFilter() {
  var cin = document.getElementById("category-input");
  var chi = document.getElementById("hidden-category-input");
  var ihi = document.getElementById("hidden-id-input");
  var options = document.getElementsByTagName("option");

  function item(originalItem, text, input) {
    if (input) {
      return originalItem(text, input);
    }

    var li = document.createElement("li");
    li.innerHTML = text;
    return li;
  }

  var awc = new Awesomplete(cin);
  awc.minChars = 0; // open dropdown on focus
  awc.maxItems = options.length; // display all options when cin is empty
  awc.sort = undefined; // sort alphabetially regardless of item length
  awc.item = item.bind(null, awc.item); // handle empty cin

  cin.addEventListener("click", function() {
    awc.evaluate();
  });

  cin.addEventListener("awesomplete-open", function() {
    this.classList.add("open");
  })

  cin.addEventListener("awesomplete-close", function() {
    this.classList.remove("open");
  })

  cin.addEventListener("awesomplete-highlight", function() {
    if (!awc.selected) {
      return;
    }

    var listRect = awc.ul.getBoundingClientRect(),
        elemRect = awc.ul.children[awc.index].getBoundingClientRect(),
        offset = elemRect.top - listRect.top;
    awc.ul.scrollTop += offset;
  });

  function setHiddenCategoryAndNextId(formElem) {
    var catname = cin.value.toLocaleLowerCase();
    var currentCategoryId = chi.value;

    chi.value = "all";
    for (var i = 0; i < options.length; i++) {
      if (options[i].label.toLocaleLowerCase() == catname) {
        chi.value = options[i].value;
      }
    }

    if (chi.value !== currentCategoryId) {
      formElem.removeChild(ihi);
    }
  }

  cin.addEventListener("awesomplete-selectcomplete", function() {
    setHiddenCategoryAndNextId(this.form);
    this.form.submit();
  });

  cin.form.addEventListener("submit", function() {
    setHiddenCategoryAndNextId(this.form);
    return true;
  });

  cin.style.visibility = '';
  cin.focus();
}

function loadCategoriesAndFilter() {
  var lang_code = document.documentElement.lang;
  var iframe = document.createElement("iframe");
  iframe.src = lang_code + "/categories.html";
  iframe.hidden = true;
  iframe.addEventListener("load", function() {
    var catlist = iframe.contentDocument.getElementById("categories");
    document.body.appendChild(catlist);

    if (document.readyState !== "loading") {
      initCategoryFilter();
    } else {
      window.addEventListener("DOMContentLoaded", function() {
        initCategoryFilter();
      });
    }
  });

  document.body.appendChild(iframe);
}

loadCategoriesAndFilter();
<commit_msg>Force autofocus only when actually autofocusing.<commit_after>function initCategoryFilter() {
  var cin = document.getElementById("category-input");
  var chi = document.getElementById("hidden-category-input");
  var ihi = document.getElementById("hidden-id-input");
  var options = document.getElementsByTagName("option");

  function item(originalItem, text, input) {
    if (input) {
      return originalItem(text, input);
    }

    var li = document.createElement("li");
    li.innerHTML = text;
    return li;
  }

  var awc = new Awesomplete(cin);
  awc.minChars = 0; // open dropdown on focus
  awc.maxItems = options.length; // display all options when cin is empty
  awc.sort = undefined; // sort alphabetially regardless of item length
  awc.item = item.bind(null, awc.item); // handle empty cin

  cin.addEventListener("click", function() {
    awc.evaluate();
  });

  cin.addEventListener("awesomplete-open", function() {
    this.classList.add("open");
  })

  cin.addEventListener("awesomplete-close", function() {
    this.classList.remove("open");
  })

  cin.addEventListener("awesomplete-highlight", function() {
    if (!awc.selected) {
      return;
    }

    var listRect = awc.ul.getBoundingClientRect(),
        elemRect = awc.ul.children[awc.index].getBoundingClientRect(),
        offset = elemRect.top - listRect.top;
    awc.ul.scrollTop += offset;
  });

  function setHiddenCategoryAndNextId(formElem) {
    var catname = cin.value.toLocaleLowerCase();
    var currentCategoryId = chi.value;

    chi.value = "all";
    for (var i = 0; i < options.length; i++) {
      if (options[i].label.toLocaleLowerCase() == catname) {
        chi.value = options[i].value;
      }
    }

    if (chi.value !== currentCategoryId) {
      formElem.removeChild(ihi);
    }
  }

  cin.addEventListener("awesomplete-selectcomplete", function() {
    setHiddenCategoryAndNextId(this.form);
    this.form.submit();
  });

  cin.form.addEventListener("submit", function() {
    setHiddenCategoryAndNextId(this.form);
    return true;
  });

  cin.style.visibility = '';
  if (cin.autofocus) {
    // Force autofocus, looks like it doesn't work on Chrome sometimes
    cin.focus();
  }
}

function loadCategoriesAndFilter() {
  var lang_code = document.documentElement.lang;
  var iframe = document.createElement("iframe");
  iframe.src = lang_code + "/categories.html";
  iframe.hidden = true;
  iframe.addEventListener("load", function() {
    var catlist = iframe.contentDocument.getElementById("categories");
    document.body.appendChild(catlist);

    if (document.readyState !== "loading") {
      initCategoryFilter();
    } else {
      window.addEventListener("DOMContentLoaded", function() {
        initCategoryFilter();
      });
    }
  });

  document.body.appendChild(iframe);
}

loadCategoriesAndFilter();
<|endoftext|>


<commit_before>/**
 * jQRangeSlider
 * A javascript slider selector that supports dates
 *
 * Copyright (C) Guillaume Gautreau 2012
 * Dual licensed under the MIT or GPL Version 2 licenses.
 */

 (function($, undefined){
 	"use strict";

 	$.widget("ui.rangeSliderDraggable", $.ui.rangeSliderMouseTouch, {
 		cache: null,

 		options: {
 			containment: null
 		},

 		_create: function(){
 			setTimeout($.proxy(this._initElement, this), 10);
 		},

 		_initElement: function(){
 			this._mouseInit();
 			this._cache();
 		},

 		_setOption: function(key, value){
 			if (key == "containment"){
 				if (value === null || $(value).length == 0){
 					this.options.containment = null
 				}else{
 					this.options.containment = $(value);
 				}
 			}
 		},

 		/*
 		 * UI mouse widget
 		 */

 		_mouseStart: function(event){
 			this._cache();
 			this.cache.click = {
 					left: event.pageX,
 					top: event.pageY
 			};

 			this.cache.initialOffset = this.element.offset();

 			this._triggerMouseEvent("mousestart");

 			return true;
 		},

 		_mouseDrag: function(event){
 			var position = event.pageX - this.cache.click.left;

 			position = this._constraintPosition(position + this.cache.initialOffset.left);

 			this._applyPosition(position);

 			this._triggerMouseEvent("drag");

 			return false;
 		},

 		_mouseStop: function(event){
 			this._triggerMouseEvent("stop");
 		},

 		/*
 		 * To be overriden
 		 */

 		_constraintPosition: function(position){
 			if (this.element.parent().length !== 0){
 				position = Math.min(position,
 					this.cache.parent.offset.left + this.cache.parent.width - this.cache.width.outer);
 				position = Math.max(position, this.cache.parent.offset.left);
 			}

 			return position;
 		},

 		_applyPosition: function(position){
 			var offset = {
 				top: this.cache.offset.top,
 				left: position
 			}

 			this.element.offset(offset);

 			this.cache.offset = offset;
 		},

 		/*
 		 * Private utils
 		 */

 		_cacheIfNecessary: function(){
 			if (this.cache === null){
 				this._cache();
 			}
 		},

 		_cache: function(){
 			this.cache = {};

 			this._cacheMargins();
 			this._cacheParent();
 			this._cacheDimensions();

 			this.cache.offset = this.element.offset();
 		},

 		_cacheMargins: function(){
 			this.cache.margin = {
 				left: this._parsePixels(this.element, "marginLeft"),
 				right: this._parsePixels(this.element, "marginRight"),
 				top: this._parsePixels(this.element, "marginTop"),
 				bottom: this._parsePixels(this.element, "marginBottom")
 			};
 		},

 		_cacheParent: function(){
 			if (this.options.parent !== null){
 				var container = this.element.parent();

	 			this.cache.parent = {
	 				offset: container.offset(),
	 				width: container.width()
	 			}
 			}else{
 				this.cache.parent = null;
 			}
 		},

 		_cacheDimensions: function(){
 			this.cache.width = {
 				outer: this.element.outerWidth(),
 				inner: this.element.width()
 			}
 		},

 		_parsePixels: function(element, string){
 			return parseInt(element.css(string), 10) || 0;
 		},

 		_triggerMouseEvent: function(event){
 			var data = this._prepareEventData();

 			this.element.trigger(event, data);
 		},

 		_prepareEventData: function(){
 			return {
 				element: this.element,
 				offset: this.cache.offset || null
 			};
 		}
 	});

 })(jQuery);<commit_msg>Bug in Opera (element positionning after drag and drop)<commit_after>/**
 * jQRangeSlider
 * A javascript slider selector that supports dates
 *
 * Copyright (C) Guillaume Gautreau 2012
 * Dual licensed under the MIT or GPL Version 2 licenses.
 */

 (function($, undefined){
 	"use strict";

 	$.widget("ui.rangeSliderDraggable", $.ui.rangeSliderMouseTouch, {
 		cache: null,

 		options: {
 			containment: null
 		},

 		_create: function(){
 			setTimeout($.proxy(this._initElement, this), 10);
 		},

 		_initElement: function(){
 			this._mouseInit();
 			this._cache();
 		},

 		_setOption: function(key, value){
 			if (key == "containment"){
 				if (value === null || $(value).length == 0){
 					this.options.containment = null
 				}else{
 					this.options.containment = $(value);
 				}
 			}
 		},

 		/*
 		 * UI mouse widget
 		 */

 		_mouseStart: function(event){
 			this._cache();
 			this.cache.click = {
 					left: event.pageX,
 					top: event.pageY
 			};

 			this.cache.initialOffset = this.element.offset();

 			this._triggerMouseEvent("mousestart");

 			return true;
 		},

 		_mouseDrag: function(event){
 			var position = event.pageX - this.cache.click.left;

 			position = this._constraintPosition(position + this.cache.initialOffset.left);

 			this._applyPosition(position);

 			this._triggerMouseEvent("drag");

 			return false;
 		},

 		_mouseStop: function(event){
 			this._triggerMouseEvent("stop");
 		},

 		/*
 		 * To be overriden
 		 */

 		_constraintPosition: function(position){
 			if (this.element.parent().length !== 0){
 				position = Math.min(position,
 					this.cache.parent.offset.left + this.cache.parent.width - this.cache.width.outer);
 				position = Math.max(position, this.cache.parent.offset.left);
 			}

 			return position;
 		},

 		_applyPosition: function(position){
 			var offset = {
 				top: this.cache.offset.top,
 				left: position
 			}

 			this.element.offset({left:position});

 			this.cache.offset = offset;
 		},

 		/*
 		 * Private utils
 		 */

 		_cacheIfNecessary: function(){
 			if (this.cache === null){
 				this._cache();
 			}
 		},

 		_cache: function(){
 			this.cache = {};

 			this._cacheMargins();
 			this._cacheParent();
 			this._cacheDimensions();

 			this.cache.offset = this.element.offset();
 		},

 		_cacheMargins: function(){
 			this.cache.margin = {
 				left: this._parsePixels(this.element, "marginLeft"),
 				right: this._parsePixels(this.element, "marginRight"),
 				top: this._parsePixels(this.element, "marginTop"),
 				bottom: this._parsePixels(this.element, "marginBottom")
 			};
 		},

 		_cacheParent: function(){
 			if (this.options.parent !== null){
 				var container = this.element.parent();

	 			this.cache.parent = {
	 				offset: container.offset(),
	 				width: container.width()
	 			}
 			}else{
 				this.cache.parent = null;
 			}
 		},

 		_cacheDimensions: function(){
 			this.cache.width = {
 				outer: this.element.outerWidth(),
 				inner: this.element.width()
 			}
 		},

 		_parsePixels: function(element, string){
 			return parseInt(element.css(string), 10) || 0;
 		},

 		_triggerMouseEvent: function(event){
 			var data = this._prepareEventData();

 			this.element.trigger(event, data);
 		},

 		_prepareEventData: function(){
 			return {
 				element: this.element,
 				offset: this.cache.offset || null
 			};
 		}
 	});

 })(jQuery);<|endoftext|>


<commit_before>/**
 * @class Oskari.mapframework.bundle.parcel.split.ParcelSplit
 *
 * Provides tools to split parcel.
 */
Oskari.clazz.define('Oskari.mapframework.bundle.parcel.split.ParcelSplit',

/**
 * @method create called automatically on construction
 * @static
 * @param {Oskari.mapframework.bundle.parcel.plugin.DrawPlugin} drawPlugin
 *          Plugin provides other elements for use if required by this class.
 */
function(drawPlugin) {
    // Class constructor initializes variables here.
    // Plugin provides other elements for use if required by this class.
    this.drawPlugin = drawPlugin;
}, {

    // Class functions and objects are defined here.
    // Items that are meant for private use only have _ prefix.

    /**
     * Initializations to be called after construction.
     */
    init : function() {
    },
    /**
     * Splits the parcel.
     *
     * {Oskari.mapframework.bundle.parcel.DrawingToolInstance} instance provides the features that are used for the splitting.
     */
    split : function() {
        if (this.drawPlugin.splitSelection) return;
        //var openLayersMap = this.drawPlugin.getMapModule().getMap();
        var parcelLayer = this.drawPlugin.drawLayer;
        var featureInd = parcelLayer.features.length-1;
        if (featureInd < 1) return;
        this.drawPlugin.splitSelection = true;
        var basePolygon = parcelLayer.features[0].geometry;
        var operatingGeometry = parcelLayer.features[featureInd].geometry;
        switch (operatingGeometry.CLASS_NAME) {
            case "OpenLayers.Geometry.Polygon":
                this.splitHole(basePolygon,operatingGeometry);
                parcelLayer.redraw();
                break;
            case "OpenLayers.Geometry.LineString":
                break;
        }
    },

    /*
     *
     */
    splitHole : function(outPolygon,inPolygon) {
        outPolygon.addComponent(inPolygon.components[0]);
    },

    /*
     *
     */
    splitLine : function(outPolygon,inPolygon) {

    }

});
<commit_msg>Added line splitting functionality.<commit_after>/**
 * @class Oskari.mapframework.bundle.parcel.split.ParcelSplit
 *
 * Provides tools to split parcel.
 */
Oskari.clazz.define('Oskari.mapframework.bundle.parcel.split.ParcelSplit',

/**
 * @method create called automatically on construction
 * @static
 * @param {Oskari.mapframework.bundle.parcel.plugin.DrawPlugin} drawPlugin
 *          Plugin provides other elements for use if required by this class.
 */
function(drawPlugin) {
    // Class constructor initializes variables here.
    // Plugin provides other elements for use if required by this class.
    this.drawPlugin = drawPlugin;
    this.intersectionPoints = [];
    this.markers = null;
    this.markerSize = new OpenLayers.Size(21,25);
    this.markerIcon = new OpenLayers.Icon('img/marker.png',this.markerSize,this.markerOffset);
    this.splitPolygons = [];
    this.map = this.drawPlugin.getMapModule().getMap();
    this.map.activeMarker = null;
}, {

    // Class functions and objects are defined here.
    // Items that are meant for private use only have _ prefix.

    /**
     * Initializations to be called after construction.
     */
    init : function() {
    },
    /**
     * Splits the parcel.
     *
     * {Oskari.mapframework.bundle.parcel.DrawingToolInstance} instance provides the features that are used for the splitting.
     */
    split : function() {
        if (this.drawPlugin.splitSelection) return;
        //var openLayersMap = this.drawPlugin.getMapModule().getMap();
        var parcelLayer = this.drawPlugin.drawLayer;
        var featureInd = parcelLayer.features.length-1;
        if (featureInd < 1) return;
        this.drawPlugin.splitSelection = true;
        var basePolygon = parcelLayer.features[0];
        var operatingFeature = parcelLayer.features[featureInd];
        switch (operatingFeature.geometry.CLASS_NAME) {
            case "OpenLayers.Geometry.Polygon":
                this.splitHole(basePolygon,operatingFeature);
                parcelLayer.redraw();
                break;
            case "OpenLayers.Geometry.LineString":
                this.splitLine(basePolygon,operatingFeature);
                break;
        }
        parcelLayer.redraw();
    },

    /*
     *
     */
    splitHole : function(outPolygon,inPolygon) {
        outPolygon.geometry.addComponent(inPolygon.geometry.components[0]);
    },

    /*
     *
     */
    splitLine : function(polygon,line) {
            var parcelLayer = this.drawPlugin.drawLayer;
            var vertices;
            var polygonEdges = [];
            var polylineEdges = [];
            var nLines = 0;
            var polylineSizes = [];
            var i, j, j1;

//            var parcelLayer = this.drawPlugin.drawLayer;

          	vertices = line.geometry.getVertices();
            polylineSizes.push(vertices.length);
            nLines = nLines+1;
            polylineEdges[nLines-1] = [];
            for (j=0; j<vertices.length-1; j++) {
                polylineEdges[nLines-1].push([vertices[j].x,vertices[j].y,vertices[j+1].x,vertices[j+1].y,line.id,j]);
            }

            vertices = polygon.geometry.getVertices();
            for (j=0; j<vertices.length; j++) {
                j1 = (j+1)%vertices.length;
                polygonEdges.push([vertices[j].x,vertices[j].y,vertices[j1].x,vertices[j1].y,polygon.id,j]);
            }

            var numIntersections = 0;
            var removedPoints = 0;
            for (i=0; i<polylineEdges.length; i++) {
                // var line = vectors.getFeatureById(polylineEdges[i][0][4]);
                var comp = line.geometry.components;
                for (j=0; j<polylineEdges[i].length; j++) {
                    if (numIntersections > 1) {
                        comp[j].outside = (typeof comp[j].outside === 'undefined');
                        continue;
                    }
                    for (var k=0; k<polygonEdges.length; k++) {
                        var p = this.intersection(polylineEdges[i][j],polygonEdges[k]);
                        if (p === null) {
                            comp[j].outside = (numIntersections < 1);
                        } else {
                            comp[j].outside = false;
                            this.intersectionPoints.push([p,polygonEdges[k][4],polygonEdges[k][5],polylineEdges[i][j][4],i,j,k]);
                            if (numIntersections === 0) {
                                comp[j].x = p[0];
                                comp[j].y = p[1];
                                numIntersections++;
                            } else {
                                numIntersections++;
                                comp[j+1].x = p[0];
                                comp[j+1].y = p[1];
                                comp[j+1].outside = false;
                                break;
                            }
                        }
                    }
                }
                if (this.intersectionPoints[0][6] > this.intersectionPoints[1][6]) this.intersectionPoints.reverse();
                if (this.intersectionPoints[0][5] > this.intersectionPoints[1][5]) {
                    polylineEdges[i].reverse();
                    for (var l = 0; l < polylineEdges[i].length; l++) {
                        var temp0 = polylineEdges[i][l][0];
                        var temp1 = polylineEdges[i][l][1];
                        polylineEdges[i][l][0] = polylineEdges[i][l][2];
                        polylineEdges[i][l][1] = polylineEdges[i][l][3];
                        polylineEdges[i][l][2] =temp0;
                        polylineEdges[i][l][3] =temp1;
                    }
                    this.intersectionPoints[0][5] = polylineEdges[i].length-1-this.intersectionPoints[0][5];
                    this.intersectionPoints[1][5] = polylineEdges[i].length-1-this.intersectionPoints[1][5];
                }

                comp[polylineEdges[i].length].outside = (typeof comp[j].outside === 'undefined');
                j = 0;
                while (j<comp.length) {
                    if (comp[j].outside) {
                        comp.splice(j,1);
                        continue;
                    }
                    j++;
                }
            }

            this.markers = new OpenLayers.Layer.Markers( "Markers" );
            //this.map.addLayers([this.markers]);
            //this.map.setLayerIndex(this.markers, 100000);
            var minPolygonEdge = Number.POSITIVE_INFINITY;
            var minPolygonEdgeIndex = -1;
            var marker;
            for (i=0; i<this.intersectionPoints.length; i++) {
                var point = new OpenLayers.Geometry.Point(this.intersectionPoints[i][0][0],this.intersectionPoints[i][0][1]);
                marker = new OpenLayers.Marker(new OpenLayers.LonLat(point.x,point.y),this.markerIcon.clone());
                marker.setOpacity(0.8);
                marker.polygonID = this.intersectionPoints[i][1];
                marker.polygonEdge = this.intersectionPoints[i][2];
                marker.polylineID = this.intersectionPoints[i][3];
                marker.polylineEdge = this.intersectionPoints[i][4];
                marker.first = false;
                marker.markerOffset = new OpenLayers.Pixel(-(this.markerSize.w/2), -this.markerSize.h);
                marker.markerMouseOffset = new OpenLayers.LonLat(0, 0);

                if (marker.polygonEdge < minPolygonEdge) {
                    minPolygonEdge = marker.polygonEdge;
                    minPolygonEdgeIndex = i;
                }
                this.markers.addMarker(marker);
            }
            if (minPolygonEdgeIndex >= 0) this.markers.markers[minPolygonEdgeIndex].first = true;

            for (i=0; i<this.markers.markers.length; i++) {
                this.markers.markers[i].events.register("mousedown", marker, this.selectActiveMarker);
            }

            this.splitPolygons = this.generateSplitPolygons(polygonEdges,polylineEdges);

            parcelLayer.removeAllFeatures();
            parcelLayer.addFeatures(this.splitPolygons);
    },

    generateSplitPolygons : function(polygonEdges, polylineEdges) {
        var point;
        var point1 = null;
        var point2;
        var points1 = [];
        var points2 = [];
        var linearRing;
        var polygons = [];
        var styles = [];
        var i;
        var commonPoints = [];

        if (this.intersectionPoints.length<1) return null;

        // leikkaus
        points1 = [];
        var polygonCorners1 = [];
        for (i=0; i<this.intersectionPoints[0][6]+1; i++) {
            point = new OpenLayers.Geometry.Point(polygonEdges[i][0], polygonEdges[i][1]);
            points1.push(point);
        }
        point = new OpenLayers.Geometry.Point(this.intersectionPoints[0][0][0],this.intersectionPoints[0][0][1]);
        points1.push(point);
        polygonCorners1.push(points1.length-1);
        commonPoints.push(point);

        for (i = this.intersectionPoints[0][5]+1; i < this.intersectionPoints[1][5]+1; i++) {
            point = new OpenLayers.Geometry.Point(polylineEdges[this.intersectionPoints[0][4]][i][0],polylineEdges[this.intersectionPoints[0][4]][i][1]);
            points1.push(point);
            commonPoints.push(point);
        }

        point = new OpenLayers.Geometry.Point(this.intersectionPoints[1][0][0],this.intersectionPoints[1][0][1]);
        points1.push(point);
        polygonCorners1.push(points1.length-1);
        commonPoints.push(point);

        for (i=this.intersectionPoints[1][6]+1; i<polygonEdges.length; i++) {
            point = new OpenLayers.Geometry.Point(polygonEdges[i][0], polygonEdges[i][1]);
            points1.push(point);
        }

        var polygon1 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(points1)]));
        var style1;
        style1 = OpenLayers.Util.applyDefaults(style1, OpenLayers.Feature.Vector.style['default']);
        style1.fillColor = this.getRandomColor();
        style1.fillOpacity = 0.6;
        polygon1.style = style1;
        polygon1.polygonCorners = polygonCorners1;

        points2 = [];
        var polygonCorners2 = [];
        for (i=this.intersectionPoints[0][6]+1; i<this.intersectionPoints[1][6]+1; i++) {
            point = new OpenLayers.Geometry.Point(polygonEdges[i][0], polygonEdges[i][1]);
            points2.push(point);
        }
        point = commonPoints[commonPoints.length-1];
        points2.push(point);
        polygonCorners2.push(points2.length-1);

        for (i = commonPoints.length-2; i>0; i--) {
            point = commonPoints[i];
            points2.push(point);
        }

        point = commonPoints[0];
        points2.push(point);
        polygonCorners2.push(points2.length-1);
        var polygon2 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(points2)]));
        var style2;
        style2 = OpenLayers.Util.applyDefaults(style2, OpenLayers.Feature.Vector.style['default']);
        style2.fillColor = this.getRandomColor();
        style2.fillOpacity = 0.6;
        polygon2.style = style2;
        polygon2.polygonCorners = polygonCorners2;

        return [polygon1,polygon2];
    },

    /*
     *
     */
    getRandomColor : function() {
        var letters = '0123456789ABCDEF'.split('');
        var color = '#';
        for (var i = 0; i < 6; i++) {
            color += letters[Math.round(Math.random() * 15)];
        }
        return color;
    },

    /*
     *
     */
    intersection : function(edge1,edge2) {
        var Ax = edge1[0];
        var Ay = edge1[1];
        var Bx = edge1[2];
        var By = edge1[3];
        var Cx = edge2[0];
        var Cy = edge2[1];
        var Dx = edge2[2];
        var Dy = edge2[3];

        var distAB, theCos, theSin, newX, ABpos;

        //  Fail if either line segment is zero-length.
        if ((Ax === Bx && Ay === By) || (Cx === Dx && Cy === Dy)) return null;

        // to-do: tarkista miten käsitellään:
        //  Fail if the segments share an end-point.
        if ((Ax === Cx && Ay === Cy) || (Bx === Cx && By === Cy)
                ||  (Ax === Dx && Ay === Dy) || (Bx === Dx && By === Dy)) {
            return null;
        }

        //  (1) Translate the system so that point A is on the origin.
        Bx-=Ax; By-=Ay;
        Cx-=Ax; Cy-=Ay;
        Dx-=Ax; Dy-=Ay;

        //  Discover the length of segment A-B.
        distAB=Math.sqrt(Bx*Bx+By*By);

        //  (2) Rotate the system so that point B is on the positive X axis.
        theCos=Bx/distAB;
        theSin=By/distAB;
        newX=Cx*theCos+Cy*theSin;
        Cy=Cy*theCos-Cx*theSin;
        Cx=newX;
        newX=Dx*theCos+Dy*theSin;
        Dy=Dy*theCos-Dx*theSin;
        Dx=newX;

        //  Fail if segment C-D doesn't cross line A-B.
        if ((Cy<0.0 && Dy<0.0) || (Cy>=0.0 && Dy>=0.0)) return null;

        //  (3) Discover the position of the intersection point along line A-B.
        ABpos=Dx+(Cx-Dx)*Dy/(Dy-Cy);

        //  Fail if segment C-D crosses line A-B outside of segment A-B.
        if ((ABpos<0.0) || (ABpos>distAB)) return null;

        //  (4) Apply the discovered position to line A-B in the original coordinate system.
        var x = Ax+ABpos*theCos;
        var y = Ay+ABpos*theSin;

        //  Success.
        return [x,y];
    },

        /*
         *
         */
        selectActiveMarker : function(evt) {
            OpenLayers.Event.stop(evt);
            var xy = this.map.events.getMousePosition(evt);
            var pixel = new OpenLayers.Pixel(xy.x,xy.y);
            var xyLonLat = this.map.getLonLatFromPixel(pixel);
            this.map.activeMarker = evt.object;
            this.markerMouseOffset.lon = xyLonLat.lon-this.map.activeMarker.lonlat.lon;
            this.markerMouseOffset.lat = xyLonLat.lat-this.map.activeMarker.lonlat.lat;
            this.map.events.register("mouseup", this.map, this.freezeActiveMarker);
            this.map.events.register("mousemove", this.map, this.moveActiveMarker);
        },

        /*
         *
         */
        moveActiveMarker : function (evt) {
            var lonlat = this.map.getLonLatFromPixel(new OpenLayers.Pixel(evt.xy.x,evt.xy.y))
            lonlat.lon -= this.markerMouseOffset.lon;
            lonlat.lat -= this.markerMouseOffset.lat;
            this.map.activeMarker.lonlat = this.map.activeMarkerProjection(lonlat);
            markers.redraw();
            OpenLayers.Event.stop(evt);
        },

        /*
         *
         */
        freezeActiveMarker : function(evt) {
            this.map.events.unregister("mousemove",this.map,this.moveActiveMarker);
            this.map.events.unregister("mouseup",this.map,this.freezeActiveMarker);
            OpenLayers.Event.stop(evt);

            var lonlat = this.map.getLonLatFromPixel(new OpenLayers.Pixel(evt.xy.x,evt.xy.y))
            lonlat.lon -= this.markerMouseOffset.lon;
            lonlat.lat -= this.markerMouseOffset.lat;
            this.map.activeMarker.lonlat = this.activeMarkerProjection(lonlat);

            var parcelLayer = this.drawPlugin.drawLayer;
            var line = parcelLayer.getFeatureById(this.map.activeMarker.polylineID);
//            var vertices = line.geometry.getVertices();
            var edgeInd = this.map.activeMarker.polylineEdge;

            if (splitPolygons !== null) {
                var comp = [];
                comp[0] = splitPolygons[0].geometry.components[0].components;
                if (this.map.activeMarker.first) {
                    comp[0][splitPolygons[0].polygonCorners[0]].x = this.map.activeMarker.lonlat.lon;
                    comp[0][splitPolygons[0].polygonCorners[0]].y = this.map.activeMarker.lonlat.lat;
                } else {
                    comp[0][splitPolygons[0].polygonCorners[1]].x = this.map.activeMarker.lonlat.lon;
                    comp[0][splitPolygons[0].polygonCorners[1]].y = this.map.activeMarker.lonlat.lat;
                }
                comp[1] = splitPolygons[1].geometry.components[0].components;
                if (this.map.activeMarker.first) {
                    comp[1][splitPolygons[1].polygonCorners[1]].x = this.map.activeMarker.lonlat.lon;
                    comp[1][splitPolygons[1].polygonCorners[1]].y = this.map.activeMarker.lonlat.lat;
                } else {
                    comp[1][splitPolygons[1].polygonCorners[0]].x = this.map.activeMarker.lonlat.lon;
                    comp[1][splitPolygons[1].polygonCorners[0]].y = this.map.activeMarker.lonlat.lat;
                }
            }

            markers.redraw();
            parcelLayer.redraw();
        },

       /**
        *
        */
        activeMarkerProjection : function(refLonlat) {
            var parcelLayer = this.drawPlugin.drawLayer;
            var point = {x: refLonlat.lon, y: refLonlat.lat};
            var polygonID = this.map.activeMarker.polygonID;
            var polygon = parcelLayer.getFeatureById(polygonID);
            var edge = this.map.activeMarker.polygonEdge;
            var vertices = polygon.geometry.getVertices();
            var nEdges = vertices.length;
            var inds = [(edge-1+nEdges)%nEdges,edge,(edge+1+nEdges)%nEdges,(edge+2+nEdges)%nEdges];
            var projPoints = [];
            var distances = [];

            var minDistInd = 0;
            for (var i = 0; i < 3; i++) {
                projPoints[i] = this.projection(point,vertices[inds[i]],vertices[inds[i+1]]);
                distances[i] = this.distance(point,projPoints[i]);
                if (distances[i] < distances[minDistInd]) minDistInd = i;
            }
            this.map.activeMarker.polygonEdge = (edge+minDistInd+nEdges-1)%nEdges;

//            return (new OpenLayers.LonLat(projPoints[minDistInd].x,projPoints[minDistInd].y));

            // kun vain yksi väli mahdollinen:
            this.map.activeMarker.polygonEdge = edge;
            return (new OpenLayers.LonLat(projPoints[1].x,projPoints[1].y));
        },

       /**
        *
        */
       projection : function(q,p0,p1) {
           var a = p1.x-p0.x;
           var b = p1.y-p0.y;
           var c = q.x*(p1.x-p0.x)+q.y*(p1.y-p0.y);
           var d = p0.y-p1.y;
           var e = p1.x-p0.x;
           var f = p0.y*(p1.x-p0.x)-p0.x*(p1.y-p0.y);
           var pq = {x:-(c*e-b*f)/(b*d-a*e), y:(c*d-a*f)/(b*d-a*e)};

           // Tarkistetaan onko segmentin sisällä
           var p0p1 = {x:p1.x-p0.x, y:p1.y-p0.y};
           var pqp1 = {x:p1.x-pq.x, y:p1.y-pq.y};
           var dp = this.dotProduct(p0p1,pqp1);
           var l =  this.dotProduct(p0p1,p0p1);
           if (dp < 0) {
               pq.x = p1.x;
               pq.y = p1.y;
           } else if (dp > l) {
               pq.x = p0.x;
               pq.y = p0.y;
           }

           return pq;
       }, // tapaus nimittäjä==0

       /**
        *
        */
        dotProduct : function(a,b) {
           return a.x* b.x+ a.y*b.y;
        },

       /**
        *
        */
        isNumber : function(n) {
          return (!isNaN(parseFloat(n)))&&(isFinite(n));
        }

});
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {

  constructor () {
    super();
    this.state = {
      val: 0
    }
    this.update = this.update.bind(this)
  }

  update () {
    this.setState({
      val: this.state.val + 1
    })
  }

  componentWillMount () {
    console.log('componentWillMount');
    this.setState({
      m: 2
    });
  }

  render () {
    console.log('render');
    return (
      <button
        onClick={this.update}
      >
        {this.state.val * this.state.m}
      </button>
    )
  }

  componentDidMount () {
    console.log('componentDidMount');
    this.inc = setInterval(this.update, 500);
  }

  componentWillUnmount () {
    console.log('componentWillUnmount');
    clearInterval(this.inc);
  }

}

class Wrapper extends React.Component {

  mount () {
    ReactDOM.render(
      <App />,
      document.getElementById('a')
    )
  }

  unmount () {
    ReactDOM.unmountComponentAtNode(
      document.getElementById('a')
    )
  }

  render () {
    return (
      <div>
        <button
          onClick={this.mount.bind(this)}
        >
          Mount
        </button>
        <button
          onClick={this.unmount.bind(this)}
        >
          UnMount
        </button>
        <div
          id="a"
        >
        </div>
      </div>
    )
  }

}

export default Wrapper
<commit_msg>[UPDATE] Control React Component Updates When New Props Are Received<commit_after>import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {

  constructor () {
    super();
    this.state = {increasing: false}
  }

  update () {
    ReactDOM.render(
      <App val={this.props.val + 1} />,
      document.getElementById('root')
    )
  }

  componentWillReceiveProps(nextProps) {
    this.setState({increasing: nextProps.val > this.props.val})
  }

  shouldComponentUpdate(nextProps, nextState) {
    return nextProps.val % 5 === 0;
  }

  render () {
    console.log(this.state.increasing)
    return (
      <button
        onClick={this.update.bind(this)}
      >
        { this.props.val }
      </button>
    )
  }

  componentDidUpdate(prevProps, prevState) {
    console.log(`prevProps: ${prevProps.val}`)
  }

}

App.defaultProps = {
  val: 0
}

export default App
<|endoftext|>


<commit_before>//Copyright 2014, Small Picture, Inc.
	//1/19/14 by DW
		//This is a shell for developing the functionality of the Fargo back-end.
		//When done, it will take requests saying that a named outline has updated.
		//It will know how to find the OPML, and from there, to find a "package" of updates.
		//Which it will then parse, and upload to a bucket on S3.
		//Still have a ways to go, but it's fun, and a lot is working! :-)

var AWS = require ("aws-sdk");
var s3 = new AWS.S3 ();
var http = require ('http');

var writeStaticFile = function (path, data, type, acl) {
	var bucketname = "";
	if (type == undefined) {
		type = "text/plain";
		}
	if (acl == undefined) {
		acl = "public-read";
		}

	//split path into bucketname and path -- like this: /tmp.scripting.com/testing/one.txt
		if (path.length > 0) {
			if (path [0] == "/") { //delete the slash
				path = path.substr (1);
				}
			var ix = path.indexOf ("/");
			bucketname = path.substr (0, ix);
			path = path.substr (ix + 1);
			console.log ("Writing to bucket: \"" + bucketname + "\" path: \"" + path + "\"");
			}

	var params = {
		ACL: acl,
		ContentType: type,
		Body: data,
		Bucket: bucketname,
		Key: path
		};
	s3.putObject (params, function (err, data) {
		console.log ("Wrote S3 file: http://" + bucketname + "/" + path);
		});
	}

console.log ("starting server");
var counter = 0;
var server = http.createServer(function(request, response) {
	response.writeHead(200, {'Content-Type': 'text/plain'});
	var color = 'blue';
	if (counter % 2 === 1) {
		color = 'no, green';
		}
	response.end(color);
	writeStaticFile ("/tmp.scripting.com/testing/" + counter + ".txt", new Date ().toString ());
	counter++;
	});
server.listen (1337);
<commit_msg>Update<commit_after>//Copyright 2014, Small Picture, Inc.
	//1/19/14 by DW
		//This is a shell for developing the functionality of the Fargo back-end.
		//When done, it will take requests saying that a named outline has updated.
		//It will know how to find the OPML, and from there, to find a "package" of updates.
		//Which it will then parse, and upload to a bucket on S3.
		//Still have a ways to go, but it's fun, and a lot is working! :-)

var AWS = require ("aws-sdk");
var s3 = new AWS.S3 ();
var http = require ('http');

var padWithZeros = function (num, ctplaces) {
	var s = num.toString ();
	while (s.length < ctplaces) {
		s = "0" + s;
		}
	return (s);
	}
var writeStaticFile = function (path, data, type, acl) {
	var bucketname = "";
	if (type == undefined) {
		type = "text/plain";
		}
	if (acl == undefined) {
		acl = "public-read";
		}

	//split path into bucketname and path -- like this: /tmp.scripting.com/testing/one.txt
		if (path.length > 0) {
			if (path [0] == "/") { //delete the slash
				path = path.substr (1);
				}
			var ix = path.indexOf ("/");
			bucketname = path.substr (0, ix);
			path = path.substr (ix + 1);
			}

	var params = {
		ACL: acl,
		ContentType: type,
		Body: data,
		Bucket: bucketname,
		Key: path
		};
	s3.putObject (params, function (err, data) {
		console.log ("Wrote S3 file: http://" + bucketname + "/" + path);
		});
	}

console.log ("starting server");
var counter = 0;
var server = http.createServer(function(request, response) {
	response.writeHead(200, {'Content-Type': 'text/plain'});
	var color = 'blue';
	if (counter % 2 === 1) {
		color = 'no, green';
		}
	response.end(color);
	writeStaticFile ("/tmp.scripting.com/testing/" + padWithZeros (counter, 4) + ".txt", new Date ().toString ());
	counter++;
	});
server.listen (1337);
<|endoftext|>