/* This file is part of Indico.
 * Copyright (C) 2002 - 2018 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

import {handleAxiosError, indicoAxios} from 'indico/utils/axios';


async function _makeUrshRequest(originalURL) {
    const urshEndpoint = '/ursh';

    let response;
    try {
        response = await indicoAxios.post(urshEndpoint, {
            original_url: originalURL,
        });
    } catch (error) {
        handleAxiosError(error);
        return;
    }

    return response.data.url;
}

function _validateAndFormatURL(url) {
    const $t = $T.domain('ursh');
    if (!url) {
        throw Error($t.gettext('Please fill in a URL to shorten'));
    }

    // if protocol is missing, prepend it
    if (url.startsWith(location.hostname)) {
        url = `${location.protocol}//${url}`;
    }

    // regular expression, because I.E. does not like the URL class
    const re = RegExp(`^(.+:)//([^/]+)(/.*)?$`);
    const urlTokens = url.match(re);
    if (!urlTokens) {
        throw Error($t.gettext('This does not look like a valid URL'));
    }

    // extract tokens
    let protocol = urlTokens[1];
    const hostname = urlTokens[2];
    const path = urlTokens[3] ? urlTokens[3] : '/';

    protocol = location.protocol;  // patch protocol to match server
    if (hostname !== location.hostname) {
        throw Error($t.gettext('Invalid host: only Indico URLs are allowed'));
    }

    return `${protocol}//${hostname}${path}`;
}

function _getUrshInput() {
    const input = $('#ursh-shorten-input');
    const inputURL = input.val().trim();

    const tip = ((msg) => {
        input.qtip({
            content: {
                text: msg
            },
            hide: {
                event: 'mouseleave',
                fixed: true,
                delay: 700
            },
            show: {
                event: false,
                ready: true
            }
        });
    });

    try {
        const formattedURL = _validateAndFormatURL(inputURL);
        input.val(formattedURL);
        return formattedURL;
    } catch (err) {
        tip(err.message);
        input.focus().select();
        return null;
    }
}

async function _handleUrshPageInput(evt) {
    evt.preventDefault();
    const originalURL = _getUrshInput();
    if (originalURL) {
        const result = await _makeUrshRequest(originalURL);
        if (result) {
            const outputElement = $('#ursh-shorten-output');
            $('#ursh-shorten-response-form').slideDown();
            outputElement.val(result);
            outputElement.select();
        }
    }
}

async function _handleUrshClick(evt) {
    evt.preventDefault();
    const originalURL = $(evt.target).attr('data-original-url');
    const result = await _makeUrshRequest(originalURL);
    $(evt.target).copyURLTooltip(result);
}

$(document)
    .on('click', '#ursh-shorten-button', _handleUrshPageInput)
    .on('keydown', '#ursh-shorten-input', (evt) => {
        if (evt.key === 'Enter') {
            _handleUrshPageInput(evt);
        }
    })
    .on('click', '.ursh-get', _handleUrshClick);

@@ -808,16 +808,316 @@
 ios';%0A%0A%0A
+function _showTip(element, msg) %7B%0A    element.qtip(%7B%0A        content: %7B%0A            text: msg%0A        %7D,%0A        hide: %7B%0A            event: 'mouseleave',%0A            fixed: true,%0A            delay: 700%0A        %7D,%0A        show: %7B%0A            event: false,%0A            ready: true%0A        %7D%0A    %7D);%0A%7D%0A%0A
 async fu
@@ -1809,16 +1809,90 @@
 L class%0A
+    // provides minimal validation, leaving the serious job to the server%0A
     cons
@@ -1908,17 +1908,24 @@
 gExp(%60%5E(
-.
+%5B%5C%5Cd%5C%5Cw%5D
 +:)//(%5B%5E
@@ -1925,18 +1925,35 @@
 :)//(%5B%5E/
-%5D+
+ .%5D+(?:%5C%5C.%5B%5E/ .%5D+)*
 )(/.*)?$
@@ -2510,448 +2510,80 @@
 put(
-) %7B%0A    const input = $('#ursh-shorten-input');%0A    const inputURL = input.val().trim();%0A%0A    const tip = ((msg) =%3E %7B%0A        input.qtip(%7B%0A            content: %7B%0A                text: msg%0A            %7D,%0A            hide: %7B%0A                event: 'mouseleave',%0A                fixed: true,%0A                delay: 700%0A            %7D,%0A            show: %7B%0A                event: false,%0A                ready: true%0A            %7D%0A        %7D);%0A    %7D
+input) %7B%0A    const inputURL = input.val().trim();%0A    input.val(inputURL
 );%0A%0A
@@ -2744,20 +2744,32 @@
         
-tip(
+_showTip(input, 
 err.mess
@@ -2897,32 +2897,111 @@
 eventDefault();%0A
+    const $t = $T.domain('ursh');%0A%0A    const input = $('#ursh-shorten-input');%0A
     const origin
@@ -3022,16 +3022,21 @@
 shInput(
+input
 );%0A    i
@@ -3321,32 +3321,165 @@
 ement.select();%0A
+        %7D else %7B%0A            _showTip(input, $t.gettext('This does not look like a valid URL'));%0A            input.focus().select();%0A
         %7D%0A    %7D%0A

Fix regex, catch more invalid URLs