{"version":3,"sources":["craftsupport/src/CraftSupportWidget.js"],"names":["$","Craft","CraftSupportWidget","Garnish","Base","extend","widgetId","envInfo","$widget","$pane","$screens","$currentScreen","$nextScreen","currentScreen","$helpBody","$feedbackBody","init","widgets","this","initScreen","find","getScreen","screen","screens","SCREEN_HOME","$screen","filter","loadScreen","reinit","HomeScreen","HelpScreen","SCREEN_HELP","SCREEN_FEEDBACK","display","velocity","handleScreenAnimationComplete","css","opacity","width","height","top","outerHeight","complete","bind","position","afterInit","widget","noop","addListener","attr","currentTarget","gotoScreen","$options","children","$formContainer","ev","bodyStartHeight","$searchParams","BaseScreen","$searchSubmit","searchTimeout","showingResults","$supportForm","$supportAttachment","$supportSubmit","$supportSpinner","$supportErrorList","$supportIframe","sendingSupportTicket","$supportMessage","$searchResultsContainer","$searchResults","$searchForm","trigger","$body","handleSearchFormSubmit","preventDefault","$more","handleBodyTextChange","text","clearSearchTimeout","setTimeout","search","prepForSearch","name","params","value","appendTo","mode","BaseSearchScreen","MODE_SEARCH","removeClass","html","getFormParams","type","addClass","keyCode","val","handleBodyKeydown","ESC_KEY","handleSupportLinkClick","prepForSupport","RETURN_KEY","isCtrlKeyPressed","url","getSearchUrl","dataType","success","clearTimeout","hideSearchResults","handleSearchSuccess","results","getSearchResults","response","ajax","length","startResultsHeight","href","getSearchResultUrl","target","endResultsHeight","max","Math","min","i","append","getSearchResultStatus","getSearchResultText","handleSupportFormSubmit","animate","remove","swapForms","MODE_SUPPORT","$out","$in","left","parseSupportResponse","errors","error","displayNotice","attribute","insertAfter","hasOwnProperty","cp","t","is_answered","query","title","encodeURIComponent","body","result","link","FeedbackScreen","items","html_url","state","jQuery"],"mappings":"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","file":"CraftSupportWidget.min.js","sourcesContent":["(function($) {\n    /** global: Craft */\n    /** global: Garnish */\n    Craft.CraftSupportWidget = Garnish.Base.extend({\n        widgetId: 0,\n        envInfo: null,\n        loading: false,\n\n        $widget: null,\n        $pane: null,\n        $screens: null,\n        $currentScreen: null,\n        $nextScreen: null,\n\n        screens: null,\n        currentScreen: null,\n        $helpBody: null,\n        $feedbackBody: null,\n\n        init: function(widgetId, envInfo) {\n            this.widgetId = widgetId;\n            this.envInfo = envInfo;\n\n            Craft.CraftSupportWidget.widgets[this.widgetId] = this;\n\n            this.$widget = $('#widget' + widgetId);\n            this.$pane = this.$widget.find('> .front > .pane');\n            this.$screens = this.$pane.find('> .body > .cs-screen');\n\n            this.screens = {};\n            this.$currentScreen = this.initScreen(Craft.CraftSupportWidget.SCREEN_HOME).$screen;\n        },\n\n        getScreen: function(screen) {\n            return this.$screens.filter('.cs-screen-' + screen + ':first');\n        },\n\n        initScreen: function(screen) {\n            // First time?\n            if (typeof this.screens[screen] === 'undefined') {\n                this.screens[screen] = this.loadScreen(screen);\n            } else {\n                this.screens[screen].reinit();\n            }\n\n            return this.screens[screen];\n        },\n\n        loadScreen: function(screen) {\n            var $screen = this.getScreen(screen);\n\n            switch (screen) {\n                case Craft.CraftSupportWidget.SCREEN_HOME:\n                    return new HomeScreen(this, screen, $screen);\n                case Craft.CraftSupportWidget.SCREEN_HELP:\n                    return new HelpScreen(this, screen, $screen);\n                case Craft.CraftSupportWidget.SCREEN_FEEDBACK:\n                    return new FeedbackScreen(this, screen, $screen);\n                default:\n                    throw 'Invalid screen: ' + screen;\n            }\n        },\n\n        gotoScreen: function(screen) {\n            // Are we right in the middle of a transition?\n            if (this.$nextScreen) {\n                // Unfortunately velocity('finish') doesn't work fast enough\n                this.$currentScreen\n                    .velocity('stop')\n                    .css({opacity: 0, display: 'none'});\n                this.$nextScreen\n                    .velocity('stop')\n                    .css({opacity: 1});\n                this.$pane.velocity('stop');\n                this.handleScreenAnimationComplete();\n            }\n\n            // Init/prep the next screen\n            this.$nextScreen = this.getScreen(screen)\n                .css({\n                    display: 'block',\n                    position: 'absolute',\n                    left: '0px',\n                    top: '0px',\n                    width: this.$pane.width() + 'px'\n                });\n\n            // Animate the new screen into view\n            this.$pane.height(this.$pane.height());\n            this.$currentScreen.velocity({opacity: 0}, {display: 'none'});\n            this.$nextScreen.velocity({opacity: 1});\n            this.$pane.velocity({height: this.$nextScreen.outerHeight()}, {\n                complete: this.handleScreenAnimationComplete.bind(this)\n            });\n\n            this.currentScreen = this.initScreen(screen);\n        },\n\n        handleScreenAnimationComplete: function() {\n            this.$pane.height('auto');\n            this.$nextScreen.css({\n                position: 'relative',\n                width: 'auto'\n            });\n            this.$currentScreen = this.$nextScreen;\n            this.$nextScreen = null;\n        }\n    }, {\n        widgets: {},\n        SCREEN_HOME: 'home',\n        SCREEN_HELP: 'help',\n        SCREEN_FEEDBACK: 'feedback'\n    });\n\n    var BaseScreen = Garnish.Base.extend({\n        widget: null,\n        screen: null,\n        $screen: null,\n\n        init: function(widget, screen, $screen) {\n            this.widget = widget;\n            this.screen = screen;\n            this.$screen = $screen;\n\n            this.afterInit();\n        },\n\n        afterInit: $.noop,\n        reinit: $.noop\n    });\n\n    var HomeScreen = BaseScreen.extend({\n        afterInit: function() {\n            var $options = this.$screen.children('.cs-opt');\n            this.addListener($options, 'click', 'handleOptionClick');\n        },\n\n        handleOptionClick: function(ev) {\n            var screen = $.attr(ev.currentTarget, 'data-screen');\n            this.widget.gotoScreen(screen);\n        }\n    });\n\n    var BaseSearchScreen = BaseScreen.extend({\n        $body: null,\n        $formContainer: null,\n        mode: null,\n        bodyStartHeight: null,\n\n        $searchResultsContainer: null,\n        $searchResults: null,\n        $searchForm: null,\n        $searchParams: null,\n        $searchSubmit: null,\n        searchTimeout: null,\n        showingResults: false,\n\n        $supportForm: null,\n        $supportMessage: null,\n        $supportAttachment: null,\n        $supportSubmit: null,\n        $supportSpinner: null,\n        $supportErrorList: null,\n        $supportIframe: null,\n        sendingSupportTicket: false,\n\n        afterInit: function() {\n            this.$body = this.$screen.find('.cs-body-text:first').trigger('focus');\n            this.$formContainer = this.$screen.children('.cs-forms');\n\n            // Search mode stuff\n            this.$searchResultsContainer = this.$screen.children('.cs-search-results-container:first');\n            this.$searchResults = this.$searchResultsContainer.find('.cs-search-results:first');\n            this.$searchForm = this.$formContainer.children('.cs-search-form:first');\n            this.$searchParams = this.$searchForm.children('.cs-search-params:first');\n            this.$searchSubmit = this.$searchForm.children('.submit:first');\n            this.addListener(this.$searchForm, 'submit', 'handleSearchFormSubmit');\n            this.addListener(this.$searchForm.find('> p > a'), 'click', 'handleSupportLinkClick');\n\n            // Support mode stuff\n            this.$supportForm = this.$formContainer.children('.cs-support-form:first');\n            this.$supportMessage = this.$supportForm.children('input.cs-support-message');\n            var $more = this.$supportForm.children('.cs-support-more');\n            this.$supportAttachment = $more.find('.cs-support-attachment:first');\n            this.$supportSubmit = this.$supportForm.children('.submit:first');\n            this.$supportSpinner = this.$supportForm.children('.spinner:first');\n            this.$supportIframe = this.$screen.children('iframe');\n            this.addListener(this.$supportForm, 'submit', 'handleSupportFormSubmit');\n\n            this.bodyStartHeight = this.$body.height();\n            this.addListener(this.$body, 'input', 'handleBodyTextChange');\n            this.addListener(this.$body, 'keydown', 'handleBodyKeydown');\n            this.prepForSearch(false);\n        },\n\n        handleSearchFormSubmit: function(ev) {\n            if (!this.$body.val()) {\n                ev.preventDefault();\n            }\n        },\n\n        handleBodyTextChange: function() {\n            var text = this.$body.val();\n\n            if (this.mode === BaseSearchScreen.MODE_SEARCH) {\n                this.clearSearchTimeout();\n                this.searchTimeout = setTimeout(this.search.bind(this), 500);\n\n                if (text) {\n                    this.$searchParams.html('');\n                    var params = this.getFormParams(text);\n                    for (var name in params) {\n                        if (params.hasOwnProperty(name)) {\n                            $('<input/>', {\n                                type: 'hidden',\n                                name: name,\n                                value: params[name]\n                            }).appendTo(this.$searchParams);\n                        }\n                    }\n                    this.$searchSubmit.removeClass('disabled');\n                } else {\n                    this.$searchSubmit.addClass('disabled');\n                }\n            } else {\n                if (text) {\n                    this.$supportMessage.val(text);\n                    this.$supportSubmit.removeClass('disabled');\n                } else {\n                    this.$supportSubmit.addClass('disabled');\n                }\n            }\n        },\n\n        handleBodyKeydown: function(ev) {\n            switch (ev.keyCode) {\n                case Garnish.ESC_KEY:\n                    if (this.mode === BaseSearchScreen.MODE_SEARCH) {\n                        this.widget.gotoScreen(Craft.CraftSupportWidget.SCREEN_HOME);\n                    } else if (!this.sendingSupportTicket) {\n                        this.prepForSearch(true);\n                    }\n                    break;\n                case Garnish.RETURN_KEY:\n                    if (Garnish.isCtrlKeyPressed(ev)) {\n                        if (this.mode === BaseSearchScreen.MODE_SEARCH) {\n                            this.$searchForm.trigger('submit');\n                        } else {\n                            this.$supportForm.trigger('submit');\n                        }\n                    }\n                    break;\n            }\n        },\n\n        handleSupportLinkClick: function() {\n            this.prepForSupport(true);\n        },\n\n        clearSearchTimeout: function() {\n            if (this.searchTimeout) {\n                clearTimeout(this.searchTimeout);\n                this.searchTimeout = null;\n            }\n        },\n\n        search: function() {\n            this.clearSearchTimeout();\n\n            var text = this.$body.val();\n\n            if (text) {\n                var url = this.getSearchUrl(this.$body.val());\n                $.ajax({\n                    url: url,\n                    dataType: 'json',\n                    success: this.handleSearchSuccess.bind(this),\n                    error: this.hideSearchResults.bind(this)\n                });\n            } else {\n                this.hideSearchResults();\n            }\n        },\n\n        handleSearchSuccess: function(response) {\n            if (this.mode !== BaseSearchScreen.MODE_SEARCH) {\n                return;\n            }\n\n            var results = this.getSearchResults(response);\n\n            if (results.length) {\n                var startResultsHeight;\n\n                if (!this.showingResults) {\n                    this.$searchResultsContainer.removeClass('hidden');\n                    startResultsHeight = 0;\n                    this.showingResults = true;\n                    this.$screen.addClass('with-results');\n                } else {\n                    startResultsHeight = this.$searchResultsContainer.height();\n                }\n\n                this.$searchResults.html('');\n\n                var max = Math.min(results.length, 20);\n                for (var i = 0; i < max; i++) {\n                    this.$searchResults.append($('<li>').append($('<a>', {\n                        href: this.getSearchResultUrl(results[i]),\n                        target: '_blank',\n                        html: '<span class=\"status ' + this.getSearchResultStatus(results[i]) + '\"></span>' + this.getSearchResultText(results[i])\n                    })));\n                }\n\n                var endResultsHeight = this.$searchResultsContainer.height('auto').height();\n                this.$searchResultsContainer\n                    .velocity('stop')\n                    .height(startResultsHeight)\n                    .velocity({height: endResultsHeight}, {\n                        complete: () => {\n                            this.$searchResultsContainer.height('auto');\n                        },\n                    });\n            } else {\n                this.hideSearchResults();\n            }\n        },\n\n        hideSearchResults: function() {\n            if (this.mode !== BaseSearchScreen.MODE_SEARCH || !this.showingResults) {\n                return;\n            }\n\n            this.$searchResultsContainer\n                .velocity('stop')\n                .height(this.$searchResultsContainer.height())\n                .velocity({height: 0}, {\n                    complete: () => {\n                        this.$searchResultsContainer.addClass('hidden');\n                    },\n                });\n\n            this.showingResults = false;\n            this.$screen.removeClass('with-results');\n        },\n\n        handleSupportFormSubmit: function(ev) {\n            if (!this.$body.val() || this.sendingSupportTicket) {\n                ev.preventDefault();\n                return;\n            }\n\n            this.sendingSupportTicket = true;\n            this.$supportSubmit.addClass('active');\n            this.$supportSpinner.removeClass('hidden');\n        },\n\n        reinit: function() {\n            this.$body.trigger('focus');\n        },\n\n        prepForSearch: function(animate) {\n            this.mode = BaseSearchScreen.MODE_SEARCH;\n\n            this.$body\n                .velocity('stop')\n                .trigger('focus');\n\n            if (this.$supportErrorList) {\n                this.$supportErrorList.remove();\n                this.$supportErrorList = null;\n            }\n\n            if (animate) {\n                this.$body.velocity({height: this.bodyStartHeight});\n            } else {\n                this.$body.height(this.bodyStartHeight);\n            }\n\n            this.swapForms(this.$supportForm, this.$searchForm, animate);\n\n            // In case there's already a search value\n            this.handleBodyTextChange();\n            this.search();\n        },\n\n        prepForSupport: function(animate) {\n            this.clearSearchTimeout();\n            this.hideSearchResults();\n\n            this.mode = BaseSearchScreen.MODE_SUPPORT;\n\n            this.$body\n                .velocity('stop')\n                .trigger('focus');\n\n            if (animate) {\n                this.$body.velocity({height: this.bodyStartHeight * 2});\n            } else {\n                this.$body.height(this.bodyStartHeight * 2);\n            }\n\n            this.swapForms(this.$searchForm, this.$supportForm, animate);\n\n            // In case there's already a search value\n            this.handleBodyTextChange();\n        },\n\n        swapForms: function($out, $in, animate) {\n            if (animate) {\n                this.$formContainer.height(this.$formContainer.height());\n                var width = this.$formContainer.width();\n\n                $out\n                    .velocity('stop')\n                    .css({position: 'absolute', top: 0, left: 0, width: width})\n                    .velocity({opacity: 0}, {\n                        complete: function() {\n                            $out\n                                .addClass('hidden')\n                                .css({position: 'relative', width: 'auto'});\n                        }\n                    });\n\n                $in\n                    .velocity('stop')\n                    .removeClass('hidden')\n                    .css({position: 'absolute', top: 0, left: 0, width: width})\n                    .velocity({opacity: 1}, {\n                        complete: function() {\n                            $in.css({position: 'relative', width: 'auto'});\n                        }\n                    });\n\n                this.$formContainer\n                    .velocity('stop')\n                    .velocity({height: $in.height()}, {\n                        complete: () => {\n                            this.$formContainer.css({height: 'auto'});\n                        },\n                    });\n            } else {\n                $out.addClass('hidden');\n                $in.removeClass('hidden');\n            }\n        },\n\n        parseSupportResponse: function(response) {\n            this.sendingSupportTicket = false;\n            this.$supportSubmit.removeClass('active');\n            this.$supportSpinner.addClass('hidden');\n\n            if (this.$supportErrorList) {\n                this.$supportErrorList.children().remove();\n            }\n\n            if (response.errors) {\n                if (!this.$supportErrorList) {\n                    this.$supportErrorList = $('<ul class=\"errors\"/>').insertAfter(this.$supportForm);\n                }\n\n                for (var attribute in response.errors) {\n                    if (response.errors.hasOwnProperty(attribute)) {\n                        for (var i = 0; i < response.errors[attribute].length; i++) {\n                            var error = response.errors[attribute][i];\n                            $('<li>' + error + '</li>').appendTo(this.$supportErrorList);\n                        }\n                    }\n                }\n            }\n\n            if (response.success) {\n                Craft.cp.displayNotice(Craft.t('app', 'Message sent successfully.'));\n                this.$body.val('');\n                this.$supportMessage.val('');\n                this.$supportAttachment.val('');\n            }\n\n            this.$supportIframe.html('');\n        },\n\n        getFormParams: function() {\n            throw 'getFormParams() must be implemented';\n        },\n        getSearchUrl: function() {\n            throw 'getSearchUrl() must be implemented';\n        },\n        getSearchResults: function() {\n            throw 'getSearchResults() must be implemented';\n        },\n        getSearchResultUrl: function() {\n            throw 'getSearchResultUrl() must be implemented';\n        },\n        getSearchResultStatus: function() {\n            throw 'getSearchResultStatus() must be implemented';\n        },\n        getSearchResultText: function() {\n            throw 'getSearchResultUrl() must be implemented';\n        }\n    }, {\n        MODE_SEARCH: 'search',\n        MODE_SUPPORT: 'support'\n    });\n\n    var HelpScreen = BaseSearchScreen.extend({\n        getFormParams: function(query) {\n            return {title: query};\n        },\n\n        getSearchUrl: function(query) {\n            return 'https://api.stackexchange.com/2.2/similar?site=craftcms&sort=relevance&order=desc&title=' + encodeURIComponent(query);\n        },\n\n        getSearchResults: function(response) {\n            return response.items || [];\n        },\n\n        getSearchResultUrl: function(result) {\n            return result.link;\n        },\n\n        getSearchResultStatus: function(result) {\n            return result.is_answered ? 'green' : '';\n        },\n\n        getSearchResultText: function(result) {\n            return result.title;\n        }\n    });\n\n    var FeedbackScreen = BaseSearchScreen.extend({\n        getFormParams: function(query) {\n            var body = \"### Description\\n\\n\\n\\n\" +\n                \"### Steps to reproduce\\n\\n\" +\n                \"1.\\n\" +\n                \"2.\\n\\n\" +\n                \"### Additional info\\n\";\n\n            for (var name in this.widget.envInfo) {\n                if (this.widget.envInfo.hasOwnProperty(name)) {\n                    body += \"\\n- \" + name + ': ' + this.widget.envInfo[name];\n                }\n            }\n\n            return {title: query, body: body};\n        },\n\n        getSearchUrl: function(query) {\n            return 'https://api.github.com/search/issues?q=type:issue+repo:craftcms/cms+' + encodeURIComponent(query);\n        },\n\n        getSearchResults: function(response) {\n            return response.items || [];\n        },\n\n        getSearchResultUrl: function(result) {\n            return result.html_url;\n        },\n\n        getSearchResultStatus: function(result) {\n            return result.state === 'open' ? 'green' : 'red';\n        },\n\n        getSearchResultText: function(result) {\n            return result.title;\n        }\n    });\n})(jQuery);\n"]}