<commit_before>/*
 * 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/misc/querystring.js (Querystring)
 */

require(["jquery", "sakai/sakai.api.core"], function($, sakai) {

    /**
     * @name sakai_global.systemtour
     *
     * @class systemtour
     *
     * @description
     * Initialize the systemtour 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.systemtour = function(tuid, showSettings){

        /////////////////////////////
        // Configuration variables //
        /////////////////////////////

        var me; // Contains information about the current user
        // Variables used to determine what the user has done
        var uploadedProfilePhoto;
        var uploadedContent;
        var sharedContent;
        var madeContactRequest;
        var halfCompletedProfile;

        ///////////////////
        // CSS SELECTORS //
        ///////////////////

        var $rootel = $("#" + tuid); // Get the main div used by the widget
        var $systemtourContainer = $("#systemtour_container", $rootel);
        var $systemtourProgressBar = $("#systemtour_progress_bar", $rootel);
        var $systemtourRemoveWidget = $("#systemtour_remove_widget", $rootel);
        var $systemtourCloseWidget = $("#systemtour_close_widget", $rootel);

        // Progress bar buttons
        var $systemtourButton = $(".systemtour_button", $rootel);
        var $systemtourAddPhoto = $("#systemtour_add_photo", $rootel);
        var $systemtourUploadFile = $("#systemtour_upload_file", $rootel);
        var $systemtourShareContent = $("#systemtour_share_content", $rootel);
        var $systemtourInvitedSomeone = $("#systemtour_add_contacts", $rootel);
        var $systemtourHalfCompleteProfile = $("#systemtour_edit_profile", $rootel);
        var $systemtourAddPhotoComplete = $("#systemtour_add_photo .systemtour_item_complete", $rootel);
        var $systemtourUploadFileComplete = $("#systemtour_upload_file .systemtour_item_complete", $rootel);
        var $systemtourShareContentComplete = $("#systemtour_share_content .systemtour_item_complete", $rootel);
        var $systemtourInvitedSomeoneComplete = $("#systemtour_add_contacts .systemtour_item_complete", $rootel);
        var $systemtourHalfCompleteProfileComplete = $("#systemtour_edit_profile .systemtour_item_complete", $rootel);

        ////////////////////////
        // Utility  functions //
        ////////////////////////

        /**
         * Updates the progress data based
         */
        var updateProgressData = function(){
            me = sakai.data.me;
            uploadedProfilePhoto = me.profile.userprogress.uploadedProfilePhoto;
            uploadedContent = me.profile.userprogress.uploadedContent;
            sharedContent = me.profile.userprogress.sharedContent;
            madeContactRequest = me.profile.userprogress.madeContactRequest;
            halfCompletedProfile = me.profile.userprogress.halfCompletedProfile;
        };

        /**
         * Updates the progress bar based on actions the user has already performed
         */
        var updateProgressBar = function(){
            if (uploadedProfilePhoto) {
                $systemtourAddPhoto.find(".systemtour_item_complete").addClass("systemtour_item_complete_full");
            }
            if (uploadedContent) {
                $systemtourUploadFile.find(".systemtour_item_complete").addClass("systemtour_item_complete_full");
            }
            if (sharedContent) {
                $systemtourShareContent.find(".systemtour_item_complete").addClass("systemtour_item_complete_full");
            }
            if (madeContactRequest) {
                $systemtourInvitedSomeone.find(".systemtour_item_complete").addClass("systemtour_item_complete_full");
            }
            if (halfCompletedProfile) {
                $systemtourHalfCompleteProfile.find(".systemtour_item_complete").addClass("systemtour_item_complete_full");
            }
        };

        /**
         * Temporary hides the progress bar
         */
        var hideProgressBar = function(){
            $systemtourContainer.hide();
            $.cookie("sakai.systemtour.hide", "true");
        };

        /**
         * Permanently hides the progress bar
         */
        var removeProgressBar = function(){
            var curDate = new Date();
            var curTimestamp = curDate.getTime();
            var progressData = {
                "hideSystemTour": true,
                "reminderTimestamp": curTimestamp
            };
            var authprofileURL = "/~" + me.user.userid + "/public/authprofile/userprogress";
            sakai.api.Server.saveJSON(authprofileURL, progressData, function(success, data){
                // Check whether save was successful
                if (success) {
                    $(window).unbind("sakai-systemtour-update");
                    $systemtourContainer.hide();
                }
            });
        };

        /**
         * Hides selected buttons
         */
        var hideSelected = function(){
            $systemtourButton.parent().removeClass("systemtour_1_selected");
            $systemtourButton.parent().removeClass("systemtour_2_selected");
            $systemtourButton.parent().removeClass("systemtour_3_selected");
            $systemtourButton.parent().removeClass("systemtour_4_selected");
            $systemtourButton.parent().removeClass("systemtour_5_selected");
            $systemtourButton.removeClass("systemtour_button_selected");
        };

        /**
         * Starts the specified tour
         * {String} id The tour we want to start
         */
        var startTour = function(id){
            $(window).trigger("sakai-tooltip-close");
            hideSelected();
            var tooltipData,
                contentLink,
                hashPos,
                newContentLink;
            switch (id) {
                case "systemtour_add_photo":
                    $(".systemtour_1").addClass("systemtour_1_selected");
                    $(".systemtour_1 a").addClass("systemtour_button_selected");
                    tooltipData = {
                        "tooltipSelector":"#changepic_container_trigger",
                        "tooltipTitle":"TOOLTIP_ADD_MY_PHOTO",
                        "tooltipDescription":"TOOLTIP_ADD_MY_PHOTO_P1",
                        "tooltipArrow":"top"
                    };
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                    break;
                case "systemtour_edit_profile":
                    $(".systemtour_2").addClass("systemtour_2_selected");
                    $(".systemtour_2 a").addClass("systemtour_button_selected");
                    tooltipData = {
                        "tooltipSelector":"#entity_edit_profile",
                        "tooltipTitle":"TOOLTIP_EDIT_MY_PROFILE",
                        "tooltipDescription":"TOOLTIP_EDIT_MY_PROFILE_P1",
                        "tooltipArrow":"top"
                    };
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                    if ($("#entity_edit_profile").attr("href") && $("#entity_edit_profile").attr("href").indexOf("editprofiletour") === -1) {
                        $("#entity_edit_profile").attr("href", $("#entity_edit_profile").attr("href") + "?editprofiletour=true");
                    }
                    break;
                case "systemtour_upload_file":
                    $(".systemtour_3").addClass("systemtour_3_selected");
                    $(".systemtour_3 a").addClass("systemtour_button_selected");
                    tooltipData = {
                        "tooltipSelector":"#mycontent_footer_upload_link",
                        "tooltipTitle":"TOOLTIP_UPLOAD_CONTENT",
                        "tooltipDescription":"TOOLTIP_UPLOAD_CONTENT_P1",
                        "tooltipArrow":"bottom"
                    };
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                    break;
                case "systemtour_share_content":
                    $(".systemtour_4").addClass("systemtour_4_selected");
                    $(".systemtour_4 a").addClass("systemtour_button_selected");
                    if (!uploadedContent){
                        tooltipData = {
                            "tooltipSelector":"#mycontent_footer_upload_link",
                            "tooltipTitle":"TOOLTIP_SHARE_CONTENT",
                            "tooltipDescription":"TOOLTIP_SHARE_CONTENT_P1",
                            "tooltipArrow":"bottom",
                            "tooltipTop":45
                        };
                    } else {
                        tooltipData = {
                            "tooltipSelector":"#mycontent_footer_upload_link",
                            "tooltipTitle":"TOOLTIP_SHARE_CONTENT",
                            "tooltipDescription":"TOOLTIP_SHARE_CONTENT_P2",
                            "tooltipArrow":"bottom",
                            "tooltipTop":70,
                            "tooltipLeft":-100
                        };
                        $(".mycontent_item_link").each(function(index) {
                            if ($(this).attr("href") && $(this).attr("href").indexOf("sharecontenttour") === -1) {
                                contentLink = $(this).attr("href");
                                hashPos = contentLink.indexOf("#");
                                newContentLink = contentLink.substr(0, hashPos) + "?sharecontenttour=true" + contentLink.substr(hashPos);
                                $(this).attr("href", newContentLink);
                            }
                        });
                    }
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                    break;
                case "systemtour_add_contacts":
                    $(".systemtour_5").addClass("systemtour_5_selected");
                    $(".systemtour_5 a").addClass("systemtour_button_selected");
                    tooltipData = {
                        "tooltipSelector":"#mycontacts_footer_search",
                        "tooltipTitle":"TOOLTIP_ADD_CONTACTS",
                        "tooltipDescription":"TOOLTIP_ADD_CONTACTS_P1",
                        "tooltipArrow":"bottom"
                    };
                    if ($("#mycontacts_footer_search").attr("href") && $("#mycontacts_footer_search").attr("href").indexOf("addcontactstour") === -1) {
                        contentLink = $("#mycontacts_footer_search").attr("href");
                        hashPos = contentLink.indexOf("#");
                        newContentLink = contentLink.substr(0, hashPos) + "?addcontactstour=true" + contentLink.substr(hashPos);
                        $("#mycontacts_footer_search").attr("href", newContentLink);
                    }
                    if ($("#navigation_people_link").attr("href") && $("#navigation_people_link").attr("href").indexOf("addcontactstour") === -1) {
                        contentLink = $("#navigation_people_link").attr("href");
                        hashPos = contentLink.indexOf("#");
                        newContentLink = contentLink.substr(0, hashPos) + "?addcontactstour=true" + contentLink.substr(hashPos);
                        $("#navigation_people_link").attr("href", newContentLink);
                    }
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                    break;
            }
        };

        /**
         * Checks if user is in the edit profile tour and displays the final tooltip
         */
        var checkEditProfileTour = function(){
            if (halfCompletedProfile){
                // display tooltip
                var tooltipData = {
                    "tooltipSelector":"#systemtour_edit_profile",
                    "tooltipTitle":"TOOLTIP_EDIT_MY_PROFILE",
                    "tooltipDescription":"TOOLTIP_EDIT_MY_PROFILE_P4",
                    "tooltipArrow":"top",
                    "tooltipTop":25,
                    "tooltipLeft":40,
                    "tooltipAutoClose":true
                };
                $(".systemtour_2").addClass("systemtour_2_selected");
                $(".systemtour_2 a").addClass("systemtour_button_selected");
                if (!sakai.tooltip || !sakai.tooltip.isReady) {
                    $(window).bind("sakai-tooltip-ready", function() {
                        $(window).trigger("sakai-tooltip-init", tooltipData);
                    });
                } else {
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                }
            }
        };

        ////////////////////
        // Event Handlers //
        ////////////////////

        /**
         * Add binding to widget elements
         */
        var addBinding = function(){
            $(window).bind("sakai-tooltip-closed", function() {
                hideSelected();
            });

            $systemtourButton.live("click", function () {
                var id = $(this).attr("id");
                startTour(id);
                return false;
            });

            $("#systemtour_tooltip_upload_file").live("click", function () {
                startTour("systemtour_upload_file");
                return false;
            });

            $systemtourCloseWidget.bind("click", function () {
                hideProgressBar();
                return false;
            });

            $systemtourRemoveWidget.bind("click", function () {
                removeProgressBar();
                return false;
            });

            $(window).bind("sakai-systemtour-update", function() {
                // update progress bar when data has changed
                updateProgressData();
                updateProgressBar();
            });
        };

        /////////////////////////////
        // Initialisation function //
        /////////////////////////////

        /**
         * Initialise the widget
         */
        var doInit = function(){
            if (!sakai.data.me.profile.userprogress){
                sakai.data.me.profile.userprogress = {};
            }

            // checks user progress and displays reminder tooltips
            // wait for some widgets to load before checking
            if (!sakai.mycontent || !sakai.mycontent.isReady) {
                $(window).bind("sakai-mycontent-ready", function() {
                    sakai.api.User.checkUserProgress();
                });
            } else {
                sakai.api.User.checkUserProgress();
            }

            updateProgressData();

            var checkEditProfileProgress = false;
            var querystring = new Querystring();
            if (querystring.contains("editprofiletour") && querystring.get("editprofiletour") === "true"){
                checkEditProfileProgress = true;
            }

            var hide = $.cookie("sakai.systemtour.hide");

            // if user has not removed the tour progress bar or completed all actions or edit profile tour is in progress
            if (!hide && !me.profile.userprogress.hideSystemTour && ((!uploadedProfilePhoto || !uploadedContent || !sharedContent || !madeContactRequest || !halfCompletedProfile || checkEditProfileProgress))) {
                // update progress bar
                updateProgressBar();

                // bind elements
                addBinding();

                // show widget
                $systemtourContainer.show();

                if (checkEditProfileProgress){
                    checkEditProfileTour();
                }
            }
        };
        doInit();
    };

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

});<commit_msg>NOJIRA cookie was added as a dependency for the systemtour widget<commit_after>/*
 * 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/misc/querystring.js (Querystring)
 * /dev/lib/jquery/plugins/jquery.cookie.js (cookie)
 */

require(["jquery", "sakai/sakai.api.core"], function($, sakai) {

    /**
     * @name sakai_global.systemtour
     *
     * @class systemtour
     *
     * @description
     * Initialize the systemtour 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.systemtour = function(tuid, showSettings){

        /////////////////////////////
        // Configuration variables //
        /////////////////////////////

        var me; // Contains information about the current user
        // Variables used to determine what the user has done
        var uploadedProfilePhoto;
        var uploadedContent;
        var sharedContent;
        var madeContactRequest;
        var halfCompletedProfile;

        ///////////////////
        // CSS SELECTORS //
        ///////////////////

        var $rootel = $("#" + tuid); // Get the main div used by the widget
        var $systemtourContainer = $("#systemtour_container", $rootel);
        var $systemtourProgressBar = $("#systemtour_progress_bar", $rootel);
        var $systemtourRemoveWidget = $("#systemtour_remove_widget", $rootel);
        var $systemtourCloseWidget = $("#systemtour_close_widget", $rootel);

        // Progress bar buttons
        var $systemtourButton = $(".systemtour_button", $rootel);
        var $systemtourAddPhoto = $("#systemtour_add_photo", $rootel);
        var $systemtourUploadFile = $("#systemtour_upload_file", $rootel);
        var $systemtourShareContent = $("#systemtour_share_content", $rootel);
        var $systemtourInvitedSomeone = $("#systemtour_add_contacts", $rootel);
        var $systemtourHalfCompleteProfile = $("#systemtour_edit_profile", $rootel);
        var $systemtourAddPhotoComplete = $("#systemtour_add_photo .systemtour_item_complete", $rootel);
        var $systemtourUploadFileComplete = $("#systemtour_upload_file .systemtour_item_complete", $rootel);
        var $systemtourShareContentComplete = $("#systemtour_share_content .systemtour_item_complete", $rootel);
        var $systemtourInvitedSomeoneComplete = $("#systemtour_add_contacts .systemtour_item_complete", $rootel);
        var $systemtourHalfCompleteProfileComplete = $("#systemtour_edit_profile .systemtour_item_complete", $rootel);

        ////////////////////////
        // Utility  functions //
        ////////////////////////

        /**
         * Updates the progress data based
         */
        var updateProgressData = function(){
            me = sakai.data.me;
            uploadedProfilePhoto = me.profile.userprogress.uploadedProfilePhoto;
            uploadedContent = me.profile.userprogress.uploadedContent;
            sharedContent = me.profile.userprogress.sharedContent;
            madeContactRequest = me.profile.userprogress.madeContactRequest;
            halfCompletedProfile = me.profile.userprogress.halfCompletedProfile;
        };

        /**
         * Updates the progress bar based on actions the user has already performed
         */
        var updateProgressBar = function(){
            if (uploadedProfilePhoto) {
                $systemtourAddPhoto.find(".systemtour_item_complete").addClass("systemtour_item_complete_full");
            }
            if (uploadedContent) {
                $systemtourUploadFile.find(".systemtour_item_complete").addClass("systemtour_item_complete_full");
            }
            if (sharedContent) {
                $systemtourShareContent.find(".systemtour_item_complete").addClass("systemtour_item_complete_full");
            }
            if (madeContactRequest) {
                $systemtourInvitedSomeone.find(".systemtour_item_complete").addClass("systemtour_item_complete_full");
            }
            if (halfCompletedProfile) {
                $systemtourHalfCompleteProfile.find(".systemtour_item_complete").addClass("systemtour_item_complete_full");
            }
        };

        /**
         * Temporary hides the progress bar
         */
        var hideProgressBar = function(){
            $systemtourContainer.hide();
            $.cookie("sakai.systemtour.hide", "true");
        };

        /**
         * Permanently hides the progress bar
         */
        var removeProgressBar = function(){
            var curDate = new Date();
            var curTimestamp = curDate.getTime();
            var progressData = {
                "hideSystemTour": true,
                "reminderTimestamp": curTimestamp
            };
            var authprofileURL = "/~" + me.user.userid + "/public/authprofile/userprogress";
            sakai.api.Server.saveJSON(authprofileURL, progressData, function(success, data){
                // Check whether save was successful
                if (success) {
                    $(window).unbind("sakai-systemtour-update");
                    $systemtourContainer.hide();
                }
            });
        };

        /**
         * Hides selected buttons
         */
        var hideSelected = function(){
            $systemtourButton.parent().removeClass("systemtour_1_selected");
            $systemtourButton.parent().removeClass("systemtour_2_selected");
            $systemtourButton.parent().removeClass("systemtour_3_selected");
            $systemtourButton.parent().removeClass("systemtour_4_selected");
            $systemtourButton.parent().removeClass("systemtour_5_selected");
            $systemtourButton.removeClass("systemtour_button_selected");
        };

        /**
         * Starts the specified tour
         * {String} id The tour we want to start
         */
        var startTour = function(id){
            $(window).trigger("sakai-tooltip-close");
            hideSelected();
            var tooltipData,
                contentLink,
                hashPos,
                newContentLink;
            switch (id) {
                case "systemtour_add_photo":
                    $(".systemtour_1").addClass("systemtour_1_selected");
                    $(".systemtour_1 a").addClass("systemtour_button_selected");
                    tooltipData = {
                        "tooltipSelector":"#changepic_container_trigger",
                        "tooltipTitle":"TOOLTIP_ADD_MY_PHOTO",
                        "tooltipDescription":"TOOLTIP_ADD_MY_PHOTO_P1",
                        "tooltipArrow":"top"
                    };
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                    break;
                case "systemtour_edit_profile":
                    $(".systemtour_2").addClass("systemtour_2_selected");
                    $(".systemtour_2 a").addClass("systemtour_button_selected");
                    tooltipData = {
                        "tooltipSelector":"#entity_edit_profile",
                        "tooltipTitle":"TOOLTIP_EDIT_MY_PROFILE",
                        "tooltipDescription":"TOOLTIP_EDIT_MY_PROFILE_P1",
                        "tooltipArrow":"top"
                    };
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                    if ($("#entity_edit_profile").attr("href") && $("#entity_edit_profile").attr("href").indexOf("editprofiletour") === -1) {
                        $("#entity_edit_profile").attr("href", $("#entity_edit_profile").attr("href") + "?editprofiletour=true");
                    }
                    break;
                case "systemtour_upload_file":
                    $(".systemtour_3").addClass("systemtour_3_selected");
                    $(".systemtour_3 a").addClass("systemtour_button_selected");
                    tooltipData = {
                        "tooltipSelector":"#mycontent_footer_upload_link",
                        "tooltipTitle":"TOOLTIP_UPLOAD_CONTENT",
                        "tooltipDescription":"TOOLTIP_UPLOAD_CONTENT_P1",
                        "tooltipArrow":"bottom"
                    };
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                    break;
                case "systemtour_share_content":
                    $(".systemtour_4").addClass("systemtour_4_selected");
                    $(".systemtour_4 a").addClass("systemtour_button_selected");
                    if (!uploadedContent){
                        tooltipData = {
                            "tooltipSelector":"#mycontent_footer_upload_link",
                            "tooltipTitle":"TOOLTIP_SHARE_CONTENT",
                            "tooltipDescription":"TOOLTIP_SHARE_CONTENT_P1",
                            "tooltipArrow":"bottom",
                            "tooltipTop":45
                        };
                    } else {
                        tooltipData = {
                            "tooltipSelector":"#mycontent_footer_upload_link",
                            "tooltipTitle":"TOOLTIP_SHARE_CONTENT",
                            "tooltipDescription":"TOOLTIP_SHARE_CONTENT_P2",
                            "tooltipArrow":"bottom",
                            "tooltipTop":70,
                            "tooltipLeft":-100
                        };
                        $(".mycontent_item_link").each(function(index) {
                            if ($(this).attr("href") && $(this).attr("href").indexOf("sharecontenttour") === -1) {
                                contentLink = $(this).attr("href");
                                hashPos = contentLink.indexOf("#");
                                newContentLink = contentLink.substr(0, hashPos) + "?sharecontenttour=true" + contentLink.substr(hashPos);
                                $(this).attr("href", newContentLink);
                            }
                        });
                    }
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                    break;
                case "systemtour_add_contacts":
                    $(".systemtour_5").addClass("systemtour_5_selected");
                    $(".systemtour_5 a").addClass("systemtour_button_selected");
                    tooltipData = {
                        "tooltipSelector":"#mycontacts_footer_search",
                        "tooltipTitle":"TOOLTIP_ADD_CONTACTS",
                        "tooltipDescription":"TOOLTIP_ADD_CONTACTS_P1",
                        "tooltipArrow":"bottom"
                    };
                    if ($("#mycontacts_footer_search").attr("href") && $("#mycontacts_footer_search").attr("href").indexOf("addcontactstour") === -1) {
                        contentLink = $("#mycontacts_footer_search").attr("href");
                        hashPos = contentLink.indexOf("#");
                        newContentLink = contentLink.substr(0, hashPos) + "?addcontactstour=true" + contentLink.substr(hashPos);
                        $("#mycontacts_footer_search").attr("href", newContentLink);
                    }
                    if ($("#navigation_people_link").attr("href") && $("#navigation_people_link").attr("href").indexOf("addcontactstour") === -1) {
                        contentLink = $("#navigation_people_link").attr("href");
                        hashPos = contentLink.indexOf("#");
                        newContentLink = contentLink.substr(0, hashPos) + "?addcontactstour=true" + contentLink.substr(hashPos);
                        $("#navigation_people_link").attr("href", newContentLink);
                    }
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                    break;
            }
        };

        /**
         * Checks if user is in the edit profile tour and displays the final tooltip
         */
        var checkEditProfileTour = function(){
            if (halfCompletedProfile){
                // display tooltip
                var tooltipData = {
                    "tooltipSelector":"#systemtour_edit_profile",
                    "tooltipTitle":"TOOLTIP_EDIT_MY_PROFILE",
                    "tooltipDescription":"TOOLTIP_EDIT_MY_PROFILE_P4",
                    "tooltipArrow":"top",
                    "tooltipTop":25,
                    "tooltipLeft":40,
                    "tooltipAutoClose":true
                };
                $(".systemtour_2").addClass("systemtour_2_selected");
                $(".systemtour_2 a").addClass("systemtour_button_selected");
                if (!sakai.tooltip || !sakai.tooltip.isReady) {
                    $(window).bind("sakai-tooltip-ready", function() {
                        $(window).trigger("sakai-tooltip-init", tooltipData);
                    });
                } else {
                    $(window).trigger("sakai-tooltip-init", tooltipData);
                }
            }
        };

        ////////////////////
        // Event Handlers //
        ////////////////////

        /**
         * Add binding to widget elements
         */
        var addBinding = function(){
            $(window).bind("sakai-tooltip-closed", function() {
                hideSelected();
            });

            $systemtourButton.live("click", function () {
                var id = $(this).attr("id");
                startTour(id);
                return false;
            });

            $("#systemtour_tooltip_upload_file").live("click", function () {
                startTour("systemtour_upload_file");
                return false;
            });

            $systemtourCloseWidget.bind("click", function () {
                hideProgressBar();
                return false;
            });

            $systemtourRemoveWidget.bind("click", function () {
                removeProgressBar();
                return false;
            });

            $(window).bind("sakai-systemtour-update", function() {
                // update progress bar when data has changed
                updateProgressData();
                updateProgressBar();
            });
        };

        /////////////////////////////
        // Initialisation function //
        /////////////////////////////

        /**
         * Initialise the widget
         */
        var doInit = function(){
            if (!sakai.data.me.profile.userprogress){
                sakai.data.me.profile.userprogress = {};
            }

            // checks user progress and displays reminder tooltips
            // wait for some widgets to load before checking
            if (!sakai.mycontent || !sakai.mycontent.isReady) {
                $(window).bind("sakai-mycontent-ready", function() {
                    sakai.api.User.checkUserProgress();
                });
            } else {
                sakai.api.User.checkUserProgress();
            }

            updateProgressData();

            var checkEditProfileProgress = false;
            var querystring = new Querystring();
            if (querystring.contains("editprofiletour") && querystring.get("editprofiletour") === "true"){
                checkEditProfileProgress = true;
            }

            var hide = $.cookie("sakai.systemtour.hide");

            // if user has not removed the tour progress bar or completed all actions or edit profile tour is in progress
            if (!hide && !me.profile.userprogress.hideSystemTour && ((!uploadedProfilePhoto || !uploadedContent || !sharedContent || !madeContactRequest || !halfCompletedProfile || checkEditProfileProgress))) {
                // update progress bar
                updateProgressBar();

                // bind elements
                addBinding();

                // show widget
                $systemtourContainer.show();

                if (checkEditProfileProgress){
                    checkEditProfileTour();
                }
            }
        };
        doInit();
    };

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

});<|endoftext|>


<commit_before>const express = require('express')
const router = express.Router()

router.get('/', function(request, response) {
  response.set('content-type', 'text/plain')
  response.status(200).send('Welcome to Sandbox!')
})

router.get('/search', function(request, response) {
  if ('q' in request.query) {
    response.set('content-type', 'text/plain')
    response.status(200).send(`You searched for: "${request.query.q}"`)
  } else {
    response.set('content-type', 'text/plain')
    response.status(400).send("You didn't provide a search query term :(")
  }
})

router.post('/things', function(request, response) {
  response.status(201)
    .set('content-type', 'text/plain')
      .send('New thing created: flying car!')
})

router.get('/somefile', function(request, response) {
  response.set('content-type', 'text/plain')
    response.status(200).send('This is a plain text file')
})

router.get('/somefiles', function(request, response) {
  response.set('content-type', 'text/html')
    response.status(200).send('<!DOCTYPE html>This is an HTML file')
})

router.post('/admin-only', function(request, response) {
  response.status(403).end();
})

router.get('/not-a-page', function(request, response) {
  response.status(404).end();
})

router.get('/server-error', function(request, response) {
  response.status(500).end();
})

// Add other routes here

module.exports = router
<commit_msg>refactor routes in es6<commit_after>const express = require('express')
const router = express.Router()

router.get('/', (request, response) => {
  response.set('content-type', 'text/plain')
  response.status(200).send('Welcome to Sandbox!')
})

router.get('/search', (request, response) => {
  if ('q' in request.query) {
    response.set('content-type', 'text/plain')
    response.status(200).send(`You searched for: "${request.query.q}"`)
  } else {
    response.set('content-type', 'text/plain')
    response.status(400).send("You didn't provide a search query term :(")
  }
})

router.post('/things', (request, response) => {
  response.status(201)
    .set('content-type', 'text/plain')
      .send('New thing created: flying car!')
})

router.get('/somefile', (request, response) => {
  response.set('content-type', 'text/plain')
    response.status(200).send('This is a plain text file')
})

router.get('/somefiles', (request, response) => {
  response.set('content-type', 'text/html')
    response.status(200).send('<!DOCTYPE html>This is an HTML file')
})

router.post('/admin-only', (request, response) => {
  response.status(403).end();
})

router.get('/not-a-page', (request, response) => {
  response.status(404).end();
})

router.get('/server-error', (request, response) => {
  response.status(500).end();
})

// Add other routes here

module.exports = router
<|endoftext|>


<commit_before>import * as React from 'react';
import PropTypes from 'prop-types';
import { StyleSheetManager } from 'styled-components';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import rtlPlugin from 'stylis-plugin-rtl';
import { useTheme } from '@material-ui/core/styles';

// Cache for the ltr version of the styles
export const cacheLtr = createCache({ key: 'css' });
cacheLtr.compat = true;

// Cache for the rtl version of the styles
const cacheRtl = createCache({
  key: 'rtl',
  stylisPlugins: [rtlPlugin],
});
cacheRtl.compat = true;

const StyledEngineProvider = (props) => {
  const theme = useTheme();

  const rtl = theme.direction === 'rtl';

  return (
    <StyleSheetManager stylisPlugins={rtl ? [rtlPlugin] : []}>
      <CacheProvider value={rtl ? cacheRtl : cacheLtr}>{props.children}</CacheProvider>
    </StyleSheetManager>
  );
};

StyledEngineProvider.propTypes = {
  children: PropTypes.node,
};

export default StyledEngineProvider;
<commit_msg>[docs] Add prepend option on emotion caches to allow JSS style overrides (#23892)<commit_after>import * as React from 'react';
import PropTypes from 'prop-types';
import { StyleSheetManager } from 'styled-components';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import rtlPlugin from 'stylis-plugin-rtl';
import { useTheme } from '@material-ui/core/styles';

// Cache for the ltr version of the styles
export const cacheLtr = createCache({ key: 'css', prepend: true });
cacheLtr.compat = true;

// Cache for the rtl version of the styles
const cacheRtl = createCache({
  key: 'rtl',
  prepend: true,
  stylisPlugins: [rtlPlugin],
});
cacheRtl.compat = true;

const StyledEngineProvider = (props) => {
  const theme = useTheme();

  const rtl = theme.direction === 'rtl';

  return (
    <StyleSheetManager stylisPlugins={rtl ? [rtlPlugin] : []}>
      <CacheProvider value={rtl ? cacheRtl : cacheLtr}>{props.children}</CacheProvider>
    </StyleSheetManager>
  );
};

StyledEngineProvider.propTypes = {
  children: PropTypes.node,
};

export default StyledEngineProvider;
<|endoftext|>


<commit_before>/**
 * Se encarga de renderar el form en cuestion teniendo en cuenta el template
 * que se tiene que usar y el elemento en donde tiene que ir el mismo.
 *
 * Este form es el que se usa para crear o editar diferentes valores de la
 * base de datos.
 */
var FormView = Class.$extend({

    /**
     * Constructor.
     *
     * @param {jQuery} element: el elemento del DOM en donde es que se va a
     *                          poner el form
     *
     *
     * @param {String} template: el template de handlebars que se tiene que
     *                           renderar.
     *
     * @param {Array(ColumnsInformation)} columnsInformation: todas las
     *                           columnas de la tabla (se tengan que renderear
     *                           o no.
     *
     * @param {FkInformation} fkInformation: tiene toda la informacion de las
     *                                       tablas relacionadas.
     */
    __init__: function(element, template, columnsInformation, fkInformation) {
        this.$element = element;
        this.template = template;
        this.columnsInformation = columnsInformation;
        this.fkInformation = fkInformation;
    },

    /**
     * Se encarga de renderear el form teniendo en cuenta los valores especificados,
     * y los posibles errores de validacion.
     */
    render: function(objectData, validationErrors) {
        var html = Handlebars.render(this.template, {
                        validationErrors: validationErrors
        });

        this.$element.clean();
        this.$element.html(html);

        for (var i = 0; i < this.columnsInformation.length; i++) {
            var columnInformation = this.columnsInformation[i];
            var formField = this.$element.find('#' + columnInformation.databaseName)

            if (! formField.exists()) {
                // en este caso estoy en una columna que esta en la base de datos
                // pero que no la estoy renderando
                continue;
            }

            if (columnInformation.type === 'date') {
                formField.datepicker({
                    format: 'dd/mm/yyyy'
                });
            } else if (columnInformation.isConst()) {
                formField.chosen();
            } else if (columnInformation.foreignKey !== null) {
                formField.chosen();
            }
        }

        // esto lo tengo que hacer aca porque sino no puedo distinguir entre
        // los textos comunes y los textare
        this.$element.find('textarea').cleditor({
                controls: "bold italic underline | " +
                          "font size | "  +
                          "color highlight | " +
                          "alignleft center alignright justify | " +
                          "bullets numbering"
        });

        if (objectData !== null) {
            utils.renderFormData(this.$element,
                                 objectData,
                                 '');
        }
        this.$element.unmask();

    }
});

/**
 * Form que se va a crear en funcion de los tipos de los campos.
 *
 * A diferencia de la opcion del FormView, aca se crea el template
 * teniendo en cuenta que se especifican cuales son los campos que se
 * quieren mostrar.
 */
var FieldFormView = FormView.$extend({

    /**
     * Constructor.
     *
     * @param {Array(String)} columnNamesToShow: el nombre de las columnas (databaseName)
     *                                           que se quieren mostrar en el form.
     */
    __init__: function(element, columnsInformation, fkInformation, columnsNamesToShow) {
        var superTemplate = '' +
            '<form role="form" class="form-horizontal">' +
                '{{#each columnsNamesToShow}}' +
                    '{{renderFormField this ../columnsInformation ../fkInformation }}' +
                '{{/each}}' +
                '
' +
                    '
' +
                        '<input type="submit" class="btn btn-primary button-save">' +
                    '
' +
                '
' +
            '</form>';

        var template = Handlebars.render(superTemplate, {
                            columnsNamesToShow: columnsNamesToShow,
                            columnsInformation: columnsInformation,
                            fkInformation: fkInformation
        });
        this.$super(element, template, columnsInformation, fkInformation);
    }
});
<commit_msg>Se usa PNotify para los forms<commit_after>/**
 * Se encarga de renderar el form en cuestion teniendo en cuenta el template
 * que se tiene que usar y el elemento en donde tiene que ir el mismo.
 *
 * Este form es el que se usa para crear o editar diferentes valores de la
 * base de datos.
 */
var FormView = Class.$extend({

    /**
     * Constructor.
     *
     * @param {jQuery} element: el elemento del DOM en donde es que se va a
     *                          poner el form
     *
     *
     * @param {String} template: el template de handlebars que se tiene que
     *                           renderar.
     *
     * @param {Array(ColumnsInformation)} columnsInformation: todas las
     *                           columnas de la tabla (se tengan que renderear
     *                           o no.
     *
     * @param {FkInformation} fkInformation: tiene toda la informacion de las
     *                                       tablas relacionadas.
     */
    __init__: function(element, template, columnsInformation, fkInformation) {
        this.$element = element;
        this.template = template;
        this.columnsInformation = columnsInformation;
        this.fkInformation = fkInformation;
    },

    /**
     * Se encarga de renderear el form teniendo en cuenta los valores especificados,
     * y los posibles errores de validacion.
     */
    render: function(objectData, validationErrors) {

        var html = Handlebars.render(this.template, {
                        validationErrors: validationErrors
        });

        this.$element.clean();
        this.$element.html(html);

        if (validationErrors) {
            new PNotify({
                title: 'Error',
                text: 'Alguno de los campos ingresados esta mal',
                delay: 1500,
                type: 'error'
            });

        }

        for (var i = 0; i < this.columnsInformation.length; i++) {
            var columnInformation = this.columnsInformation[i];
            var formField = this.$element.find('#' + columnInformation.databaseName)

            if (! formField.exists()) {
                // en este caso estoy en una columna que esta en la base de datos
                // pero que no la estoy renderando
                continue;
            }

            if (columnInformation.type === 'date') {
                formField.datepicker({
                    format: 'dd/mm/yyyy'
                });
            } else if (columnInformation.isConst()) {
                formField.chosen();
            } else if (columnInformation.foreignKey !== null) {
                formField.chosen();
            }
        }

        // esto lo tengo que hacer aca porque sino no puedo distinguir entre
        // los textos comunes y los textare
        this.$element.find('textarea').cleditor({
                controls: "bold italic underline | " +
                          "font size | "  +
                          "color highlight | " +
                          "alignleft center alignright justify | " +
                          "bullets numbering"
        });

        if (objectData !== null) {
            utils.renderFormData(this.$element,
                                 objectData,
                                 '');
        }
        this.$element.unmask();

    }
});

/**
 * Form que se va a crear en funcion de los tipos de los campos.
 *
 * A diferencia de la opcion del FormView, aca se crea el template
 * teniendo en cuenta que se especifican cuales son los campos que se
 * quieren mostrar.
 */
var FieldFormView = FormView.$extend({

    /**
     * Constructor.
     *
     * @param {Array(String)} columnNamesToShow: el nombre de las columnas (databaseName)
     *                                           que se quieren mostrar en el form.
     */
    __init__: function(element, columnsInformation, fkInformation, columnsNamesToShow) {
        var superTemplate = '' +
            '<form role="form" class="form-horizontal">' +
                '{{#each columnsNamesToShow}}' +
                    '{{renderFormField this ../columnsInformation ../fkInformation }}' +
                '{{/each}}' +
                '
' +
                    '
' +
                        '<input type="submit" class="btn btn-primary button-save">' +
                    '
' +
                '
' +
            '</form>';

        var template = Handlebars.render(superTemplate, {
                            columnsNamesToShow: columnsNamesToShow,
                            columnsInformation: columnsInformation,
                            fkInformation: fkInformation
        });
        this.$super(element, template, columnsInformation, fkInformation);
    }
});
<|endoftext|>


<commit_before>'use strict';

var React = require('react-native');
var {
  StyleSheet,
  Text,
  View,
  TouchableOpacity,
  Animated,
} = React;

var { Icon, } = require('react-native-icons');

var styles = StyleSheet.create({
  tab: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    paddingBottom: 10,
  },

  tabs: {
    height: 45,
    flexDirection: 'row',
    paddingTop: 5,
    borderWidth: 1,
    borderTopWidth: 0,
    borderLeftWidth: 0,
    borderRightWidth: 0,
    borderBottomColor: 'rgba(0,0,0,0.05)',
  },
});

var FacebookTabBar = React.createClass({
  selectedTabIcons: [],
  unselectedTabIcons: [],

  propTypes: {
    goToPage: React.PropTypes.func,
    activeTab: React.PropTypes.number,
    tabs: React.PropTypes.array
  },

  renderTabOption(name, page) {
    var isTabActive = this.props.activeTab === page;

    return (
      <TouchableOpacity key={name} onPress={() => this.props.goToPage(page)} style={[styles.tab]}>
        <Icon name={name} size={30} color='#3B5998' style={{width: 30, height: 30, position: 'absolute', top: 0, left: 20}}
              ref={(icon) => { this.selectedTabIcons[page] = icon }}/>
        <Icon name={name} size={30} color='#ccc' style={{width: 30, height: 30, position: 'absolute', top: 0, left: 20}}
              ref={(icon) => { this.unselectedTabIcons[page] = icon }}/>
      </TouchableOpacity>
    );
  },

  componentDidMount() {
    this.setAnimationValue({value: this.props.activeTab});
    this._listener = this.props.scrollValue.addListener(this.setAnimationValue);
  },

  setAnimationValue({value}) {
    var currentPage = this.props.activeTab;

    this.unselectedTabIcons.forEach((icon, i) => {
      var iconRef = icon;

      if (!icon.setNativeProps && icon !== null) {
        iconRef = icon.refs.icon_image
      }

      if (value - i >= 0 && value - i <= 1) {
        iconRef.setNativeProps({opacity: value - i});
      }
      if (i - value >= 0 &&  i - value <= 1) {
        iconRef.setNativeProps({opacity: i - value});
      }
    });
  },

  render() {
    var containerWidth = this.props.containerWidth;
    var numberOfTabs = this.props.tabs.length;
    var tabUnderlineStyle = {
      position: 'absolute',
      width: containerWidth / numberOfTabs,
      height: 3,
      backgroundColor: '#3b5998',
      bottom: 0,
    };

    var left = this.props.scrollValue.interpolate({
      inputRange: [0, 1], outputRange: [0, containerWidth / numberOfTabs]
    });

    return (
      <View>
        <View style={styles.tabs}>
          {this.props.tabs.map((tab, i) => this.renderTabOption(tab, i))}
        </View>
        <Animated.View style={[tabUnderlineStyle, {left}]} />
      </View>
    );
  },
});

module.exports = FacebookTabBar;
<commit_msg>improve styles<commit_after>'use strict';

var React = require('react-native');
var {
  StyleSheet,
  Text,
  View,
  TouchableOpacity,
  Animated,
} = React;

var { Icon, } = require('react-native-icons');

var styles = StyleSheet.create({
  tab: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    paddingBottom: 10,
  },
  tabs: {
    height: 45,
    flexDirection: 'row',
    paddingTop: 5,
    borderWidth: 1,
    borderTopWidth: 0,
    borderLeftWidth: 0,
    borderRightWidth: 0,
    borderBottomColor: 'rgba(0,0,0,0.05)',
  },
  icon: {
    width: 30,
    height: 30,
    position: 'absolute',
    top: 0,
    left: 20,
  },
});

var FacebookTabBar = React.createClass({
  selectedTabIcons: [],
  unselectedTabIcons: [],

  propTypes: {
    goToPage: React.PropTypes.func,
    activeTab: React.PropTypes.number,
    tabs: React.PropTypes.array
  },

  renderTabOption(name, page) {
    var isTabActive = this.props.activeTab === page;

    return (
      <TouchableOpacity key={name} onPress={() => this.props.goToPage(page)} style={styles.tab}>
        <Icon name={name} size={30} color='#3B5998' style={styles.icon}
              ref={(icon) => { this.selectedTabIcons[page] = icon }}/>
        <Icon name={name} size={30} color='#ccc' style={styles.icon}
              ref={(icon) => { this.unselectedTabIcons[page] = icon }}/>
      </TouchableOpacity>
    );
  },

  componentDidMount() {
    this.setAnimationValue({value: this.props.activeTab});
    this._listener = this.props.scrollValue.addListener(this.setAnimationValue);
  },

  setAnimationValue({value}) {
    var currentPage = this.props.activeTab;

    this.unselectedTabIcons.forEach((icon, i) => {
      var iconRef = icon;

      if (!icon.setNativeProps && icon !== null) {
        iconRef = icon.refs.icon_image
      }

      if (value - i >= 0 && value - i <= 1) {
        iconRef.setNativeProps({opacity: value - i});
      }
      if (i - value >= 0 &&  i - value <= 1) {
        iconRef.setNativeProps({opacity: i - value});
      }
    });
  },

  render() {
    var containerWidth = this.props.containerWidth;
    var numberOfTabs = this.props.tabs.length;
    var tabUnderlineStyle = {
      position: 'absolute',
      width: containerWidth / numberOfTabs,
      height: 3,
      backgroundColor: '#3b5998',
      bottom: 0,
    };

    var left = this.props.scrollValue.interpolate({
      inputRange: [0, 1], outputRange: [0, containerWidth / numberOfTabs]
    });

    return (
      <View>
        <View style={styles.tabs}>
          {this.props.tabs.map((tab, i) => this.renderTabOption(tab, i))}
        </View>
        <Animated.View style={[tabUnderlineStyle, {left}]} />
      </View>
    );
  },
});

module.exports = FacebookTabBar;
<|endoftext|>


<commit_before><commit_msg>Create bootstrap.min.js<commit_after><|endoftext|>


<commit_before>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple Inc. All rights reserved.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

// sc_resource('setup_body_class_names'); // publish into inline format

// sc_require("system/loader");

if (SC.setupBodyClassNames) SC.setupBodyClassNames() ;
<commit_msg>This require doesn't seem to be necessary<commit_after>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple Inc. All rights reserved.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

// sc_resource('setup_body_class_names'); // publish into inline format

if (SC.setupBodyClassNames) SC.setupBodyClassNames() ;
<|endoftext|>


<commit_before>/*
 * This file is part of Search NEU and licensed under AGPL3.
 * See the license file in the root folder for details.
 */

import React from 'react';
import PropTypes from 'prop-types';
import CSSModules from 'react-css-modules';
import classNames from 'classnames/bind';

import chevronDown from './chevron-down.svg';
import chevronRight from './chevron-right.svg';
import mobileCss from './MobileClassPanel.css';
import baseCss from './BaseClassPanel.css';
import MobileSectionPanel from './MobileSectionPanel';
import Keys from '../../../common/Keys';
import BaseClassPanel from './BaseClassPanel';
import macros from '../macros';

const css = {};

Object.assign(css, mobileCss, baseCss);

const cx = classNames.bind(css);

// Class Panel that renders the box with the class title, class description, and class sections
// If mobile, uses MobileSectionPanel to show the sections.
// The code for desktop is inside this file.

class MobileClassPanel extends BaseClassPanel {
  constructor(props) {
    super(props);

    this.state.showMoreThanTitle = false;
    this.state.showAllClassDetails = false;

    this.toggleShowMoreThanTitle = this.toggleShowMoreThanTitle.bind(this);
    this.toggleShowAllClassDetails = this.toggleShowAllClassDetails.bind(this);
  }

  toggleShowMoreThanTitle() {
    const newTitleValue = !this.state.showMoreThanTitle;
    let newShowAllClassDetails = this.state.showAllClassDetails;

    // If closing the class accordian, reset the showAllClassDetails back to the default.
    let newState = {};
    if (!newTitleValue) {
      newShowAllClassDetails = false;
      newState = this.getInitialRenderedSectionState();
    }

    newState.showMoreThanTitle = newTitleValue;
    newState.showAllClassDetails = newShowAllClassDetails;

    this.setState(newState);
  }

  toggleShowAllClassDetails() {
    this.setState({
      showAllClassDetails: !this.state.showAllClassDetails,
    });
  }

  getClassBody() {
    const aClass = this.props.aClass;

    let showFullClassBody = false;

    if (this.state.showAllClassDetails) {
      showFullClassBody = true;
    } else if (!aClass.desc || aClass.desc.length < 50) {
      showFullClassBody = true;
    }

    if (showFullClassBody) {
      // Figure out the credits string
      const creditsString = this.getCreditsString();

      return (

          {aClass.desc}

            {creditsString}

            Updated {aClass.getLastUpdateString()}

              {`View on ${aClass.host}`}

            Prerequisites: {this.optionalDisplay(macros.prereqTypes.PREREQ)} {this.showMore(macros.prereqTypes.PREREQ)}

            Corequisites: {this.optionalDisplay(macros.prereqTypes.COREQ)} {this.showMore(macros.prereqTypes.COREQ)}

            Prerequisite for: {this.optionalDisplay(macros.prereqTypes.PREREQ_FOR)} {this.showMore(macros.prereqTypes.PREREQ_FOR)}

            Optional Prerequisite for: {this.optionalDisplay(macros.prereqTypes.OPT_PREREQ_FOR)} {this.showMore(macros.prereqTypes.OPT_PREREQ_FOR)}

      );
    }

    // Remove everything past 80 characters
    // and then keep on removing characters until the end of a word is hit.
    let sliceDesc = aClass.desc.slice(0, 80);
    while (!sliceDesc.endsWith(' ')) {
      sliceDesc = sliceDesc.slice(0, sliceDesc.length - 1);
    }

    // Also remove any symbols.
    while (!sliceDesc[sliceDesc.length - 1].match(/[a-z]/i)) {
      sliceDesc = sliceDesc.slice(0, sliceDesc.length - 1);
    }
    sliceDesc = sliceDesc.trim();

    return (

          {`${sliceDesc}...`}

              Show More...

    );
  }

  render() {
    const aClass = this.props.aClass;

    let sectionTable = null;

    if (aClass.sections && aClass.sections.length > 0) {
      sectionTable = this.state.renderedSections.map((section) => {
        return <MobileSectionPanel key={ Keys.create(section).getHash() } section={ section } />;
      });
    }

    // Render the Show More.. Button
    const showMoreSections = this.getShowMoreButton();

    // Decide which chevron to use based on whether the panel is expanded or not.
    let chevron;
    if (this.state.showMoreThanTitle) {
      chevron = chevronDown;
    } else {
      chevron = chevronRight;
    }

    return (

        <div className={ `${css.container} ui segment` }>

              {aClass.subject} {aClass.classId}: {aClass.name}

              {this.getClassBody()}

            {sectionTable}

            {showMoreSections}

    );
  }
}

// Number of sections to show by default.
MobileClassPanel.sectionsShownByDefault = 1;

MobileClassPanel.propTypes = {
  aClass: PropTypes.object.isRequired,
};

export default CSSModules(MobileClassPanel, css);
<commit_msg>cleaned up mobileClassPanel.js<commit_after>/*
 * This file is part of Search NEU and licensed under AGPL3.
 * See the license file in the root folder for details.
 */

import React from 'react';
import PropTypes from 'prop-types';
import CSSModules from 'react-css-modules';
import classNames from 'classnames/bind';

import chevronDown from './chevron-down.svg';
import chevronRight from './chevron-right.svg';
import mobileCss from './MobileClassPanel.css';
import baseCss from './BaseClassPanel.css';
import MobileSectionPanel from './MobileSectionPanel';
import Keys from '../../../common/Keys';
import BaseClassPanel from './BaseClassPanel';
import macros from '../macros';

const css = {};

Object.assign(css, mobileCss, baseCss);

const cx = classNames.bind(css);

// Class Panel that renders the box with the class title, class description, and class sections
// If mobile, uses MobileSectionPanel to show the sections.
// The code for desktop is inside this file.

class MobileClassPanel extends BaseClassPanel {
  static propTypes = {
    aClass: PropTypes.object.isRequired,
  };

  toggleShowMoreThanTitle = () => {
    // If closing the class accordian, reset the showAllClassDetails back to the default.
    const newState = (this.state.showMoreThanTitle) ?
      this.getInitialRenderedSectionState() : {};

    newState.showMoreThanTitle = !this.state.showMoreThanTitle;

    this.setState(newState);
  }

  getClassBody() {
    const aClass = this.props.aClass;

    let showFullClassBody = false;

    if (this.state.showAllClassDetails) {
      showFullClassBody = true;
    } else if (!aClass.desc || aClass.desc.length < 50) {
      showFullClassBody = true;
    }

    if (showFullClassBody) {
      // Figure out the credits string
      const creditsString = this.getCreditsString();

      return (

          {aClass.desc}

            {creditsString}

            Updated {aClass.getLastUpdateString()}

              {`View on ${aClass.host}`}

            Prerequisites: {this.optionalDisplay(macros.prereqTypes.PREREQ)} {this.showMore(macros.prereqTypes.PREREQ)}

            Corequisites: {this.optionalDisplay(macros.prereqTypes.COREQ)} {this.showMore(macros.prereqTypes.COREQ)}

            Prerequisite for: {this.optionalDisplay(macros.prereqTypes.PREREQ_FOR)} {this.showMore(macros.prereqTypes.PREREQ_FOR)}

            Optional Prerequisite for: {this.optionalDisplay(macros.prereqTypes.OPT_PREREQ_FOR)} {this.showMore(macros.prereqTypes.OPT_PREREQ_FOR)}

      );
    }

    // Remove everything past 80 characters
    // and then keep on removing characters until the end of a word is hit.
    let sliceDesc = aClass.desc.slice(0, 80);
    while (!sliceDesc.endsWith(' ')) {
      sliceDesc = sliceDesc.slice(0, sliceDesc.length - 1);
    }

    // Also remove any symbols.
    while (!sliceDesc[sliceDesc.length - 1].match(/[a-z]/i)) {
      sliceDesc = sliceDesc.slice(0, sliceDesc.length - 1);
    }
    sliceDesc = sliceDesc.trim();

    return (

          {`${sliceDesc}...`}

           {
              this.setState({
                showAllClassDetails: !this.state.showAllClassDetails,
              });
            } }
            style={{ display:'inline-block' }}
            role='button'
            tabIndex={ 0 }
          >
              Show More...

    );
  }

  render() {
    const aClass = this.props.aClass;

    let sectionTable = null;

    if (aClass.sections && aClass.sections.length > 0) {
      sectionTable = this.state.renderedSections.map((section) => {
        return <MobileSectionPanel key={ Keys.create(section).getHash() } section={ section } />;
      });
    }

    // Render the Show More.. Button
    const showMoreSections = this.getShowMoreButton();

    // Decide which chevron to use based on whether the panel is expanded or not.
    let chevron;
    if (this.state.showMoreThanTitle) {
      chevron = chevronDown;
    } else {
      chevron = chevronRight;
    }

    return (

        <div className={ `${css.container} ui segment` }>

              {aClass.subject} {aClass.classId}: {aClass.name}

              {this.getClassBody()}

            {sectionTable}

            {showMoreSections}

    );
  }
}

// Number of sections to show by default.
MobileClassPanel.sectionsShownByDefault = 1;

export default CSSModules(MobileClassPanel, css);
<|endoftext|>


<commit_before>import { shallow, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import VueRouter from 'vue-router'
import RegisterTable from '@/registry/components/RegisterTable'
import { FETCH_DRILLER_LIST } from '@/registry/store/actions.types'

const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(VueRouter)

describe('RegisterTable.vue', () => {
  let store
  let getters
  let actions

  beforeEach(() => {
    getters = {
      user: () => {},
      loading: () => false,
      listError: () => null,
      drillers: () => {
        return {
          next: 'http://www.example.com/api/?limit=30&offset=60',
          previous: 'http://www.example.com/api/?limit=30&offset=0',
          results: [
            {
              person_guid: '1',
              first_name: 'Bob',
              surname: 'Driller'
            },
            {
              person_guid: '2',
              first_name: 'Rob',
              surname: 'Well'
            }
          ]
        }
      }
    }
    actions = {
      [FETCH_DRILLER_LIST]: jest.fn()
    }
    store = new Vuex.Store({ getters, actions })
  })

  it('has a row for every person', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    expect(wrapper.findAll('#registry-table-row').length)
      .toEqual(2)
  })

  it('has the right people in each row', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    // first row
    expect(wrapper.findAll('#registry-table-row').at(0).text())
      .toContain('Driller')
    expect(wrapper.findAll('#registry-table-row').at(0).text())
      .not.toContain('Well')
    expect(wrapper.findAll('#registry-table-row').at(1).text())
      .toContain('Well')
    expect(wrapper.findAll('#registry-table-row').at(1).text())
      .not.toContain('Driller')
  })
  it('shows the pagination button for next page when a link is returned by API', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    expect(wrapper.find('#table-pagination-next').text()).toEqual('Next')
  })
  it('shows the pagination button for previous page when a link is returned by API', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    expect(wrapper.find('#table-pagination-prev').text()).toEqual('Previous')
  })
  it('dispatches fetch driller list with correct querystring when pagination next clicked', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    wrapper.find('#table-pagination-next').trigger('click')
    expect(actions.fetchDrillers.mock.calls[0][1]).toEqual({limit: '30', offset: '60'})
  })
  it('dispatches fetch driller list with correct querystring when pagination prev clicked', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    wrapper.find('#table-pagination-prev').trigger('click')
    expect(actions.fetchDrillers.mock.calls[0][1]).toEqual({limit: '30', offset: '0'})
  })
  it('emits the column code (e.g. surname) to be sorted when column sort button clicked', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    wrapper.find('th i').trigger('click')
    expect(wrapper.emitted('sort')).toEqual([['surname']])
  })
})
<commit_msg>add test for columns for drillers and pump installers<commit_after>import { shallow, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import VueRouter from 'vue-router'
import RegisterTable from '@/registry/components/RegisterTable'
import { FETCH_DRILLER_LIST } from '@/registry/store/actions.types'

const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(VueRouter)

describe('RegisterTable.vue', () => {
  let store
  let getters
  let actions

  beforeEach(() => {
    getters = {
      user: () => {},
      loading: () => false,
      listError: () => null,
      drillers: () => {
        return {
          next: 'http://www.example.com/api/?limit=30&offset=60',
          previous: 'http://www.example.com/api/?limit=30&offset=0',
          results: [
            {
              person_guid: '1',
              first_name: 'Bob',
              surname: 'Driller'
            },
            {
              person_guid: '2',
              first_name: 'Rob',
              surname: 'Well'
            }
          ]
        }
      }
    }
    actions = {
      [FETCH_DRILLER_LIST]: jest.fn()
    }
    store = new Vuex.Store({ getters, actions })
  })

  it('has a row for every person', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    expect(wrapper.findAll('#registry-table-row').length)
      .toEqual(2)
  })

  it('has the right people in each row', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    // first row
    expect(wrapper.findAll('#registry-table-row').at(0).text())
      .toContain('Driller')
    expect(wrapper.findAll('#registry-table-row').at(0).text())
      .not.toContain('Well')
    expect(wrapper.findAll('#registry-table-row').at(1).text())
      .toContain('Well')
    expect(wrapper.findAll('#registry-table-row').at(1).text())
      .not.toContain('Driller')
  })
  it('shows the pagination button for next page when a link is returned by API', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    expect(wrapper.find('#table-pagination-next').text()).toEqual('Next')
  })
  it('shows the pagination button for previous page when a link is returned by API', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    expect(wrapper.find('#table-pagination-prev').text()).toEqual('Previous')
  })
  it('dispatches fetch driller list with correct querystring when pagination next clicked', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    wrapper.find('#table-pagination-next').trigger('click')
    expect(actions.fetchDrillers.mock.calls[0][1]).toEqual({limit: '30', offset: '60'})
  })
  it('dispatches fetch driller list with correct querystring when pagination prev clicked', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    wrapper.find('#table-pagination-prev').trigger('click')
    expect(actions.fetchDrillers.mock.calls[0][1]).toEqual({limit: '30', offset: '0'})
  })
  it('emits the column code (e.g. surname) to be sorted when column sort button clicked', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    wrapper.find('th i').trigger('click')
    expect(wrapper.emitted('sort')).toEqual([['surname']])
  })
  it('has the right columns when searching for drillers', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    wrapper.setProps({ activity: 'DRILL' })
    const tableHeaders = wrapper.findAll('th')
    const expectedHeaders = [
      'Name',
      'Company Name',
      'Company Address',
      'Contact Information',
      'Qualified to Drill',
      'Certificate Issued By'
    ]
    expect(tableHeaders.length).toEqual(6)
    for (let i = 0; i < tableHeaders.length; i++) {
      expect(tableHeaders.wrappers[i].text()).toEqual(expectedHeaders[i])
    }
  })
  it('has the right columns when searching for well pump installers', () => {
    const wrapper = shallow(RegisterTable, {
      store,
      localVue,
      stubs: ['router-link', 'router-view']
    })
    wrapper.setProps({ activity: 'PUMP' })
    const tableHeaders = wrapper.findAll('th')
    const expectedHeaders = [
      'Name',
      'Company Name',
      'Company Address',
      'Contact Information',
      'Certificate Issued By'
    ]
    expect(tableHeaders.length).toEqual(5)
    for (let i = 0; i < tableHeaders.length; i++) {
      expect(tableHeaders.wrappers[i].text()).toEqual(expectedHeaders[i])
    }
  })
})
<|endoftext|>


<commit_before>/*global global,globalDocument,isHostMethod */

/*
Description:
Relies on `document.addEventListener`.
*/

/*
Degrades:
IE8, IE7, IE6, IE5.5, IE5, IE4, IE3
*/

var attachDocumentListener;

if(globalDocument && isHostMethod(globalDocument, 'addEventListener')) {
	attachDocumentListener = function(eventType, fn) {

		var listener = function(e) {
			fn.call(e, e);
		};

		document.addEventListener(eventType, listener, false);

		return listener;
	};
}<commit_msg>fix this to be document as opposed to event<commit_after>/*global global,globalDocument,isHostMethod */

/*
Description:
Relies on `document.addEventListener`.
*/

/*
Degrades:
IE8, IE7, IE6, IE5.5, IE5, IE4, IE3
*/

var attachDocumentListener;

if(globalDocument && isHostMethod(globalDocument, 'addEventListener')) {
	attachDocumentListener = function(eventType, fn) {

		var listener = function(e) {
			fn.call(document, e);
		};

		document.addEventListener(eventType, listener, false);

		return listener;
	};
}<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)
//
// Licensed 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.

//////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////

// Helper function for getting ahold of an Arguments object.
function returnArgs() { return arguments; }

//////////////////////////////////////////////////////
// ElementsAre
//////////////////////////////////////////////////////

function ElementsAreTest() {}
registerTestSuite(ElementsAreTest);

ElementsAreTest.prototype.nonArrayArgument = function() {
  var error;

  expectThat(function() { elementsAre(null) },
             throwsError(/TypeError.*elementsAre.*array or Arguments/));

  expectThat(function() { elementsAre(undefined) },
             throwsError(/TypeError.*elementsAre.*array or Arguments/));

  expectThat(function() { elementsAre(2) },
             throwsError(/TypeError.*elementsAre.*array or Arguments/));
};

ElementsAreTest.prototype.nonArrayCandidates = function() {
  var pred = elementsAre([]).predicate;

  expectEq('which isn\'t an array or Arguments object', pred(undefined));
  expectEq('which isn\'t an array or Arguments object', pred(null));
  expectEq('which isn\'t an array or Arguments object', pred(''));
  expectEq('which isn\'t an array or Arguments object', pred({}));
  expectEq('which isn\'t an array or Arguments object', pred(2));
  expectEq('which isn\'t an array or Arguments object', pred(equals(2)));
};

ElementsAreTest.prototype.wrongLength = function() {
  var pred = elementsAre([_, _]).predicate;

  expectEq('which has length 0', pred([]));
  expectEq('which has length 1', pred([0]));
  expectEq('which has length 3', pred([0, 1, 2]));
};

ElementsAreTest.prototype.nonMatchingMatchers = function() {
  var pred =
    elementsAre([equals(0), containsRegExp(/^t.*o$/)]).predicate;

  expectEq('whose element 0 doesn\'t match', pred([1, 'taco']));
  expectEq('whose element 1 doesn\'t match', pred([0, 'taco filling']));
};

ElementsAreTest.prototype.allMatch = function() {
  var pred =
    elementsAre([equals(17), containsRegExp(/^t.*o$/)]).predicate;

  expectTrue(pred([17, 'taco']));
  expectTrue(pred([17, 'taco and burrito']));
};

ElementsAreTest.prototype.matcherReturnsString = function() {
  var innerMatcher = new gjstest.Matcher('', '', function() { return 'taco'; });
  var pred = elementsAre([innerMatcher]).predicate;

  expectEq('whose element 0 doesn\'t match', pred([undefined]));
};

ElementsAreTest.prototype.rawValues = function() {
  var obj = {};
  var pred = elementsAre([null, 0, 'taco', obj]).predicate;

  // Everything equal.
  expectTrue(pred([null, 0, 'taco', obj]));

  // Some non-equal.
  expectEq('whose element 0 doesn\'t match', pred([0, 0, 'taco', obj]));
  expectEq('whose element 1 doesn\'t match', pred([null, false, 'taco', obj]));
  expectEq('whose element 2 doesn\'t match', pred([null, 0, 'burrito', obj]));
  expectEq('whose element 3 doesn\'t match', pred([null, 0, 'taco', {}]));
};

ElementsAreTest.prototype.argumentsObject = function() {
  var obj = {};
  var pred = elementsAre([obj, containsRegExp(/t.+o/)]).predicate;

  // Everything equal.
  expectTrue(pred(returnArgs(obj, 'taco')));

  // Some non-equal.
  expectEq('whose element 0 doesn\'t match', pred(returnArgs({}, 'taco')));
  expectEq('whose element 1 doesn\'t match', pred(returnArgs(obj, 'burrito')));
};

ElementsAreTest.prototype.emptyArrays = function() {
  var pred = elementsAre([]).predicate;

  expectTrue(pred([]));
  expectEq('which has length 1', pred([0]));
};

ElementsAreTest.prototype.description = function() {
  var matcher;

  // Empty
  matcher = elementsAre([]);
  expectEq('is an empty array or Arguments object', matcher.description);
  expectEq('is not an empty array or Arguments object',
           matcher.negativeDescription);

  // Length 2
  matcher = elementsAre(['taco', containsRegExp(/t/)]);

  expectEq('is an array or Arguments object of length 2 with elements ' +
               'matching: ' +
               '[ \'taco\', partially matches regex: /t/ ]',
           matcher.description);

  expectEq('is not an array or Arguments object of length 2 with elements ' +
               'matching: ' +
               '[ \'taco\', partially matches regex: /t/ ]',
           matcher.negativeDescription);
};

//////////////////////////////////////////////////////
// Contains
//////////////////////////////////////////////////////

function ContainsTest() {
  this.wrappedPred_ = createMockFunction();
  this.wrapped_ = new gjstest.Matcher('', '', this.wrappedPred_);
  this.matcher_ = contains(this.wrapped_);
  this.predicate_ = this.matcher_.predicate;
}
registerTestSuite(ContainsTest);

ContainsTest.prototype.NonArrayCandidates = function() {
  var pred = this.predicate_;

  expectEq('which isn\'t an array or Arguments object', pred(undefined));
  expectEq('which isn\'t an array or Arguments object', pred(null));
  expectEq('which isn\'t an array or Arguments object', pred(''));
  expectEq('which isn\'t an array or Arguments object', pred({}));
  expectEq('which isn\'t an array or Arguments object', pred(2));
  expectEq('which isn\'t an array or Arguments object', pred(equals(2)));
};

ContainsTest.prototype.EmptyArray = function() {
  expectEq('which is empty', this.predicate_([]));
};

ContainsTest.prototype.EmptyArgs = function() {
  expectEq('which is empty', this.predicate_(returnArgs()));
};

ContainsTest.prototype.CallsPredicateForArray = function() {
  var candidate = [ 1, 'taco' ];

  expectCall(this.wrappedPred_)(1)
      .willOnce(returnWith(false));

  expectCall(this.wrappedPred_)('taco')
      .willOnce(returnWith(false));

  this.predicate_(candidate);
};

ContainsTest.prototype.CallsPredicateForArgs = function() {
  var candidate = returnArgs(1, 'taco');

  expectCall(this.wrappedPred_)(1)
      .willOnce(returnWith(false));

  expectCall(this.wrappedPred_)('taco')
      .willOnce(returnWith(false));

  this.predicate_(candidate);
};

ContainsTest.prototype.PredicateSaysNo = function() {
  expectCall(this.wrappedPred_)(_)
      .willOnce(returnWith(false));

  expectFalse(this.predicate_([17]));
};

ContainsTest.prototype.PredicateReturnsString = function() {
  expectCall(this.wrappedPred_)(_)
      .willOnce(returnWith('that is foo'));

  expectFalse(this.predicate_([17]));
};

ContainsTest.prototype.PredicateSaysYesForOneElement = function() {
  expectCall(this.wrappedPred_)(_)
      .willOnce(returnWith(false))
      .willOnce(returnWith(true));

  expectTrue(this.predicate_([17, 19, 23]));
};

ContainsTest.prototype.RawValueInsteadOfMatcher = function() {
  var pred = contains('taco').predicate;

  expectFalse(pred([1, 'taco_stuff', 2]));
  expectTrue(pred([1, 'taco', 2]));
};

ContainsTest.prototype.DescriptionWithMatcher = function() {
};

ContainsTest.prototype.DescriptionWithRawValue = function() {
};
<commit_msg>ContainsTest.DescriptionWithRawValue<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)
//
// Licensed 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.

//////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////

// Helper function for getting ahold of an Arguments object.
function returnArgs() { return arguments; }

//////////////////////////////////////////////////////
// ElementsAre
//////////////////////////////////////////////////////

function ElementsAreTest() {}
registerTestSuite(ElementsAreTest);

ElementsAreTest.prototype.nonArrayArgument = function() {
  var error;

  expectThat(function() { elementsAre(null) },
             throwsError(/TypeError.*elementsAre.*array or Arguments/));

  expectThat(function() { elementsAre(undefined) },
             throwsError(/TypeError.*elementsAre.*array or Arguments/));

  expectThat(function() { elementsAre(2) },
             throwsError(/TypeError.*elementsAre.*array or Arguments/));
};

ElementsAreTest.prototype.nonArrayCandidates = function() {
  var pred = elementsAre([]).predicate;

  expectEq('which isn\'t an array or Arguments object', pred(undefined));
  expectEq('which isn\'t an array or Arguments object', pred(null));
  expectEq('which isn\'t an array or Arguments object', pred(''));
  expectEq('which isn\'t an array or Arguments object', pred({}));
  expectEq('which isn\'t an array or Arguments object', pred(2));
  expectEq('which isn\'t an array or Arguments object', pred(equals(2)));
};

ElementsAreTest.prototype.wrongLength = function() {
  var pred = elementsAre([_, _]).predicate;

  expectEq('which has length 0', pred([]));
  expectEq('which has length 1', pred([0]));
  expectEq('which has length 3', pred([0, 1, 2]));
};

ElementsAreTest.prototype.nonMatchingMatchers = function() {
  var pred =
    elementsAre([equals(0), containsRegExp(/^t.*o$/)]).predicate;

  expectEq('whose element 0 doesn\'t match', pred([1, 'taco']));
  expectEq('whose element 1 doesn\'t match', pred([0, 'taco filling']));
};

ElementsAreTest.prototype.allMatch = function() {
  var pred =
    elementsAre([equals(17), containsRegExp(/^t.*o$/)]).predicate;

  expectTrue(pred([17, 'taco']));
  expectTrue(pred([17, 'taco and burrito']));
};

ElementsAreTest.prototype.matcherReturnsString = function() {
  var innerMatcher = new gjstest.Matcher('', '', function() { return 'taco'; });
  var pred = elementsAre([innerMatcher]).predicate;

  expectEq('whose element 0 doesn\'t match', pred([undefined]));
};

ElementsAreTest.prototype.rawValues = function() {
  var obj = {};
  var pred = elementsAre([null, 0, 'taco', obj]).predicate;

  // Everything equal.
  expectTrue(pred([null, 0, 'taco', obj]));

  // Some non-equal.
  expectEq('whose element 0 doesn\'t match', pred([0, 0, 'taco', obj]));
  expectEq('whose element 1 doesn\'t match', pred([null, false, 'taco', obj]));
  expectEq('whose element 2 doesn\'t match', pred([null, 0, 'burrito', obj]));
  expectEq('whose element 3 doesn\'t match', pred([null, 0, 'taco', {}]));
};

ElementsAreTest.prototype.argumentsObject = function() {
  var obj = {};
  var pred = elementsAre([obj, containsRegExp(/t.+o/)]).predicate;

  // Everything equal.
  expectTrue(pred(returnArgs(obj, 'taco')));

  // Some non-equal.
  expectEq('whose element 0 doesn\'t match', pred(returnArgs({}, 'taco')));
  expectEq('whose element 1 doesn\'t match', pred(returnArgs(obj, 'burrito')));
};

ElementsAreTest.prototype.emptyArrays = function() {
  var pred = elementsAre([]).predicate;

  expectTrue(pred([]));
  expectEq('which has length 1', pred([0]));
};

ElementsAreTest.prototype.description = function() {
  var matcher;

  // Empty
  matcher = elementsAre([]);
  expectEq('is an empty array or Arguments object', matcher.description);
  expectEq('is not an empty array or Arguments object',
           matcher.negativeDescription);

  // Length 2
  matcher = elementsAre(['taco', containsRegExp(/t/)]);

  expectEq('is an array or Arguments object of length 2 with elements ' +
               'matching: ' +
               '[ \'taco\', partially matches regex: /t/ ]',
           matcher.description);

  expectEq('is not an array or Arguments object of length 2 with elements ' +
               'matching: ' +
               '[ \'taco\', partially matches regex: /t/ ]',
           matcher.negativeDescription);
};

//////////////////////////////////////////////////////
// Contains
//////////////////////////////////////////////////////

function ContainsTest() {
  this.wrappedPred_ = createMockFunction();
  this.wrapped_ = new gjstest.Matcher('', '', this.wrappedPred_);
  this.matcher_ = contains(this.wrapped_);
  this.predicate_ = this.matcher_.predicate;
}
registerTestSuite(ContainsTest);

ContainsTest.prototype.NonArrayCandidates = function() {
  var pred = this.predicate_;

  expectEq('which isn\'t an array or Arguments object', pred(undefined));
  expectEq('which isn\'t an array or Arguments object', pred(null));
  expectEq('which isn\'t an array or Arguments object', pred(''));
  expectEq('which isn\'t an array or Arguments object', pred({}));
  expectEq('which isn\'t an array or Arguments object', pred(2));
  expectEq('which isn\'t an array or Arguments object', pred(equals(2)));
};

ContainsTest.prototype.EmptyArray = function() {
  expectEq('which is empty', this.predicate_([]));
};

ContainsTest.prototype.EmptyArgs = function() {
  expectEq('which is empty', this.predicate_(returnArgs()));
};

ContainsTest.prototype.CallsPredicateForArray = function() {
  var candidate = [ 1, 'taco' ];

  expectCall(this.wrappedPred_)(1)
      .willOnce(returnWith(false));

  expectCall(this.wrappedPred_)('taco')
      .willOnce(returnWith(false));

  this.predicate_(candidate);
};

ContainsTest.prototype.CallsPredicateForArgs = function() {
  var candidate = returnArgs(1, 'taco');

  expectCall(this.wrappedPred_)(1)
      .willOnce(returnWith(false));

  expectCall(this.wrappedPred_)('taco')
      .willOnce(returnWith(false));

  this.predicate_(candidate);
};

ContainsTest.prototype.PredicateSaysNo = function() {
  expectCall(this.wrappedPred_)(_)
      .willOnce(returnWith(false));

  expectFalse(this.predicate_([17]));
};

ContainsTest.prototype.PredicateReturnsString = function() {
  expectCall(this.wrappedPred_)(_)
      .willOnce(returnWith('that is foo'));

  expectFalse(this.predicate_([17]));
};

ContainsTest.prototype.PredicateSaysYesForOneElement = function() {
  expectCall(this.wrappedPred_)(_)
      .willOnce(returnWith(false))
      .willOnce(returnWith(true));

  expectTrue(this.predicate_([17, 19, 23]));
};

ContainsTest.prototype.RawValueInsteadOfMatcher = function() {
  var pred = contains('taco').predicate;

  expectFalse(pred([1, 'taco_stuff', 2]));
  expectTrue(pred([1, 'taco', 2]));
};

ContainsTest.prototype.DescriptionWithMatcher = function() {
  var matcher = contains(containsRegExp(/t/));

  expectEq('is an array or Arguments object containing an element that' +
               'partially matches regex: /t/',
           matcher.description);

  expectEq('is not an array or Arguments object containing an element that' +
               'partially matches regex: /t/',
           matcher.negativeDescription);
};

ContainsTest.prototype.DescriptionWithRawValue = function() {
  var matcher = contains('taco');

  expectEq('is an array or Arguments object containing \'taco\'',
           matcher.description);

  expectEq('is not an array or Arguments object containing \'taco\'',
           matcher.description);
};
<|endoftext|>