<commit_before>/// <reference path="../../typings/react/react.d.ts" />
/// <reference path="../../typings/react/react-dom.d.ts" />

import * as React from "react";
import * as ReactDOM from "react-dom";
import * as workspace from "./workspace";
import * as data from "./data";
import * as pkg from "./package";

import Cloud = ks.Cloud;
import Util = ks.Util;

var lf = Util.lf;

export type Component<S, T> = data.Component<S, T>;

export function hideLoading() {
    $('.ui.page.dimmer .loadingcontent').remove();
    $('body').dimmer('hide');
}

export function showLoading(msg: string) {
    $('body').dimmer('show');
    $('.ui.page.dimmer').html(`
  <div class="content loadingcontent">
    <div class="ui text large loader msg">{lf("Please wait")}</div>
  </div>
`)
    $('.ui.page.dimmer .msg').text(msg)
}

export function navigateInWindow(url: string) {
    window.location.href = url;
}

export function findChild(c: React.Component<any, any>, selector: string) {
    let self = $(ReactDOM.findDOMNode(c))
    if (!selector) return self
    return self.find(selector)
}

export function parseQueryString(qs: string) {
    let r: Util.StringMap<string> = {}
    qs.replace(/\+/g, " ").replace(/([^&=]+)=?([^&]*)/g, (f: string, k: string, v: string) => {
        r[decodeURIComponent(k)] = decodeURIComponent(v)
        return ""
    })
    return r
}

let lastTime: any = {}

function htmlmsg(kind: string, msg: string) {
    let now = Date.now()
    let prev = lastTime[kind] || 0
    if (now - prev < 100)
        $('#' + kind + 'msg').text(msg);
    else {
        lastTime[kind] = now
        $('#' + kind + 'msg').finish().text(msg).fadeIn('fast').delay(3000).fadeOut('slow');
    }
}

export function errorNotification(msg: string) {
    console.log("ERROR", msg)
    htmlmsg("err", msg)
}

export function warningNotification(msg: string) {
    console.log("WARNING", msg)
    htmlmsg("warn", msg)
}

export function infoNotification(msg: string) {
    console.log("INFO", msg)
    htmlmsg("info", msg)
}

export function browserDownloadText(text: string, name: string, contentType: string = "application/octet-stream") {
    console.log('trigger download')
    var buf = Util.stringToUint8Array(Util.toUTF8(text))
    var uri = browserDownloadUInt8Array(buf, name, contentType);
    $('#compilemsg').finish()
        .html(`${lf("Download ready.")} <a href='" + encodeURI(uri) + "' download='" + name + "' target='_blank'>${lf("Use this link to save to another location.")}</a>`)
        .fadeIn('fast').delay(7000).fadeOut('slow');
}

export var isMobileBrowser = /mobile/.test(navigator.userAgent);

function browserDownloadUInt8Array(buf: Uint8Array, name: string, contentType: string = "application/octet-stream"): string {
    var dataurl = "data:" + contentType + ";base64," + btoa(Util.uint8ArrayToString(buf))
    try {
        if ((<any>window).navigator.msSaveOrOpenBlob && !isMobileBrowser) {
            var b = new Blob([buf], { type: contentType })
            var result = (<any>window).navigator.msSaveOrOpenBlob(b, name);
        } else {
            var link = <any>window.document.createElement('a');
            if (typeof link.download == "string") {
                link.href = dataurl;
                link.download = name;
                document.body.appendChild(link); // for FF
                link.click();
                document.body.removeChild(link);
            } else {
                document.location.href = dataurl;
            }
        }
    } catch (e) {
        errorNotification(lf("saving file failed..."))
    }
    return dataurl;
}

export function handleNetworkError(e: any) {
    let statusCode = <number>e.status
    if (e.isOffline) {
        warningNotification(lf("Network request failed; you appear to be offline"))
    } else {
        throw e;
    }
}

export interface ConfirmOptions {
    header: string;
    body?: string;
    htmlBody?: string;
    agreeLbl?: string;
    disagreeLbl?: string;
    agreeIcon?: string;
    agreeClass?: string;
    hideCancel?: boolean;
    hideAgree?: boolean;
    onLoaded?: (_: JQuery) => void;
}

export function confirmAsync(options: ConfirmOptions) {
    let html = `
  <div class="ui small modal">
    <div class="header">
        ${Util.htmlEscape(options.header)}      
    </div>
    <div class="content">
      ${options.body ? "<p>" + Util.htmlEscape(options.body) + "</p>" : ""}
      ${options.htmlBody || ""}
    </div>`
    if (!options.hideCancel || !options.hideAgree) {
        html += `<div class="actions">`
        if (!options.hideCancel) {
            html += `<div class="ui right labeled icon button">
        ${Util.htmlEscape(options.disagreeLbl || lf("Cancel"))}
        <i class="cancel icon"></i>
      </div>`
        }
        if (!options.hideAgree) {
            html += `
      <div class="ui approve right labeled icon button ${options.agreeClass || "positive"}">
        ${Util.htmlEscape(options.agreeLbl || lf("Go ahead!"))}
        <i class="${options.agreeIcon || "checkmark"} icon"></i>
      </div>`
        }
        
        html += `</div>`
    }
    html += `</div>`
    
    let modal = $(html)
    let done = false
    $('#root').append(modal)
    if (options.onLoaded) options.onLoaded(modal)

    modal.find('img').on('load', () => {
        modal.modal('refresh')                
    })

    return new Promise((resolve, reject) =>
        modal.modal({
            observeChanges: true,
            closeable: !options.hideCancel,
            onHidden: () => {
                modal.remove()
            },
            onApprove: () => {
                if (!done) {
                    done = true
                    resolve(true)
                }
            },
            onHide: () => {
                if (!done) {
                    done = true
                    resolve(false)
                }
            },
        }).modal("show"))
}

export function confirmDelete(what: string, cb: () => Promise<void>) {
    confirmAsync({
        header: lf("Are you sure to delete '{0}'?", what),
        body: lf("It will be deleted for good. No undo."),
        agreeLbl: lf("Delete"),
        agreeClass: "red",
        agreeIcon: "trash",
    }).then(res => {
        if (res) {
            cb().done()
        }
    }).done()
}

export interface ShareOptions {
    header: string;
    body?: string;
    link: string;
    okClass?: string;
    okIcon?: string;
    okLabel?: string;
}

export function shareLinkAsync(options: ShareOptions) {
    let html = `
  <div class="ui small modal"><commit_msg>rephrasing delete dialog<commit_after>/// <reference path="../../typings/react/react.d.ts" />
/// <reference path="../../typings/react/react-dom.d.ts" />

import * as React from "react";
import * as ReactDOM from "react-dom";
import * as workspace from "./workspace";
import * as data from "./data";
import * as pkg from "./package";

import Cloud = ks.Cloud;
import Util = ks.Util;

var lf = Util.lf;

export type Component<S, T> = data.Component<S, T>;

export function hideLoading() {
    $('.ui.page.dimmer .loadingcontent').remove();
    $('body').dimmer('hide');
}

export function showLoading(msg: string) {
    $('body').dimmer('show');
    $('.ui.page.dimmer').html(`
  <div class="content loadingcontent">
    <div class="ui text large loader msg">{lf("Please wait")}</div>
  </div>
`)
    $('.ui.page.dimmer .msg').text(msg)
}

export function navigateInWindow(url: string) {
    window.location.href = url;
}

export function findChild(c: React.Component<any, any>, selector: string) {
    let self = $(ReactDOM.findDOMNode(c))
    if (!selector) return self
    return self.find(selector)
}

export function parseQueryString(qs: string) {
    let r: Util.StringMap<string> = {}
    qs.replace(/\+/g, " ").replace(/([^&=]+)=?([^&]*)/g, (f: string, k: string, v: string) => {
        r[decodeURIComponent(k)] = decodeURIComponent(v)
        return ""
    })
    return r
}

let lastTime: any = {}

function htmlmsg(kind: string, msg: string) {
    let now = Date.now()
    let prev = lastTime[kind] || 0
    if (now - prev < 100)
        $('#' + kind + 'msg').text(msg);
    else {
        lastTime[kind] = now
        $('#' + kind + 'msg').finish().text(msg).fadeIn('fast').delay(3000).fadeOut('slow');
    }
}

export function errorNotification(msg: string) {
    console.log("ERROR", msg)
    htmlmsg("err", msg)
}

export function warningNotification(msg: string) {
    console.log("WARNING", msg)
    htmlmsg("warn", msg)
}

export function infoNotification(msg: string) {
    console.log("INFO", msg)
    htmlmsg("info", msg)
}

export function browserDownloadText(text: string, name: string, contentType: string = "application/octet-stream") {
    console.log('trigger download')
    var buf = Util.stringToUint8Array(Util.toUTF8(text))
    var uri = browserDownloadUInt8Array(buf, name, contentType);
    $('#compilemsg').finish()
        .html(`${lf("Download ready.")} <a href='" + encodeURI(uri) + "' download='" + name + "' target='_blank'>${lf("Use this link to save to another location.")}</a>`)
        .fadeIn('fast').delay(7000).fadeOut('slow');
}

export var isMobileBrowser = /mobile/.test(navigator.userAgent);

function browserDownloadUInt8Array(buf: Uint8Array, name: string, contentType: string = "application/octet-stream"): string {
    var dataurl = "data:" + contentType + ";base64," + btoa(Util.uint8ArrayToString(buf))
    try {
        if ((<any>window).navigator.msSaveOrOpenBlob && !isMobileBrowser) {
            var b = new Blob([buf], { type: contentType })
            var result = (<any>window).navigator.msSaveOrOpenBlob(b, name);
        } else {
            var link = <any>window.document.createElement('a');
            if (typeof link.download == "string") {
                link.href = dataurl;
                link.download = name;
                document.body.appendChild(link); // for FF
                link.click();
                document.body.removeChild(link);
            } else {
                document.location.href = dataurl;
            }
        }
    } catch (e) {
        errorNotification(lf("saving file failed..."))
    }
    return dataurl;
}

export function handleNetworkError(e: any) {
    let statusCode = <number>e.status
    if (e.isOffline) {
        warningNotification(lf("Network request failed; you appear to be offline"))
    } else {
        throw e;
    }
}

export interface ConfirmOptions {
    header: string;
    body?: string;
    htmlBody?: string;
    agreeLbl?: string;
    disagreeLbl?: string;
    agreeIcon?: string;
    agreeClass?: string;
    hideCancel?: boolean;
    hideAgree?: boolean;
    onLoaded?: (_: JQuery) => void;
}

export function confirmAsync(options: ConfirmOptions) {
    let html = `
  <div class="ui small modal">
    <div class="header">
        ${Util.htmlEscape(options.header)}      
    </div>
    <div class="content">
      ${options.body ? "<p>" + Util.htmlEscape(options.body) + "</p>" : ""}
      ${options.htmlBody || ""}
    </div>`
    if (!options.hideCancel || !options.hideAgree) {
        html += `<div class="actions">`
        if (!options.hideCancel) {
            html += `<div class="ui right labeled icon button">
        ${Util.htmlEscape(options.disagreeLbl || lf("Cancel"))}
        <i class="cancel icon"></i>
      </div>`
        }
        if (!options.hideAgree) {
            html += `
      <div class="ui approve right labeled icon button ${options.agreeClass || "positive"}">
        ${Util.htmlEscape(options.agreeLbl || lf("Go ahead!"))}
        <i class="${options.agreeIcon || "checkmark"} icon"></i>
      </div>`
        }
        
        html += `</div>`
    }
    html += `</div>`
    
    let modal = $(html)
    let done = false
    $('#root').append(modal)
    if (options.onLoaded) options.onLoaded(modal)

    modal.find('img').on('load', () => {
        modal.modal('refresh')                
    })

    return new Promise((resolve, reject) =>
        modal.modal({
            observeChanges: true,
            closeable: !options.hideCancel,
            onHidden: () => {
                modal.remove()
            },
            onApprove: () => {
                if (!done) {
                    done = true
                    resolve(true)
                }
            },
            onHide: () => {
                if (!done) {
                    done = true
                    resolve(false)
                }
            },
        }).modal("show"))
}

export function confirmDelete(what: string, cb: () => Promise<void>) {
    confirmAsync({
        header: lf("Would you like to delete '{0}'?", what),
        body: lf("It will be deleted for good. No undo."),
        agreeLbl: lf("Delete"),
        agreeClass: "red",
        agreeIcon: "trash",
    }).then(res => {
        if (res) {
            cb().done()
        }
    }).done()
}

export interface ShareOptions {
    header: string;
    body?: string;
    link: string;
    okClass?: string;
    okIcon?: string;
    okLabel?: string;
}

export function shareLinkAsync(options: ShareOptions) {
    let html = `
  <div class="ui small modal">
{'fraction_non_alphanumeric': 0.16650208887200912, 'fraction_numerical': 0.0031902772502848463, 'mean_word_length': 2.411764705882353, 'pattern_counts': {'":': 0, '<': 77, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1733041', 'n_tokens_mistral': 4077, 'n_tokens_neox': 3980, 'n_words': 931}