All Downloads are FREE. Search and download functionalities are using the official Maven repository.

SLING-INF.content.devwidgets.changepic.javascript.changepic.js Maven / Gradle / Ivy

/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

/*
 * Dependencies
 *
 * /dev/lib/jquery/plugins/imgareaselect/jquery.imgareaselect.js (imgAreaSelect)
 * /dev/lib/jquery/plugins/jqmodal.sakai-edited.js
 * /dev/lib/jquery/plugins/jquery.json.js (toJSON)
 */

require(["jquery", "sakai/sakai.api.core", "/dev/lib/jquery/plugins/imgareaselect/jquery.imgareaselect.js"], function($, sakai) {

    /**
     * @name sakai_global.changepic
     *
     * @class changepic
     *
     * @description
     * Changepic widget
     *
     * @version 0.0.1
     * @param {String} tuid Unique id of the widget
     * @param {Boolean} showSettings Show the settings of the widget or not
     */
    sakai_global.changepic = function(tuid, showSettings){


        //////////////////////
        // Config Variables //
        //////////////////////

        var realw = 0;
        var realh = 0;
        var picture = false;
        var ratio = 1;
        var userSelection = null; // The object returned by imgAreaSelect that contains the user his choice.
        var originalPic = null; // current or default selection area
        var me = null;
        var imageareaobject;
        var id = null;
        var mode = null;
        var fullPicHeight = 300;
        var fullPicWidth = 325;

        // These values are just in case there are no css values specified.
        // If you want to change the size of a thumbnail please do this in the CSS.
        var thumbnailWidth = 100;
        var thumbnailHeight = 100;


        //////////////
        // CSS IDS  //
        //////////////

        var containerTrigger = '#changepic_container_trigger'; // This is the id that will trigger this widget.

        // others
        var selectContentArea = "#changepic_selectpicture";
        var container = "#changepic_container";
        var picForm = "#changepic_form";
        var picInput = "#profilepicture";
        var picInputError = "#changepic_nofile_error";
        var uploadProcessing = "#changepic_uploading";
        var uploadNewButtons = "#changepic_uploadnew_buttons";
        var uploadNewCancel = "#profile_upload_cancel";
        var pictureMeasurer = "#picture_measurer";
        var pictureMeasurerImage = "#picture_measurer_image";
        var saveNewSelection = "#save_new_selection";
        var fullPicture = "#changepic_fullpicture_img";
        var fullPictureSpan = "#changepic_fullpicture";
        var thumbnail = "#thumbnail_img";
        var thumbnailSpan = "#thumbnail";
        var thumbnailContainer = "#thumbnail_container";
        var picInputErrorClass = "changepic_input_error";
        var fileName = false;
        var existingPicture = false;

        // An array with selectors pointing to images that need to be changed.
        var imagesToChange = ["#picture_holder img", "#entity_profile_picture", "#myprofile_pic", "#chat_available_me .chat_available_image img", "#profile_userinfo_picture"];


        ///////////////////
        // UTIL FUNCTIONS //
        ///////////////////

         /**
         * Hides and reset image select area
         */
        var hideSelectArea = function(){
            if (imageareaobject) {
                imageareaobject.setOptions({
                    hide: true,
                    disable: true
                });
                imageareaobject.update();
            }

            $(selectContentArea).hide();
            $(uploadNewCancel).show();
        };

         /**
         * Shows image select area
         */
        var showSelectArea = function(){
            $(uploadNewCancel).hide();
            $(selectContentArea).show();
        };

        /**
         * When the user has drawn a square this function will be called by imgAreaSelect.
         * This will draw the thumbnail by modifying it's css values.
         * @param {Object} img    The thumbnail
         * @param {Object} selection The selection object from imgAreaSelect
         */
        var preview = function(img, selection){
            // Save the user his selection in a global variable.
            userSelection = selection;

            // How much has the user scaled down the image?
            var scaleX = thumbnailWidth / (selection.width || 1);
            var scaleY = thumbnailHeight / (selection.height || 1);

            // Change the thumbnail according to the user his selection via CSS.
            $(thumbnail).css({
                width: Math.round(scaleX * img.width) + 'px',
                height: Math.round(scaleY * img.height) + 'px',
                marginLeft: '-' + Math.round(scaleX * selection.x1) + 'px',
                marginTop: '-' + Math.round(scaleY * selection.y1) + 'px'
            });
        };

        /**
         * Shows file input error
         */
        var showInputError = function(){
            $(picInputError).show();
            $(picInput).addClass(picInputErrorClass);
            if ($(selectContentArea + ":visible") && imageareaobject){
                imageareaobject.update();
            }
        };

        /**
         * Hides file input error
         */
        var hideInputError = function(){
            $(picInputError).hide();
            $(picInput).removeClass(picInputErrorClass);
            if ($(selectContentArea + ":visible") && imageareaobject){
                imageareaobject.update();
            }
        };

         /**
         * Empty upload field by resetting the form
         */
        var resetUploadField = function(){
            $(picForm).reset();
            hideInputError();
            $(uploadProcessing).hide();
            $(uploadNewButtons).show();
            $('#profile_upload').attr('disabled', 'disabled');
        };

        // Add click event to all cancel buttons in the overlay
        // Since file upload form is reset every time overlay closes do this in init function
        $("#changepic_container .jqmClose").click(function(){
            resetUploadField();
            // hide any tooltips if they are open
            $(window).trigger("done.tooltip.sakai");
        });

        /**
         * On changepic form submit, check that a file has been selected
         * and submit the form.
         */
        $("#profile_upload").unbind("click").bind("click", function(){
            // validate args
            // file extension allow for image
            var extensionArray = [".png", ".jpg", ".jpeg",".gif"];
            // get file name
            fileName = $(picInput).val();
            // get extension from the file name.
            var extension = fileName.slice(fileName.lastIndexOf(".")).toLowerCase();
            var allowSubmit = false;

            for (var i = 0; i < extensionArray.length; i++) {
                 // extension is acceptable image format
                 if (extensionArray[i] === extension) {
                    allowSubmit = true;
                    break;
                 }
            }
            // if image format is acceptable
            if(allowSubmit) {
                hideInputError();
                $(uploadNewButtons).hide();
                $(uploadProcessing).show();
                fileName = "tmp" + new Date().getTime() + ".jpg";
                $(picInput).attr("name",fileName);
                hideSelectArea();
                $(picForm).ajaxForm({
                    success: function(data){
                        doInit(true);
                    },
                    error: function(){
                        showInputError();
                        return false;
                    }
                });
                $(picForm).submit();
            } else {
                // no input, show error
                showInputError();
                return false;
            }
        });

        /**
         * Initilise function
         * @param {boolean} newpic True if a new picture has just been uploaded
         */
        var doInit = function(newpic){
            hideSelectArea();

            if (!id) {
                id = sakai.data.me.user.userid;
                mode = "user";
            }

            var showPicture = true;
            var json;

            if (mode === "group") {
                // fetch group data to check if it has a picture
                $.ajax({
                    url: "/~" + id + "/public.infinity.json",
                    async: false,
                    success: function(data){
                        json = data.authprofile;
                    }
                });
            } else {
                // Check whether there is a base picture at all
                me = sakai.data.me;
                json = me.profile;
            }
            // If the image is freshly uploaded then reset the imageareaobject to reset all values on init
            if (newpic) {
                imageareaobject = null;
                picture = {
                    "_name": fileName,
                    "selectedx1":0,
                    "selectedy1":0,
                    "selectedx2":64,
                    "selectedy2":64
                };
            }
            else if (json.picture) {
                picture = $.parseJSON(json.picture);
            } else {
                showPicture = false;
            }

            $(picForm).attr("action", "/~" + sakai.api.Util.safeURL(id) + "/public/profile");

            // Get the preferred size for the thumbnail.
            var prefThumbWidth = parseInt($(thumbnailContainer).css("width").replace(/px/gi,""), 10);
            var prefThumbHeight = parseInt($(thumbnailContainer).css("height").replace(/px/gi,""), 10);

            // Make sure we don't have 0
            thumbnailWidth  = (prefThumbWidth > 0) ? prefThumbWidth : thumbnailWidth;
            thumbnailHeight  = (prefThumbHeight > 0) ? prefThumbHeight : thumbnailHeight;

            if (showPicture && picture && picture._name) {
                // The user has already uploaded a picture.
                // Show the image select area
                existingPicture = true;

                // Set the unvisible image to the full blown image. (make sure to filter the # out)
                $(pictureMeasurer).html(sakai.api.Security.saneHTML(""));

                // Check the current picture's size
                $(pictureMeasurerImage).bind("load", function(ev){
                    resetUploadField();

                    // save the image size in global var.
                    realw = $(pictureMeasurerImage).width();
                    realh = $(pictureMeasurerImage).height();

                    // Set the images
                    $(fullPictureSpan).html('' + $(');
                    $(thumbnailSpan).html('' + $(');

                    // Reset ratio
                    ratio = 1;

                    // fullPicWidth (500) and fullPicHeight (300) set in config variables
                    // Width < 500 ; Height < 300 => set the original height and width
                    if (realw < fullPicWidth && realh < fullPicHeight){
                        $(fullPicture).width(realw);
                        $(fullPicture).height(realh);

                    // Width > 500 ; Height < 300 => Width = 500
                    } else if (realw > fullPicWidth && (realh / (realw / fullPicWidth) < fullPicHeight)){
                        ratio = realw / fullPicWidth;
                        $(fullPicture).width(fullPicWidth);
                        $(fullPicture).height(Math.floor(realh / ratio));

                    // Width < 500 ; Height > 300 => Height = 300
                    } else if (realh > fullPicHeight && (realw / (realh / fullPicHeight) < fullPicWidth)) {
                        ratio = realh / fullPicHeight;
                        $(fullPicture).height(fullPicHeight);
                        $(fullPicture).width(Math.floor(realw / ratio));

                    // Width > 500 ; Height > 300
                    } else if (realh > fullPicHeight && (realw / (realh / fullPicHeight) > fullPicWidth)) {

                        var heightonchangedwidth = realh / (realw / fullPicWidth);
                        if (heightonchangedwidth > fullPicHeight){
                            ratio = realh / fullPicHeight;
                            $(fullPicture).height(fullPicHeight);
                        } else {
                            ratio = realw / fullPicWidth;
                            $(fullPicture).width(fullPicWidth);
                        }
                    }

                    var selectionObj = {
                        width : picture.selectedx2 - picture.selectedx1,
                        height :picture.selectedy2 - picture.selectedy1,
                        x1 : picture.selectedx1,
                        y1 : picture.selectedy1,
                        x2 : picture.selectedx2,
                        y2 : picture.selectedy2,
                        picture : picture._name
                    };
                    if (!newpic){
                        originalPic = selectionObj;
                    }

                    // Set the imgAreaSelect to a function so we can access it later on
                    imageareaobject = $(fullPicture).imgAreaSelect({
                        aspectRatio: "1:1",
                        enable: true,
                        show: true,
                        instance: true,
                        onInit: function(){
                            // If the image gets loaded, make a first selection
                            imageareaobject.setSelection(picture.selectedx1, picture.selectedy1, picture.selectedx2, picture.selectedy2);
                            imageareaobject.setOptions({show: true, enable: true});
                            imageareaobject.update();
                            preview($("img" + fullPicture)[0], selectionObj);
                            // display help tooltip
                            var tooltipData = {
                                "tooltipSelector":"#save_new_selection",
                                "tooltipTitle":"TOOLTIP_ADD_MY_PHOTO",
                                "tooltipDescription":"TOOLTIP_ADD_MY_PHOTO_P4",
                                "tooltipArrow":"top",
                                "tooltipLeft":50
                            };
                            $(window).trigger("update.tooltip.sakai", tooltipData);
                        },
                        onSelectChange: preview
                    });
                    showSelectArea();
                });

                // if there is upload error show the error message
                $(pictureMeasurerImage).bind("error", function(){
                    showInputError();
                });
            }
        };

        // Remove error notification when a new file is chosen
        $(picInput).bind("change", function(){
            hideInputError();
            $('#profile_upload').removeAttr('disabled');
            // display help tooltip
            var tooltipData = {
                "tooltipSelector":"#profile_upload",
                "tooltipTitle":"TOOLTIP_ADD_MY_PHOTO",
                "tooltipDescription":"TOOLTIP_ADD_MY_PHOTO_P3",
                "tooltipArrow":"bottom"
            };
            $(window).trigger("update.tooltip.sakai", tooltipData);
        });

        // This is the function that will be called when a user has cut out a selection
        // and saves it.
        $(saveNewSelection).click(function(ev){
            if (!userSelection) {
                userSelection = imageareaobject.getSelection();
                savePicture();
            } else if (originalPic &&
                (userSelection.x1 === originalPic.x1 &&
                userSelection.x2 === originalPic.x2 &&
                userSelection.y1 === originalPic.y1 &&
                userSelection.y2 === originalPic.y2 &&
                userSelection.picture === originalPic.picture)){
                // no need to save if picture hasn't changed, so just close the dialog
                // Hide the layover.
                $(container).jqmHide();
            } else {
                savePicture();
            }
        });

        /**
         * savePicture
         */
        var savePicture = function(){
            // The parameters for the cropit service.
            var data = {
                img: "/~" + id + "/public/profile/" + picture._name,
                save: "/~" + id + "/public/profile",
                x: Math.floor(userSelection.x1 * ratio),
                y: Math.floor(userSelection.y1 * ratio),
                width: Math.floor(userSelection.width * ratio),
                height:Math.floor(userSelection.height * ratio),
                dimensions: "256x256",
                "_charset_":"utf-8"
            };

            if(data.width === 0 || data.height === 0){
                data.width = $(fullPicture).width();
                data.height = $(fullPicture).height();
                data.x = 0;
                data.y = 0;
            }

            // Post all of this to the server
            $.ajax({
                url: sakai.config.URL.IMAGE_SERVICE,
                type: "POST",
                data: data,
                success: function(data){

                    var tosave = {
                        "name": "256x256_" + picture._name,
                        "_name": picture._name,
                        "_charset_":"utf-8",
                        "selectedx1" : userSelection.x1,
                        "selectedy1" : userSelection.y1,
                        "selectedx2" : userSelection.width + userSelection.x1,
                        "selectedy2" : userSelection.height + userSelection.y1
                    };

                    var stringtosave = $.toJSON(tosave);

                    sakai.data.me.profile.picture = stringtosave;

                    // Do a patch request to the profile info so that it gets updated with the new information.
                    $.ajax({
                        url: "/~" + sakai.api.Util.safeURL(id) + "/public/authprofile.profile.json",
                        type : "POST",
                        data : {
                            "picture" : $.toJSON(tosave),
                            "_charset_":"utf-8"
                        },
                        success : function(data) {
                            // Change the picture in the page. (This is for my_sakai.html)
                            // Math.random is for cache issues.
                            for (var i = 0; i < imagesToChange.length;i++) {
                                $(imagesToChange[i]).attr("src", "/~" + id + "/public/profile/" + tosave.name + "?sid=" + Math.random());
                            }

                            // display help tooltip
                            var tooltipData = {
                                "tooltipSelector":"#systemtour_add_photo",
                                "tooltipTitle":"TOOLTIP_ADD_MY_PHOTO",
                                "tooltipDescription":"TOOLTIP_ADD_MY_PHOTO_P5",
                                "tooltipArrow":"top",
                                "tooltipTop":25,
                                "tooltipLeft":40,
                                "tooltipAutoClose":true
                            };
                            $(window).trigger("update.tooltip.sakai", tooltipData);

                            // Hide the layover.
                            $(container).jqmHide();

                            if (mode !== "group") {
                                // record that user uploaded their profile picture
                                sakai.api.User.addUserProgress("uploadedProfilePhoto");
                            } else if (sakai.currentgroup && sakai.currentgroup.data && sakai.currentgroup.data.authprofile) {
                                sakai.currentgroup.data.authprofile.picture = $.toJSON(tosave);
                            }
                        },
                        error: function(xhr, textStatus, thrownError) {
                            sakai.api.Util.notification.show(sakai.api.i18n.getValueForKey("AN_ERROR_HAS_OCCURRED"),"",sakai.api.Util.notification.type.ERROR);
                        }
                    });

                },
                error: function(xhr, textStatus, thrownError) {
                    sakai.api.Util.notification.show(sakai.api.i18n.getValueForKey("AN_ERROR_HAS_OCCURRED"),"",sakai.api.Util.notification.type.ERROR);
                }
            });

        };


        ////////////////////////////
        // jQuery Modal functions //
        ////////////////////////////

        /**
         * Hide the layover
         * @param {Object} hash the object that represents the layover
         */
        var hideArea = function(hash){
            // Remove the selecting of an area on an image.
            if (imageareaobject) {
                imageareaobject.setOptions({
                    hide: true,
                    disable: true
                });
                imageareaobject.update();
            }

            hash.w.hide();
            hash.o.remove();
        };

        /**
         * Show the layover.
         * @param {Object} hash
         */
        var showArea = function(hash){
            doInit();
            hash.w.show();
            if (!existingPicture) {
                // display help tooltip
                var tooltipData = {
                    "tooltipSelector": "#profilepicture",
                    "tooltipTitle": "TOOLTIP_ADD_MY_PHOTO",
                    "tooltipDescription": "TOOLTIP_ADD_MY_PHOTO_P2",
                    "tooltipArrow": "top"
                };
                $(window).trigger("update.tooltip.sakai", tooltipData);
            }
        };

        // This will make the widget popup as a layover.
        $(container).jqm({
            modal: true,
            overlay: 20,
            toTop: true,
            onHide: hideArea,
            onShow: showArea
        });

        $(containerTrigger).live("click", function(){
            sakai.api.Util.bindDialogFocus(container);
            $(container).jqmShow();
        });

        $(window).bind("setData.changepic.sakai", function(e, _mode, _id) {
            mode = _mode;
            id = _id;
        });

        $(window).trigger("ready.changepic.sakai");
    };

    sakai.api.Widgets.widgetLoader.informOnLoad("changepic");

});




© 2015 - 2025 Weber Informatics LLC | Privacy Policy