chatcontrol_dk/img/chatapp.svg

863 lines
32 KiB
XML

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300"
height="600"
viewBox="0 0 300 600"
onload="run()"
overflow="auto"
style="font-family: sans; border-radius: 10px;"
>
<defs>
<symbol id="kaereste_foto" width="60" height="200">
<g style="fill: pink; stroke: pink;">
<circle cx="20" cy="20" r="20" />
<line x1="20" y1="40" x2="20" y2="60" />
<ellipse cx="20" cy="110" rx="10" ry="50" />
<!-- left arm -->
<polyline fill="none"
points="15,70 5,50 0,40" />
<!-- right arm -->
<polyline fill="none"
points="25,70 35,50 40,40" />
<!-- left leg -->
<polyline fill="none"
points="15,155 5,135 0,125" />
<!-- right leg -->
<polyline fill="none"
points="25,155 35,135 40,125" />
<!-- the thing -->
<text x="14" y="160" style="font: bold 20px sans-serif" fill="black">?</text>
</g>
</symbol>
<symbol id="strand" width="80" height="1200">
<rect width="80" height="130" fill="yellow"></rect>
<g style="fill: pink; stroke: pink;">
<circle cx="60" cy="20" r="20" />
<!-- spine -->
<line x1="55" y1="40" x2="22" y2="100" />
<!-- left leg -->
<polyline fill="none" points="20,100 60,90 35,125" />
<!-- right leg -->
<polyline fill="none" points="20,100 50,75 25,120" />
<!-- left arm -->
<polyline fill="none" points="37,70 20,45" />
<!-- right arm + bucket -->
<polyline fill="none" points="39,71 70,50" />
</g>
</symbol>
<symbol id="flag_denmark" width="20" height="15">
<path fill="#c8102e" d="M0,0H20V15H0Z"/>
<path fill="#fff" d="M0,6H6V0H8V6H20V8H8V15H6V8H0Z"/>
</symbol>
<symbol id="flag_uk" width="50" height="30">
<clipPath id="t">
<path d="M25,15h25v15zv15h-25zh-25v-15zv-15h25z"/>
</clipPath>
<path d="M0,0v30h50v-30z" fill="#012169"/>
<path d="M0,0 50,30M50,0 0,30" stroke="#fff" stroke-width="6"/>
<path d="M0,0 50,30M50,0 0,30" clip-path="url(#t)" stroke="#C8102E" stroke-width="4"/>
<path d="M-1 11h22v-12h8v12h22v8h-22v12h-8v-12h-22z" fill="#C8102E" stroke="#FFF" stroke-width="2"/>
</symbol>
</defs>
<script type="application/ecmascript">
<![CDATA[
'use strict';
const svgns = "http://www.w3.org/2000/svg";
// must be the same as the SVG dimensions
const width = 300;
const height = 550;
const line_height = 14;
const bubble_padding = 6;
const bubble_spacing = 5;
const visible_chat_area = {'top': 60,
'bottom': height - 100 // minus status & input areas
};
const typing_speed = 50;
var conversation_count = 0;
var current_dialog = null;
var current_discussion_index = parseInt(new URLSearchParams(location.search).get('discussion') ?? 0);
var current_language = new URLSearchParams(location.search).get('lang') ?? 'da';
/// SVG 1.1 doesn't do proper text splitting into several lines.
/// we need to do it ourselves.
function split_text_into_lines(text, upper_line_length) {
let result = [];
while(text.length) {
if(text.length < upper_line_length) {
result.push(text);
break; // we are done
}
let found_split_point = false;
for(let i = upper_line_length; i; i--) {
if(text[i] == ' ') {
result.push(text.slice(0, i));
text = text.slice(i+1);
found_split_point = true;
break;
}
}
if(!found_split_point) {
// no <space> found. Split at character boundary instead
result.push(text.slice(0, upper_line_length));
text = text.slice(upper_line_length);
}
}
return result;
}
function is_hyperlink(str) {
return str.startsWith('http');
}
function create_link_node(url) {
let link = create_svg_node('a', {target:'_blank', href: url});
link.appendChild(document.createTextNode(url));
return link;
}
/// A class holding a text chat message.
///
/// *ChatMessages are owned by a Dialog.
function TextChatMessage(message_text, is_myself) {
let lines = split_text_into_lines(message_text, 28);
let bubble_color = (is_myself)? '#0084FF': '#E4E6EB';
let text_color = (is_myself)? 'white': 'black';
let container = document.getElementById('messages');
// attributes
this.height = 0; // height on screen when fully visible
this.group = null; // a <g> with a transform=translate(0,y_shift) attribute
/// Render the chat message on the screen
this.draw = function(y_offset, y_shift) {
let group = create_svg_node('g', {'transform': `translate(0, ${y_shift})`});
let x = (is_myself ? 195 : 105);
let text = create_svg_node('text', {
'x': `${x}%`,
'font-size': `${line_height}px`,
'text-anchor': is_myself ? 'end' : 'start'
});
let height_so_far = y_offset;
lines.forEach(function(line) {
let y = height_so_far;
let tspan = create_svg_node('tspan', {
'x': `${x}%`,
'y': `${y + line_height}`, // important: y is lower text baseline
'fill': text_color,
'width': '5%'
});
enable_scrolling(tspan)
if(is_hyperlink(line)) {
tspan.appendChild(create_link_node(line));
} else {
tspan.appendChild(document.createTextNode(line));
}
text.appendChild(tspan);
height_so_far += line_height;
});
group.appendChild(text); // needs to be part of the DOM *now*
container.appendChild(group);
let bubble = create_bubble(text, bubble_color);
group.appendChild(bubble);
redraw_on_top(text);
this.height = bubble.getBBox().height + bubble_spacing;
this.group = group;
}
/// Move a chat message on the screen (to simulate scrolling)
this.shift_y_pos = function(by) {
redraw_on_top(document.getElementById('contact_name_box'));
this.group.setAttribute('transform', `translate(0, ${by})`);
}
}
/// A class holding a image-based chat message.
///
/// *ChatMessages are owned by a Dialog.
function ImageChatMessage(symbol_id, is_myself) {
let container = document.getElementById('messages');
let bubble_color = (is_myself)? 'white': '#DDFF66';
// attributes
this.height = 0; // height on screen when fully visible
this.group = null; // a <g> with a transform=translate(0,y_shift) attribute
this.draw = function(y_offset, y_shift) {
let group = create_svg_node('g', {'transform': `translate(0, ${y_shift})`});
let x = (is_myself ? 190 : 110);
let img = create_svg_node('use', {
'href': symbol_id,
x: `${x}%`,
y: y_offset,
});
group.appendChild(img); // needs to be part of the DOM *now*
container.appendChild(group);
let bubble = create_bubble(img, bubble_color);
group.appendChild(bubble);
redraw_on_top(img);
this.height = bubble.getBBox().height + bubble_spacing;
this.group = group;
}
this.shift_y_pos = function(by) {
redraw_on_top(document.getElementById('contact_name_box'));
this.group.setAttribute('transform', `translate(0, ${by})`);
}
}
/// A class for holding a final message that says that the chat partner is offline
///
/// *ChatMessages are owned by a Dialog.
function OfflineChatMessage(dollar_message, _is_myself) {
let offline_message = dollar_message.substring(1);
let container = document.getElementById('messages');
// attributes
this.height = 0; // height on screen when fully visible
this.group = null; // a <g> with a transform=translate(0,y_shift) attribute
this.draw = function(y_offset, y_shift) {
let group = create_svg_node('g', {'transform': `translate(0, ${y_shift})`});
let height_so_far = y_offset;
function post_process(element) {
enable_scrolling(element);
height_so_far += line_height;
group.appendChild(element);
redraw_on_top(element);
}
let x = 101;
let bar = create_svg_node('rect', {
'x': `${x}%`,
'y': `${height_so_far + line_height}`,
'fill': '#CCCCCC',
'width': '90%',
'height': '4px'
});
post_process(bar);
height_so_far += 5; // spacing
let text = create_svg_node('text', {
'x': `${x}%`,
'y': `${height_so_far + line_height}`,
'font-size': `${line_height}px`,
'text-anchor': 'start'
});
text.appendChild(document.createTextNode(offline_message));
post_process(text);
let back_link_text = create_svg_node('text', {
'x': `${x}%`,
'y': `${height_so_far + line_height}`,
'font-size': `${line_height}px`,
'text-anchor': 'start',
'style': 'text-decoration: underline',
'fill': 'blue'
});
let back_link = create_svg_node('a', {
'href': 'javascript: swipe_viewport()',
});
let link_text = 'tilbage til kontaktlisten';
if(current_language == 'en') {
link_text = 'back to the contact list';
}
back_link_text.appendChild(document.createTextNode(link_text));
back_link.appendChild(back_link_text);
post_process(back_link);
container.appendChild(group);
this.height = height_so_far - y_offset;
this.group = group;
}
this.shift_y_pos = function(by) {
redraw_on_top(document.getElementById('contact_name_box'));
this.group.setAttribute('transform', `translate(0, ${by})`);
}
}
function create_chat_message(content, is_myself) {
let constr = null;
if(content.startsWith('#')) {
constr = ImageChatMessage;
} else if(content.startsWith('$')) {
constr = OfflineChatMessage;
} else {
constr = TextChatMessage;
}
return new constr(content, is_myself);
}
/// Promise-based version of setTimeout
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
/// toggle viewport between message list and contact list
/// That means: show either the left or right side of the SVG
function swipe_viewport() {
let svg = document.getElementsByTagName('svg')[0];
let coords = svg.getAttribute('viewBox').split(' ');
let x = parseInt(coords.shift());
if(x == 0) {
// moving from messages to contacts
var step = 5;
var end = width;
} else {
// moving from contacts to messages
var step = -5;
var end = 0;
}
let viewBox_suffix = coords.join(' '); // only 3 elements
async function animate(resolve, reject) {
while(x!=end) {
await wait(1);
x += step;
svg.setAttribute('viewBox', `${x} ${viewBox_suffix}`);
}
resolve();
};
new Promise(animate);
}
// Create a chat bubble around an element.
//
// The element must already be inside the DOM for this to work.
function create_bubble(inner_element, color) {
const bbox = inner_element.getBBox();
let bubble = create_svg_node('rect', {
'x': bbox.x - bubble_padding,
'y': bbox.y - bubble_padding,
'width': bbox.width + 2 * bubble_padding,
'height': bbox.height + 2 * bubble_padding,
'rx': 8,
'fill': color,
});
enable_scrolling(bubble);
return bubble;
}
function create_svg_node(tag_name, attrs) {
let node = document.createElementNS(svgns, tag_name);
for(let attr in attrs) {
node.setAttribute(attr, attrs[attr]);
}
return node;
}
/// Ensure that an element is redrawn above all other elements
///
/// The element's children will also be redrawn on top
function redraw_on_top(element) {
let parent = element.parentNode;
parent.appendChild(parent.removeChild(element));
}
function removeAllChildren(parentNode) {
while(parentNode.firstChild) {
parentNode.removeChild(parentNode.lastChild);
}
}
function start_chat(index) {
current_discussion_index = index;
let contact = contact_list[current_language][index];
let who = contact.name;
let indicator = document.getElementById('contact_indicator');
indicator.childNodes[0].data = `Kontakt: ${who}`;
removeAllChildren(document.getElementById('messages'));
swipe_viewport();
contact.dialog();
}
function Dialog() {
let conversation_id = ++conversation_count;
this.messages = [];
this.y_shift = visible_chat_area.top; // for scrolling
this.all_elements_height = 0; // also for scrolling
this.is_active = function() {
return conversation_id == conversation_count;
}
async function post_message(dialog, message, is_myself) {
if(!is_myself && dialog.messages.length) {
await wait(message.length * typing_speed);
} // first message should be instant
if(!dialog.is_active()) {
return; // Do not add messages to old conversation
}
let chat_message = create_chat_message(message, is_myself);
chat_message.draw(dialog.all_elements_height, // offset
dialog.y_shift);
dialog.all_elements_height += chat_message.height;
dialog.messages.push(chat_message);
let bottom = dialog.all_elements_height + dialog.y_shift;
let scroll = Math.max(0, bottom - visible_chat_area.bottom);
while(scroll > line_height) {
dialog.scroll_by(-line_height);
scroll -= line_height;
await wait(50);
}
}
this.scroll_by = function(change) {
this.y_shift += change;
this.messages.forEach(msg => msg.shift_y_pos(this.y_shift));
}
this.me = async function(message, will_be_flagged) {
await wait(1500); // give me some time to read
if(!this.is_active()) return;
await type_message(this, message);
if(!this.is_active()) return;
hit_send_button();
await local_message_processing(will_be_flagged);
clear_input_field();
release_send_button();
await post_message(this, message, true);
}
this.you = async function(message) {
await post_message(this, message, false);
}
this.end = async function(message) {
await post_message(this, `$${message}`, true);
}
}
async function type_message(dialog, message) {
clear_input_field(); // just to be sure
let text = document.getElementById('message_input_data').firstChild;
let lines = split_text_into_lines(message, 22);
for(let line of lines) {
text.data = '';
for(let c of line) {
await wait(typing_speed);
text.data += c;
}
if(!dialog.is_active()) break;
await wait(20); // otherwise it's too fast
}
}
function hit_send_button() {
document.getElementById('message_submit_button').setAttribute('fill', 'white');
document.getElementById('message_submit_box').setAttribute('fill', '#888888');
}
function release_send_button() {
document.getElementById('message_submit_button').setAttribute('fill', 'black');
document.getElementById('message_submit_box').setAttribute('fill', '#CCCCCC');
}
function clear_input_field() {
let element = document.getElementById('message_input_data')
removeAllChildren(element);
element.appendChild(document.createTextNode(''));
}
async function local_message_processing(will_be_flagged) {
let text_element = document.getElementById('message_status');
let indicator = text_element.childNodes[0];
indicator.data = 'scanning for illegal content';
await wait(800);
if(will_be_flagged) {
let box = document.getElementById('message_status_box');
text_element.setAttribute('fill', 'red');
box.setAttribute('fill', 'yellow');
indicator.data = 'Reporting suspicious content';
await wait(1000);
text_element.setAttribute('fill', 'white');
box.setAttribute('fill', '#FF7B00');
}
indicator.data = 'encrypting message';
await wait(550);
indicator.data = 'sending message';
await wait(500);
indicator.data = 'message was sent';
}
async function scroll_up() {
current_dialog.scroll_by(line_height);
}
async function scroll_down() {
current_dialog.scroll_by(-line_height);
}
const on_wheel = (e) => { e.deltaY < 0 ? scroll_up() : scroll_down() }
const enable_scrolling = (elem) => elem.addEventListener('wheel', on_wheel);
// enable scrolling
document.addEventListener(
"DOMContentLoaded",
() => document.getElementById("message_box").addEventListener('wheel', on_wheel)
)
async function switch_language(language_code) {
let url = new URL(document.location);
url.searchParams.set('lang', language_code);
url.searchParams.set('discussion', current_discussion_index);
location.href = url;
}
async function dialog_ven_da() {
let d = new Dialog();
current_dialog = d;
await d.me("hej");
await d.you("tak for sidst!");
await d.you('Har du hørt om den nye EU lov "ChatControl"?');
await d.me("nej, det har jeg ikke");
await d.me("hvad handler det om?");
await d.you('EU kommissionen planlægger at læse alle chatbeskeder i EU');
await d.me('Ja, men vi krypterer jo vores beskeder? Tough luck!');
await d.you('Det tager de højde for. Aflytningen sker før krypteringen på din telefon!');
await d.me('Det lyder overhovedet ikke rart. Hvorfor vil de gøre det?');
await d.you('De siger at det er for at beskytte børn på nettet.');
await d.you('Men det giver ikke meget mening');
await d.me('Alle vores beskeder skal scannes på grund af børn på nettet? Det lyder dumt!', true);
await d.you('Her kan du læse mere om det:');
await d.you('https://chatcontrol.dk');
await d.end('din ven er offline nu');
}
async function dialog_ven_en() {
let d = new Dialog();
current_dialog = d;
await d.me("hi");
await d.you("hi, what's up?");
await d.you('Have you heard about the new EU law "ChatControl"?');
await d.me("No, I haven't");
await d.me("What is it about?");
await d.you('The EU commission plans to read all chat messages in the EU');
await d.me('Yeah? But we encrypt all of our chats? Tough luck!');
await d.you('That has been taken into account. The eavesdropping will happen before the encryption step on your phone!');
await d.me('That sounds stupid. Why do they want to do that?');
await d.you('They claim that this is for protecting children on the internet');
await d.you("But that doesn't make any sense.");
await d.me('All of our messages will be scanned because of children on the internet? That sounds really stupid!', true);
await d.you('Here you can read more about it:');
await d.you('https://chatcontrol.dk');
await d.end('Your friend is offline now');
}
async function dialog_mor_da() {
let d = new Dialog();
current_dialog = d;
await d.you("Jeg har fundet nogle gamle familiebilleder fra vores ferie for 10 år siden");
await d.you("Her leger du på stranden");
await d.you("#strand");
await d.me('Tak, men jeg vil heller ikke at mine nøgenbilleder kommer på nettet', true);
await d.you('Hvorfor er du bekymret over det? Det er jo bare dig som barn. Lange tid siden');
await d.me('Internettet er ikke et godt sted til at dele meget private billeder');
await d.me('Man taber let kontrollen over dem');
await d.you('Ja, men det er bare os to som deler billederne?');
await d.me('Vi krypterer faktisk vores beskeder, så er det ikke så slemt');
await d.me('Men EU komissionen vil indføre en funktion at alle beskeder kan scannes, selv om de er krypteret');
await d.me('Det vil ikke være bare os to, som har adgang til vores private billeder');
await d.you('Det overrasker mig. Men så tænker jeg at jeg vil bare give dig en USB-nøgle næste gang du kommer på besøg');
await d.me('God idé. Tak :-)');
await d.end('Din mor er offline nu');
}
async function dialog_mor_en() {
let d = new Dialog();
current_dialog = d;
await d.you("I have found some old family photos from our holiday from 10 years ago");
await d.you("This is you playing on the beach");
await d.you("#strand");
await d.me('Thanks, but I would rather not have my nude pictures on the internet', true);
await d.you('Why do you worry about that? This is just you as a child a long time ago');
await d.me('The Internet is not a good place to share very private pictures');
await d.me('It is very easy to lose control over them');
await d.you('Well, but it is just us who share the pictures?');
await d.me('We encrypt our messages, so it is kinda fine.');
await d.me('But the EU commission wants to introduce a function for scanning all messages even if they are encrypted');
await d.me('It won\'t be just us two who will have access to our private pictures');
await d.you('That surprises me. But then I think I will give you a USB stick next time you visit me');
await d.me('Good idea! Thanks :-)');
await d.end('Your mom is offline now');
}
async function dialog_kaereste_da() {
let d = new Dialog();
current_dialog = d;
await d.me('hej smukkeste');
await d.you('hej, jeg har lige tænkt på dig!');
await d.you('og derfor har jeg taget et sexet billede');
await d.you('#kaereste_foto');
await d.me('tak. Det har jeg savnet!', true);
await d.me('du ser stadig så ung ud.');
await d.me('Jeg tror at vi skal være forsigtige, fordi vores beskeder bliver overvåget');
await d.you('What the fuck??? Hvem overvåger os?????');
await d.me('Det kan være at udbyderen gør det, fordi de har lov til det');
await d.me("Men i fremtiden vil det faktisk blive obligatorisk at scanne beskeder i EU");
await d.me('Og hvis der er beskeder som "ligner" børneporno får politiet en kopi af dem');
await d.you('Jeg vil heller ikke have at politiet får mine nøgenbilleder. Det er min krop og jeg vil selv bestemme over den!');
await d.end('Din kæreste er offline nu');
}
async function dialog_kaereste_en() {
let d = new Dialog();
current_dialog = d;
await d.me('Hi beautiful');
await d.you('hi, I just thought about you');
await d.you("and that's why I have taken a sexy picture");
await d.you('#kaereste_foto');
await d.me('Thanks! I missed that!', true);
await d.me('you still look so young.');
await d.me('I think we have to be careful, because our messages are being read');
await d.you('What the fuck??? Who is watching us?????');
await d.me('It can be that the chat provider does this, because they are allowed to search for illegal material');
await d.me('But in the future it will also become mandatory to scan chat messages in the EU');
await d.me('And if a message looks like child pornography then the police will get a copy of it');
await d.you("I don't want to share my nudes with the police. This is my body and I decide who I share it with!");
await d.end('Your better half is offline now');
}
async function dialog_politi_da() {
let d = new Dialog();
current_dialog = d;
await d.me('Hej, jeg har et spørgsmål');
await d.me('Har du hørt om chatcontrollen og hvad tænker du på det?');
await d.you('Jeg er bekendt med det. Og det er faktisk et ret dårlig idé');
await d.you('Problemet er at der er så mange falske positiver som skal analyseres');
await d.you('Og jeg gider ikke kigge på folkets private beskeder. Det er jo deres fortrolige samtaler');
await d.you('Jeg vil heller ikke have at mine kolleger se hvad jeg skriver til min kæreste, kun fordi jeg hypotetisk kunne gøre noget illegalt');
await d.you('Tænk bare hvor absurd idén er: Hvorfor aflytter vi ikke bare alle telefoner? Der vil være nogle forbrydelser vi vil opdage!');
await d.you('Men så har vi masseovervågning og ikke længere et frit samfund.');
await d.end('Politibejenten er offline nu');
}
async function dialog_politi_en() {
let d = new Dialog();
current_dialog = d;
await d.me('Hi, I have a question');
await d.me('Have you heard about ChatControl and what do you think about it?');
await d.you('I know about it. It is actually a really bad idea');
await d.you('The problem is that there are many false positive hits that need to be analysed manually');
await d.you("And I do not want to read through people's private messages. These are confidential conversations");
await d.you("I don't like that my collegues can potentially see what I write to by partner, just because I could potentially do something illegal while chatting");
await d.you("Just think about how absurd the idea is: Why don't we wiretap all phones? There will be some crimes that we will detect!");
await d.you('But then we have total surveillance and no longer a free society.');
await d.end('The police officer is offline now');
}
async function dialog_support_da() {
let d = new Dialog();
current_dialog = d;
await d.you('Velkommen til ChatWorld supporten. Hvad kan jeg hjælpe dig med?');
await d.me('Jeg mistænker at chatprogrammet scanner mine end-to-end krypterede beskeder. Er det rigtigt?');
await d.you('Ja, det er en feature som chefen ville gerne have.');
await d.you('Der var nogle som har misbrugt chattjenesten til børneporno og det giver meget dårlig PR. Derfor har chefen valgt at scanne end-to-end krypterede beskeder');
await d.you('børneporno er jo en meget dårlig ting. Men jeg synes ikke at det giver mening at aflytte alle private beskeder.');
await d.you('og teknologien kan misbruges til mange ting. Jeg som teknikker kan ikke se hvad søgefunktionen faktisk leder efter.');
await d.you('Det kan være at den kunne finde alternative politiske beskeder og markere dem som illegale selv om de ikke er det.');
await d.you('Det er en fare for demokratiet hvis fortrolige beskeder bliver scannet for ting som den politiske elite ikke ønsker');
await d.you('Men det er desværre mit job at vedligeholde driften af overvågningen');
await d.me('Det løser ikke mit problem. Men tak for informationen. Jeg vil se hvad jeg kan gøre for at undgå overvågning i fremtiden', true);
await d.you('Beklager at jeg ikke kan gøre mere. Men jeg håber at du forstår situationen');
await d.end('Chatsupporten er offline nu');
}
async function dialog_support_en() {
let d = new Dialog();
current_dialog = d;
await d.you('Welcome to the ChatWorld support. How can I help you?');
await d.me('I suspect that the chat program is scanning my end-to-end encrypted messages. Am I right?');
await d.you('Yes, that is a feature that our boss wanted to have');
await d.you('Some people have abused the chat service to share child pornography and that gives bad publicity. The boss has therefore chosen to scan all end-to-end encrypted messages');
await d.you("Child pornography is a really bad thing. But I don't think it is sensible to scan all messages.");
await d.you('and the scan technology can be abused for many things. I as a software engineer can not even see what the scanner is searching for');
await d.you("It can be that it will look for alternative political views and marks them as illegal even though they aren't");
await d.you('It is a danger to our democracy when confidential messages are scanned for things that the political elite does not like');
await d.you('But it is unfortunately my job to keep the surveillance working');
await d.me('That does not solve the problem. But thank you for the information. I will look for ways to avoid the surveillance in the future', true);
await d.you('I apologize that I can not offer something better. But I hope you understand the situation');
await d.end('The chat support is offline now');
}
async function dialog_nabopige_da() {
let d = new Dialog();
current_dialog = d;
await d.you('Gæt hvem der snart har fødselsdag!');
await d.me('Er det dig?');
await d.you('Netop! Det var måske for nemt');
await d.me('Hvor gammel bliver du så?');
await d.you('ti');
await d.you('Jeg glæder mig så meget til festen. Jeg har inviteret en masse mennesker');
await d.you('Du er også inviteret!');
await d.you('Hej, jeg vil gerne fortælle dig en hemmelighed');
await d.you('Men jeg kan desværre ikke gøre det over chatten');
await d.you('Fordi jeg ved at hvad vi skriver her bliver analyseret');
await d.you('Og det vil ikke være en hemmelighed hvis der er andre læser med');
await d.me('Du kan fortælle mig hjemligheden i morgen, når jeg kommer forbi', true);
await d.me('Jeg er overrasket over at du ved noget om chatovervågningen');
await d.you('Ja, det er trist. Jeg har læst noget om det og jeg kan overhovet ikke lide det');
await d.you('Det er bedre hvis man har gode voksne venner som man har tillid til, end hvis der er en computer som læser alt hvad man skriver');
await d.me('helt enig');
await d.me('børn har også brug for fortrolighed!');
await d.end('Pigen er afsted nu');
}
async function dialog_nabopige_en() {
let d = new Dialog();
current_dialog = d;
await d.you("Guess who's birthday it is soon!");
await d.me("It's yours?");
await d.you('Right! That was maybe too easy');
await d.me('How old will you be?');
await d.you('ten');
await d.you('I am excited for the party. I have invited a lot of people');
await d.you('You are also invited!');
await d.you('Hi, I want to tell you a secret');
await d.you("But I just can't do that in the chat");
await d.you('Because what we write here is being analysed');
await d.you('And it is not going to be a secret when there are others who read the messages');
await d.me('You can tell me the secret tomorrow, when I come to your house', true);
await d.me('I am surprised that you know about the chat surveillance');
await d.you("Yes, it is stupid. I have read about it and I really don't like it");
await d.you('It is better to have adult friends whom I can trust that a computer who reads everything that I write.');
await d.me('Completely agree');
await d.me('Children also need their secrets and confidentiality');
await d.end('The girl is gone now');
}
const contact_list = {
"da": [
{name: "Ven",
dialog: dialog_ven_da},
{name: "Mor",
dialog: dialog_mor_da},
{name: "Kæreste ❤️",
dialog: dialog_kaereste_da},
{name: "Politiven",
dialog: dialog_politi_da},
{name: "Chat support",
dialog: dialog_support_da},
{name: "Nabopige",
dialog: dialog_nabopige_da}
],
"en": [
{name: "Friend",
dialog: dialog_ven_en},
{name: "Mom",
dialog: dialog_mor_en},
{name: "Sweetheart ❤️",
dialog: dialog_kaereste_en},
{name: "Police friend",
dialog: dialog_politi_en},
{name: "Chat support",
dialog: dialog_support_en},
{name: "Neighborhood girl",
dialog: dialog_nabopige_en}
]
};
function fill_contact_list(lang) {
let x = 15;
let y = 75;
let y_step = 25;
let group = document.getElementById('contacts');
removeAllChildren(group);
let contacts = contact_list[lang];
for(let i=0; i < contacts.length; i++) {
let text = create_svg_node('text', {
x: x,
y: y
});
y += y_step;
let contact = contacts[i];
text.onclick = function() { start_chat(i) };
text.appendChild(document.createTextNode(contact.name));
group.appendChild(text);
}
}
function run() {
fill_contact_list(current_language);
start_chat(current_discussion_index);
}
]]>
</script>
<!-- [right] contact name view -->
<g id="contact_name_box">
<rect x="300" y="0" width="300" height="50" fill="#F5F5F5"/>
<polyline points="300,20 320,0 320,40" fill="#0084FF" onclick="swipe_viewport()" id="to_contact_list_button" />
<polyline points="560,20 600,20 580,0" fill="#0084FF" onclick="scroll_up()" />
<polyline points="560,30 600,30 580,50" fill="#0084FF" onclick="scroll_down()" />
<text x="325" y="30" id="contact_indicator">loading...</text>
<use href="#flag_denmark" x="500" y="35" onclick="switch_language('da')" />
<g transform="scale(0.5,0.5)">
<use href="#flag_uk" x="1050" y="70" onclick="switch_language('en')" />
</g>
</g>
<!-- [right] messages view -->
<rect id="message_box" x="300" y="50" width="300" height="450" fill="white" />
<g id="messages"></g>
<!-- [right] message status -->
<rect id="message_status_box" x="300" y="520" fill="#FF7B00" width="300" height="30" />
<text id="message_status" x="310" y="540" fill="white">status</text>
<!-- [right] text input -->
<rect id="message_input_box" x="300" y="550" stroke="black" fill="white" width="250" height="50" />
<rect id="message_submit_box" x="550" y="550" stroke="black" fill="#CCCCCC" width="50" height="50" />
<text id="message_input_data" x="310" y="575" fill="black"></text>
<text id="message_submit_button" x="555" y="580" fill="black">SEND</text>
<!-- [left] contact list -->
<rect x="0" y="0" width="300" height="50" fill="#E4E6EB" />
<text x="60" y="30">Dine kontakter</text>
<rect x="0" y="50" width="300" height="550" style="stroke: green; stroke-width: 0px" fill="white" />
<!-- contact list -->
<g id="contacts"></g>
</svg>