From d9769648054223292b80a1e9e5985b0f7d33ebfc Mon Sep 17 00:00:00 2001 From: Salif Mehmed Date: Fri, 23 Aug 2024 20:27:15 +0300 Subject: [PATCH] Release v2.2.0 --- .nojekyll | 0 LICENSE | 2 +- README.md | 62 ++++++--- gleam.toml | 5 +- index.html | 230 ++++++++++++++++++++++++++------ index.js | 157 ---------------------- justfile | 15 ++- manifest.toml | 2 +- src/characters.gleam | 2 + src/morse_code_translator.gleam | 71 ++++++---- 10 files changed, 292 insertions(+), 254 deletions(-) create mode 100644 .nojekyll delete mode 100644 index.js diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE b/LICENSE index c0bd069..911a241 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021,2024 Salif Mehmed +Copyright 2021,2024 Salif Mehmed Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 6177ddb..e6a0372 100644 --- a/README.md +++ b/README.md @@ -5,19 +5,24 @@ ## Links -* [Homepage](https://salif.github.io/morse-code-translator/) +* [Web tool](https://salif.github.io/morse-code-translator/) * [Source code](https://codeberg.org/salif/morse-code-translator) * [Discussions (Github)](https://github.com/salif/morse-code-translator/discussions) -## Usage +## Gleam library + +### Installation ```sh -gleam add morse_code_translator +gleam add morse_code_translator@2 ``` +### Usage + ```gleam import gleam/io import gleam/option.{None, Some} +import gleam/result import morse_code_translator as mct pub fn main() { @@ -28,7 +33,7 @@ pub fn main() { output_space: None, output_separator: None, is_uppercase: None, - language_num: None, + language: None, ) let demo_decode_options = @@ -38,23 +43,23 @@ pub fn main() { input_space: None, input_separator: None, to_uppercase: None, - language_num: None, + language: None, ) - let demo_encode: Result(String, mct.MorseCodeError) = - mct.encode(" Test ", demo_encode_options, None) - io.debug(demo_encode) - // Ok("/ - . ... - /") + " Test " + |> mct.encode(demo_encode_options, None) + |> result.map(io.println) + // "/ - . ... - /" - let demo_decode: Result(String, mct.MorseCodeError) = - mct.decode("/ - . ... - /", demo_decode_options, None) - io.debug(demo_decode) - // Ok(" test ") + "/ - . ... - /" + |> mct.decode(demo_decode_options, None) + |> result.map(io.println) + // " test " "demo" |> mct.encode_to_string(demo_encode_options, None) |> mct.decode_to_string(demo_decode_options, None) - |> io.debug + |> io.println // "demo" "_.. . __ ___" @@ -62,11 +67,11 @@ pub fn main() { mct.DecodeOptions( ..demo_decode_options, input_dash: Some("_"), - language_num: Some(mct.language_num_cyrillic), + language: Some(mct.language_cyrillic), ), None, ) - |> io.debug + |> io.println // "демо" let demo_convert_options = @@ -83,20 +88,39 @@ pub fn main() { "-.. . -- ---" |> mct.convert(demo_convert_options) - |> io.debug - // Ok("100 0 11 111") + |> result.map(io.println) + // "100 0 11 111" "=" |> mct.convert_to_string(demo_convert_options) - |> io.debug + |> io.println // "Invalid morse code symbol: =" } ``` +### Version 2.2.0 + +Version `2.2.0` contains backward incompatible changes. +If you are using `EncodeOptions` and `DecodeOptions`, change `language_num` to `language`. + Further documentation can be found at . +## Web tool + +### Add new page language + +Open `index.html` and find all occurrences of `set_page_language`, `data-lo=` +and `dataset.lo =`, then add translations and send a pull request. + +### Manually set page language + +Use this bookmarklet, save it as bookmark, then open it at the web page. + + ## Development ```sh +# just format just build +just serve ``` diff --git a/gleam.toml b/gleam.toml index 3187d9d..888e92c 100644 --- a/gleam.toml +++ b/gleam.toml @@ -1,14 +1,13 @@ name = "morse_code_translator" -version = "2.1.0" +version = "2.2.0" description = "Morse Code Translator" licences = ["MIT"] links = [ - {title = "Website", href = "https://salif.github.io/morse-code-translator"}, + {title = "Web tool", href = "https://salif.github.io/morse-code-translator/"}, {title = "Github", href = "https://github.com/salif/morse-code-translator"}, ] repository = {type = "codeberg", user = "salif", repo = "morse-code-translator"} -target = "javascript" [dependencies] gleam_stdlib = ">= 0.39.0 and < 1.0.0" diff --git a/index.html b/index.html index 7d475a4..8900598 100644 --- a/index.html +++ b/index.html @@ -3,16 +3,13 @@ - - + Morse Code Translator - + @@ -68,64 +70,210 @@ -     source code - - + diff --git a/index.js b/index.js deleted file mode 100644 index 98b0111..0000000 --- a/index.js +++ /dev/null @@ -1,157 +0,0 @@ -import * as morse_code from "./build/dev/javascript/morse_code_translator/morse_code_translator.mjs" -import * as option from "./build/dev/javascript/gleam_stdlib/gleam/option.mjs" - -// button.onclick -function set_lang(mc_lang) { - window.mc_lang = mc_lang - oninp(window.inputs[0]) -} - -// button.onclick -function add_row(dot, dash, sp, sep) { - document.getElementById("add_row_div").style.display = "block"; - if (dot.value.length == 0) { dot.focus(); return; } - if (dash.value.length == 0) { dash.focus(); return; } - if (sp.value.length == 0) { sp.focus(); return; } - if (sep.value.lenth == 0) { sep.focus(); return; } - main_table_add_row(oninp, { - str_dot: dot.value, str_dash: dash.value, str_sp: sp.value, str_sep: sep.value - }) - dot.value = "" - dash.value = "" - sp.value = "" - sep.value = "" - document.getElementById("add_row_div").style.display = "none"; -} - -// textarea.oninput -function oninp(this_inp, skip_abc) { - // if abc textarea - if (this_inp.str_dot === "abc" && this_inp.str_dash === "") { - // first non abc textarea - const t_inp = window.inputs[0] - const result = morse_code.encode(this_inp.el.value, new morse_code.EncodeOptions( - new option.Some(t_inp.str_dot), new option.Some(t_inp.str_dash), - new option.Some(t_inp.str_sp), new option.Some(t_inp.str_sep), - new option.Some(false), new option.Some(window.mc_lang)), - window.characters_list) - // TODO: improve - if (result.isOk()) { - t_inp.el.value = result["0"] - } else { - window.inputs.forEach(inp => { - inp.el.value = result["0"].msg - }) - return - } - // only convert - oninp(window.inputs[0], true) - } else { - // skip because abc is input - if (!skip_abc) { - window.input_abc.el.value = morse_code.decode_to_string( - this_inp.el.value, new morse_code.DecodeOptions( - new option.Some(this_inp.str_dot), new option.Some(this_inp.str_dash), - new option.Some(this_inp.str_sp), new option.Some(this_inp.str_sep), - new option.Some(false), new option.Some(window.mc_lang)), - window.characters_list) - - } - window.inputs.forEach(inp => { - // skip input object - if (!(this_inp.str_dot === inp.str_dot && this_inp.str_dash === inp.str_dash && - this_inp.str_sp === inp.str_sp && this_inp.str_sep === inp.str_sep)) { - inp.el.value = morse_code.convert_to_string(this_inp.el.value, - new morse_code.ConvertOptions( - this_inp.str_dot, inp.str_dot, - this_inp.str_dash, inp.str_dash, - this_inp.str_sp, inp.str_sp, - this_inp.str_sep, inp.str_sep)) - - } - }) - } -} - -function set_element_language(d, dlo, lang) { - try { - const dp = JSON.parse(dlo) - if (!dp.hasOwnProperty(lang)) { - lang = "en" - } - switch (dp.type) { - case 0: window.document.title = dp[lang]; break; - case 1: d.textContent = dp[lang]; break; - case 2: d.textContent = dp[lang]; break; - case 3: d.value = dp[lang]; break; - case 4: d.placeholder = dp[lang]; break; - default: console.warn(dp); break; - } - } catch (err) { - console.error(err) - } -} - -function set_page_language(lang) { - document.documentElement.lang = lang - document.querySelectorAll('[data-lo]').forEach(d => { - set_element_language(d, d.dataset.lo, lang) - }) - set_element_language(null, '{"type": 0, "en": "Morse Code Translator", "ru": "Переводчик Азбуки Морзе", "bg": "Преводач на морзова азбука"}', lang) -} - -function escapeHtml(unsafe) { - return unsafe.replaceAll('&', '&').replaceAll('<', '<').replaceAll( - '>', '>').replaceAll('"', '"').replaceAll("'", ''') -} - -function main_table_add_row(fn_oninput, options) { - const new_row = window.main_table.insertRow(0) - const new_row_span = document.createElement("span") - new_row_span.textContent = options.str_dot + options.str_dash - new_row.insertCell(0).appendChild(new_row_span) - const new_cell = new_row.insertCell(1) - new_cell.style.width = "100%" - const el_text_area = document.createElement("textarea") - el_text_area.rows = "5" - el_text_area.style.width = "100%" - el_text_area.dataset.lo = '{"type": 4, "en": "enter code", "ru": "введите код", "bg": "въведете код"}' - options.el = el_text_area - el_text_area.oninput = function () { - fn_oninput(options) - } - new_cell.appendChild(el_text_area) - if (options.str_dot === "abc" || options.str_dash === "") { - new_row_span.dataset.lo = '{"type": 1, "en": "abc", "ru": "абв", "bg": "абв"}' - el_text_area.dataset.lo = '{"type": 4, "en": "enter text", "ru": "введите текст", "bg": "въведете текст"}' - window.input_abc = options - } else { - window.inputs.push(options) - } - set_element_language(el_text_area, el_text_area.dataset.lo, document.documentElement.lang) -} - -document.body.onload = function () { - window.inputs = [] - window.input_abc = {} - window.characters_list = new option.Some(morse_code.morse_code_list) - window.mc_lang = "1" - // html table - window.el_main_table = document.getElementById("main_table") - // used in html - window.set_lang = set_lang - window.add_row = add_row - - main_table_add_row(oninp, { str_dot: "•", str_dash: "−", str_sp: "/", str_sep: " " }) - main_table_add_row(oninp, { str_dot: ".", str_dash: "-", str_sp: "/", str_sep: " " }) - main_table_add_row(oninp, { str_dot: "abc", str_dash: "", str_sp: "/", str_sep: " " }) - - window.set_page_language = set_page_language - switch (navigator.language || navigator.userLanguage) { - case "ru": set_page_language("ru"); break; - case "bg": set_page_language("bg"); break; - } - - // focus first textarea - window.input_abc.el.focus() -} diff --git a/justfile b/justfile index 93a0ed1..31cfd60 100755 --- a/justfile +++ b/justfile @@ -1,6 +1,4 @@ -#!/usr/bin/just -f - -files := "" +#!/usr/bin/env -S just -f _: @just --list @@ -10,10 +8,10 @@ build: format: gleam format ./src/morse_code_translator.gleam - just files="./src/morse_code_translator.gleam" format-js + just format-js ./src/morse_code_translator.gleam [private] -format-js: +format-js files: #!/usr/bin/env node const fs = require('fs'); "{{ files }}".split(";").forEach(f => { @@ -23,6 +21,13 @@ format-js: } }) +[private] +build-ifn: + @if ! test -d build/dev/javascript/morse_code_translator; then just build; fi + +serve port='8080': build-ifn + python3 -m http.server {{port}} + [confirm] gh-pages: git switch gh-pages diff --git a/manifest.toml b/manifest.toml index c2f357f..2c7c2cc 100644 --- a/manifest.toml +++ b/manifest.toml @@ -2,7 +2,7 @@ # You typically do not need to edit this file packages = [ - { name = "gleam_stdlib", version = "0.39.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "2D7DE885A6EA7F1D5015D1698920C9BAF7241102836CE0C3837A4F160128A9C4" }, + { name = "gleam_stdlib", version = "0.40.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86606B75A600BBD05E539EB59FABC6E307EEEA7B1E5865AFB6D980A93BCB2181" }, ] [requirements] diff --git a/src/characters.gleam b/src/characters.gleam index 83cc4ef..8c74a03 100644 --- a/src/characters.gleam +++ b/src/characters.gleam @@ -1,3 +1,5 @@ +// Do not format +// See `../morse-decoder.md` pub const base_characters: List(#(String, String, List(Bool))) = [ #("1", "A", [False, True]), #("1", "B", [True, False, False, False]), diff --git a/src/morse_code_translator.gleam b/src/morse_code_translator.gleam index 71b4af9..9cc9cb4 100644 --- a/src/morse_code_translator.gleam +++ b/src/morse_code_translator.gleam @@ -14,35 +14,50 @@ pub const default_space: String = "/" pub const default_separator: String = " " -pub const default_language_num: String = language_num_latin +/// Default language is ASCII +pub const default_language: Language = language_latin +/// Input will be converted to uppercase pub const default_is_uppercase: Bool = False +/// Output will be converted to lowercase pub const default_to_uppercase: Bool = False -pub const language_num_latin: String = "1" +/// ASCII +pub const language_latin = Language("1") -pub const language_num_numbers: String = "2" +/// Numbers +pub const language_numbers = Language("2") -pub const language_num_punctuation: String = "3" +/// Punctuation +pub const language_punctuation = Language("3") -pub const language_num_latin_extended: String = "4" +/// Latin Extended (Turkish, Polish etc.) +pub const language_latin_extended = Language("4") -pub const language_num_cyrillic: String = "5" +/// Cyrillic languages +pub const language_cyrillic = Language("5") -pub const language_num_greek: String = "6" +/// Greek +pub const language_greek = Language("6") -pub const language_num_hebrew: String = "7" +/// Hebrew +pub const language_hebrew = Language("7") -pub const language_num_arabic: String = "8" +/// Arabic +pub const language_arabic = Language("8") -pub const language_num_persian: String = "9" +/// Persian +pub const language_persian = Language("9") -pub const language_num_japanese: String = "10" +/// Japanese +pub const language_japanese = Language("10") -pub const language_num_korean: String = "11" +/// Korean +pub const language_korean = Language("11") -pub const language_num_thai: String = "12" +/// Thai +pub const language_thai = Language("12") pub type MorseCodeList = List(#(String, String, List(Bool))) @@ -51,6 +66,10 @@ pub type MorseCodeError { MorseCodeError(msg: String) } +pub type Language { + Language(num: String) +} + pub type EncodeOptions { EncodeOptions( output_dot: option.Option(String), @@ -58,7 +77,7 @@ pub type EncodeOptions { output_space: option.Option(String), output_separator: option.Option(String), is_uppercase: option.Option(Bool), - language_num: option.Option(String), + language: option.Option(Language), ) } @@ -76,8 +95,8 @@ pub fn encode( option.unwrap(options.output_separator, default_separator) let opt_is_uppercase: Bool = option.unwrap(options.is_uppercase, default_is_uppercase) - let opt_language_num: String = - option.unwrap(options.language_num, default_language_num) + let opt_language: String = + option.unwrap(options.language, default_language).num input |> string.to_graphemes @@ -90,7 +109,7 @@ pub fn encode( list_key_find( option.unwrap(morse_code_dict, morse_code_list), g, - opt_language_num, + opt_language, ) { Ok(bools) -> { @@ -125,7 +144,7 @@ pub type DecodeOptions { input_space: option.Option(String), input_separator: option.Option(String), to_uppercase: option.Option(Bool), - language_num: option.Option(String), + language: option.Option(Language), ) } @@ -142,8 +161,8 @@ pub fn decode( option.unwrap(options.input_separator, default_separator) let opt_to_uppercase: Bool = option.unwrap(options.to_uppercase, default_to_uppercase) - let opt_language_num: String = - option.unwrap(options.language_num, default_language_num) + let opt_language: String = + option.unwrap(options.language, default_language).num input |> string.split(opt_input_separator) @@ -169,7 +188,7 @@ pub fn decode( list_value_find( option.unwrap(morse_code_dict, morse_code_list), bools, - opt_language_num, + opt_language, ) { Ok(value) -> @@ -201,13 +220,13 @@ pub fn decode_to_string( fn list_key_find( keys: MorseCodeList, desired_key: String, - language_num: String, + language: String, ) -> Result(List(Bool), Nil) { case list.filter(keys, fn(k) { k.1 == desired_key }) { [] -> Error(Nil) [only_key] -> Ok(only_key.2) dublic_keys -> - case list.filter(dublic_keys, fn(key) { key.0 == language_num }) { + case list.filter(dublic_keys, fn(key) { key.0 == language }) { [] -> dublic_keys |> list.first @@ -224,15 +243,13 @@ fn list_key_find( fn list_value_find( values: MorseCodeList, desired_value: List(Bool), - language_num: String, + language: String, ) -> Result(String, Nil) { case list.filter(values, fn(v) { v.2 == desired_value }) { [] -> Error(Nil) [only_value] -> Ok(only_value.1) dublic_values -> - case - list.filter(dublic_values, fn(value) { value.0 == language_num }) - { + case list.filter(dublic_values, fn(value) { value.0 == language }) { [] -> dublic_values |> list.first