Initial Commit after switching from SVN to git

This commit is contained in:
2026-05-03 01:43:52 +02:00
parent ab8638e5bb
commit a4284234b2
910 changed files with 359931 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
# Visual Studio
.vs/
*.user
*.suo
# Build Output
bin/
obj/
# NuGet
packages/
*.nupkg
# Logs
*.log
@@ -0,0 +1,161 @@
using System.Globalization;
using Fuchs.intranet;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using OCORE.SQL;
using static OCORE.commons;
using static OCORE.io;
using static OCORE.SQL.sql;
using static OCORE.web.mvc_helper_async;
namespace Fuchs.Controllers;
// Partial class: Banking processing
public partial class IntranetController
{
private async Task<IActionResult> Do_Process_Bankings(string fn, string id, string code)
{
switch (id.ToLower())
{
case "auth":
return await JSONAsync(new { manage = 1 });
case "up":
foreach (var fle in Request.Form.Files)
{
using var stream = fle.OpenReadStream();
var schemaDt = (await getSQLDatatable_async(
"DECLARE @tmp [dbo].[fds__tt__bankingtransactions]; SELECT TOP(0) * FROM @tmp;",
_intranet.Intranet__SQLConnectionString,
Security: DbSec, options: SqlOpt(fn, id, code))).DataTable;
var tbl = Banking.ParseToDatatable(stream, schemaDt);
var tmptbl = "bs_" + Guid.NewGuid().ToString().Replace("-", "");
var dtwa = new DatatableWriterAsync(tbl, _intranet.Intranet__SQLConnectionString)
{
CommandAfter = new SqlCommand(
"EXECUTE [dbo].[fds__merge_bankingtransactions] @tblname, @authuser;")
};
dtwa.CommandAfter.Parameters.AddRange(new[]
{
new SqlParameter("@tblname", dtwa.DestinationTableName),
SQL_VarChar("@authuser", UserAccountID)
});
dtwa.CommandAfterError = new SqlCommand(
$"SELECT * INTO [{tmptbl}] FROM {dtwa.DestinationTableName};");
dtwa.OnError += (_, exc, _) =>
_intranet.debug_log("IntranetController.bam.up - sql exception",
exc, UserAccountID, new { uid = dtwa.InstanceGUID, tmptbl });
dtwa.OnCommandAfterError += (_, exc) =>
_intranet.debug_log("IntranetController.bam.up - command-after exception",
exc, UserAccountID, new { uid = dtwa.InstanceGUID, tmptbl });
dtwa.DoSubmit();
}
return Ok();
case "qtl":
{
if (!HasForm("mode")) return BadRequest400();
var pl = StdParamlist(SQL_VarChar("@mode", Form("mode")));
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getBankingtransfers_questionable] @mode, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "admin", "transfers" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
bs = dset.Tables("transfers").toArrayofObjectDictionaries()
});
}
case "btl":
{
if (!HasForm("mode")) return BadRequest400();
string mode = Form("mode").ToLower();
if (mode == "s" && Form("tgt").Contains(':'))
{
var pl = StdParamlist(
SQL_VarChar("@mode", Form("mode")),
SQL_VarChar("@search", Form("tgt")));
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getBankingtransactions_list2] @mode, @search, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "admin", "bank" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
bank = dset.Tables("bank").toArrayofObjectDictionaries()
});
}
if (!DateTime.TryParseExact(Form("tgt"), "yy-MM-dd",
CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var tgtdate))
return BadRequest400();
{
var pl = StdParamlist(
SQL_Date("@tgtdate", tgtdate),
SQL_VarChar("@mode", Form("mode").ne("m")),
SQL_VarChar("@includes", Form("includes").ne(Form("all") == "true" ? "all" : "")));
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getBankingtransfers_list] @tgtdate, @mode, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "admin", "bank" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
bank = dset.Tables("bank").toArrayofObjectDictionaries()
});
}
}
case "smd":
{
if (!HasForm("taid")) return BadRequest400();
var pl = StdParamlist(SQL_VarChar("@taID", Form("taid"), dbNull_IfEmpty: true));
var res = await getSQLValue_async(
"EXECUTE [dbo].[fds__setBankingtransaction_done] @taID, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
Security: DbSec, options: SqlOpt(fn, id, code));
return res.Result is true ? Ok() : StatusCode(500, new { error = "not successful" });
}
case "ati":
{
if (!HasForm("taid", "iid")) return BadRequest400();
var pl = StdParamlist(
SQL_VarChar("@taid", Form("taid"), dbNull_IfEmpty: true),
SQL_VarChar("@invoice_id", Form("iid"), dbNull_IfEmpty: true));
var res = await getSQLValue_async(
"EXECUTE [dbo].[fds__setBankingtransaction_assignToIvoice] @taID, @invoice_id, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
Security: DbSec, options: SqlOpt(fn, id, code));
return res.Result is true ? Ok() : StatusCode(500, new { error = "not successful" });
}
case "vfi":
{
if (!HasForm("invid")) return BadRequest400();
var pl = StdParamlist(SQL_VarChar("@InvoiceId", Form("invid"), dbNull_IfEmpty: true));
var res = await getSQLDatatable_async(
"SELECT [Id],[InvoiceId],[SendToAddress] FROM [dbo].[fds__invoices]" +
" WHERE [InvoiceId] LIKE ('%' + @InvoiceId) AND [InvoiceId] IS NOT NULL AND [DateFinalized] IS NOT NULL;",
_intranet.Intranet__SQLConnectionString, pl,
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(res.DataTable.toArrayofObjectDictionaries());
}
default:
return Ok();
}
}
// ── Form helpers ─────────────────────────────────────────────────────────
protected bool HasForm(params string[] keys) =>
keys.All(k => Request.Form.ContainsKey(k) && !string.IsNullOrWhiteSpace(Request.Form[k]));
protected string Form(string key, string fallback = "") =>
Request.Form.TryGetValue(key, out var v) ? v.ToString() : fallback;
}
@@ -0,0 +1,94 @@
using System.Globalization;
using System.Web;
using Fuchs.intranet;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using MFR_RESTClient.generic;
using OCORE.SQL;
using static OCORE.commons;
using static OCORE.io;
using static OCORE.SQL.sql;
using static OCORE.web.mvc_helper_async;
namespace Fuchs.Controllers;
// Partial class: Invoice processing (dispatch + simple actions)
public partial class IntranetController
{
private async Task<IActionResult> Do_Process_Invoices(string fn, string id, string code)
{
switch (id.ToLower())
{
case "auth":
return await JSONAsync(new { manage = 1 });
case "setpyd":
if (!HasForm("id")) return BadRequest400();
return await setSQLValue_async(
"EXECUTE [dbo].[fds__setInvoicePayed] @Id, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@Id", Form("id"))),
Security: DbSec, options: SqlOpt(fn, id, code))
? Ok() : StatusCode(500);
case "setupd":
if (!HasForm("id")) return BadRequest400();
return await setSQLValue_async(
"EXECUTE [dbo].[fds__setInvoiceUNPayed] @Id, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@Id", Form("id"))),
Security: DbSec, options: SqlOpt(fn, id, code))
? Ok() : StatusCode(500);
case "setvat":
if (!float.TryParse(Form("val").Replace("%", "").Replace(",", ".").Trim(),
NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out float vatVal))
return BadRequest400();
{
var pl = StdParamlist(
SQL_BigInt("@id", Form("id")),
SQL_VarChar("@entitytype", "report"),
new SqlParameter("@vat", vatVal),
SQL_VarChar("@userid", UserAccountID));
string sqlEx = ""; int? sqlCode = null;
setSQLValue("EXECUTE [dbo].[fds__setReportVAT] @id, @entitytype, @vat, @authuser;",
_intranet.Intranet_SqlCon(), ref sqlEx, ref sqlCode, pl, Security: DbSec);
return string.IsNullOrEmpty(sqlEx) ? Ok() : StatusCode(500, new { error = sqlEx });
}
case "sis":
if (!HasForm("id")) return BadRequest400();
{
var pl = StdParamlist(SQL_VarChar("@Id", Form("id")), SQL_Bit("@auto", false));
var dt2 = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__setInvoiceSent] @Id, @auto, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
Security: DbSec, options: SqlOpt(fn, id, code));
return string.IsNullOrEmpty(dt2.Exception) ? Ok() : StatusCode(500);
}
case "pget": return await HandleInvoicePget(fn, id, code);
case "get": return await HandleInvoiceGet(fn, id, code);
case "icget": return await HandleInvoiceIcGet(fn, id, code);
case "storno":
case "credit": return await HandleInvoiceStornoCredit(fn, id, code);
case "invl": return await HandleInvoiceList(fn, id, code);
case "rqi": return await HandleInvoiceRequestItems(fn, id, code);
case "pyi": return await HandleInvoicePayments(fn, id, code);
case "datev": return await HandleDatev(fn, id, code);
case "rdoc": return await HandleReportDoc(fn, id, code, Form("id"));
case "rdocn": return await HandleReportDocByName(fn, id, code);
case "datevzip": return await HandleDatevZip(fn, id, code);
case "getrem": return await HandleGetReminder(fn, id, code);
case "mfrrel":
if (!HasForm("id") || !long.TryParse(Form("id"), out long relId)) return BadRequest400();
using (var mfr = new fds.FdsMfrClient())
await mfr.Update__entitytable(EntityTypes.Invoice,
fds.FdsMfr.UpdateNeed.Reset, new[] { relId });
return Ok();
default: return Ok();
}
}
}
@@ -0,0 +1,323 @@
using System.Globalization;
using System.Web;
using Fuchs.intranet;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using MFR_RESTClient.generic;
using OCORE.pdf;
using OCORE.SQL;
using static OCORE.commons;
using static OCORE.io;
using static OCORE.SQL.sql;
using static OCORE.web.mvc_helper_async;
namespace Fuchs.Controllers;
// Partial class: Invoice sub-handlers
public partial class IntranetController
{
private async Task<IActionResult> HandleInvoicePget(string fn, string id, string code)
{
if (!HasForm("id")) return BadRequest400();
if (!long.TryParse(Form("id"), out long tgtid)) return BadRequest400();
using (var mfr = new fds.FdsMfrClient())
await mfr.Update__entitytable(EntityTypes.Invoice,
fds.FdsMfr.UpdateNeed.Reset, new[] { tgtid });
var dt = await getSQLDatatable_async(
"SELECT * FROM [dbo].[fds__getInvoiceTreeIds](@srqid);",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_BigInt("@srqid", tgtid)),
Security: DbSec, options: SqlOpt(fn, id, code));
if (dt.Count > 0)
{
var invIds = new List<long>();
var srqIds = new List<long>();
foreach (System.Data.DataRow rw in dt.DataTable.Rows)
{
long iid = rw.nint64("Id", -1);
switch (rw.nz("type"))
{
case "invoice": if (iid > 0 && !invIds.Contains(iid)) invIds.Add(iid); break;
case "servicerequest": if (iid > 0 && !srqIds.Contains(iid)) srqIds.Add(iid); break;
}
}
using var mfr2 = new fds.FdsMfrClient();
foreach (var iid in invIds)
await mfr2.Update__entitytable(EntityTypes.Invoice, fds.FdsMfr.UpdateNeed.Reset, new[] { iid });
foreach (var iid in srqIds)
await mfr2.Update__entitytable(EntityTypes.ServiceRequest, fds.FdsMfr.UpdateNeed.Reset, new[] { iid });
}
return Ok();
}
private async Task<IActionResult> HandleInvoiceGet(string fn, string id, string code)
{
try
{
if (!HasForm("id")) return BadRequest400();
var sqldset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getInvoice] @Id, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@Id", Form("id"))),
tablenames: new[] { "admin", "inv", "req", "itm" },
Security: DbSec, options: SqlOpt(fn, id, code));
var ldic = BuildInvoiceRequestList(sqldset);
var adminDic = sqldset.Table("admin").FirstRow.toObjectDictionary();
var invDic = sqldset.Table("inv").FirstRow.toObjectDictionary();
if (invDic.nz("InvoiceOptions", "").Split(',').Contains("§13b"))
adminDic["p13b"] = true;
return await JSONAsync(new { admin = adminDic, inv = invDic, req = ldic });
}
catch { return StatusCode(500); }
}
private async Task<IActionResult> HandleInvoiceIcGet(string fn, string id, string code)
{
if (!HasForm("id")) return BadRequest400();
var sqldset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__prepStorno_recreate] @InvId, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@InvId", Form("id"))),
tablenames: new[] { "admin", "requests", "items", "steps", "companies", "locations" },
Security: DbSec, options: SqlOpt(fn, id, code));
var ldic = BuildRequestItemList(sqldset);
return await JSONAsync(new
{
admin = sqldset.Table("admin").FirstRow.toObjectDictionary(),
requests = ldic,
companies = sqldset.Tables("companies").toArrayofObjectDictionaries(),
locations = sqldset.Tables("locations").toArrayofObjectDictionaries()
});
}
private async Task<IActionResult> HandleInvoiceStornoCredit(string fn, string id, string code)
{
if (!HasForm("id", "mode")) return BadRequest400();
string sqlcmd = Form("mode") switch
{
"credit" => "EXECUTE [dbo].[fds__createCredit_simple] @Id, @authuser;",
"simple" => "EXECUTE [dbo].[fds__createStorno_simple] @Id, @authuser;",
"copy" => "EXECUTE [dbo].[fds__createStorno_copy] @Id, @authuser;",
_ => ""
};
if (string.IsNullOrEmpty(sqlcmd)) return StatusCode(500, new { error = "function not allowed" });
var sqldset = await getSQLDataSet_async(sqlcmd,
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@Id", Form("id"))),
tablenames: new[] { "admin", "inv", "req", "itm" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
admin = sqldset.Table("admin").FirstRow.toObjectDictionary(),
inv = sqldset.Table("inv").FirstRow.toObjectDictionary(),
req = BuildInvoiceRequestList(sqldset)
});
}
private async Task<IActionResult> HandleInvoiceList(string fn, string id, string code)
{
if (!HasForm("mode")) return BadRequest400();
string mode = Form("mode").ToLower();
if (mode == "s" && Form("tgt").Contains(':'))
{
var pl = StdParamlist(
SQL_Date("@tgtdate", DBNull.Value),
SQL_VarChar("@mode", Form("mode").ne("m")),
SQL_Bit("@include_drafts", Form("all")),
SQL_VarChar("@search", Form("tgt")));
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getInvoices_list2] @tgtdate, @mode, @include_drafts, @search, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "admin", "invoices" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
invoices = dset.Tables("invoices").toArrayofObjectDictionaries()
});
}
if (!DateTime.TryParseExact(Form("tgt"), "yy-MM-dd",
CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var tgtdate))
return BadRequest400();
{
var pl = StdParamlist(
SQL_Date("@tgtdate", tgtdate),
SQL_VarChar("@mode", Form("mode").ne("m")),
SQL_VarChar("@includes", Form("includes").ne(Form("all") == "true" ? "all" : "")));
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getInvoices_list_vario] @tgtdate, @mode, @includes, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "admin", "invoices" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
invoices = dset.Tables("invoices").toArrayofObjectDictionaries()
});
}
}
private async Task<IActionResult> HandleInvoiceRequestItems(string fn, string id, string code)
{
if (!HasForm("id")) return BadRequest400();
var sqldt = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getInvRequestItems] @invoiceid, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@invoiceid", Form("id"))),
tablenames: new[] { "requests", "items" },
Security: DbSec, options: SqlOpt(fn, id, code));
var ldic = new List<Dictionary<string, object?>>();
foreach (System.Data.DataRow sq in sqldt.Tables("requests").Select("",
sqldt.Tables("requests").Columns.Contains("order") ? "order" : ""))
{
var sdic = sq.toObjectDictionary();
sdic["items"] = sqldt.Tables("items")
.Select($"[ServiceRequestId] = {sdic["id"]}", sqldt.Tables("items").Columns.Contains("order") ? "order" : "")
.Select(r => r.toObjectDictionary()).ToList();
ldic.Add(sdic!);
}
return await JSONAsync(new { requests = ldic });
}
private async Task<IActionResult> HandleInvoicePayments(string fn, string id, string code)
{
if (!HasForm("id")) return BadRequest400();
var sqldt = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getInvPayments] @invoiceid, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@invoiceid", Form("id"))),
tablenames: new[] { "items" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new { payments = sqldt.Tables("items").toArrayofObjectDictionaries() });
}
private async Task<IActionResult> HandleDatev(string fn, string id, string code)
{
if (!DateTime.TryParseExact(Form("tgt"), "yy-MM-dd",
CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var tgtdate))
return BadRequest400();
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getDatevExports] @tgtdate, @mode, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_Date("@tgtdate", tgtdate), SQL_VarChar("@mode", Form("mode").ne("m"))),
tablenames: new[] { "files", "invoices", "debits" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
files = dset.Tables("files").toArrayofObjectDictionaries(),
invoices = dset.Tables("invoices").toArrayofObjectDictionaries()
});
}
private async Task<IActionResult> HandleReportDoc(string fn, string id, string code, string reportid)
{
byte[]? content = null;
var file = _mfr.GetReportDoc(ref content, reportid);
if (file == null) return StatusCode(404, new { error = "Dokument wurde nicht gefunden" });
return Form("typ") != "img"
? await FileContentResultAsync(content!, file.MimeType(), file.Name)
: await JSONAsync(new { id = reportid, img = await BuildPdfImageArray(content!) });
}
private async Task<IActionResult> HandleReportDocByName(string fn, string id, string code)
{
if (!HasForm("name")) return BadRequest400();
string nme = Form("name").LeftToFirst("(").Trim();
if (string.IsNullOrEmpty(nme)) return StatusCode(404);
var so = await getSQLValue_async(
"SELECT [dbo].[fds__fn_InvoiceIdByName](@nme);",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@nme", nme)),
Security: DbSec, options: SqlOpt(fn, id, code));
string reportid = so.Result?.ToString() ?? "";
return string.IsNullOrEmpty(reportid)
? StatusCode(404)
: await HandleReportDoc(fn, id, code, reportid);
}
private async Task<IActionResult> HandleDatevZip(string fn, string id, string code)
{
if (!DateTime.TryParseExact(Form("tgt"), "yy-MM-dd",
CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var tgtdate))
return BadRequest400();
Stream? ms = new MemoryStream();
var file = _mfr.GetDatevZip(ref ms, tgtdate,
mode: Form("mode").ne("m"),
authUser: UserAccountID,
includeFiles: Form("files", "1") != "0");
if (file == null) return BadRequest400();
ms!.Position = 0;
return await FileStreamResultAsync(ms, file.MimeType(), file.Name);
}
private async Task<IActionResult> HandleGetReminder(string fn, string id, string code)
{
if (!HasForm("id")) return BadRequest400();
var pl = StdParamlist(
SQL_VarChar("@InvId", Form("id")),
SQL_Bit("@include_drafts", Form("drafts")));
var sqldt = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getInvoiceReminder] @InvId, @include_drafts, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "reminder" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(sqldt.Table("reminder").DataTable.toArrayofObjectDictionaries());
}
// -- Shared builder helpers ------------------------------------------------
private static List<Dictionary<string, object?>> BuildInvoiceRequestList(SQLDataSet sqldset)
{
var ldic = new List<Dictionary<string, object?>>();
foreach (System.Data.DataRow rq in sqldset.Tables("req").Select("",
sqldset.Tables("req").Columns.Contains("order") ? "order" : ""))
{
var rdic = rq.toObjectDictionary();
var sdic = new Dictionary<string, object?>
{
["Id"] = rdic["mfr__servicerequest"],
["InvRqId"] = rdic["Id"],
["text"] = HttpUtility.HtmlDecode(rdic["title"]?.ToString() ?? "")
};
if (sqldset.Contains("itm"))
{
var itm = new List<Dictionary<string, object?>>();
foreach (System.Data.DataRow sitm in sqldset.Tables("itm").Select(
$"[InvRqId] = '{rdic["Id"]}'",
sqldset.Tables("itm").Columns.Contains("order") ? "order" : ""))
{
var d = sitm.toObjectDictionary();
double net = Convert.ToDouble(d.no("value_total", 0));
double vat = Convert.ToDouble(d.no("vat", 0));
itm.Add(new Dictionary<string, object?>
{
["Id"] = d["Id"],
["net_val"] = net,
["vat_val"] = net * vat * 0.01,
["vat"] = vat == 0 ? "" : vat.ToString("0.00", FuchsPdf.DeCulture) + "%",
["svcnet_val"] = d.no("value_service", 0),
["net"] = d.no("value", 0),
["quantity"] = d["Quantity"],
["Type"] = d["Type"],
["Note"] = null,
["htmltext"] = d["Text"],
["position"] = d["Position"],
["SortOrder"] = d["SortOrder"]
});
}
sdic["items"] = itm;
}
ldic.Add(sdic);
}
return ldic;
}
private static async Task<string[]> BuildPdfImageArray(byte[] content)
{
var imgcol = await FuchsPdf.BytesToImageCollection(content);
return imgcol.ImgB64Array;
}
}
@@ -0,0 +1,198 @@
using Fuchs.intranet;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using Newtonsoft.Json;
using OCORE.pdf;
using OCORE.SQL;
using static OCORE.commons;
using static OCORE.io;
using static OCORE.SQL.sql;
using static OCORE.web.mvc_helper_async;
namespace Fuchs.Controllers;
// Partial class: Reminder processing
public partial class IntranetController
{
private async Task<IActionResult> Do_Process_Reminder(string fn, string id, string code)
{
switch (id.ToLower())
{
case "get":
{
if (!HasForm("id")) return BadRequest400();
var pl = StdParamlist(
SQL_VarChar("@InvId", Form("id")),
SQL_VarChar("@type", Form("type")),
SQL_Int("@level", Form("level")));
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__prepReminder] @InvId, @authuser, @type, @level;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "rem" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new { rm = dset.Table("rem").FirstRow.toObjectDictionary() });
}
case "prep":
{
if (!HasForm("remc")) return BadRequest400();
var ctd = JsonConvert.DeserializeObject(Form("remc"))!;
var fdRem = new FdsReminderData(ctd);
fdRem.RegisterReminder(this, change: false, remId: "");
if (!string.IsNullOrEmpty(fdRem.Id))
{
var imgcol = await FuchsPdf.DocToImageCollection(fdRem.ReminderPDF(this));
return await JSONAsync(new { id = fdRem.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
}
return StatusCode(500, new { error = "Erinnerung wurde nicht registriert" });
}
case "conf": return await HandleReminderConf(fn, id, code);
case "srs":
{
if (!HasForm("id")) return BadRequest400();
var pl = StdParamlist(SQL_VarChar("@Id", Form("id")), SQL_Bit("@auto", false));
var dt2 = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__setReminderSent] @Id, @auto, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
Security: DbSec, options: SqlOpt(fn, id, code));
return string.IsNullOrEmpty(dt2.Exception) ? Ok() : StatusCode(500);
}
case "rdoc":
{
if (!HasForm("id")) return BadRequest400();
byte[]? fc = null;
var file = FdsReminderData.GetStoredFile(ref fc, Form("id"), this);
if (file == null) return StatusCode(404, new { error = "Dokument wurde nicht gefunden" });
return Form("typ") != "img"
? await FileContentResultAsync(fc!, file.MimeType(), file.Name)
: await JSONAsync(new { id = Form("id"), img = await BuildPdfImageArray(fc!) });
}
case "idoc": return await HandleReminderIdoc(fn, id, code);
case "resend": return await HandleReminderResend(fn, id, code);
case "lrem":
{
if (!HasForm("id")) return BadRequest400();
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__lookupReminders] @InvId, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@InvId", Form("id"))),
tablenames: new[] { "ov", "rem" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
ov = dset.Table("ov").FirstRow.toStringDictionary(),
lst = dset.Tables("rem").toArrayofObjectDictionaries()
});
}
default: return Ok();
}
}
private async Task<IActionResult> HandleReminderConf(string fn, string id, string code)
{
if (!HasForm("id")) return BadRequest400();
var dt = await getSQLDatatable_async(
"EXECUTE [dbo].[fds__setReminderFinal] @Id, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@Id", Form("id"))),
Security: DbSec, options: SqlOpt(fn, id, code));
var frdic = dt.FirstRow.toObjectDictionary();
if (frdic.TryGetValue("IsFinal", out var isFinal) && isFinal is true)
{
string remId = frdic["Id"]?.ToString() ?? "";
var fdRem = new FdsReminderData(remId, this);
byte[] filebyte = await fdRem.StoreReminderDocumentFile(this);
string email = frdic.nz("SendToEmail", "");
if (!string.IsNullOrEmpty(email) && filebyte.Length > 0)
{
var remdoc = new Dictionary<string, byte[]>
{ [frdic.nz("DocumentName", "").ne("Zahlungserinnerung.pdf")] = filebyte };
if (!string.IsNullOrEmpty(frdic.nz("InvoiceFileName")) &&
frdic.no("InvoiceFile", null!) is byte[] invFile)
remdoc[frdic.nz("InvoiceFileName")] = invFile;
bool sent = await FuchsFdsEmail.SendEmail(
$"inv_{remId}",
$"SanitärFuchs - {frdic.nz("subject").ne(frdic.nz("DocumentName"))}",
BuildReminderBody(Convert.ToDouble(frdic.no("amount_open", 0))),
email.Trim(), "", remdoc, _intranet);
if (sent)
{
var pls = StdParamlist(SQL_VarChar("@Id", remId), SQL_Bit("@auto", true));
await getSQLDatatable_async(
"EXECUTE [dbo].[fds__setReminderSent] @Id, @auto, @authuser;",
_intranet.Intranet__SQLConnectionString, pls,
Security: DbSec, options: SqlOpt(fn, id, code));
}
}
return Ok();
}
return StatusCode(500, new { error = "Aktion war nicht erfolgreich" });
}
private async Task<IActionResult> HandleReminderIdoc(string fn, string id, string code)
{
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
var fdRem = new FdsReminderData(Form("id"), this);
if (string.IsNullOrEmpty(fdRem.Id)) return StatusCode(404, new { error = "Erinnerung wurde nicht gefunden" });
string filename = fdRem.ReminderRegistration.nz("DocumentName").ne($"Zahlungserinnerung_{fdRem.Id}.pdf");
if (Form("typ") != "img")
{
byte[] ct = Form("create", "0") != "1"
? (await fdRem.GetReminderFile(this)) is { Length: > 0 } f1 ? f1 : await fdRem.StoreReminderDocumentFile(this)
: FuchsPdf.DocToPdfBytes(fdRem.ReminderPDF(this));
return await FileContentResultAsync(ct, "application/pdf", filename, inline: true);
}
var imgcol = await FuchsPdf.DocToImageCollection(fdRem.ReminderPDF(this));
return await JSONAsync(new { id = fdRem.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
}
private async Task<IActionResult> HandleReminderResend(string fn, string id, string code)
{
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
var pl = StdParamlist(SQL_VarChar("@Id", Form("id")), new SqlParameter("@includefile", true));
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getReminder] @Id, @includefile, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "admin", "inv", "req", "itm" },
Security: DbSec, options: SqlOpt(fn, id, code));
var frdic = dset.Table("inv").FirstRow.toObjectDictionary();
if (frdic.TryGetValue("IsFinal", out var isFinal) && isFinal is true)
{
string remId = frdic["Id"]?.ToString() ?? "";
byte[] filebyte = frdic.no("file", null!) as byte[] ?? Array.Empty<byte>();
string email = frdic.nz("SendToEmail", "");
if (!string.IsNullOrEmpty(email) && filebyte.Length > 0)
{
var remdoc = new Dictionary<string, byte[]>
{ [frdic.nz("DocumentName", "").ne("Zahlungserinnerung.pdf")] = filebyte };
if (!string.IsNullOrEmpty(frdic.nz("InvoiceFileName")) &&
frdic.no("InvoiceFile", null!) is byte[] invFile)
remdoc[frdic.nz("InvoiceFileName")] = invFile;
await FuchsFdsEmail.SendEmail($"rem_{remId}",
$"SanitärFuchs - {frdic.nz("subject").ne(frdic.nz("DocumentName"))}",
BuildReminderBody(Convert.ToDouble(frdic.no("amount_open", 0))),
email.Trim(), "", remdoc, _intranet);
}
return Ok();
}
return StatusCode(500, new { error = "Aktion war nicht erfolgreich" });
}
private static string BuildReminderBody(double amountOpen) =>
"<p>Sehr geehrte Damen und Herren,<br/>wir vermissen Ihren Zahlungseingang.</p>" +
(amountOpen != 0
? $"<p>Der offene Betrag beläuft sich auf (inkl. MwSt.): {((float)amountOpen).ToString("0.00 ", FuchsPdf.DeCulture)}</p>"
: "<p>Die Erinnerung mit allen Details finden Sie angehängt an diese Email.</p>") +
"<p>Bitte überweisen Sie den Rechnungsbetrag innerhalb von einer Woche auf unser Konto:<br/>" +
"IBAN: DE76300501100045014800, BIC DUSSSDEDDXXX (Stadtsparkasse Düsseldorf)</p>" +
"<p>Wenn Sie mit uns zufrieden waren, empfehlen Sie uns gerne weiter, " +
"wenn nicht, dann sagen Sie es uns unter " +
"<a href=\"mailto:info@sanitaerfuchs.de\">info@sanitaerfuchs.de</a>.</p>";
}
@@ -0,0 +1,52 @@
using Fuchs.intranet;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using OCORE.SQL;
using static OCORE.commons;
using static OCORE.SQL.sql;
using static OCORE.web.mvc_helper_async;
namespace Fuchs.Controllers;
// Partial class: Reports processing
public partial class IntranetController
{
private async Task<IActionResult> Do_Process_Reports(string fn, string id, string code)
{
switch (id.ToLower())
{
case "auth":
return await JSONAsync(new { manage = 1 });
case "catalog":
{
var pl = StdParamlist(SQL_VarChar("@report_name", Form("report"), dbNull_IfEmpty: true));
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__admin_getReportCatalog] @report_name, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "reports", "params", "categories", "tags" },
Security: DbSec, options: SqlOpt(fn, id, code));
var reps = dset.Tables("reports").toArrayofObjectDictionaries();
foreach (var ri in reps)
{
try
{
ri["params"] = dset.Tables("params")
.toArrayofObjectDictionaries($"[object_id] = {ri["object_id"]} AND [name] <> '@authuser'");
}
catch { ri["params"] = Array.Empty<Dictionary<string, object>>(); }
}
return await JSONAsync(new
{
reports = reps,
categories = dset.Tables("categories").toArrayofObjectDictionaries(),
tags = dset.Tables("tags").toArrayofObjectDictionaries()
});
}
default:
return await FuchsReports.ProcessFdsRequest(this, id.ToLower(), code);
}
}
}
@@ -0,0 +1,349 @@
using System.Globalization;
using Fuchs.intranet;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using MFR_RESTClient.generic;
using Newtonsoft.Json;
using OCORE.pdf;
using OCORE.SQL;
using static OCORE.commons;
using static OCORE.io;
using static OCORE.SQL.sql;
using static OCORE.web.mvc_helper_async;
namespace Fuchs.Controllers;
// Partial class: Service request processing
public partial class IntranetController
{
private async Task<IActionResult> Do_Process_Requests(string fn, string id, string code)
{
switch (id.ToLower())
{
case "auth":
return await JSONAsync(new { manage = 1 });
case "rthd":
{
if (!HasForm("id")) return BadRequest400();
var sqldt = await getSQLDatatable_async(
"EXECUTE [dbo].[fds__toggleRequestHidden] @Id, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_BigInt("@Id", Form("id"))),
Security: DbSec, options: SqlOpt(fn, id, code));
if (sqldt.Count == 0) return StatusCode(404, new { error = "not found" });
var dic = sqldt.FirstRow.toObjectDictionary();
return await JSONAsync(new { id = dic["EntityId"], visible = dic.no("hidden", false) is not true });
}
case "reql": return await HandleRequestList(fn, id, code);
case "pget": return await HandleRequestPget(fn, id, code);
case "get": return await HandleRequestGet(fn, id, code);
case "iget": return await HandleRequestIget(fn, id, code);
case "save":
{
if (!HasForm("invc")) return BadRequest400();
var fdInv = new FdsInvoiceData(JsonConvert.DeserializeObject(Form("invc"))!);
fdInv.RegisterInvoice(this, change: !string.IsNullOrEmpty(Form("id")), invId: Form("id"));
return !string.IsNullOrEmpty(fdInv.Id)
? await JSONAsync(new { id = fdInv.Id })
: StatusCode(500, new { error = "Rechnung wurde nicht gespeichert" });
}
case "sprep":
{
if (!HasForm("invc")) return BadRequest400();
var fdInv = new FdsInvoiceData(JsonConvert.DeserializeObject(Form("invc"))!);
fdInv.RegisterInvoice(this, change: false, invId: "");
if (!string.IsNullOrEmpty(fdInv.Id))
{
var imgcol = await FuchsPdf.DocToImageCollection(fdInv.InvoicePDF(this));
return await JSONAsync(new { id = fdInv.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
}
return StatusCode(500, new { error = "Rechnung wurde nicht registriert" });
}
case "sedit":
{
if (!HasForm("id", "invc")) return BadRequest400();
var fdInv = new FdsInvoiceData(JsonConvert.DeserializeObject(Form("invc"))!);
fdInv.RegisterInvoice(this, change: true, invId: Form("id"));
if (!string.IsNullOrEmpty(fdInv.Id))
{
var imgcol = await FuchsPdf.DocToImageCollection(fdInv.InvoicePDF(this));
return await JSONAsync(new { id = fdInv.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
}
return StatusCode(500, new { error = "Rechnung wurde nicht registriert" });
}
case "sdel":
if (!HasForm("id")) return BadRequest400();
await setSQLValue_async("EXECUTE [dbo].[fds__remInvoice] @Id, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@Id", Form("id"))),
Security: DbSec, options: SqlOpt(fn, id, code));
return Ok();
case "sconf": return await HandleRequestSconf(fn, id, code);
case "idoc": return await HandleRequestIdoc(fn, id, code);
case "resend": return await HandleRequestResend(fn, id, code);
default: return Ok();
}
}
private async Task<IActionResult> HandleRequestList(string fn, string id, string code)
{
if (!HasForm("mode")) return BadRequest400();
string mode = Form("mode").ToLower();
if (mode == "s" && Form("tgt").Contains(':'))
{
var pl = StdParamlist(
SQL_Date("@tgtdate", DBNull.Value),
SQL_VarChar("@mode", mode),
SQL_Bit("@completed", true),
SQL_VarChar("@search", Form("tgt")));
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getRequests_list2] @tgtdate, @mode, @completed, @search, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "admin", "requests", "reports" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
requests = AttachReports(dset)
});
}
if (!DateTime.TryParseExact(Form("tgt"), "yy-MM-dd",
CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var tgtdate))
return BadRequest400();
{
var pl = StdParamlist(
SQL_Date("@tgtdate", tgtdate),
SQL_VarChar("@mode", mode),
SQL_Bit("@completed", true));
var dset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getRequests_list] @tgtdate, @mode, @completed, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "admin", "requests", "reports" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
admin = dset.Table("admin").FirstRow.toObjectDictionary(),
requests = AttachReports(dset)
});
}
}
private static List<Dictionary<string, object?>> AttachReports(SQLDataSet dset)
{
var req = new List<Dictionary<string, object?>>(dset.Tables("requests").toArrayofObjectDictionaries()!);
foreach (var r in req)
{
try { r["reports"] = dset.Tables("reports").toArrayofObjectDictionaries($"[requestID] = {r["Id"]}"); }
catch { /* no reports table */ }
}
return req;
}
private async Task<IActionResult> HandleRequestPget(string fn, string id, string code)
{
if (!HasForm("id") || !long.TryParse(Form("id"), out long tgtid)) return BadRequest400();
var dt = await getSQLDatatable_async(
"SELECT * FROM [dbo].[fds__getRequestTreeIds](@srqid);",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_BigInt("@srqid", tgtid)),
Security: DbSec, options: SqlOpt(fn, id, code));
var ids = new List<long> { tgtid };
if (dt.Count > 0)
{
foreach (System.Data.DataRow rw in dt.DataTable.Rows)
{
long iid = rw.nint64("Id", -1);
if (iid > 0 && !ids.Contains(iid)) ids.Add(iid);
}
}
var schemaDic = new Dictionary<string, fds.FdsMfrClient.DatabaseSchema>
{
[EntityHelper.EntityName(EntityTypes.ServiceRequest)] =
new fds.FdsMfrClient.DatabaseSchema(EntityTypes.ServiceRequest)
};
using var mfr = new fds.FdsMfrClient();
await mfr.Update__entitytable(EntityTypes.ServiceRequest,
fds.FdsMfr.UpdateNeed.Reset, ids.ToArray(), schemaDic: schemaDic);
return Ok();
}
private async Task<IActionResult> HandleRequestGet(string fn, string id, string code)
{
if (!HasForm("id")) return BadRequest400();
string modeVal = Form("mode").ne("ov");
string[] tn = modeVal switch
{
"r" => new[] { "admin", "requests", "inv" },
"ful" => new[] { "admin", "requests", "items", "steps", "companies", "locations", "inv" },
_ => new[] { "admin", "requests", "items", "inv" }
};
var pl = StdParamlist(
SQL_BigInt("@servicerequestid", Form("id")),
SQL_VarChar("@mode", modeVal));
var sqldset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getRequest_details] @servicerequestid, @mode, @authuser;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: tn, Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
admin = sqldset.Table("admin").FirstRow.toObjectDictionary(),
requests = BuildRequestItemList(sqldset),
companies = sqldset.Tables("companies").toArrayofObjectDictionaries(),
locations = sqldset.Tables("locations").toArrayofObjectDictionaries(),
inv = sqldset.Tables("inv").toArrayofObjectDictionaries()
});
}
private async Task<IActionResult> HandleRequestIget(string fn, string id, string code)
{
if (!HasForm("id", "typ")) return BadRequest400();
var pl = StdParamlist(
SQL_BigInt("@servicerequestid", Form("id")),
SQL_VarChar("@mode", Form("mode").ne("ov")),
SQL_Char("@type", Form("typ").Substr(0, 1).ToLower()),
SQL_VarChar("sel", Form("sel")));
var sqldset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__prepInvoice] @servicerequestid, @mode, @authuser, @type, @sel;",
_intranet.Intranet__SQLConnectionString, pl,
tablenames: new[] { "admin", "requests", "items", "steps", "companies", "locations" },
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new
{
admin = sqldset.Table("admin").FirstRow.toObjectDictionary(),
requests = BuildRequestItemList(sqldset),
companies = sqldset.Tables("companies").toArrayofObjectDictionaries(),
locations = sqldset.Tables("locations").toArrayofObjectDictionaries()
});
}
private static List<Dictionary<string, object?>> BuildRequestItemList(SQLDataSet sqldset)
{
var ldic = new List<Dictionary<string, object?>>();
foreach (System.Data.DataRow sq in sqldset.Tables("requests").Select("",
sqldset.Tables("requests").Columns.Contains("order") ? "order" : ""))
{
var sdic = sq.toObjectDictionary();
if (sqldset.Contains("items"))
sdic["items"] = sqldset.Tables("items")
.Select($"[ServiceRequestId] = {sdic["Id"]}", sqldset.Tables("items").Columns.Contains("order") ? "order" : "")
.Select(r => r.toObjectDictionary()).ToList();
if (sqldset.Contains("steps"))
sdic["steps"] = sqldset.Tables("steps")
.Select($"[ServiceRequestId] = {sdic["Id"]}", sqldset.Tables("steps").Columns.Contains("order") ? "order" : "")
.Select(r => r.toObjectDictionary()).ToList();
ldic.Add(sdic!);
}
return ldic;
}
private async Task<IActionResult> HandleRequestSconf(string fn, string id, string code)
{
if (!HasForm("id")) return BadRequest400();
var dt = await getSQLDatatable_async(
"EXECUTE [dbo].[fds__setInvoiceFinal] @Id, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@Id", Form("id"))),
Security: DbSec, options: SqlOpt(fn, id, code));
var frdic = dt.FirstRow.toObjectDictionary();
if (frdic.TryGetValue("IsFinal", out var isFinal) && isFinal is true)
{
string invId = frdic["Id"]?.ToString() ?? "";
var fdInv = new FdsInvoiceData(invId, this);
byte[] filebyte = await fdInv.StoreInvoiceDocumentFile(this);
var dtset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getInvoice] @Id, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@Id", Form("id"))),
tablenames: new[] { "admin", "inv", "req", "itm" },
Security: DbSec, options: SqlOpt(fn, id, code));
frdic = dtset.Table("inv").FirstRow.toObjectDictionary();
string email = frdic.nz("SendToEmail", "");
if (!string.IsNullOrEmpty(email) && filebyte.Length > 0)
{
var inv = new Dictionary<string, byte[]> { [frdic.nz("DocumentName")] = filebyte };
double bal = Convert.ToDouble(frdic.no("InvoiceBalance", 0));
string terms = fdInv.PaymentTerms.Replace("wd", " Werktagen").Replace("d", " Tagen").Replace("wk", " Wochen").ne("10 Tagen");
string body = BuildInvoiceBody(bal, terms);
bool sent = await FuchsFdsEmail.SendEmail(
$"inv_{invId}", $"Sanit\u00e4rFuchs - {frdic.nz("DocumentName")}",
body, email.Trim(), "", inv, _intranet);
if (sent)
{
var pls = StdParamlist(SQL_VarChar("@Id", invId), SQL_Bit("@auto", true));
await getSQLDatatable_async("EXECUTE [dbo].[fds__setInvoiceSent] @Id, @auto, @authuser;",
_intranet.Intranet__SQLConnectionString, pls,
Security: DbSec, options: SqlOpt(fn, id, code));
}
}
return Ok();
}
return StatusCode(500, new { error = "Aktion war nicht erfolgreich" });
}
private async Task<IActionResult> HandleRequestIdoc(string fn, string id, string code)
{
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
var fdInv = new FdsInvoiceData(Form("id"), this);
if (string.IsNullOrEmpty(fdInv.Id)) return StatusCode(404, new { error = "Rechnung wurde nicht gefunden" });
string filename = fdInv.InvoiceRegistration.nz("DocumentName").ne($"Rechnung_{fdInv.Id}.pdf");
if (Form("typ") != "img")
{
byte[]? ct = Form("create", "0") != "1"
? await fdInv.GetInvoiceFile(this) is { Length: > 0 } f1 ? f1 : await fdInv.StoreInvoiceDocumentFile(this)
: FuchsPdf.DocToPdfBytes(fdInv.InvoicePDF(this));
return ct != null
? await FileContentResultAsync(ct, "application/pdf", filename, inline: true)
: StatusCode(500, new { error = "Rechnungs-PDF konnte nicht erstellt werden" });
}
var imgcol = await FuchsPdf.DocToImageCollection(fdInv.InvoicePDF(this));
return await JSONAsync(new { id = fdInv.Id, img = imgcol.ImgB64Array, total = imgcol.TotalPages });
}
private async Task<IActionResult> HandleRequestResend(string fn, string id, string code)
{
if (!HasForm("id") || string.IsNullOrEmpty(Form("id"))) return StatusCode(404);
var dtset = await getSQLDataSet_async(
"EXECUTE [dbo].[fds__getInvoice] @Id, @authuser;",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@Id", Form("id"))),
tablenames: new[] { "admin", "inv", "req", "itm" },
Security: DbSec);
var frdic = dtset.Table("inv").FirstRow.toObjectDictionary();
if (frdic.TryGetValue("IsFinal", out var isFinal) && isFinal is true)
{
string invId = frdic["Id"]?.ToString() ?? "";
var fdInv = new FdsInvoiceData(invId, this);
byte[] filebyte = FuchsPdf.DocToPdfBytes(fdInv.InvoicePDF(this));
string email = frdic.nz("SendToEmail", "");
if (!string.IsNullOrEmpty(email) && filebyte.Length > 0)
{
double bal = Convert.ToDouble(frdic.no("InvoiceBalance", 0));
string terms = fdInv.PaymentTerms.Replace("wd", " Werktagen").Replace("d", " Tagen").Replace("wk", " Wochen").ne("10 Tagen");
await FuchsFdsEmail.SendEmail(
$"inv_{invId}", $"Sanit\u00e4rFuchs - {frdic.nz("DocumentName")}",
BuildInvoiceBody(bal, terms), email.Trim(), "",
new Dictionary<string, byte[]> { [frdic.nz("DocumentName")] = filebyte },
_intranet);
}
return Ok();
}
return StatusCode(500, new { error = "Aktion war nicht erfolgreich" });
}
private static string BuildInvoiceBody(double balance, string paymentTerms) =>
"<p>Sehr geehrte Damen und Herren,<br/>vielen Dank für Ihren Auftrag, wir haben gern für Sie gearbeitet.</p>" +
(balance != 0
? $"<p>Unsere Dienstleistung stellen wir wie folgt In Rechnung (inkl. MwSt.): {((float)balance).ToString("0.00 ", FuchsPdf.DeCulture)}</p>"
: "<p>Die Abrechnung unserer Dienstleistung finden Sie angehängt an diese Email.</p>") +
$"<p>Bitte überweisen Sie den Rechnungsbetrag innerhalb von {paymentTerms} auf unser Konto:<br/>" +
"IBAN: DE76300501100045014800, BIC DUSSSDEDDXXX (Stadtsparkasse Düsseldorf)</p>";
}
+307
View File
@@ -0,0 +1,307 @@
using System.Web;
using Fuchs.intranet;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using MFR_RESTClient.generic;
using Newtonsoft.Json;
using OCORE.security;
using OCORE.SQL;
using static OCORE.commons;
using static OCORE.OCORE_dictionaries;
using static OCORE.SQL.sql;
using static OCORE.web.mvc_helper_async;
namespace Fuchs.Controllers;
/// <summary>
/// Fuchs Intranet MVC Controller.
/// Handles all intranet requests: authentication, invoices, reminders, requests, banking, reports.
/// </summary>
public partial class IntranetController : Microsoft.AspNetCore.Mvc.Controller
{
internal readonly Fuchs_intranet _intranet;
internal readonly fds.IFdsMfr _mfr;
private readonly ILogger<IntranetController> _logger;
private readonly List<string> _allowedNonAuth = new() { "spwc", "spw" };
private readonly List<string> _allowedGet = new()
{
"inv|datevzip", "inv|rdoc", "inv|rdocn",
"req|idoc", "req|resend",
"rem|idoc", "rem|resend",
"bam|up", "mfr", "mfr_update", "todos"
};
private FuchsUserIdentity? _userIdent;
private FuchsUserIdentity UserIdent => _userIdent ??= new FuchsUserIdentity(User);
public string UserAccountID => UserIdent.UserAccountId;
public string AuthAccount => UserIdent.Email;
public IntranetController(Fuchs_intranet intranet, fds.IFdsMfr mfr, ILogger<IntranetController> logger)
{
_intranet = intranet;
_mfr = mfr;
_logger = logger;
}
// ── Standard param list (pre-populates @authuser) ────────────────────────
public List<SqlParameter> StdParamlist(params SqlParameter[] extra)
{
var list = new List<SqlParameter> { SQL_VarChar("@authuser", UserAccountID) };
list.AddRange(extra);
return list;
}
public List<SqlParameter> StdParamlist(string key, object value, params SqlParameter[] extra)
{
var list = StdParamlist(extra);
list.Insert(0, SQL_VarChar(key, value?.ToString() ?? ""));
return list;
}
public DatabaseSecurity DbSec => _intranet.GetDbSecurity(UserAccountID);
public FIS_SQLOptions SqlOpt(string fn, string id, string code) =>
new(new Dictionary<string, object> { ["fn"] = fn, ["id"] = id, ["code"] = code });
// ── Action helpers ────────────────────────────────────────────────────────
protected IActionResult Unauthorized401() => StatusCode(401);
protected IActionResult BadRequest400() => BadRequest();
protected IActionResult ServerError(string msg = "") => StatusCode(500, new { error = msg });
// ── Index (GET /) ─────────────────────────────────────────────────────────
[AllowAnonymous]
public IActionResult Index(string? fn, string? id, string? code) =>
View("intranet");
// ── Do (POST+GET /do/{fn}/{id}/{code}) ─────────────────────────────────
[AllowAnonymous]
public async Task<IActionResult> Do(string? fn, string? id, string? code)
{
fn = (fn ?? "").ToLower();
id ??= "";
code ??= "";
bool isGet = HttpContext.Request.Method.Equals("GET", StringComparison.OrdinalIgnoreCase);
if (!UserIdent.IsAuthenticated && !(new string[] { "login","logout" }).Contains(fn.ToLower()) && !_allowedNonAuth.Contains(fn.ToLower()))
{
if (!_allowedGet.Contains(fn.ToLower()) && !_allowedGet.Contains($"{fn.ToLower()}|{id.ToLower()}"))
_logger.LogInformation($"rejected function on do {fn}");
return Unauthorized401();
}
try
{
IActionResult? result = fn.ToLower() switch
{
"ping" => Ok(),
"wdg" => await FuchsWidgets.IntranetWdg(this, id),
"todos" => new PhysicalFileResult(
Path.Combine(Directory.GetCurrentDirectory(), "Data", "ProjectToDos.html"),
"text/html"),
"req" => await Do_Process_Requests(fn, id, code),
"inv" => await Do_Process_Invoices(fn, id, code),
"rem" => await Do_Process_Reminder(fn, id, code),
"rep" => await Do_Process_Reports(fn, id, code),
"bam" => await Do_Process_Bankings(fn, id, code),
"auth" => await HandleAuth(fn, id, code),
"spwc" => await HandleSendPasswordCode(fn, id, code),
"spw" => await HandleSendPassword(fn, id, code),
"account" => await HandleAccount(fn, id, code),
"mfr" => await HandleMfr(fn, id, code),
"mfr_update" => await HandleMfrUpdate(fn, id, code),
"login" => await HandleLogin(fn, id, code),
"logout" => await HandleLogout(),
_ => null
};
return result ?? Ok();
}
catch (Exception ex)
{
_intranet.debug_log("IntranetController.Do", ex, UserAccountID,
data: new { fn, id, code });
return ServerError();
}
}
// ── Auth helper ───────────────────────────────────────────────────────────
private async Task<IActionResult> HandleAuth(string fn, string id, string code)
{
if (!Request.Form.ContainsKey("module")) return BadRequest400();
string module = Request.Form["module"].ToString();
if (Request.Form["array"] == "1")
{
var dt = await getSQLDatatable_async(
"SELECT * FROM [dbo].[fis_getModuleAuthList](@module, @authuser);",
_intranet.Intranet__SQLConnectionString,
StdParamlist(SQL_VarChar("@module", module)),
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(dt.DataTable.ToDictionary(KeyColumn: "module", ValueColumn: "auth"));
}
else
{
var val = await getSQLValue_async<int>(
"SELECT [dbo].[fis_getModuleAuth](@module, @authuser);",
_intranet.Intranet__SQLConnectionString, -1,
StdParamlist(SQL_VarChar("@module", module)),
Security: DbSec, options: SqlOpt(fn, id, code));
return await JSONAsync(new { auth = val.Result });
}
}
// ── Login / Logout ────────────────────────────────────────────────────────
[AllowAnonymous]
private async Task<IActionResult> HandleLogin(string fn, string id, string code)
{
string email = Request.Form["userinfo"].ToString();
string password = Request.Form["userpass"].ToString();
var row = await _intranet.AuthenticateAsync(email, password);
if (row == null)
{
_logger.LogWarning("Login failed for '{Email}' from {IP}",
email, HttpContext.Connection.RemoteIpAddress);
_intranet.debug_log("HandleLogin: failed",
data: new { email, ip = HttpContext.Connection.RemoteIpAddress?.ToString() });
return Unauthorized401();
}
string userId = row.nz("useraccount_id");
string userEmail = row.nz("email");
int auth = int.TryParse(row.nz("authorization"), out var a) ? a : 0;
var identity = FuchsUserIdentity.BuildIdentity(userId, userEmail, auth, Fuchs_intranet.AuthScheme);
var principal = new System.Security.Claims.ClaimsPrincipal(identity);
await HttpContext.SignInAsync(Fuchs_intranet.AuthScheme, principal);
return await JSONAsync(new
{
login = userEmail,
useraccount_id = userId,
email = userEmail,
authorization = auth,
requestedaccount = "",
accountrequired = false
});
}
private async Task<IActionResult> HandleLogout()
{
await HttpContext.SignOutAsync(Fuchs_intranet.AuthScheme);
return Ok();
}
// ── Password helpers ──────────────────────────────────────────────────────
private async Task<IActionResult> HandleSendPasswordCode(string fn, string id, string code)
{
string? lastname = Request.Form["lastname"];
string? email = Request.Form["email"];
if (string.IsNullOrEmpty(lastname) || string.IsNullOrEmpty(email)) return BadRequest400();
var row = await _intranet.GetUserAccountByEmailAsync(email);
if (row != null && row.nz("email").Length > 5 &&
row.nz("name").ToLower().Trim() == lastname.ToLower().Trim() &&
row.nz("mobile").Length > 5 && !Request.Host.Host.ToLower().Contains("localhost"))
{
OCORE.sms.SMS77.Settings.APIKey = _intranet.Intranet__SMS_API_key;
using var sms = new OCORE.sms.SMS77.SMS("ProcessWeb");
string totp = OCORE.security.TFA.generateTotp_12h(_intranet.Intranet__TOTPsharedsecret_base);
if (long.TryParse(row.nz("mobile").Replace("+", "00").Replace(" ", ""), out long smsNum))
sms.SendSMS_sync(smsNum,
"Zur Bestätigung des Passwortversands auf sanitarfuchs.de, verwenden Sie bitte folgenden Code:" + totp);
}
return Ok(); // always OK to prevent enumeration
}
private async Task<IActionResult> HandleSendPassword(string fn, string id, string code)
{
string? lastname = Request.Form["lastname"];
string? email = Request.Form["email"];
string? totpCode = Request.Form["code"];
if (string.IsNullOrEmpty(lastname) || string.IsNullOrEmpty(email) || string.IsNullOrEmpty(totpCode))
return BadRequest400();
if (OCORE.security.TFA.validateTotp_12h(_intranet.Intranet__TOTPsharedsecret_base, totpCode).isVerifiedInTime)
{
var row = await _intranet.GetUserAccountByEmailAsync(email, includePassword: true);
if (row != null && row.nz("email").Length > 5)
{
await FuchsFdsEmail.SendEmail("pw_" + row.nz("email"),
"sanitaerfuchs.de Intranet Passwort",
$"<p>Guten Tag {row.nz("firstname")} {row.nz("name")},<br/>Ihr Passwort: {HttpUtility.HtmlEncode(row.nz("password"))}</p>",
row.nz("email"), $"{row.nz("firstname")} {row.nz("name")}", null, _intranet);
}
}
return Ok();
}
private async Task<IActionResult> HandleAccount(string fn, string id, string code)
{
switch (id.ToLower())
{
case "sms":
var row = await _intranet.GetUserAccountByEmailAsync(UserIdent.Email, includePassword: true);
if (row != null && row.nz("mobile").Length > 5 && !Request.Host.Host.Contains("localhost"))
{
OCORE.sms.SMS77.Settings.APIKey = _intranet.Intranet__SMS_API_key;
using var sms2 = new OCORE.sms.SMS77.SMS("ProcessWeb");
string totp2 = OCORE.security.TFA.generateTotp_3h(_intranet.Intranet__TOTPsharedsecret_base + "3MDR");
if (long.TryParse(row.nz("mobile").Replace("+", "00").Replace(" ", ""), out long mob2))
sms2.SendSMS_sync(mob2, "Zur Bestätigung der Passwortänderung auf sanitarfuchs.de: " + totp2);
}
return Ok();
case "changepassword":
string? npw = Request.Form["npw"];
string? npwc = Request.Form["npwc"];
string? totpCode = Request.Form["code"];
if (string.IsNullOrEmpty(npw) || string.IsNullOrEmpty(npwc) || string.IsNullOrEmpty(totpCode))
return BadRequest400();
if (!OCORE.security.TFA.validateTotp_3h(_intranet.Intranet__TOTPsharedsecret_base + "3MDR", totpCode).isVerifiedInTime)
return StatusCode(409, new { error = "sms" });
await setSQLValue_async(
"EXECUTE [dbo].[fis_admin_setNewPassword] @useraccount_id, @oldpassword, @newpassword, @enc_key;",
_intranet.Intranet__SQLConnectionString,
new List<SqlParameter>
{
SQL_VarChar("@useraccount_id", UserAccountID),
SQL_VarChar("@oldpassword", Request.Form["opw"].ToString()),
SQL_VarChar("@newpassword", npw)
},
Security: DbSec, options: SqlOpt(fn, id, code));
return Ok();
}
return Ok();
}
private async Task<IActionResult> HandleMfr(string fn, string id, string code)
{
if (!string.IsNullOrEmpty(UserAccountID) && UserIdent.Authorization > 3)
{
string path = id + (!string.IsNullOrEmpty(code) ? "/" + code : HttpUtility.UrlDecode(Request.QueryString.Value ?? ""));
using var mfrRead = new fds.FdsMfrClient();
var result = await mfrRead.ReadOData(path, throwErrorIfNotOk: false);
return Content(JsonConvert.SerializeObject(result), "application/json");
}
return Ok();
}
private async Task<IActionResult> HandleMfrUpdate(string fn, string id, string code)
{
var et = EntityHelper.EntityValue(Request.Form["type"].ToString());
if (et != EntityTypes.none && string.IsNullOrEmpty(Request.Form["need"]))
{
using var mfrSingle = new fds.FdsMfrClient();
await mfrSingle.Update__entitytable(et, fds.FdsMfr.UpdateNeed.Short);
return Ok();
}
if (et != EntityTypes.none && !string.IsNullOrEmpty(Request.Form["need"]))
{
var need = fds.FdsMfr.UpdateNeedValue(Request.Form["need"].ToString());
using var mfr = new fds.FdsMfrClient();
await mfr.Update__entitytable(et, updateNeed: need, debugDetails: false);
return Ok();
}
return BadRequest400();
}
}
+351
View File
@@ -0,0 +1,351 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
a:link
{color:#0563C1;
text-decoration:underline;
text-underline:single;
}
.auto-style1 {
text-indent: -18.0pt;
line-height: 107%;
font-size: 11.0pt;
font-family: Calibri, sans-serif;
margin-left: 36.0pt;
margin-right: 0cm;
margin-top: 0cm;
margin-bottom: 0cm;
}
.auto-style2 {
text-indent: -18.0pt;
line-height: 107%;
font-size: 11.0pt;
font-family: Calibri, sans-serif;
margin-left: 36.0pt;
margin-right: 0cm;
margin-top: 0cm;
margin-bottom: 8.0pt;
}
</style>
</head>
<body>
<div style="display: block;padding:1rem;">
<h1 style="margin-bottom:1rem;">Projekt ToDos und Ideen</h1>
</div>
<p>
&nbsp;</p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]>Rechnungseditor<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153"><span style="mso-list:
Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153">Opt. Textfeld oberhalb der Tabelle<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153"><span style="mso-list:
Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153">Opt. Textfeld unterhalb der Tabelle<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Textbausteine<o:p></o:p></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#9CC2E5;
mso-themecolor:accent5;mso-themetint:153"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;
mso-themetint:153">Eigene Rechnung hochladen (nicht autom/online erzeugt)<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153">Anlegen eines Datensatzes (zur Nummernvergabe) <o:p></o:p></span>
</p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153">Upload des pdf-Dokuments<o:p></o:p></span></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]>Rechnungen<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>UTC -&gt; local<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><s><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span></s><![endif]>Rechnungs-Nummernkreis für FDS<span style="mso-spacerun:yes">&nbsp;&nbsp; </span>(<span style="mso-spacerun:yes">&nbsp; </span><s>ab R2021-1196<span style="mso-spacerun:yes">&nbsp; </span>)<o:p></o:p></s></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Storno-Rechnung<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">„Freigabe“ des Auftrags/der Aufträge<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level4 lfo1">
<![if !supportLists]><span style="font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:
Symbol;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">wahlweise ohne Freigabe der Aufträge<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Storno als neue Rechnung mit neg. Betrag<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Storno als Kopie der stornierten Rechnung mit Berücksichtigung des stornierten Betrages<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Fortsetzen von Rechnungsentwürfen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family: &quot;Courier New&quot;; mso-fareast-font-family: &quot;Courier New&quot;; color: #70AD47; mso-themecolor: accent6; background: yellow; mso-highlight: yellow"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color: #70AD47; mso-themecolor: accent6; background: yellow; mso-highlight: yellow">Löschen von Rechnungsentwürfen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Abschlags-Rechnungen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Abschlagsrechnungen erstellen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">„Offen lassen“ von Aufträgen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Berücksichtigung von Abschlagsrechnungen in abschließende Rechnungen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Angepasste Texte für A.Rechnungen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Nummerierte Abschlagsrechnungen je „Hauptauftrag“</span><o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Anzeige der Abschlagsrechnungen unterhalb aller Aufträge und Zwischensummen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Zahlungs-Status anzeigen<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Zahlungs-Summe anzeigen<span style="mso-spacerun:yes">&nbsp; </span>(eingegangene Beträge)<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Zugeordnete Buchungen anzeigen<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Manuelles Abschließen<span style="mso-spacerun:yes">&nbsp; </span>(Bezahlt markieren = ist bezahlt)<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Manuelles Abschließen<span style="mso-spacerun:yes">&nbsp; </span>(Bezahlt markieren = ist nicht (vollst.) bezahlt)<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#92D050"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Seitenzahlen in das Layout<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#92D050"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">GoDB-Konforme elektronische Rechnungen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>ZUGFeRD<span style="mso-spacerun:yes">&nbsp; </span>Meta-Daten für E-Invoicing<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>GiroCode<span style="mso-spacerun:yes">&nbsp; </span>(EPC-QR-Code mit Rechnungsdaten;<span style="mso-spacerun:yes">&nbsp; </span>Banking Apps können das lesen)<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#92D050"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#92D050">Auf der Rechnung<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Auf der Mahnung <span style="mso-spacerun:yes">&nbsp;&nbsp;</span>(nur offener Betrag)<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]>In den Emails<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#92D050"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Emails individualisiert<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family: &quot;Courier New&quot;; mso-fareast-font-family: &quot;Courier New&quot;; background: yellow; mso-highlight: yellow"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="background: yellow; mso-highlight: yellow">Hinweis wenn keine Email-Adresse<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level2 lfo2">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;
mso-themetint:153">Post-Versand über „</span><a href="https://emailbrief.de/"><span style="color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153">Emailbrief</span></a><span style="color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153">.de“<span style="mso-spacerun:yes">&nbsp; </span>(Die pdfs werden direkt über einen Online-Dienst postalisch versandt)<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level2 lfo2">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Änderungen Rechnung 09.06.2021<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Auftragsname veränderbar<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Anstatt Auftragsnamen -&gt; Ausgeführte Arbeiten aus der Checkliste<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Positionsnummern aktualisieren bei gelöschten Zeilen,<span style="mso-spacerun:yes">&nbsp; </span>wenn da gewesen.<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Keine Zwischensumme wenn nur ein Auftrag<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]>Default<span style="mso-spacerun:yes">&nbsp; </span>UsT<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">USt pro Auftrag „zusammen“ verändern<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Finanzamtshinweis<span style="mso-spacerun:yes">&nbsp;&nbsp;&nbsp; </span>„Als Privathaushalt<span style="mso-spacerun:yes">&nbsp;&nbsp;&nbsp;&nbsp; </span>….. von dieser Rechnung<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Rechnungsnummer = nicht auswählbar in der Liste<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Datum des Auftrags<span style="mso-spacerun:yes">&nbsp; </span>bei jedem Auftrag<span style="mso-spacerun:yes">&nbsp; </span>„01.01.21: “ <o:p></o:p></span>
</p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Formular :<span style="mso-spacerun:yes">&nbsp;&nbsp; </span>Anzahl verändern -&gt; Gesamtbetrag verändern<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Doppelung der Hinweistexte<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Zeitraum<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level2 lfo2">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Auftragsliste<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#70AD47;
mso-themecolor:accent6"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Kunden in Liste<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]>Kunde in Detail-Ansicht<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#70AD47;
mso-themecolor:accent6"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Einsatzorte korrigieren<o:p></o:p></span></p>
<p class="auto-style1" style="mso-list: l1 level1 lfo2">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#9CC2E5;
mso-themecolor:accent5;mso-themetint:153"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;
mso-themetint:153"><o:p>&nbsp;</o:p></span></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]>Datev-Export:<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Rechnungskopie im Zip<span style="mso-spacerun:yes">&nbsp; </span>(für nicht-MFR-Rechnungen (fds))<o:p></o:p></span></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]>Download von Rechnungen<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Aktualisierung des Button in der Rechnungsliste für fds-Dokumente<o:p></o:p></span></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]>Übersicht je Kunde<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Rechnungen<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Aufträge<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Kontobewegungen<o:p></o:p></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;
mso-themetint:153">Unterschiedliche Rechte für Rechnungen mit und ohne Preisanpassungen</span><o:p></o:p></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]>Verarbeitung von Kontobewegungen<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Zuordnungsliste<span style="mso-spacerun:yes">&nbsp; </span>(alle Buchungen mit autom. + manuellen Zuordnungen)<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Manuelle Zuordnung<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Manuelle Bestätigung erforderlich<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Autom. Zuordnung zu Rechnungen<span style="mso-spacerun:yes">&nbsp; </span>(Abgleich mit Kunden- und Rechnungsinfos)<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Überlauf<span style="mso-spacerun:yes">&nbsp; </span>(Eingänge nicht zuordenbar)<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Zuordnung löschen<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level2 lfo2">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;
mso-themetint:153">Anbindung ein Banking-API System (bspw </span><a href="https://banksapi.de/api/"><span style="color:#9CC2E5;mso-themecolor:accent5;
mso-themetint:153;text-decoration:none;text-underline:none">https://banksapi.de/api/</span></a><span style="color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153">) zur autom. Abfrage von Buchungen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]>Mahnungs-Modul<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>Mahnungsvorschläge<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><s><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span></s><![endif]><s>Mahnsperre ?<o:p></o:p></s></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Mahnungserstellung <o:p></o:p></span>
</p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">3 Mahn-Stufen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Online-Editor<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#70AD47;mso-themecolor:accent6"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#70AD47;mso-themecolor:accent6">Autom. Versand<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#B4C7E7;mso-themecolor:accent1;mso-themetint:102;mso-style-textfill-fill-color:
#B4C7E7;mso-style-textfill-fill-themecolor:accent1;mso-style-textfill-fill-alpha:
100.0%;mso-style-textfill-fill-colortransforms:&quot;lumm=40000 lumo=60000&quot;"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#B4C7E7;mso-themecolor:accent1;mso-themetint:102;mso-style-textfill-fill-color:
#B4C7E7;mso-style-textfill-fill-themecolor:accent1;mso-style-textfill-fill-alpha:
100.0%;mso-style-textfill-fill-colortransforms:&quot;lumm=40000 lumo=60000&quot;">Postversand<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l1 level2 lfo2">
<![if !supportLists]><s><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span></s><![endif]><s><span style="color:#9CC2E5;mso-themecolor:
accent5;mso-themetint:153">Unterschiedliche Texte/Vorlagen für unterschiedliche Kunden-Typen<o:p></o:p></span></s></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#9CC2E5;
mso-themecolor:accent5;mso-themetint:153"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;
mso-themetint:153">Tageszusammenfassungen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153"><span style="mso-list:
Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153">Neue fertige Aufträge<span style="mso-spacerun:yes">&nbsp;&nbsp; </span>(für Rechnungen)<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153"><span style="mso-list:
Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153">Neue überfällige Rechnungen<span style="mso-spacerun:yes">&nbsp; </span>(für Mahnungen)<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153"><span style="mso-list:
Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#9CC2E5;mso-themecolor:accent5;mso-themetint:153">Auffällige Kontobuchungen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><s><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></s><![endif]><s>Adressbuch<o:p></o:p></s></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><s><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span></s><![endif]><s>Matching zu MFR-Kunden<span style="mso-spacerun:yes">&nbsp; </span>(CustomerID)<o:p></o:p></s></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><s><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span></s><![endif]><s>Kontaktpersonen<o:p></o:p></s></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><s><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span></s><![endif]><s>„Liefer“-Adressen<o:p></o:p></s></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><s><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span></s><![endif]><s>Administrative Standardadressen<span style="mso-spacerun:yes">&nbsp; </span>(Post und Email) für best. Zwecke (z.B. Rechnungen, Mahnungen, Ansprechpartner)<o:p></o:p></s></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><s><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span></s><![endif]><s>Auswahlmöglichkeit im Rechnungs- und Mahnungs-Editor<o:p></o:p></s></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri;color:#92D050"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#92D050">Email-Log<o:p></o:p></span></p>
<p class="auto-style1" style="mso-list: l0 level1 lfo1">
<![if !supportLists]><span style="mso-ascii-font-family:Calibri;mso-fareast-font-family:Calibri;
mso-hansi-font-family:Calibri;mso-bidi-font-family:Calibri"><span style="mso-list:Ignore">-<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]>Sicherheit<o:p></o:p></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#5B9BD5;mso-themecolor:accent5"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#5B9BD5;mso-themecolor:accent5">Verschlüsselung der Datenbank<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;;
color:#5B9BD5;mso-themecolor:accent5"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]><span style="color:#5B9BD5;mso-themecolor:accent5">Modul-Autorisierungen<o:p></o:p></span></p>
<p class="auto-style1" style="mso-add-space: auto; mso-list: l0 level3 lfo1">
<![if !supportLists]><span style="font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings;color:#5B9BD5;mso-themecolor:accent5"><span style="mso-list:Ignore">§<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp; </span></span></span><![endif]><span style="color:#5B9BD5;mso-themecolor:accent5">Unterschiedliche Rechte für Rechnungen mit und ohne Preisanpassungen<o:p></o:p></span></p>
<p class="auto-style2" style="mso-add-space: auto; mso-list: l0 level2 lfo1">
<![if !supportLists]><span style="font-family:&quot;Courier New&quot;;mso-fareast-font-family:&quot;Courier New&quot;"><span style="mso-list:Ignore">o<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp; </span></span></span><![endif]>S/MIME-Signatur der ausgehenden Emails<o:p></o:p></p>
<p class="MsoNormal">
<o:p>&nbsp;</o:p></p>
<p class="MsoNormal">
<o:p>&nbsp;</o:p></p>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

+398
View File
@@ -0,0 +1,398 @@
# Fuchs Intranet — Solution Architecture
> Auto-generated architecture analysis
> .NET 10 · ASP.NET Core MVC · SQL Server
---
## 1. Solution Overview
The **Fuchs Intranet** solution is a line-of-business web application for **Sebastian Fuchs Bad und Heizung GmbH & Co. KG** (a plumbing/heating company in Düsseldorf). It manages invoices, reminders, service requests, banking transactions, reports, and user authentication — all exposed through a single-page intranet front-end.
| Project | Type | Purpose |
|---|---|---|
| **Fuchs** | ASP.NET Core Web (MVC) | Main web application — the intranet |
| **Fuchs_DataService** | Console / Windows Service (Topshelf) | Background data sync service (MFR ERP polling) |
| **MFR_RESTClient** | Class Library | REST/OData client for the MFR ERP system |
| **OCORE** | Class Library (shared) | Core utilities: SQL, crypto, email, IO, logging |
| **OCORE_web** | Class Library (shared) | Web utilities: MVC helpers, middleware, auth, captcha |
| **OCORE_web_pdf** | Class Library (shared) | PDF generation (MigraDoc/PDFsharp, HTML→PDF) |
| **OCORE_Charting** | Class Library (shared) | Data visualization / charting (ported System.Windows.Forms.DataVisualization) |
| **MT940Parser** | Class Library (shared) | SWIFT MT940/MT942 bank statement parser |
**All projects target `net10.0`.**
---
## 2. Architecture Diagram
```
┌─────────────────────────────────────────────────────────────────────────┐
│ CLIENTS (Browser) │
│ SPA-like JS front-end (js/intranet/) │
└──────────────────────────────┬──────────────────────────────────────────┘
│ HTTP (GET / POST)
┌─────────────────────────────────────────────────────────────────────────┐
│ Fuchs (ASP.NET Core MVC) │
│ │
│ Program.cs ─── ConfigureServices / ConfigureApp │
│ │ │
│ ├── Cookie Authentication (scheme: "fuchs_intranet") │
│ ├── Distributed Memory Cache │
│ └── DI Registrations: │
│ • Fuchs_intranet (singleton — config + auth + DB helper) │
│ • IFdsMfr → FdsMfr (singleton — ERP sync) │
│ │
│ Routes: │
│ /{fn?}/{id?}/{code?} → IntranetController.Index (SPA shell) │
│ /do/{fn?}/{id?}/{code?} → IntranetController.Do (API) │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ IntranetController (partial class) │ │
│ │ │ │
│ │ .cs — core: Index, Do dispatcher, Auth, Login/Logout │ │
│ │ .Invoices.cs — invoice CRUD, DATEV export, PDF │ │
│ │ .Invoices2.cs— invoice sub-handlers (MFR refresh, get, list) │ │
│ │ .Reminder.cs — payment reminder CRUD + PDF │ │
│ │ .Requests.cs — service request management │ │
│ │ .Banking.cs — MT940 upload, transaction queries │ │
│ │ .Reports.cs — report catalog, execution │ │
│ └──────────┬──────────────────────────────────────────────────────┘ │
│ │ calls │
│ ┌──────────▼──────────────────────────────────────────────────────┐ │
│ │ code/ (Business Logic) │ │
│ │ │ │
│ │ FuchsIntranet.cs — Fuchs_intranet singleton (config, auth, │ │
│ │ DB connections, debug logging) │ │
│ │ FdsInvoiceData.cs — Invoice data model + PDF generation │ │
│ │ FdsReminderData.cs — Reminder data model + PDF generation │ │
│ │ FuchsPdf.cs — PDF layout/rendering (MigraDoc) │ │
│ │ FuchsWidgets.cs — Dashboard widget data (SQL-driven) │ │
│ │ FuchsReports.cs — Report dispatch │ │
│ │ FuchsFdsEmail.cs — Email sending + DB logging │ │
│ │ Banking.cs — MT940 parsing to DataTable │ │
│ │ MigraDocExtensions — MigraDoc helper extensions │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ Logging/FuchsLoggerProvider.cs — custom ILoggerProvider │
└────────┬────────────────┬──────────────────┬───────────────────────┬────┘
│ │ │ │
▼ ▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌────────────────┐ ┌──────────────────┐
│ OCORE │ │ OCORE_web │ │ OCORE_web_pdf │ │ MT940Parser │
│ │ │ │ │ │ │ │
│ • SQL helper │ │ • MVC helper │ │ • MigraDoc/ │ │ • SWIFT MT940/ │
│ (ADO.NET) │ │ (JSON,File)│ │ PDFsharp │ │ MT942 parser │
│ • Email │ │ • Cookie Auth│ │ • HTML→PDF │ │ │
│ • IO/Files │ │ • Middleware │ │ • Font resolver │ │ │
│ • Crypto │ │ • Captcha │ │ │ │ │
│ • Logging │ │ • Background │ │ │ │ │
│ • CSV/XML │ │ services │ │ │ │ │
│ • DateTime │ │ • Security │ │ │ │ │
└──────────────┘ └──────────────┘ └────────────────┘ └──────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Fuchs_DataService (Windows Service / Console) │
│ │
│ FdsMain.cs — Topshelf host, job definitions │
│ PeriodicHostedService — BackgroundService with PeriodicTimer │
│ FdsMfr.cs (IFdsMfr) — MFR sync orchestration │
│ FdsMfrClient.cs — MFR REST client wrapper │
│ FdsShared.cs — FdsConfig (appsettings.json reader) │
│ FdsZip.cs — 7-Zip archive handling (DATEV export) │
│ FdsDebug.cs — Debug/file logging │
│ │
│ Jobs: MfrSync (every N min) │
│ → UpdateIfNecessary_async (entity table sync) │
│ → UpdateRequested_async (on-demand entity refresh) │
│ → GetInvoiceFiles_async (invoice PDF download) │
└────────────────────────┬────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ MFR_RESTClient │
│ │
│ MFRClient.cs — RestSharp-based REST/OData client │
│ MFRClientModels.cs — Config, credentials, entity types │
│ ODataEnvelope.cs — OData response wrapper │
│ Entities/MfrGeneric.cs— Generic entity helpers │
└────────────────────────┬────────────────────────────────────────────────┘
┌─────────────────────┐
│ MFR ERP System │
│ (External REST) │
└─────────────────────┘
┌─────────────────────┐
All projects ──────►│ SQL Server │
│ (fuchs_fds DB) │
│ Stored procedures │
│ Symmetric key enc. │
└─────────────────────┘
```
---
## 3. Dependency Graph
```
Fuchs (Web)
├── OCORE
├── OCORE_web ──► OCORE
├── OCORE_web_pdf
├── MT940Parser
├── MFR_RESTClient
└── Fuchs_DataService
├── OCORE
├── OCORE_web
└── MFR_RESTClient
OCORE_Charting (standalone — referenced by solution but no direct project reference)
```
---
## 4. Key Architectural Patterns
### 4.1 Partial Controller Pattern
`IntranetController` is split across **7 partial-class files**, each handling a business domain (invoices, reminders, banking, etc.). The main `Do()` action uses a `switch` expression to dispatch to domain-specific methods.
### 4.2 Singleton Configuration Object
`Fuchs_intranet` is a manually-managed singleton (via `FuchsOcmsIntranet`) initialized at startup with `IConfiguration`. It holds connection strings, app settings, auth helpers, and DB connection factory methods.
### 4.3 Static Business Logic Classes
Most business logic lives in **static classes** (`FuchsPdf`, `FuchsWidgets`, `FuchsReports`, `FuchsFdsEmail`, `Banking`) that receive the controller instance or `Fuchs_intranet` as a parameter. This is a legacy pattern from the VB.NET conversion.
### 4.4 SQL-First Data Access
There is no ORM (no EF Core). All data access uses **ADO.NET via OCORE SQL helpers** (`getSQLDatatable_async`, `getSQLDataSet_async`, `setSQLValue_async`) calling stored procedures and inline SQL. `DataTable`/`DataRow` is the primary data transfer mechanism.
### 4.5 Background Service
`Fuchs_DataService` runs as a Windows Service (Topshelf) with a `PeriodicHostedService` that polls the MFR ERP system on a timer, syncing entities and downloading invoice files.
### 4.6 Authentication
Cookie-based authentication (`CookieAuthenticationDefaults`) with custom claims (`FuchsUserIdentity`). SQL-based user/password verification.
---
## 5. DI Service Extraction Candidates
The following static classes and tightly-coupled code sections are strong candidates for refactoring into proper DI-registered services. This improves testability, decouples dependencies, and aligns with ASP.NET Core best practices.
---
### 5.1 `FuchsFdsEmail` → `IEmailService`
**Current state:** Static class using `System.Configuration.ConfigurationManager` (legacy!) and receiving `Fuchs_intranet` as a parameter.
**Problem:** Uses `cfg.AppSettings["FDS_EmailSettings"]` — violates the project's own rule to not use `System.Configuration.ConfigurationManager`. Untestable. Static state (`_settings` cache).
**Proposed service:**
```csharp
public interface IEmailService
{
Task<bool> SendEmailAsync(string reference, string subject, string html,
string email, string name, Dictionary<string, byte[]>? attachments);
}
public class FuchsEmailService : IEmailService
{
private readonly EmailServerSettings _settings;
private readonly Fuchs_intranet _intranet;
// Inject IConfiguration, Fuchs_intranet, ILogger<FuchsEmailService>
}
```
**Registration:** `builder.Services.AddSingleton<IEmailService, FuchsEmailService>();`
**Files affected:** `Fuchs\code\FuchsFdsEmail.cs`, all callers in controller partials.
---
### 5.2 `FuchsPdf` → `IPdfService`
**Current state:** Large static class with static helper methods, hardcoded license key, company-specific constants.
**Problem:** Not injectable, not testable, mixes configuration (colors, company data) with PDF rendering logic.
**Proposed service:**
```csharp
public interface IPdfService
{
Document CreateInvoicePdf(FdsInvoiceData invoice);
Document CreateReminderPdf(FdsReminderData reminder);
Task<PdfImageCollection> DocToImageCollectionAsync(Document doc);
}
public class FuchsPdfService : IPdfService
{
// Inject ILogger<FuchsPdfService>
// Company data could come from IOptions<FuchsPdfOptions>
}
```
**Registration:** `builder.Services.AddSingleton<IPdfService, FuchsPdfService>();`
**Files affected:** `Fuchs\code\FuchsPdf.cs`, `FdsInvoiceData.cs`, `FdsReminderData.cs`, controller partials.
---
### 5.3 `FuchsWidgets` → `IWidgetService`
**Current state:** Static class that receives the entire `IntranetController` as a parameter to access `_intranet`, `UserAccountID`, `DbSec`, etc.
**Problem:** Tight coupling to controller — passes the whole controller instance. Cannot be unit tested independently.
**Proposed service:**
```csharp
public interface IWidgetService
{
Task<object> GetUserWidgetsAsync(string userAccountId, DatabaseSecurity dbSec);
Task<object> GetWidgetDataAsync(string widgetId, string userAccountId, DatabaseSecurity dbSec);
Task<object> GetSingleWidgetAsync(string shortName, string userAccountId, DatabaseSecurity dbSec);
}
public class FuchsWidgetService : IWidgetService
{
private readonly Fuchs_intranet _intranet;
// Inject Fuchs_intranet, ILogger<FuchsWidgetService>
}
```
**Registration:** `builder.Services.AddScoped<IWidgetService, FuchsWidgetService>();`
**Files affected:** `Fuchs\code\FuchsWidgets.cs`, `IntranetController.cs` (Do method).
---
### 5.4 `Banking` → `IBankingService`
**Current state:** Static class with MT940 parsing logic.
**Problem:** Minor — already fairly stateless, but takes `ILogger` as parameter instead of injection.
**Proposed service:**
```csharp
public interface IBankingService
{
DataTable ParseMT940(Stream stream, DataTable? schema = null);
}
public class BankingService : IBankingService
{
private readonly ILogger<BankingService> _logger;
// Inject ILogger
}
```
**Registration:** `builder.Services.AddSingleton<IBankingService, BankingService>();`
**Files affected:** `Fuchs\code\Banking.cs`, `IntranetController.Banking.cs`.
---
### 5.5 `FdsInvoiceData` / `FdsReminderData` → Factory Services
**Current state:** Data model classes that directly call stored procedures and PDF generation in their constructors/methods. They receive `IntranetController` as a parameter for DB access.
**Problem:** Business objects doing their own persistence (Active Record anti-pattern). Tightly coupled to controller.
**Proposed services:**
```csharp
public interface IInvoiceService
{
Task<FdsInvoiceData> LoadInvoiceAsync(string id, string userAccountId);
Task<string> RegisterInvoiceAsync(FdsInvoiceData invoice, bool change);
Task<Document> GenerateInvoicePdfAsync(FdsInvoiceData invoice);
}
public interface IReminderService
{
Task<FdsReminderData> LoadReminderAsync(string id, string userAccountId);
Task<string> RegisterReminderAsync(FdsReminderData reminder, bool change);
Task<Document> GenerateReminderPdfAsync(FdsReminderData reminder);
}
```
**Registration:** `builder.Services.AddScoped<IInvoiceService, InvoiceService>();`
**Files affected:** `FdsInvoiceData.cs`, `FdsReminderData.cs`, all controller partials that create these objects.
---
### 5.6 `FuchsReports` → `IReportService`
**Current state:** Static class with a single dispatch method, receives controller.
**Proposed service:**
```csharp
public interface IReportService
{
Task<IActionResult> ProcessRequestAsync(string action, string id,
string userAccountId, DatabaseSecurity dbSec);
}
```
---
### 5.7 `FdsMfrClient` → Injectable MFR Client
**Current state:** Created with `new FdsMfrClient()` directly in controller code (e.g., `IntranetController.Invoices2.cs` line 26). Uses static `FdsConfig` for credentials.
**Problem:** Cannot be mocked for testing. Credentials hardwired to static config.
**Proposed service:**
```csharp
public interface IMfrClientFactory
{
FdsMfrClient Create();
}
public class MfrClientFactory : IMfrClientFactory, IDisposable
{
private readonly ILoggerFactory _loggerFactory;
private readonly MFRClientCredentials _credentials;
// Inject ILoggerFactory, IOptions<MfrSettings>
}
```
**Registration:** `builder.Services.AddSingleton<IMfrClientFactory, MfrClientFactory>();`
**Files affected:** `FdsMfrClient.cs`, `IntranetController.Invoices2.cs`, any code doing `new FdsMfrClient()`.
---
### 5.8 `Fuchs_intranet` — Decompose the God Object
**Current state:** Single class handling configuration, DB connections, authentication, module auth queries, debug logging, and PDF licensing.
**Recommended split:**
| Responsibility | Proposed Service | Lifetime |
|---|---|---|
| Configuration (conn strings, app settings) | `IOptions<FuchsSettings>` | Singleton |
| DB connection factory | `IDbConnectionFactory` | Singleton |
| User authentication | `IAuthenticationService` | Scoped |
| Module authorization | `IAuthorizationService` (custom) | Scoped |
| Debug/error logging | Use built-in `ILogger<T>` | — |
---
## 6. Priority Ranking
| Priority | Candidate | Impact | Effort |
|---|---|---|---|
| 🔴 **1** | `FuchsFdsEmail``IEmailService` | Fixes `ConfigurationManager` violation, high testability gain | Low |
| 🔴 **2** | `FuchsWidgets``IWidgetService` | Removes controller coupling | Low |
| 🟡 **3** | `FdsMfrClient``IMfrClientFactory` | Removes `new` in controllers, enables mocking | Medium |
| 🟡 **4** | `Banking``IBankingService` | Clean DI pattern, minor effort | Low |
| 🟡 **5** | `FuchsPdf``IPdfService` | Large file, significant but high-value refactor | Medium |
| 🟠 **6** | `FdsInvoiceData`/`FdsReminderData` → Services | Major architectural improvement, most effort | High |
| 🟠 **7** | `Fuchs_intranet` decomposition | God-object split, foundational but risky | High |
| 🟢 **8** | `FuchsReports``IReportService` | Minimal current logic, prep for future | Low |
---
## 7. Additional Observations
1. **`System.Configuration.ConfigurationManager` usage** in `FuchsFdsEmail.cs` directly violates the project's coding standards (`appsettings.json` only).
2. **No dependency injection in `FdsInvoiceData`/`FdsReminderData`** — these classes receive the entire controller, creating circular-style dependencies.
3. **`FdsMfrClient` is `new`-ed directly** in controller partials (e.g., `IntranetController.Invoices2.cs`) instead of being injected.
4. **`OCORE_Charting`** is in the solution but not directly referenced by any project — verify if it's still needed.
5. **Topshelf** in `Fuchs_DataService` could be replaced with native `dotnet` Worker Service hosting for .NET 10 alignment.
+96
View File
@@ -0,0 +1,96 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>Fuchs</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Configurations>db-dev.processweb.de;Debug;Release;server02.processweb.de</Configurations>
<NoWarn>CA1416</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\WebProjectComponents\MT940Parser\MT940Parser\MT940Parser.csproj" />
<ProjectReference Include="..\..\..\WebProjectComponents\OCORE_web\OCORE_web.csproj" />
<ProjectReference Include="..\..\..\WebProjectComponents\OCORE\OCORE\OCORE.csproj" />
<ProjectReference Include="..\Fuchs_DataService\Fuchs_DataService.csproj" />
<ProjectReference Include="..\MFR_RESTClient\MFR_RESTClient.csproj" />
<ProjectReference Include="..\..\..\WebProjectComponents\OCORE_web_pdf\OCORE_web_pdf.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="code\7z.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="Data\**" CopyToOutputDirectory="PreserveNewest" />
<Content Include="favicon.ico" />
</ItemGroup>
<ItemGroup>
<!-- Compatible packages (kept) -->
<PackageReference Include="BouncyCastle" Version="1.8.9" />
<PackageReference Include="HtmlAgilityPack" Version="1.12.4" />
<PackageReference Include="MailKit" Version="4.16.0" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="QRCoder" Version="1.8.0" />
<PackageReference Include="PDFsharp" Version="6.2.4" />
<PackageReference Include="PDFsharp-MigraDoc" Version="6.2.4" />
<PackageReference Include="Spire.PDF" Version="[8.10.5,8.10.5]" allowedVersions="[8.10.5,8.10.5]" />
<PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.2.24" />
<!-- Updated packages -->
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" />
<PackageReference Include="MimeKit" Version="4.16.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<!-- New packages (needed for .NET 10) -->
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.0.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="10.0.6" />
<PackageReference Include="System.Drawing.Common" Version="10.0.6" />
</ItemGroup>
<ItemGroup>
<Folder Include="App_Data\cache\" />
<Folder Include="Models\" />
<Folder Include="wwwroot\lib\tinymce\" />
</ItemGroup>
<!-- UsingTask für plattformneutrales Zippen nach Publish -->
<UsingTask TaskName="ZipDir" TaskFactory="CodeTaskFactory" AssemblyName="Microsoft.Build.Tasks.Core">
<ParameterGroup>
<Source ParameterType="System.String" Required="true" />
<Destination ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Code Type="Fragment" Language="cs">
<![CDATA[
if (System.IO.File.Exists(Destination)) {
Log.LogMessage("Deleting existing zip " + Destination);
System.IO.File.Delete(Destination);
}
// Verwende CompressionLevel.Optimal für Kompatibilität mit älteren .NET Framework Hosts (SmallestSize evtl. nicht vorhanden)
System.IO.Compression.ZipFile.CreateFromDirectory(Source, Destination, System.IO.Compression.CompressionLevel.Optimal, false);
Log.LogMessage("Created zip: " + Destination);
return true;
]]>
</Code>
</Task>
</UsingTask>
<Target Name="ZipPublish" AfterTargets="Publish">
<!-- Zeitstempel im UTC Format -->
<PropertyGroup>
<_ZipStamp>$([System.DateTime]::UtcNow.ToString("yyyyMMdd_HHmmss"))</_ZipStamp>
<!-- Immer das aktuelle Publish-Ergebnis zippen (PublishDir/PubTmp\Out), nicht das Zielverzeichnis vom Profil -->
<_SourceDir>$([System.IO.Path]::GetFullPath('$(PublishDir)'))</_SourceDir>
<!-- ZIP nach Möglichkeit neben dem Zielordner aus dem Publish-Profil ablegen, sonst neben PublishDir -->
<_ZipOutputDir Condition="'$(PublishUrl)' != ''">$([System.IO.Path]::GetFullPath('$(PublishUrl)\..\'))</_ZipOutputDir>
<_ZipOutputDir Condition="'$(_ZipOutputDir)' == ''">$([System.IO.Path]::GetFullPath('$(_SourceDir)\..\'))</_ZipOutputDir>
<_ZipFileName>$(MSBuildProjectName)-publish-$(_ZipStamp).zip</_ZipFileName>
<_ZipPath>$(_ZipOutputDir)$(_ZipFileName)</_ZipPath>
</PropertyGroup>
<MakeDir Directories="$(_ZipOutputDir)" />
<Message Text="Zipping final publish output '$(_SourceDir)' to '$(_ZipPath)'" Importance="High" />
<ZipDir Source="$(_SourceDir)" Destination="$(_ZipPath)" />
</Target>
</Project>
+1
View File
@@ -0,0 +1 @@
<%@ Application Codebehind="Global.asax.vb" Inherits="Fuchs.MvcApplication" Language="VB" %>
+117
View File
@@ -0,0 +1,117 @@
using Microsoft.Extensions.Logging;
using System.Diagnostics;
namespace Fuchs.Logging;
/// <summary>
/// Writes log entries to Debug output and a rolling file.
/// Database logging is wired up but disabled — set <see cref="DatabaseLoggingEnabled"/> to true to activate.
/// </summary>
public sealed class FuchsLoggerProvider : ILoggerProvider
{
private readonly string _logDirectory;
/// <summary>Set to true to activate database logging via the Fuchs admin log procedure.</summary>
public static bool DatabaseLoggingEnabled { get; set; } = false;
public FuchsLoggerProvider(string? logDirectory = null)
{
_logDirectory = logDirectory
?? Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
Directory.CreateDirectory(_logDirectory);
}
public ILogger CreateLogger(string categoryName) =>
new FuchsLogger(categoryName, _logDirectory);
public void Dispose() { }
}
internal sealed class FuchsLogger : ILogger
{
private readonly string _categoryName;
private readonly string _logDirectory;
private static readonly Lock _fileLock = new();
internal FuchsLogger(string categoryName, string logDirectory)
{
_categoryName = categoryName;
_logDirectory = logDirectory;
}
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;
public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
Exception? exception, Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel)) return;
string message = formatter(state, exception);
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
string levelTag = logLevel switch
{
LogLevel.Trace => "TRC",
LogLevel.Debug => "DBG",
LogLevel.Information => "INF",
LogLevel.Warning => "WRN",
LogLevel.Error => "ERR",
LogLevel.Critical => "CRT",
_ => "???"
};
string line = $"{timestamp} [{levelTag}] {_categoryName}: {message}";
if (exception != null)
line += $"\r\n Exception: {exception.Message}\r\n Stack: {exception.StackTrace}";
// Always emit to Debug output
Debug.WriteLine(line);
// Write to file
string filename = logLevel >= LogLevel.Error ? "ErrorLog.txt" : "AppLog.txt";
AppendToFile(filename, line);
// Database logging — prepared, not activated
if (FuchsLoggerProvider.DatabaseLoggingEnabled)
WriteToDatabase(_categoryName, message, exception);
}
private void AppendToFile(string filename, string line)
{
try
{
lock (_fileLock)
File.AppendAllText(Path.Combine(_logDirectory, filename), line + "\r\n");
}
catch { /* never throw from logger */ }
}
/// <summary>
/// Prepared DB logging for the Fuchs web project.
/// Enable by setting <see cref="FuchsLoggerProvider.DatabaseLoggingEnabled"/> = true in Program.cs or appsettings.
/// </summary>
private static void WriteToDatabase(string codeReference, string message, Exception? exception)
{
// Activate by setting FuchsLoggerProvider.DatabaseLoggingEnabled = true.
//
// using var con = new Microsoft.Data.SqlClient.SqlConnection(/* Fuchs connection string */);
// using var cmd = new Microsoft.Data.SqlClient.SqlCommand(
// "EXECUTE [dbo].[fuchs__admin_logdebug] @CodeReference, @ExceptionMessage, @StackTrace, @Data;", con);
// cmd.Parameters.AddWithValue("@CodeReference", codeReference);
// cmd.Parameters.AddWithValue("@ExceptionMessage", (object?)exception?.Message ?? DBNull.Value);
// cmd.Parameters.AddWithValue("@StackTrace", (object?)exception?.StackTrace ?? DBNull.Value);
// cmd.Parameters.AddWithValue("@Data", message);
// con.Open();
// cmd.ExecuteNonQuery();
}
}
public static class FuchsLoggingExtensions
{
public static ILoggingBuilder AddFuchsLogging(this ILoggingBuilder builder, string? logDirectory = null)
{
builder.AddProvider(new FuchsLoggerProvider(logDirectory));
return builder;
}
}
+116
View File
@@ -0,0 +1,116 @@
using Fuchs.intranet;
using Fuchs.Logging;
using Fuchs.Services;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using OCORE.security;
using OCORE.web;
namespace Fuchs;
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
ConfigureServices(builder);
var app = builder.Build();
ConfigureApp(app);
app.Run();
}
private static void ConfigureServices(WebApplicationBuilder builder)
{
// Custom logging: Debug output + file; DB logging prepared but not activated
builder.Logging
.SetMinimumLevel(LogLevel.Debug)
.AddFuchsLogging();
// Initialize the Fuchs intranet singleton with configuration
FuchsOcmsIntranet.Initialize(builder.Configuration);
// Initialize FdsConfig so FdsMfr / FdsMfrClient can resolve connection strings
fds.FdsConfig.Initialize();
// FDS MFR singleton — ILogger<FdsMfr> and ILoggerFactory are supplied by the ASP.NET Core DI container
builder.Services.AddSingleton<fds.IFdsMfr, fds.FdsMfr>();
// MVC with Razor view support
builder.Services.AddControllersWithViews();
// Fuchs intranet singleton
builder.Services.AddSingleton(_ => FuchsOcmsIntranet.Instance);
// Distributed cache (required by OCORE controller base)
builder.Services.AddDistributedMemoryCache();
// Cookie authentication for the Fuchs intranet
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = Fuchs_intranet.AuthScheme;
options.DefaultChallengeScheme = Fuchs_intranet.AuthScheme;
})
.AddCookie(Fuchs_intranet.AuthScheme, options =>
{
options.Cookie.Name = FuchsOcmsIntranet.Instance.Intranet__cookiename;
options.LoginPath = "/login";
options.AccessDeniedPath = "/denied";
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromHours(8);
options.Events = new OCORECookieAuthenticationEvents(
api_paths: new[] { new[] { "/do" } },
xhr_paths: Array.Empty<string[]>());
});
builder.Services.AddAuthorization();
builder.Services.AddHttpContextAccessor();
// Email service
builder.Services.Configure<FuchsEmailSettings>(builder.Configuration.GetSection("Fuchs:Email"));
builder.Services.AddScoped<IEmailService, FuchsEmailService>();
}
private static void ConfigureApp(WebApplication app)
{
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// Serve the gulp-built assets from the project-level web/ folder at /web
var webFolder = Path.Combine(app.Environment.ContentRootPath, "web");
if (Directory.Exists(webFolder))
{
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(webFolder),
RequestPath = "/web",
ContentTypeProvider = new FileExtensionContentTypeProvider()
});
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
// Intranet routes (root-level — this IS the website)
app.MapControllerRoute(
name: "intranet-do",
pattern: "do/{fn?}/{id?}/{code?}",
defaults: new { controller = "Intranet", action = "Do" });
app.MapControllerRoute(
name: "intranet-index",
pattern: "{fn?}/{id?}/{code?}",
defaults: new { controller = "Intranet", action = "Index" });
// One-time application start
Fuchs_intranet.SetPdfLicense();
}
}
+12
View File
@@ -0,0 +1,12 @@
{
"profiles": {
"Fuchs": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:63661;http://localhost:63662"
}
}
}
File diff suppressed because it is too large Load Diff
+10716
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+1661
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+746
View File
@@ -0,0 +1,746 @@
/**
* @license
* Unobtrusive validation support library for jQuery and jQuery Validate
* Copyright (c) .NET Foundation. All rights reserved.
* Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
* @version v4.0.0
*/
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global document: false, jQuery: false */
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define("jquery.validate.unobtrusive", ['jquery-validation'], factory);
} else if (typeof module === 'object' && module.exports) {
// CommonJS-like environments that support module.exports
module.exports = factory(require('jquery-validation'));
} else {
// Browser global
jQuery.validator.unobtrusive = factory(jQuery);
}
}(function ($) {
var $jQval = $.validator,
adapters,
data_validation = "unobtrusiveValidation";
function setValidationValues(options, ruleName, value) {
options.rules[ruleName] = value;
if (options.message) {
options.messages[ruleName] = options.message;
}
}
function splitAndTrim(value) {
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
}
function escapeAttributeValue(value) {
// As mentioned on http://api.jquery.com/category/selectors/
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
}
function getModelPrefix(fieldName) {
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}
function appendModelPrefix(value, prefix) {
if (value.indexOf("*.") === 0) {
value = value.replace("*.", prefix);
}
return value;
}
function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
}
function onErrors(event, validator) { // 'this' is the form element
var container = $(this).find("[data-valmsg-summary=true]"),
list = container.find("ul");
if (list && list.length && validator.errorList.length) {
list.empty();
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
$.each(validator.errorList, function () {
$("<li />").html(this.message).appendTo(list);
});
}
}
function onSuccess(error) { // 'this' is the form element
var container = error.data("unobtrusiveContainer");
if (container) {
var replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
container.addClass("field-validation-valid").removeClass("field-validation-error");
error.removeData("unobtrusiveContainer");
if (replace) {
container.empty();
}
}
}
function onReset(event) { // 'this' is the form element
var $form = $(this),
key = '__jquery_unobtrusive_validation_form_reset';
if ($form.data(key)) {
return;
}
// Set a flag that indicates we're currently resetting the form.
$form.data(key, true);
try {
$form.data("validator").resetForm();
} finally {
$form.removeData(key);
}
$form.find(".validation-summary-errors")
.addClass("validation-summary-valid")
.removeClass("validation-summary-errors");
$form.find(".field-validation-error")
.addClass("field-validation-valid")
.removeClass("field-validation-error")
.removeData("unobtrusiveContainer")
.find(">*") // If we were using valmsg-replace, get the underlying error
.removeData("unobtrusiveContainer");
}
function validationInfo(form) {
var $form = $(form),
result = $form.data(data_validation),
onResetProxy = $.proxy(onReset, form),
defaultOptions = $jQval.unobtrusive.options || {},
execInContext = function (name, args) {
var func = defaultOptions[name];
func && $.isFunction(func) && func.apply(form, args);
};
if (!result) {
result = {
options: { // options structure passed to jQuery Validate's validate() method
errorClass: defaultOptions.errorClass || "input-validation-error",
errorElement: defaultOptions.errorElement || "span",
errorPlacement: function () {
onError.apply(form, arguments);
execInContext("errorPlacement", arguments);
},
invalidHandler: function () {
onErrors.apply(form, arguments);
execInContext("invalidHandler", arguments);
},
messages: {},
rules: {},
success: function () {
onSuccess.apply(form, arguments);
execInContext("success", arguments);
}
},
attachValidation: function () {
$form
.off("reset." + data_validation, onResetProxy)
.on("reset." + data_validation, onResetProxy)
.validate(this.options);
},
validate: function () { // a validation function that is called by unobtrusive Ajax
$form.validate();
return $form.valid();
}
};
$form.data(data_validation, result);
}
return result;
}
$jQval.unobtrusive = {
adapters: [],
parseElement: function (element, skipAttach) {
/// <summary>
/// Parses a single HTML element for unobtrusive validation attributes.
/// </summary>
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
/// validation to the form. If parsing just this single element, you should specify true.
/// If parsing several elements, you should specify false, and manually attach the validation
/// to the form when you are finished. The default is false.</param>
var $element = $(element),
form = $element.parents("form")[0],
valInfo, rules, messages;
if (!form) { // Cannot do client-side validation without a form
return;
}
valInfo = validationInfo(form);
valInfo.options.rules[element.name] = rules = {};
valInfo.options.messages[element.name] = messages = {};
$.each(this.adapters, function () {
var prefix = "data-val-" + this.name,
message = $element.attr(prefix),
paramValues = {};
if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
prefix += "-";
$.each(this.params, function () {
paramValues[this] = $element.attr(prefix + this);
});
this.adapt({
element: element,
form: form,
message: message,
params: paramValues,
rules: rules,
messages: messages
});
}
});
$.extend(rules, { "__dummy__": true });
if (!skipAttach) {
valInfo.attachValidation();
}
},
parse: function (selector) {
/// <summary>
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
/// attribute values.
/// </summary>
/// <param name="selector" type="String">Any valid jQuery selector.</param>
// $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
// element with data-val=true
var $selector = $(selector),
$forms = $selector.parents()
.addBack()
.filter("form")
.add($selector.find("form"))
.has("[data-val=true]");
$selector.find("[data-val=true]").each(function () {
$jQval.unobtrusive.parseElement(this, true);
});
$forms.each(function () {
var info = validationInfo(this);
if (info) {
info.attachValidation();
}
});
}
};
adapters = $jQval.unobtrusive.adapters;
adapters.add = function (adapterName, params, fn) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
/// mmmm is the parameter name).</param>
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
/// attributes into jQuery Validate rules and/or messages.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
if (!fn) { // Called with no params, just a function
fn = params;
params = [];
}
this.push({ name: adapterName, params: params, adapt: fn });
return this;
};
adapters.addBool = function (adapterName, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has no parameter values.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, function (options) {
setValidationValues(options, ruleName || adapterName, true);
});
};
adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a minimum value.</param>
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a maximum value.</param>
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
/// have both a minimum and maximum value.</param>
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the minimum value. The default is "min".</param>
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the maximum value. The default is "max".</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
var min = options.params.min,
max = options.params.max;
if (min && max) {
setValidationValues(options, minMaxRuleName, [min, max]);
}
else if (min) {
setValidationValues(options, minRuleName, min);
}
else if (max) {
setValidationValues(options, maxRuleName, max);
}
});
};
adapters.addSingleVal = function (adapterName, attribute, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has a single value.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
/// The default is "val".</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [attribute || "val"], function (options) {
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
});
};
$jQval.addMethod("__dummy__", function (value, element, params) {
return true;
});
$jQval.addMethod("regex", function (value, element, params) {
var match;
if (this.optional(element)) {
return true;
}
match = new RegExp(params).exec(value);
return (match && (match.index === 0) && (match[0].length === value.length));
});
$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
var match;
if (nonalphamin) {
match = value.match(/\W/g);
match = match && match.length >= nonalphamin;
}
return match;
});
if ($jQval.methods.extension) {
adapters.addSingleVal("accept", "mimtype");
adapters.addSingleVal("extension", "extension");
} else {
// for backward compatibility, when the 'extension' validation method does not exist, such as with versions
// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
// validating the extension, and ignore mime-type validations as they are not supported.
adapters.addSingleVal("extension", "extension", "accept");
}
adapters.addSingleVal("regex", "pattern");
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
adapters.add("equalto", ["other"], function (options) {
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
setValidationValues(options, "equalTo", element);
});
adapters.add("required", function (options) {
// jQuery Validate equates "required" with "mandatory" for checkbox elements
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
setValidationValues(options, "required", true);
}
});
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
var value = {
url: options.params.url,
type: options.params.type || "GET",
data: {}
},
prefix = getModelPrefix(options.element.name);
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
var paramName = appendModelPrefix(fieldName, prefix);
value.data[paramName] = function () {
var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
// For checkboxes and radio buttons, only pick up values from checked fields.
if (field.is(":checkbox")) {
return field.filter(":checked").val() || field.filter(":hidden").val() || '';
}
else if (field.is(":radio")) {
return field.filter(":checked").val() || '';
}
return field.val();
};
});
setValidationValues(options, "remote", value);
});
adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
if (options.params.min) {
setValidationValues(options, "minlength", options.params.min);
}
if (options.params.nonalphamin) {
setValidationValues(options, "nonalphamin", options.params.nonalphamin);
}
if (options.params.regex) {
setValidationValues(options, "regex", options.params.regex);
}
});
adapters.add("fileextensions", ["extensions"], function (options) {
setValidationValues(options, "extension", options.params.extensions);
});
$(function () {
$jQval.unobtrusive.parse(document);
});
return $jQval.unobtrusive;
}));
// SIG // Begin signature block
// SIG // MIInnwYJKoZIhvcNAQcCoIInkDCCJ4wCAQExDzANBglg
// SIG // hkgBZQMEAgEFADB3BgorBgEEAYI3AgEEoGkwZzAyBgor
// SIG // BgEEAYI3AgEeMCQCAQEEEBDgyQbOONQRoqMAEEvTUJAC
// SIG // AQACAQACAQACAQACAQAwMTANBglghkgBZQMEAgEFAAQg
// SIG // pCPo0ZtVE24ghUz4BvttWNOJo2KI5p4X9KD+kCoh/Q+g
// SIG // gg2BMIIF/zCCA+egAwIBAgITMwAAAlKLM6r4lfM52wAA
// SIG // AAACUjANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV
// SIG // UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
// SIG // UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
// SIG // cmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBT
// SIG // aWduaW5nIFBDQSAyMDExMB4XDTIxMDkwMjE4MzI1OVoX
// SIG // DTIyMDkwMTE4MzI1OVowdDELMAkGA1UEBhMCVVMxEzAR
// SIG // BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
// SIG // bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
// SIG // bjEeMBwGA1UEAxMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
// SIG // MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
// SIG // 0OTPj7P1+wTbr+Qf9COrqA8I9DSTqNSq1UKju4IEV3HJ
// SIG // Jck61i+MTEoYyKLtiLG2Jxeu8F81QKuTpuKHvi380gzs
// SIG // 43G+prNNIAaNDkGqsENQYo8iezbw3/NCNX1vTi++irdF
// SIG // qXNs6xoc3B3W+7qT678b0jTVL8St7IMO2E7d9eNdL6RK
// SIG // fMnwRJf4XfGcwL+OwwoCeY9c5tvebNUVWRzaejKIkBVT
// SIG // hApuAMCtpdvIvmBEdSTuCKZUx+OLr81/aEZyR2jL1s2R
// SIG // KaMz8uIzTtgw6m3DbOM4ewFjIRNT1hVQPghyPxJ+ZwEr
// SIG // wry5rkf7fKuG3PF0fECGSUEqftlOptpXTQIDAQABo4IB
// SIG // fjCCAXowHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYB
// SIG // BQUHAwMwHQYDVR0OBBYEFDWSWhFBi9hrsLe2TgLuHnxG
// SIG // F3nRMFAGA1UdEQRJMEekRTBDMSkwJwYDVQQLEyBNaWNy
// SIG // b3NvZnQgT3BlcmF0aW9ucyBQdWVydG8gUmljbzEWMBQG
// SIG // A1UEBRMNMjMwMDEyKzQ2NzU5NzAfBgNVHSMEGDAWgBRI
// SIG // bmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmg
// SIG // R6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtp
// SIG // b3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDct
// SIG // MDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcw
// SIG // AoZFaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w
// SIG // cy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDct
// SIG // MDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEL
// SIG // BQADggIBABZJN7ksZExAYdTbQJewYryBLAFnYF9amfhH
// SIG // WTGG0CmrGOiIUi10TMRdQdzinUfSv5HHKZLzXBpfA+2M
// SIG // mEuJoQlDAUflS64N3/D1I9/APVeWomNvyaJO1mRTgJoz
// SIG // 0TTRp8noO5dJU4k4RahPtmjrOvoXnoKgHXpRoDSSkRy1
// SIG // kboRiriyMOZZIMfSsvkL2a5/w3YvLkyIFiqfjBhvMWOj
// SIG // wb744LfY0EoZZz62d1GPAb8Muq8p4VwWldFdE0y9IBMe
// SIG // 3ofytaPDImq7urP+xcqji3lEuL0x4fU4AS+Q7cQmLq12
// SIG // 0gVbS9RY+OPjnf+nJgvZpr67Yshu9PWN0Xd2HSY9n9xi
// SIG // au2OynVqtEGIWrSoQXoOH8Y4YNMrrdoOmjNZsYzT6xOP
// SIG // M+h1gjRrvYDCuWbnZXUcOGuOWdOgKJLaH9AqjskxK76t
// SIG // GI6BOF6WtPvO0/z1VFzan+2PqklO/vS7S0LjGEeMN3Ej
// SIG // 47jbrLy3/YAZ3IeUajO5Gg7WFg4C8geNhH7MXjKsClsA
// SIG // Pk1YtB61kan0sdqJWxOeoSXBJDIzkis97EbrqRQl91K6
// SIG // MmH+di/tolU63WvF1nrDxutjJ590/ALi383iRbgG3zkh
// SIG // EceyBWTvdlD6FxNbhIy+bJJdck2QdzLm4DgOBfCqETYb
// SIG // 4hQBEk/pxvHPLiLG2Xm9PEnmEDKo1RJpMIIHejCCBWKg
// SIG // AwIBAgIKYQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCB
// SIG // iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
// SIG // b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p
// SIG // Y3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWlj
// SIG // cm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
// SIG // IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw
// SIG // OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
// SIG // aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
// SIG // ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQD
// SIG // Ex9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDEx
// SIG // MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
// SIG // q/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4Bjga
// SIG // BEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSH
// SIG // fpRgJGyvnkmc6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpg
// SIG // GgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpc
// SIG // oRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnn
// SIG // Db6gE3e+lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD
// SIG // 2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLT
// SIG // swM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOE
// SIG // y/S6A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2
// SIG // z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
// SIG // A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL
// SIG // 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uD
// SIG // jexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmnEyim
// SIG // p31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8Hh
// SIG // hUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX
// SIG // 3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0wggHpMBAG
// SIG // CSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXT
// SIG // gqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMA
// SIG // dQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
// SIG // AwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx
// SIG // 0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3Js
// SIG // Lm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9N
// SIG // aWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4G
// SIG // CCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDov
// SIG // L3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNS
// SIG // b29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
// SIG // HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF
// SIG // BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3Br
// SIG // aW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsGAQUF
// SIG // BwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5
// SIG // AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3
// SIG // DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKbC5YR4WOS
// SIG // mUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np
// SIG // 22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r
// SIG // 4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6I/MTfaaQdION
// SIG // 9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWlu
// SIG // WpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiX
// SIG // mE0OPQvyCInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ
// SIG // 2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNA
// SIG // BQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPD
// SIG // XVJihsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yH
// SIG // PgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
// SIG // XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS
// SIG // oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5
// SIG // GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33VtY5E9
// SIG // 0Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZO
// SIG // SEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCGXYw
// SIG // ghlyAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQI
// SIG // EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
// SIG // HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAm
// SIG // BgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENB
// SIG // IDIwMTECEzMAAAJSizOq+JXzOdsAAAAAAlIwDQYJYIZI
// SIG // AWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQB
// SIG // gjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcC
// SIG // ARUwLwYJKoZIhvcNAQkEMSIEIDci2fDjH7Gssy4BSZv2
// SIG // cxpXQvfdFVJ8kyBVKwl9Y0wPMEIGCisGAQQBgjcCAQwx
// SIG // NDAyoBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRw
// SIG // Oi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
// SIG // BQAEggEAWH2w+r+Zm+c6mT22Vp1iM+cW4XJ8BoVIbsCv
// SIG // VpcZM46wD8Xc0OnjNJD8UKWgxXLkYYFVjCTrS64rlJWL
// SIG // 07lbJwtTHSwUYD54BHkR1nMOAQw190HJAGeO/d1NtFsG
// SIG // 5iJcMjCrgJ81YqRH2ruY9lGqE3SSYTeU0WviooG5THzj
// SIG // bjfV8vqP2tFhJ+/QEkXWmofwF4qZOwJTMvtiAoOBG0km
// SIG // npwqcjvEIGVP7W30+7d74QZ5ZjrllD7xuS1Xk+hHAt7Q
// SIG // vqKgKOoBUQKTE8KVsuLt49BGHkSpm/WCH19uqqqBHYpr
// SIG // jJPgU3CRiesy3KjerWz8vmLuRsY2ZnzosYC0OsBYNaGC
// SIG // FwAwghb8BgorBgEEAYI3AwMBMYIW7DCCFugGCSqGSIb3
// SIG // DQEHAqCCFtkwghbVAgEDMQ8wDQYJYIZIAWUDBAIBBQAw
// SIG // ggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYK
// SIG // KwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUABCBpx5RV
// SIG // iZSiuYGcUqppKrwAEbGsdZolX0MmvzBca/ZckQIGYs/1
// SIG // J/IsGBMyMDIyMDcxOTIzMTcxMy41NTRaMASAAgH0oIHQ
// SIG // pIHNMIHKMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
// SIG // aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
// SIG // ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQL
// SIG // ExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMSYw
// SIG // JAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpERDhDLUUzMzct
// SIG // MkZBRTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3Rh
// SIG // bXAgU2VydmljZaCCEVcwggcMMIIE9KADAgECAhMzAAAB
// SIG // nA+mTWHSnksoAAEAAAGcMA0GCSqGSIb3DQEBCwUAMHwx
// SIG // CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
// SIG // MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
// SIG // b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jv
// SIG // c29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTIxMTIw
// SIG // MjE5MDUxOVoXDTIzMDIyODE5MDUxOVowgcoxCzAJBgNV
// SIG // BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
// SIG // VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
// SIG // Q29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBB
// SIG // bWVyaWNhIE9wZXJhdGlvbnMxJjAkBgNVBAsTHVRoYWxl
// SIG // cyBUU1MgRVNOOkREOEMtRTMzNy0yRkFFMSUwIwYDVQQD
// SIG // ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIC
// SIG // IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA21Iq
// SIG // DBldSRY/rOtdrNNpirttyj1DbO9Tow3iRrcZExfa0lk4
// SIG // rgPF4GJAAIv+fthX+wpOyXCkPR/1w9TisINf2x9xNajt
// SIG // c/F0ctD5aRoZsopYBOyrDr1vDyGQn9uNynZXYDq8ay/B
// SIG // yokKHTsErck+ZS1mKTLLk9nx/JPKIoY3uE5aVohT2gii
// SIG // 5xQ2gAdAnMuryHbR42AdSHt4jmT4rKri/rzXQse4DoQf
// SIG // Iok5k3bFPDklKQvLQU3kyGD85oWsUGXeJqDZOqngicou
// SIG // 34luH8l3R62d6LZoMcWuaV8+aVFK/nBI1fnMCGATJGmO
// SIG // ZBzPXOnRBpIB59GQyb3bf+eBTnUhutVsB4ePnr1IcL12
// SIG // geCwjGSHQreWnDnzb7Q41dwh8hTqeQFP6oAMBn7R1PW6
// SIG // 7+BFMHLrXhACh+OjbnxNtJf1o5TVIe4AL7dsyjIzuM10
// SIG // cQlE4f6awUMFyYlGXhUqxF4jn5Lr0pQZ4sgGGGaeZDp2
// SIG // sXwinRmI76+ECwPd70CeqdjsdyB7znQj2gq/C7ClXBac
// SIG // qfDBIYSUzPtS8KhyahQxeTtWfZo22L5t0fbz4ZBvkQyy
// SIG // qE6a+5k4JGk5Y3fcb5veDm6fAQ/R5OJj4udZrYC4rjfP
// SIG // +mmVRElWV7b0rjZA+Q5yCUHqyMuY2kSlv1tqwnvZ4DQy
// SIG // WnUu0fehhkZeyCBN+5cCAwEAAaOCATYwggEyMB0GA1Ud
// SIG // DgQWBBS7aQlnU12OXbXXZLKcvqMYwgP6sjAfBgNVHSME
// SIG // GDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNVHR8E
// SIG // WDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
// SIG // b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0
// SIG // YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUH
// SIG // AQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1p
// SIG // Y3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29m
// SIG // dCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNy
// SIG // dDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUF
// SIG // BwMIMA0GCSqGSIb3DQEBCwUAA4ICAQCnACqmIxhHM01j
// SIG // LPc9Ju2KNt7IKlRdy8iuoDjM+0whwCTfhb272ZEOd1ZL
// SIG // 62VHdbBOmvU6BpXXCZzpgXOoroQZab3TdQSwUTvEEkw9
// SIG // eN91U4+FwkHe9+8DQ9fnqihtwXY682w5LBMHxuL+ez4K
// SIG // zf0+7Oz5BI1Bl3yIBUEJK/E0Ivvx2WfZEZTXHIHgAqpX
// SIG // 2+Lhj8Z+bHYUD6MXTL5gt6hvQzjSeVLEvSrTvm3svqIV
// SIG // Ew2vS7xE6HOEM8uX7h49h9SbJgmihu/J16X1qcASwcWW
// SIG // EqX5pdvaJzfI3Buyg/Jxkkv++jw5W9hjELL7/kWtCYC+
// SIG // hbRkRoGJhwqTOs1a3+Ff2vkqB3AvrXHRmJNmilOSjpb/
// SIG // nxRN59NuFfs+eLQwCkfc+/K3o3QgVqn78uXAVEPXOft7
// SIG // pxw9PARKe6j9q4KaA/OerzQ4BMDu+5+xFk++p5fyMq2y
// SIG // tpI2xy81DKYRaVyp1dX2FiSNvhP9Cx71xRhqheDrzAUc
// SIG // W6yVZ9N09g8uXW+rOU8yc0mkLwq12KgOByr7LUFpKpKb
// SIG // wR01/DNPfv78kW1Vzcaz3Xl8OqA9kOA5LMpAhX5/Ddo9
// SIG // i3YsRPcBuYopb+vXc7LxyDf4PQPfrYZAEAlW/Q1Ejk2j
// SIG // CBoLDqg2BY4U+s3vZZIRxxr/xBCJMY/ZekuIalEMlnqx
// SIG // ZGlFg13J2TCCB3EwggVZoAMCAQICEzMAAAAVxedrngKb
// SIG // SZkAAAAAABUwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNV
// SIG // BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
// SIG // VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
// SIG // Q29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBS
// SIG // b290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4X
// SIG // DTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDEL
// SIG // MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
// SIG // EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv
// SIG // c29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z
// SIG // b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqG
// SIG // SIb3DQEBAQUAA4ICDwAwggIKAoICAQDk4aZM57RyIQt5
// SIG // osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25
// SIG // PhdgM/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLA
// SIG // EBjoYH1qUoNEt6aORmsHFPPFdvWGUNzBRMhxXFExN6AK
// SIG // OG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
// SIG // GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v
// SIG // 3byNpOORj7I5LFGc6XBpDco2LXCOMcg1KL3jtIckw+DJ
// SIG // j361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50ZuyjLV
// SIG // wIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4d
// SIG // Pf0gz3N9QZpGdc3EXzTdEonW/aUgfX782Z5F37ZyL9t9
// SIG // X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0lBw0gg/w
// SIG // EPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8Qmgu
// SIG // EOqEUUbi0b1qGFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoS
// SIG // CtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ+QuJYfM2BjUY
// SIG // hEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435
// SIG // UsSFF5PAPBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57
// SIG // t7c+auIurQIDAQABo4IB3TCCAdkwEgYJKwYBBAGCNxUB
// SIG // BAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6C
// SIG // kTxGNSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl
// SIG // 0mWnG1M1GelyMFwGA1UdIARVMFMwUQYMKwYBBAGCN0yD
// SIG // fQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
// SIG // cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5
// SIG // Lmh0bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkrBgEE
// SIG // AYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYw
// SIG // DwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbL
// SIG // j+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEugSaBH
// SIG // hkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
// SIG // bC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0y
// SIG // My5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAC
// SIG // hj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2Nl
// SIG // cnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDAN
// SIG // BgkqhkiG9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvh
// SIG // nnJL/Klv6lwUtj5OR2R4sQaTlz0xM7U518JxNj/aZGx8
// SIG // 0HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYu
// SIG // nKmCVgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5t
// SIG // ggz1bSNU5HhTdSRXud2f8449xvNo32X2pFaq95W2KFUn
// SIG // 0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
// SIG // nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU
// SIG // 6ZGyqVvfSaN0DLzskYDSPeZKPmY7T7uG+jIa2Zb0j/aR
// SIG // AfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2dY3RI
// SIG // LLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltE
// SIG // AY5aGZFrDZ+kKNxnGSgkujhLmm77IVRrakURR6nxt67I
// SIG // 6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+CrvsQWY9af3L
// SIG // wUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmN
// SIG // cP7ntdAoGokLjzbaukz5m/8K6TT4JDVnK+ANuOaMmdbh
// SIG // IurwJ0I9JZTmdHRbatGePu1+oDEzfbzL6Xu/OHBE0ZDx
// SIG // yKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6Fw
// SIG // ZvKhggLOMIICNwIBATCB+KGB0KSBzTCByjELMAkGA1UE
// SIG // BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
// SIG // BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
// SIG // b3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFt
// SIG // ZXJpY2EgT3BlcmF0aW9uczEmMCQGA1UECxMdVGhhbGVz
// SIG // IFRTUyBFU046REQ4Qy1FMzM3LTJGQUUxJTAjBgNVBAMT
// SIG // HE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoB
// SIG // ATAHBgUrDgMCGgMVAM3Zaerd8LP25xK25vXNDPvXb1NA
// SIG // oIGDMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
// SIG // Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
// SIG // BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG
// SIG // A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
// SIG // MTAwDQYJKoZIhvcNAQEFBQACBQDmgbO/MCIYDzIwMjIw
// SIG // NzIwMDY1MDM5WhgPMjAyMjA3MjEwNjUwMzlaMHcwPQYK
// SIG // KwYBBAGEWQoEATEvMC0wCgIFAOaBs78CAQAwCgIBAAIC
// SIG // GRACAf8wBwIBAAICEbQwCgIFAOaDBT8CAQAwNgYKKwYB
// SIG // BAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQAC
// SIG // AwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQUFAAOB
// SIG // gQDhnkkk9l83XejEc5hAJm4Hvm/XJ5HAOk+Wc3CK1XJx
// SIG // /Shg6CvcuSoi0r3TxZsEh4Jmogp+6Qvdjm6W3ztf6dxr
// SIG // WXUgeB8F2m5yobNSJMD1AGQ347Q9ZHrWKux15Y52CRsB
// SIG // LuvjAv+Uk8bSGheh22gPrYYqi7ZdQSKTXGGj7DQywzGC
// SIG // BA0wggQJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYD
// SIG // VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
// SIG // MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
// SIG // JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD
// SIG // QSAyMDEwAhMzAAABnA+mTWHSnksoAAEAAAGcMA0GCWCG
// SIG // SAFlAwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZI
// SIG // hvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIHYWWxbR8tV6
// SIG // 2g7PPhclxKRjhr+0m45CKtJ/xGRmQ+scMIH6BgsqhkiG
// SIG // 9w0BCRACLzGB6jCB5zCB5DCBvQQgNw9FhSCNLMo6EXf1
// SIG // 3hCBtFlCCs87suj+oTka29J6prwwgZgwgYCkfjB8MQsw
// SIG // CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ
// SIG // MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
// SIG // b2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3Nv
// SIG // ZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAZwPpk1h
// SIG // 0p5LKAABAAABnDAiBCC1LRLSh59KrU8j8kpCoJz019+F
// SIG // uD2pblUM0JLbAOUTqjANBgkqhkiG9w0BAQsFAASCAgCp
// SIG // 7olUd02noSOVdnFjfbq05FZrosbKJmNEpNHeMyknPiw4
// SIG // R3bxhC6gQvD9fYgMyV7d9xK6LNBQH2cIn/9jMifI7Xw9
// SIG // QU2+yW3fu+h5yS+8zyINcYlvBIJ6HtfR+ZKU7wlWKjZv
// SIG // G68izEAiYbs6eJvpFaQ0HYvXAyguk0+N2CUIWsxQ3zxb
// SIG // LH4yGPgl5M6ezMRteuG6D+UElzk9G/d5v4w69FvPBgDv
// SIG // CoRR47ec+awclX/RgX5EhXTfFfa4+YuJN9Sm8IxUi5Jh
// SIG // Su5D1IZcHM4P77f199xo8UcgjxaoNzDPH+D2fhGX0rP/
// SIG // 4e4iR5Nl4z6xNi6Qdk5D3+Uhpy7bbsHzO+M1D3SxGt0q
// SIG // W/wCK4i0GEQ0Y0LWZrXnIIV8lK/GRsdkwznhpjTokStF
// SIG // 0S6FKbh39LP7HlFQd4S7NeGyROzDXtVDZO7MFuM/uFw6
// SIG // 1o5TbJd1G1wVdP3du18tBwYqY5m7Pe2Tnn66YvS9Vcaq
// SIG // n3Tpoe4cPAOEUr9oSKYseGDzyleHsOOFESLyK/Ayqipo
// SIG // XVvTaklPq8jopVQYN8k/3Oa5w0ePzepJYebz388nZtaG
// SIG // 0hPDqPel6INXH6LKw+9eqlaA+f3cLbCC36cb9yUJqotn
// SIG // 6ne+GsUpKe3S40OxEo+i/fAo2CiQdjNV3dV/d36AjFx3
// SIG // 1xc5mmXuD4FQz5kJEs10aA==
// SIG // End signature block
File diff suppressed because one or more lines are too long
+1406
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,185 @@
tinymce.IconManager.add('default', {
icons: {
'accessibility-check': '<svg width="24" height="24"><path d="M12 2a2 2 0 0 1 2 2 2 2 0 0 1-2 2 2 2 0 0 1-2-2c0-1.1.9-2 2-2Zm8 7h-5v12c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-5c0-.6-.4-1-1-1a1 1 0 0 0-1 1v5c0 .6-.4 1-1 1a1 1 0 0 1-1-1V9H4a1 1 0 1 1 0-2h16c.6 0 1 .4 1 1s-.4 1-1 1Z" fill-rule="nonzero"/></svg>',
'action-next': '<svg width="24" height="24"><path fill-rule="nonzero" d="M5.7 7.3a1 1 0 0 0-1.4 1.4l7.7 7.7 7.7-7.7a1 1 0 1 0-1.4-1.4L12 13.6 5.7 7.3Z"/></svg>',
'action-prev': '<svg width="24" height="24"><path fill-rule="nonzero" d="M18.3 15.7a1 1 0 0 0 1.4-1.4L12 6.6l-7.7 7.7a1 1 0 0 0 1.4 1.4L12 9.4l6.3 6.3Z"/></svg>',
'addtag': '<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M15 5a2 2 0 0 1 1.6.8L21 12l-4.4 6.2a2 2 0 0 1-1.6.8h-3v-2h3l3.5-5L15 7H5v3H3V7c0-1.1.9-2 2-2h10Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M6 12a1 1 0 0 0-1 1v2H3a1 1 0 1 0 0 2h2v2a1 1 0 1 0 2 0v-2h2a1 1 0 1 0 0-2H7v-2c0-.6-.4-1-1-1Z"/></svg>',
'align-center': '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm3 4h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 1 1 0-2Zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Zm-3-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
'align-justify': '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
'align-left': '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 4h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Zm0-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
'align-none': '<svg width="24" height="24"><path d="M14.2 5 13 7H5a1 1 0 1 1 0-2h9.2Zm4 0h.8a1 1 0 0 1 0 2h-2l1.2-2Zm-6.4 4-1.2 2H5a1 1 0 0 1 0-2h6.8Zm4 0H19a1 1 0 0 1 0 2h-4.4l1.2-2Zm-6.4 4-1.2 2H5a1 1 0 0 1 0-2h4.4Zm4 0H19a1 1 0 0 1 0 2h-6.8l1.2-2ZM7 17l-1.2 2H5a1 1 0 0 1 0-2h2Zm4 0h8a1 1 0 0 1 0 2H9.8l1.2-2Zm5.2-13.5 1.3.7-9.7 16.3-1.3-.7 9.7-16.3Z" fill-rule="evenodd"/></svg>',
'align-right': '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm6 4h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm-6-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
'arrow-left': '<svg width="24" height="24"><path d="m5.6 13 12 6a1 1 0 0 0 1.4-1V6a1 1 0 0 0-1.4-.9l-12 6a1 1 0 0 0 0 1.8Z" fill-rule="evenodd"/></svg>',
'arrow-right': '<svg width="24" height="24"><path d="m18.5 13-12 6A1 1 0 0 1 5 18V6a1 1 0 0 1 1.4-.9l12 6a1 1 0 0 1 0 1.8Z" fill-rule="evenodd"/></svg>',
'bold': '<svg width="24" height="24"><path d="M7.8 19c-.3 0-.5 0-.6-.2l-.2-.5V5.7c0-.2 0-.4.2-.5l.6-.2h5c1.5 0 2.7.3 3.5 1 .7.6 1.1 1.4 1.1 2.5a3 3 0 0 1-.6 1.9c-.4.6-1 1-1.6 1.2.4.1.9.3 1.3.6s.8.7 1 1.2c.4.4.5 1 .5 1.6 0 1.3-.4 2.3-1.3 3-.8.7-2.1 1-3.8 1H7.8Zm5-8.3c.6 0 1.2-.1 1.6-.5.4-.3.6-.7.6-1.3 0-1.1-.8-1.7-2.3-1.7H9.3v3.5h3.4Zm.5 6c.7 0 1.3-.1 1.7-.4.4-.4.6-.9.6-1.5s-.2-1-.7-1.4c-.4-.3-1-.4-2-.4H9.4v3.8h4Z" fill-rule="evenodd"/></svg>',
'bookmark': '<svg width="24" height="24"><path d="M6 4v17l6-4 6 4V4c0-.6-.4-1-1-1H7a1 1 0 0 0-1 1Z" fill-rule="nonzero"/></svg>',
'border-style': '<svg width="24" height="24"><g fill-rule="evenodd"><rect width="18" height="2" x="3" y="6" rx="1"/><rect width="2.8" height="2" x="3" y="16" rx="1"/><rect width="2.8" height="2" x="6.8" y="16" rx="1"/><rect width="2.8" height="2" x="10.6" y="16" rx="1"/><rect width="2.8" height="2" x="14.4" y="16" rx="1"/><rect width="2.8" height="2" x="18.2" y="16" rx="1"/><rect width="8" height="2" x="3" y="11" rx="1"/><rect width="8" height="2" x="13" y="11" rx="1"/></g></svg>',
'border-width': '<svg width="24" height="24"><g fill-rule="evenodd"><rect width="18" height="5" x="3" y="5" rx="1"/><rect width="18" height="3.5" x="3" y="11.5" rx="1"/><rect width="18" height="2" x="3" y="17" rx="1"/></g></svg>',
'brightness': '<svg width="24" height="24"><path d="M12 17c.3 0 .5.1.7.3.2.2.3.4.3.7v1c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7v-1c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3Zm0-10a1 1 0 0 1-.7-.3A1 1 0 0 1 11 6V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3.3 0 .5.1.7.3.2.2.3.4.3.7v1c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3Zm7 4c.3 0 .5.1.7.3.2.2.3.4.3.7 0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-1a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h1ZM7 12c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3H5a1 1 0 0 1-.7-.3A1 1 0 0 1 4 12c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h1c.3 0 .5.1.7.3.2.2.3.4.3.7Zm10 3.5.7.8c.2.1.3.4.3.6 0 .3-.1.6-.3.8a1 1 0 0 1-.8.3 1 1 0 0 1-.6-.3l-.8-.7a1 1 0 0 1-.3-.8c0-.2.1-.5.3-.7a1 1 0 0 1 1.4 0Zm-10-7-.7-.8a1 1 0 0 1-.3-.6c0-.3.1-.6.3-.8.2-.2.5-.3.8-.3.2 0 .5.1.7.3l.7.7c.2.2.3.5.3.8 0 .2-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.8-.3Zm10 0a1 1 0 0 1-.8.3 1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.6.3-.8l.8-.7c.1-.2.4-.3.6-.3.3 0 .6.1.8.3.2.2.3.5.3.8 0 .2-.1.5-.3.7l-.7.7Zm-10 7c.2-.2.5-.3.8-.3.2 0 .5.1.7.3a1 1 0 0 1 0 1.4l-.8.8a1 1 0 0 1-.6.3 1 1 0 0 1-.8-.3 1 1 0 0 1-.3-.8c0-.2.1-.5.3-.6l.7-.8ZM12 8a4 4 0 0 1 3.7 2.4 4 4 0 0 1 0 3.2A4 4 0 0 1 12 16a4 4 0 0 1-3.7-2.4 4 4 0 0 1 0-3.2A4 4 0 0 1 12 8Zm0 6.5c.7 0 1.3-.2 1.8-.7.5-.5.7-1.1.7-1.8s-.2-1.3-.7-1.8c-.5-.5-1.1-.7-1.8-.7s-1.3.2-1.8.7c-.5.5-.7 1.1-.7 1.8s.2 1.3.7 1.8c.5.5 1.1.7 1.8.7Z" fill-rule="evenodd"/></svg>',
'browse': '<svg width="24" height="24"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-4v-2h4V8H5v10h4v2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 9.4-2.3 2.3a1 1 0 1 1-1.4-1.4l4-4a1 1 0 0 1 1.4 0l4 4a1 1 0 0 1-1.4 1.4L13 13.4V20a1 1 0 0 1-2 0v-6.6Z" fill-rule="nonzero"/></svg>',
'cancel': '<svg width="24" height="24"><path d="M12 4.6a7.4 7.4 0 1 1 0 14.8 7.4 7.4 0 0 1 0-14.8ZM12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18Zm0 8L14.8 8l1 1.1-2.7 2.8 2.7 2.7-1.1 1.1-2.7-2.7-2.7 2.7-1-1.1 2.6-2.7-2.7-2.7 1-1.1 2.8 2.7Z" fill-rule="nonzero"/></svg>',
'cell-background-color': '<svg width="24" height="24"><path d="m15.7 2 1.6 1.6-2.7 2.6 5.9 5.8c.7.7.7 1.7 0 2.4l-6.3 6.1a1.7 1.7 0 0 1-2.4 0l-6.3-6.1c-.7-.7-.7-1.7 0-2.4L15.7 2ZM18 12l-4.5-4L9 12h9ZM4 16s2 2.4 2 3.8C6 21 5.1 22 4 22s-2-1-2-2.2C2 18.4 4 16 4 16Z"/></svg>',
'cell-border-color': '<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M5 13v5h2v2H5a2 2 0 0 1-2-2v-5h2zm8-7V4h6a2 2 0 0 1 2 2h-8z" opacity=".2"/><path fill-rule="nonzero" d="M13 4v2H5v7H3V6c0-1.1.9-2 2-2h8zm-2.6 14.1.1-.1.1.1.2.3.2.2.2.2c.4.6.8 1.2.8 1.7 0 .8-.7 1.5-1.5 1.5S9 21.3 9 20.5c0-.5.4-1.1.8-1.7l.2-.2.2-.2.2-.3z"/><path d="m13 11-2 2H5v-2h6V6h2z"/><path fill-rule="nonzero" d="m18.4 8 1 1-1.8 1.9 4 4c.5.4.5 1.1 0 1.6l-4.3 4.2a1.2 1.2 0 0 1-1.6 0l-4.4-4.2c-.4-.5-.4-1.2 0-1.7l7-6.8Zm1.6 7-3-3-3 3h6Z"/></g></svg>',
'change-case': '<svg width="24" height="24"><path d="M18.4 18.2v-.6c-.5.8-1.3 1.2-2.4 1.2-2.2 0-3.3-1.6-3.3-4.8 0-3.1 1-4.7 3.3-4.7 1.1 0 1.8.3 2.4 1.1v-.6c0-.5.4-.8.8-.8s.8.3.8.8v8.4c0 .5-.4.8-.8.8a.8.8 0 0 1-.8-.8zm-2-7.4c-1.3 0-1.8.9-1.8 3.2 0 2.4.5 3.3 1.7 3.3 1.3 0 1.8-.9 1.8-3.2 0-2.4-.5-3.3-1.7-3.3zM10 15.7H5.5l-.8 2.6a1 1 0 0 1-1 .7h-.2a.7.7 0 0 1-.7-1l4-12a1 1 0 0 1 2 0l4 12a.7.7 0 0 1-.8 1h-.2a1 1 0 0 1-1-.7l-.8-2.6zm-.3-1.5-2-6.5-1.9 6.5h3.9z" fill-rule="evenodd"/></svg>',
'character-count': '<svg width="24" height="24"><path d="M4 11.5h16v1H4v-1Zm4.8-6.8V10H7.7V5.8h-1v-1h2ZM11 8.3V9h2v1h-3V7.7l2-1v-.9h-2v-1h3v2.4l-2 1Zm6.3-3.4V10h-3.1V9h2.1V8h-2.1V6.8h2.1v-1h-2.1v-1h3.1ZM5.8 16.4c0-.5.2-.8.5-1 .2-.2.6-.3 1.2-.3l.8.1c.2 0 .4.2.5.3l.4.4v2.8l.2.3H8.2V18.7l-.6.3H7c-.4 0-.7 0-1-.2a1 1 0 0 1-.3-.9c0-.3 0-.6.3-.8.3-.2.7-.4 1.2-.4l.6-.2h.3v-.2l-.1-.2a.8.8 0 0 0-.5-.1 1 1 0 0 0-.4 0l-.3.4h-1Zm2.3.8h-.2l-.2.1-.4.1a1 1 0 0 0-.4.2l-.2.2.1.3.5.1h.4l.4-.4v-.6Zm2-3.4h1.2v1.7l.5-.3h.5c.5 0 .9.1 1.2.5.3.4.5.8.5 1.4 0 .6-.2 1.1-.5 1.5-.3.4-.7.6-1.3.6l-.6-.1-.4-.4v.4h-1.1v-5.4Zm1.1 3.3c0 .3 0 .6.2.8a.7.7 0 0 0 1.2 0l.2-.8c0-.4 0-.6-.2-.8a.7.7 0 0 0-.6-.3l-.6.3-.2.8Zm6.1-.5c0-.2 0-.3-.2-.4a.8.8 0 0 0-.5-.2c-.3 0-.5.1-.6.3l-.2.9c0 .3 0 .6.2.8.1.2.3.3.6.3.2 0 .4 0 .5-.2l.2-.4h1.1c0 .5-.3.8-.6 1.1a2 2 0 0 1-1.3.4c-.5 0-1-.2-1.3-.6a2 2 0 0 1-.5-1.4c0-.6.1-1.1.5-1.5.3-.4.8-.5 1.4-.5.5 0 1 0 1.2.3.4.3.5.7.5 1.2h-1v-.1Z" fill-rule="evenodd"/></svg>',
'checklist-rtl': '<svg width="24" height="24"><path d="M5 17h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm14.2 11c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 20c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 14c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 8c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8z" fill-rule="evenodd"/></svg>',
'checklist': '<svg width="24" height="24"><path d="M11 17h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8a1 1 0 0 1 0 2h-8a1 1 0 0 1 0-2ZM7.2 16c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 20c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8Zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 14c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8Zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 8c-.2.3-.7.4-1 0L3.8 6.9a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8Z" fill-rule="evenodd"/></svg>',
'checkmark': '<svg width="24" height="24"><path d="M18.2 5.4a1 1 0 0 1 1.6 1.2l-8 12a1 1 0 0 1-1.5.1l-5-5a1 1 0 1 1 1.4-1.4l4.1 4.1 7.4-11Z" fill-rule="nonzero"/></svg>',
'chevron-down': '<svg width="10" height="10"><path d="M8.7 2.2c.3-.3.8-.3 1 0 .4.4.4.9 0 1.2L5.7 7.8c-.3.3-.9.3-1.2 0L.2 3.4a.8.8 0 0 1 0-1.2c.3-.3.8-.3 1.1 0L5 6l3.7-3.8Z" fill-rule="nonzero"/></svg>',
'chevron-left': '<svg width="10" height="10"><path d="M7.8 1.3 4 5l3.8 3.7c.3.3.3.8 0 1-.4.4-.9.4-1.2 0L2.2 5.7a.8.8 0 0 1 0-1.2L6.6.2C7 0 7.4 0 7.8.2c.3.3.3.8 0 1.1Z" fill-rule="nonzero"/></svg>',
'chevron-right': '<svg width="10" height="10"><path d="M2.2 1.3a.8.8 0 0 1 0-1c.4-.4.9-.4 1.2 0l4.4 4.1c.3.4.3.9 0 1.2L3.4 9.8c-.3.3-.8.3-1.2 0a.8.8 0 0 1 0-1.1L6 5 2.2 1.3Z" fill-rule="nonzero"/></svg>',
'chevron-up': '<svg width="10" height="10"><path d="M8.7 7.8 5 4 1.3 7.8c-.3.3-.8.3-1 0a.8.8 0 0 1 0-1.2l4.1-4.4c.3-.3.9-.3 1.2 0l4.2 4.4c.3.3.3.9 0 1.2-.3.3-.8.3-1.1 0Z" fill-rule="nonzero"/></svg>',
'close': '<svg width="24" height="24"><path d="M17.3 8.2 13.4 12l3.9 3.8a1 1 0 0 1-1.5 1.5L12 13.4l-3.8 3.9a1 1 0 0 1-1.5-1.5l3.9-3.8-3.9-3.8a1 1 0 0 1 1.5-1.5l3.8 3.9 3.8-3.9a1 1 0 0 1 1.5 1.5Z" fill-rule="evenodd"/></svg>',
'code-sample': '<svg width="24" height="26"><path d="M7.1 11a2.8 2.8 0 0 1-.8 2 2.8 2.8 0 0 1 .8 2v1.7c0 .3.1.6.4.8.2.3.5.4.8.4.3 0 .4.2.4.4v.8c0 .2-.1.4-.4.4-.7 0-1.4-.3-2-.8-.5-.6-.8-1.3-.8-2V15c0-.3-.1-.6-.4-.8-.2-.3-.5-.4-.8-.4a.4.4 0 0 1-.4-.4v-.8c0-.2.2-.4.4-.4.3 0 .6-.1.8-.4.3-.2.4-.5.4-.8V9.3c0-.7.3-1.4.8-2 .6-.5 1.3-.8 2-.8.3 0 .4.2.4.4v.8c0 .2-.1.4-.4.4-.3 0-.6.1-.8.4-.3.2-.4.5-.4.8V11Zm9.8 0V9.3c0-.3-.1-.6-.4-.8-.2-.3-.5-.4-.8-.4a.4.4 0 0 1-.4-.4V7c0-.2.1-.4.4-.4.7 0 1.4.3 2 .8.5.6.8 1.3.8 2V11c0 .3.1.6.4.8.2.3.5.4.8.4.2 0 .4.2.4.4v.8c0 .2-.2.4-.4.4-.3 0-.6.1-.8.4-.3.2-.4.5-.4.8v1.7c0 .7-.3 1.4-.8 2-.6.5-1.3.8-2 .8a.4.4 0 0 1-.4-.4v-.8c0-.2.1-.4.4-.4.3 0 .6-.1.8-.4.3-.2.4-.5.4-.8V15a2.8 2.8 0 0 1 .8-2 2.8 2.8 0 0 1-.8-2Zm-3.3-.4c0 .4-.1.8-.5 1.1-.3.3-.7.5-1.1.5-.4 0-.8-.2-1.1-.5-.4-.3-.5-.7-.5-1.1 0-.5.1-.9.5-1.2.3-.3.7-.4 1.1-.4.4 0 .8.1 1.1.4.4.3.5.7.5 1.2ZM12 13c.4 0 .8.1 1.1.5.4.3.5.7.5 1.1 0 1-.1 1.6-.5 2a3 3 0 0 1-1.1 1c-.4.3-.8.4-1.1.4a.5.5 0 0 1-.5-.5V17a3 3 0 0 0 1-.2l.6-.6c-.6 0-1-.2-1.3-.5-.2-.3-.3-.7-.3-1 0-.5.1-1 .5-1.2.3-.4.7-.5 1.1-.5Z" fill-rule="evenodd"/></svg>',
'color-levels': '<svg width="24" height="24"><path d="M17.5 11.4A9 9 0 0 1 18 14c0 .5 0 1-.2 1.4 0 .4-.3.9-.5 1.3a6.2 6.2 0 0 1-3.7 3 5.7 5.7 0 0 1-3.2 0A5.9 5.9 0 0 1 7.6 18a6.2 6.2 0 0 1-1.4-2.6 6.7 6.7 0 0 1 0-2.8c0-.4.1-.9.3-1.3a13.6 13.6 0 0 1 2.3-4A20 20 0 0 1 12 4a26.4 26.4 0 0 1 3.2 3.4 18.2 18.2 0 0 1 2.3 4Zm-2 4.5c.4-.7.5-1.4.5-2a7.3 7.3 0 0 0-1-3.2c.2.6.2 1.2.2 1.9a4.5 4.5 0 0 1-1.3 3 5.3 5.3 0 0 1-2.3 1.5 4.9 4.9 0 0 1-2 .1 4.3 4.3 0 0 0 2.4.8 4 4 0 0 0 2-.6 4 4 0 0 0 1.5-1.5Z" fill-rule="evenodd"/></svg>',
'color-picker': '<svg width="24" height="24"><path d="M12 3a9 9 0 0 0 0 18 1.5 1.5 0 0 0 1.1-2.5c-.2-.3-.4-.6-.4-1 0-.8.7-1.5 1.5-1.5H16a5 5 0 0 0 5-5c0-4.4-4-8-9-8Zm-5.5 9a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm3-4a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm3 4a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Z" fill-rule="nonzero"/></svg>',
'color-swatch-remove-color': '<svg width="24" height="24"><path stroke="#000" stroke-width="2" d="M21 3 3 21" fill-rule="evenodd"/></svg>',
'color-swatch': '<svg width="24" height="24"><rect x="3" y="3" width="18" height="18" rx="1" fill-rule="evenodd"/></svg>',
'comment-add': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="m9 19 3-2h7c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H5a1 1 0 0 0-1 1v10c0 .6.4 1 1 1h4v2Zm-2 4v-4H5a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h14a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3h-6.4L7 23Z"/><path d="M13 10h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0v-2H9a1 1 0 0 1 0-2h2V8a1 1 0 0 1 2 0v2Z"/></g></svg>',
'comment': '<svg width="24" height="24"><path fill-rule="nonzero" d="m9 19 3-2h7c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H5a1 1 0 0 0-1 1v10c0 .6.4 1 1 1h4v2Zm-2 4v-4H5a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h14a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3h-6.4L7 23Z"/></svg>',
'contrast': '<svg width="24" height="24"><path d="M12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4Zm-6 8a6 6 0 0 0 6 6V6a6 6 0 0 0-6 6Z" fill-rule="evenodd"/></svg>',
'copy': '<svg width="24" height="24"><path d="M16 3H6a2 2 0 0 0-2 2v11h2V5h10V3Zm1 4a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-7a2 2 0 0 1-2-2V9c0-1.2.9-2 2-2h7Zm0 12V9h-7v10h7Z" fill-rule="nonzero"/></svg>',
'crop': '<svg width="24" height="24"><path d="M17 8v7h2c.6 0 1 .4 1 1s-.4 1-1 1h-2v2c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-2H7V9H5a1 1 0 1 1 0-2h2V5c0-.6.4-1 1-1s1 .4 1 1v2h7l3-3 1 1-3 3ZM9 9v5l5-5H9Zm1 6h5v-5l-5 5Z" fill-rule="evenodd"/></svg>',
'cut-column': '<svg width="24" height="24"><path fill-rule="evenodd" d="M7.2 4.5c.9 0 1.6.4 2.2 1A3.7 3.7 0 0 1 10.5 8v.5l1 1 4-4 1-.5a3.3 3.3 0 0 1 2 0c.4 0 .7.3 1 .5L17 8h4v13h-6V10l-1.5 1.5.5.5v4l-2.5-2.5-1 1v.5c0 .4 0 .8-.3 1.2-.2.5-.4.9-.8 1.2-.6.7-1.3 1-2.2 1-.8.2-1.5 0-2-.6l-.5-.8-.2-1c0-.4 0-.8.3-1.2A3.9 3.9 0 0 1 7 12.7c.5-.2 1-.3 1.5-.2l1-1-1-1c-.5 0-1 0-1.5-.2-.5-.1-1-.4-1.4-.9-.4-.3-.6-.7-.8-1.2L4.5 7c0-.4 0-.7.2-1 0-.3.3-.6.5-.8.5-.5 1.2-.8 2-.7Zm12.3 5h-3v10h3v-10ZM8 13.8h-.3l-.4.2a2.8 2.8 0 0 0-.7.4v.1a2.8 2.8 0 0 0-.6.8l-.1.4v.7l.2.5.5.2h.7a2.6 2.6 0 0 0 .8-.3 2.4 2.4 0 0 0 .7-.7 2.5 2.5 0 0 0 .3-.8 1.5 1.5 0 0 0 0-.8 1 1 0 0 0-.2-.4 1 1 0 0 0-.5-.2H8Zm3.5-3.7c-.4 0-.7.1-1 .4-.3.3-.4.6-.4 1s.1.7.4 1c.3.3.6.4 1 .4s.7-.1 1-.4c.3-.3.4-.6.4-1s-.1-.7-.4-1c-.3-.3-.6-.4-1-.4ZM7 5.8h-.4a1 1 0 0 0-.5.3 1 1 0 0 0-.2.5v.7a2.5 2.5 0 0 0 .3.8l.2.3h.1l.4.4.4.2.4.1h.7L9 9l.2-.4a1.6 1.6 0 0 0 0-.8 2.6 2.6 0 0 0-.3-.8A2.5 2.5 0 0 0 7.7 6l-.4-.1H7Z"/></svg>',
'cut-row': '<svg width="24" height="24"><path fill-rule="evenodd" d="M22 3v5H9l3 3 2-2h4l-4 4 1 1h.5c.4 0 .8 0 1.2.3.5.2.9.4 1.2.8.7.6 1 1.3 1 2.2.2.8 0 1.5-.6 2l-.8.5-1 .2c-.4 0-.8 0-1.2-.3a3.9 3.9 0 0 1-2.1-2.2c-.2-.5-.3-1-.2-1.5l-1-1-1 1c0 .5 0 1-.2 1.5-.1.5-.4 1-.9 1.4-.3.4-.7.6-1.2.8l-1.2.3c-.4 0-.7 0-1-.2-.3 0-.6-.3-.8-.5-.5-.5-.8-1.2-.7-2 0-.9.4-1.6 1-2.2A3.7 3.7 0 0 1 8.6 14H9l1-1-4-4-.5-1a3.3 3.3 0 0 1 0-2c0-.4.3-.7.5-1l2 2V3h14ZM8.5 15.3h-.3a2.6 2.6 0 0 0-.8.4 2.5 2.5 0 0 0-.9 1.1l-.1.4v.7l.2.5.5.2h.7a2.5 2.5 0 0 0 .8-.3L9 18V18l.4-.4.2-.4.1-.4v-.7a1 1 0 0 0-.2-.5 1 1 0 0 0-.4-.2h-.5Zm7 0H15a1 1 0 0 0-.4.3 1 1 0 0 0-.2.5 1.5 1.5 0 0 0 0 .7v.4a2.8 2.8 0 0 0 .5.7h.1a2.8 2.8 0 0 0 .8.6l.4.1h.7l.5-.2.2-.5v-.7a2.6 2.6 0 0 0-.3-.8 2.4 2.4 0 0 0-.7-.7 2.5 2.5 0 0 0-.8-.3h-.3ZM12 11.6c-.4 0-.7.1-1 .4-.3.3-.4.6-.4 1s.1.7.4 1c.3.3.6.4 1 .4s.7-.1 1-.4c.3-.3.4-.6.4-1s-.1-.7-.4-1c-.3-.3-.6-.4-1-.4Zm8.5-7.1h-11v2h11v-2Z"/></svg>',
'cut': '<svg width="24" height="24"><path d="M18 15c.6.7 1 1.4 1 2.3 0 .8-.2 1.5-.7 2l-.8.5-1 .2c-.4 0-.8 0-1.2-.3a3.9 3.9 0 0 1-2.1-2.2c-.2-.5-.3-1-.2-1.5l-1-1-1 1c0 .5 0 1-.2 1.5-.1.5-.4 1-.9 1.4-.3.4-.7.6-1.2.8l-1.2.3c-.4 0-.7 0-1-.2-.3 0-.6-.3-.8-.5-.5-.5-.8-1.2-.7-2 0-.9.4-1.6 1-2.2A3.7 3.7 0 0 1 8.6 14H9l1-1-4-4-.5-1a3.3 3.3 0 0 1 0-2c0-.4.3-.7.5-1l6 6 6-6 .5 1a3.3 3.3 0 0 1 0 2c0 .4-.3.7-.5 1l-4 4 1 1h.5c.4 0 .8 0 1.2.3.5.2.9.4 1.2.8Zm-8.5 2.2.1-.4v-.7a1 1 0 0 0-.2-.5 1 1 0 0 0-.4-.2 1.6 1.6 0 0 0-.8 0 2.6 2.6 0 0 0-.8.3 2.5 2.5 0 0 0-.9 1.1l-.1.4v.7l.2.5.5.2h.7a2.5 2.5 0 0 0 .8-.3 2.8 2.8 0 0 0 1-1Zm2.5-2.8c.4 0 .7-.1 1-.4.3-.3.4-.6.4-1s-.1-.7-.4-1c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-.3.3-.4.6-.4 1s.1.7.4 1c.3.3.6.4 1 .4Zm5.4 4 .2-.5v-.7a2.6 2.6 0 0 0-.3-.8 2.4 2.4 0 0 0-.7-.7 2.5 2.5 0 0 0-.8-.3 1.5 1.5 0 0 0-.8 0 1 1 0 0 0-.4.2 1 1 0 0 0-.2.5 1.5 1.5 0 0 0 0 .7v.4l.3.4.3.4a2.8 2.8 0 0 0 .8.5l.4.1h.7l.5-.2Z" fill-rule="evenodd"/></svg>',
'document-properties': '<svg width="24" height="24"><path d="M14.4 3H7a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h10a2 2 0 0 0 2-2V7.6L14.4 3ZM17 19H7V5h6v4h4v10Z" fill-rule="nonzero"/></svg>',
'drag': '<svg width="24" height="24"><path d="M13 5h2v2h-2V5Zm0 4h2v2h-2V9ZM9 9h2v2H9V9Zm4 4h2v2h-2v-2Zm-4 0h2v2H9v-2Zm0 4h2v2H9v-2Zm4 0h2v2h-2v-2ZM9 5h2v2H9V5Z" fill-rule="evenodd"/></svg>',
'duplicate-column': '<svg width="24" height="24"><path d="M17 6v16h-7V6h7Zm-2 2h-3v12h3V8Zm-2-6v2H8v15H6V2h7Z"/></svg>',
'duplicate-row': '<svg width="24" height="24"><path d="M22 11v7H6v-7h16Zm-2 2H8v3h12v-3Zm-1-6v2H4v5H2V7h17Z"/></svg>',
'duplicate': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M16 3v2H6v11H4V5c0-1.1.9-2 2-2h10Zm3 8h-2V9h-7v10h9a2 2 0 0 1-2 2h-7a2 2 0 0 1-2-2V9c0-1.2.9-2 2-2h7a2 2 0 0 1 2 2v2Z"/><path d="M17 14h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0v-1h-1a1 1 0 0 1 0-2h1v-1a1 1 0 0 1 2 0v1Z"/></g></svg>',
'edit-block': '<svg width="24" height="24"><path fill-rule="nonzero" d="m19.8 8.8-9.4 9.4c-.2.2-.5.4-.9.4l-5.4 1.2 1.2-5.4.5-.8 9.4-9.4c.7-.7 1.8-.7 2.5 0l2.1 2.1c.7.7.7 1.8 0 2.5Zm-2-.2 1-.9v-.3l-2.2-2.2a.3.3 0 0 0-.3 0l-1 1L18 8.5Zm-1 1-2.5-2.4-6 6 2.5 2.5 6-6Zm-7 7.1-2.6-2.4-.3.3-.1.2-.7 3 3.1-.6h.1l.4-.5Z"/></svg>',
'edit-image': '<svg width="24" height="24"><path d="M18 16h2V7a2 2 0 0 0-2-2H7v2h11v9ZM6 17h15a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0v-1H6a2 2 0 0 1-2-2V7H3a1 1 0 1 1 0-2h1V4a1 1 0 1 1 2 0v13Zm3-5.3 1.3 2 3-4.7 3.7 6H7l2-3.3Z" fill-rule="nonzero"/></svg>',
'embed-page': '<svg width="24" height="24"><path d="M19 6V5H5v14h2A13 13 0 0 1 19 6Zm0 1.4c-.8.8-1.6 2.4-2.2 4.6H19V7.4Zm0 5.6h-2.4c-.4 1.8-.6 3.8-.6 6h3v-6Zm-4 6c0-2.2.2-4.2.6-6H13c-.7 1.8-1.1 3.8-1.1 6h3Zm-4 0c0-2.2.4-4.2 1-6H9.6A12 12 0 0 0 8 19h3ZM4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm11.8 9c.4-1.9 1-3.4 1.8-4.5a9.2 9.2 0 0 0-4 4.5h2.2Zm-3.4 0a12 12 0 0 1 2.8-4 12 12 0 0 0-5 4h2.2Z" fill-rule="nonzero"/></svg>',
'embed': '<svg width="24" height="24"><path d="M4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm1 2v14h14V5H5Zm4.8 2.6 5.6 4a.5.5 0 0 1 0 .8l-5.6 4A.5.5 0 0 1 9 16V8a.5.5 0 0 1 .8-.4Z" fill-rule="nonzero"/></svg>',
'emoji': '<svg width="24" height="24"><path d="M9 11c.6 0 1-.4 1-1s-.4-1-1-1a1 1 0 0 0-1 1c0 .6.4 1 1 1Zm6 0c.6 0 1-.4 1-1s-.4-1-1-1a1 1 0 0 0-1 1c0 .6.4 1 1 1Zm-3 5.5c2.1 0 4-1.5 4.4-3.5H7.6c.5 2 2.3 3.5 4.4 3.5ZM12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm0 14.5a6.5 6.5 0 1 1 0-13 6.5 6.5 0 0 1 0 13Z" fill-rule="nonzero"/></svg>',
'export': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M14.4 3 18 7v1h-5V5H7v14h9a1 1 0 0 1 2 0c0 1-.8 2-1.9 2H7c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2h7.5Z"/><path d="M18.1 12c.5 0 .9.4.9 1 0 .5-.3 1-.8 1h-7.3c-.5 0-.9-.4-.9-1 0-.5.3-1 .8-1h7.3Z"/><path d="M16.4 9.2a1 1 0 0 1 1.4.2l2.4 3.6-2.4 3.6a1 1 0 0 1-1.7-1v-.2l1.7-2.4-1.6-2.4a1 1 0 0 1 .2-1.4Z"/></g></svg>',
'fill': '<svg width="24" height="26"><path d="m16.6 12-9-9-1.4 1.4 2.4 2.4-5.2 5.1c-.5.6-.5 1.6 0 2.2L9 19.6a1.5 1.5 0 0 0 2.2 0l5.5-5.5c.5-.6.5-1.6 0-2.2ZM5.2 13 10 8.2l4.8 4.8H5.2ZM19 14.5s-2 2.2-2 3.5c0 1.1.9 2 2 2a2 2 0 0 0 2-2c0-1.3-2-3.5-2-3.5Z" fill-rule="nonzero"/></svg>',
'flip-horizontally': '<svg width="24" height="24"><path d="M14 19h2v-2h-2v2Zm4-8h2V9h-2v2ZM4 7v10c0 1.1.9 2 2 2h3v-2H6V7h3V5H6a2 2 0 0 0-2 2Zm14-2v2h2a2 2 0 0 0-2-2Zm-7 16h2V3h-2v18Zm7-6h2v-2h-2v2Zm-4-8h2V5h-2v2Zm4 12a2 2 0 0 0 2-2h-2v2Z" fill-rule="nonzero"/></svg>',
'flip-vertically': '<svg width="24" height="24"><path d="M5 14v2h2v-2H5Zm8 4v2h2v-2h-2Zm4-14H7a2 2 0 0 0-2 2v3h2V6h10v3h2V6a2 2 0 0 0-2-2Zm2 14h-2v2a2 2 0 0 0 2-2ZM3 11v2h18v-2H3Zm6 7v2h2v-2H9Zm8-4v2h2v-2h-2ZM5 18c0 1.1.9 2 2 2v-2H5Z" fill-rule="nonzero"/></svg>',
'footnote': '<svg width="24" height="24"><path d="M19 13c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2h14Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M19 4v6h-1V5h-1.5V4h2.6Z"/><path d="M12 18c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2h7ZM14 8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2h9Z"/></svg>',
'format-painter': '<svg width="24" height="24"><path d="M18 5V4c0-.5-.4-1-1-1H5a1 1 0 0 0-1 1v4c0 .6.5 1 1 1h12c.6 0 1-.4 1-1V7h1v4H9v9c0 .6.4 1 1 1h2c.6 0 1-.4 1-1v-7h8V5h-3Z" fill-rule="nonzero"/></svg>',
'format': '<svg width="24" height="24"><path fill-rule="evenodd" d="M17 5a1 1 0 0 1 0 2h-4v11a1 1 0 0 1-2 0V7H7a1 1 0 1 1 0-2h10Z"/></svg>',
'fullscreen': '<svg width="24" height="24"><path d="m15.3 10-1.2-1.3 2.9-3h-2.3a.9.9 0 1 1 0-1.7H19c.5 0 .9.4.9.9v4.4a.9.9 0 1 1-1.8 0V7l-2.9 3Zm0 4 3 3v-2.3a.9.9 0 1 1 1.7 0V19c0 .5-.4.9-.9.9h-4.4a.9.9 0 1 1 0-1.8H17l-3-2.9 1.3-1.2ZM10 15.4l-2.9 3h2.3a.9.9 0 1 1 0 1.7H5a.9.9 0 0 1-.9-.9v-4.4a.9.9 0 1 1 1.8 0V17l2.9-3 1.2 1.3ZM8.7 10 5.7 7v2.3a.9.9 0 0 1-1.7 0V5c0-.5.4-.9.9-.9h4.4a.9.9 0 0 1 0 1.8H7l3 2.9-1.3 1.2Z" fill-rule="nonzero"/></svg>',
'gallery': '<svg width="24" height="24"><path fill-rule="nonzero" d="m5 15.7 2.3-2.2c.3-.3.7-.3 1 0L11 16l5.1-5c.3-.4.8-.4 1 0l2 1.9V8H5v7.7ZM5 18V19h3l1.8-1.9-2-2L5 17.9Zm14-3-2.5-2.4-6.4 6.5H19v-4ZM4 6h16c.6 0 1 .4 1 1v13c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V7c0-.6.4-1 1-1Zm6 7a2 2 0 1 1 0-4 2 2 0 0 1 0 4ZM4.5 4h15a.5.5 0 1 1 0 1h-15a.5.5 0 0 1 0-1Zm2-2h11a.5.5 0 1 1 0 1h-11a.5.5 0 0 1 0-1Z"/></svg>',
'gamma': '<svg width="24" height="24"><path d="M4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm1 2v14h14V5H5Zm6.5 11.8V14L9.2 8.7a5.1 5.1 0 0 0-.4-.8l-.1-.2H8v-1l.3-.1.3-.1h.7a1 1 0 0 1 .6.5l.1.3a8.5 8.5 0 0 1 .3.6l1.9 4.6 2-5.2a1 1 0 0 1 1-.6.5.5 0 0 1 .5.6L13 14v2.8a.7.7 0 0 1-1.4 0Z" fill-rule="nonzero"/></svg>',
'help': '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M12 5.5a6.5 6.5 0 0 0-6 9 6.3 6.3 0 0 0 1.4 2l1 1a6.3 6.3 0 0 0 3.6 1 6.5 6.5 0 0 0 6-9 6.3 6.3 0 0 0-1.4-2l-1-1a6.3 6.3 0 0 0-3.6-1ZM12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4Z"/><path d="M9.6 9.7a.7.7 0 0 1-.7-.8c0-1.1 1.5-1.8 3.2-1.8 1.8 0 3.2.8 3.2 2.4 0 1.4-.4 2.1-1.5 2.8-.2 0-.3.1-.3.2a2 2 0 0 0-.8.8.8.8 0 0 1-1.4-.6c.3-.7.8-1 1.3-1.5l.4-.2c.7-.4.8-.6.8-1.5 0-.5-.6-.9-1.7-.9-.5 0-1 .1-1.4.3-.2 0-.3.1-.3.2v-.2c0 .4-.4.8-.8.8Z" fill-rule="nonzero"/><circle cx="12" cy="16" r="1"/></g></svg>',
'highlight-bg-color': '<svg width="24" height="24"><g fill-rule="evenodd"><path id="tox-icon-highlight-bg-color__color" d="M3 18h18v3H3z"/><path fill-rule="nonzero" d="M7.7 16.7H3l3.3-3.3-.7-.8L10.2 8l4 4.1-4 4.2c-.2.2-.6.2-.8 0l-.6-.7-1.1 1.1zm5-7.5L11 7.4l3-2.9a2 2 0 0 1 2.6 0L18 6c.7.7.7 2 0 2.7l-2.9 2.9-1.8-1.8-.5-.6"/></g></svg>',
'home': '<svg width="24" height="24"><path fill-rule="nonzero" d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>',
'horizontal-rule': '<svg width="24" height="24"><path d="M4 11h16v2H4z" fill-rule="evenodd"/></svg>',
'image-options': '<svg width="24" height="24"><path d="M6 10a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm12 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm-6 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Z" fill-rule="nonzero"/></svg>',
'image': '<svg width="24" height="24"><path d="m5 15.7 3.3-3.2c.3-.3.7-.3 1 0L12 15l4.1-4c.3-.4.8-.4 1 0l2 1.9V5H5v10.7ZM5 18V19h3l2.8-2.9-2-2L5 17.9Zm14-3-2.5-2.4-6.4 6.5H19v-4ZM4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm6 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z" fill-rule="nonzero"/></svg>',
'indent': '<svg width="24" height="24"><path d="M7 5h12c.6 0 1 .4 1 1s-.4 1-1 1H7a1 1 0 1 1 0-2Zm5 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm0 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm-5 4h12a1 1 0 0 1 0 2H7a1 1 0 0 1 0-2Zm-2.6-3.8L6.2 12l-1.8-1.2a1 1 0 0 1 1.2-1.6l3 2a1 1 0 0 1 0 1.6l-3 2a1 1 0 1 1-1.2-1.6Z" fill-rule="evenodd"/></svg>',
'info': '<svg width="24" height="24"><path d="M12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4Zm-1 3v2h2V7h-2Zm3 10v-1h-1v-5h-3v1h1v4h-1v1h4Z" fill-rule="evenodd"/></svg>',
'insert-character': '<svg width="24" height="24"><path d="M15 18h4l1-2v4h-6v-3.3l1.4-1a6 6 0 0 0 1.8-2.9 6.3 6.3 0 0 0-.1-4.1 5.8 5.8 0 0 0-3-3.2c-.6-.3-1.3-.5-2.1-.5a5.1 5.1 0 0 0-3.9 1.8 6.3 6.3 0 0 0-1.3 6 6.2 6.2 0 0 0 1.8 3l1.4.9V20H4v-4l1 2h4v-.5l-2-1L5.4 15A6.5 6.5 0 0 1 4 11c0-1 .2-1.9.6-2.7A7 7 0 0 1 6.3 6C7.1 5.4 8 5 9 4.5c1-.3 2-.5 3.1-.5a8.8 8.8 0 0 1 5.7 2 7 7 0 0 1 1.7 2.3 6 6 0 0 1 .2 4.8c-.2.7-.6 1.3-1 1.9a7.6 7.6 0 0 1-3.6 2.5v.5Z" fill-rule="evenodd"/></svg>',
'insert-time': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M12 19a7 7 0 1 0 0-14 7 7 0 0 0 0 14Zm0 2a9 9 0 1 1 0-18 9 9 0 0 1 0 18Z"/><path d="M16 12h-3V7c0-.6-.4-1-1-1a1 1 0 0 0-1 1v7h5c.6 0 1-.4 1-1s-.4-1-1-1Z"/></g></svg>',
'invert': '<svg width="24" height="24"><path d="M18 19.3 16.5 18a5.8 5.8 0 0 1-3.1 1.9 6.1 6.1 0 0 1-5.5-1.6A5.8 5.8 0 0 1 6 14v-.3l.1-1.2A13.9 13.9 0 0 1 7.7 9l-3-3 .7-.8 2.8 2.9 9 8.9 1.5 1.6-.7.6Zm0-5.5v.3l-.1 1.1-.4 1-1.2-1.2a4.3 4.3 0 0 0 .2-1v-.2c0-.4 0-.8-.2-1.3l-.5-1.4a14.8 14.8 0 0 0-3-4.2L12 6a26.1 26.1 0 0 0-2.2 2.5l-1-1a20.9 20.9 0 0 1 2.9-3.3L12 4l1 .8a22.2 22.2 0 0 1 4 5.4c.6 1.2 1 2.4 1 3.6Z" fill-rule="evenodd"/></svg>',
'italic': '<svg width="24" height="24"><path d="m16.7 4.7-.1.9h-.3c-.6 0-1 0-1.4.3-.3.3-.4.6-.5 1.1l-2.1 9.8v.6c0 .5.4.8 1.4.8h.2l-.2.8H8l.2-.8h.2c1.1 0 1.8-.5 2-1.5l2-9.8.1-.5c0-.6-.4-.8-1.4-.8h-.3l.2-.9h5.8Z" fill-rule="evenodd"/></svg>',
'language': '<svg width="24" height="24"><path d="M12 3a9 9 0 1 1 0 18 9 9 0 0 1 0-18Zm4.3 13.3c-.5 1-1.2 2-2 2.9a7.5 7.5 0 0 0 3.2-2.1l-.2-.2a6 6 0 0 0-1-.6Zm-8.6 0c-.5.2-.9.5-1.2.8.9 1 2 1.7 3.2 2a10 10 0 0 1-2-2.8Zm3.6-.8c-.8 0-1.6.1-2.2.3.5 1 1.2 1.9 2.1 2.7Zm1.5 0v3c.9-.8 1.6-1.7 2.1-2.7-.6-.2-1.4-.3-2.1-.3Zm-6-2.7H4.5c.2 1 .5 2.1 1 3h.3l1.3-1a10 10 0 0 1-.3-2Zm12.7 0h-2.3c0 .7-.1 1.4-.3 2l1.6 1.1c.5-1 .9-2 1-3.1Zm-3.8 0h-3V14c1 0 2 .1 2.7.4.2-.5.3-1 .3-1.6Zm-4.4 0h-3l.3 1.6c.8-.3 1.7-.4 2.7-.4v-1.3Zm-5.5-5c-.7 1-1.1 2.2-1.3 3.5h2.3c0-1 .2-1.8.5-2.6l-1.5-1Zm2.9 1.4v.1c-.2.6-.4 1.3-.4 2h3V9.4c-1 0-1.8-.1-2.6-.3Zm6.6 0h-.1l-2.4.3v1.8h3l-.5-2.1Zm3-1.4-.3.1-1.3.8c.3.8.5 1.6.5 2.6h2.3a7.5 7.5 0 0 0-1.3-3.5Zm-9 0 2 .2V5.5a9 9 0 0 0-2 2.2Zm3.5-2.3V8c.6 0 1.3 0 1.9-.2a9 9 0 0 0-2-2.3Zm-3-.7h-.1c-1.1.4-2.1 1-3 1.8l1.2.7a10 10 0 0 1 1.9-2.5Zm4.4 0 .1.1a10 10 0 0 1 1.8 2.4l1.1-.7a7.5 7.5 0 0 0-3-1.8Z"/></svg>',
'line-height': '<svg width="24" height="24"><path d="M21 5a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zm0 4a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zm0 4a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zm0 4a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zM7 3.6l3.7 3.7a1 1 0 0 1-1.3 1.5h-.1L8 7.3v9.2l1.3-1.3a1 1 0 0 1 1.3 0h.1c.4.4.4 1 0 1.3v.1L7 20.4l-3.7-3.7a1 1 0 0 1 1.3-1.5h.1L6 16.7V7.4L4.7 8.7a1 1 0 0 1-1.3 0h-.1a1 1 0 0 1 0-1.3v-.1L7 3.6z"/></svg>',
'line': '<svg width="24" height="24"><path d="m15 9-8 8H4v-3l8-8 3 3Zm1-1-3-3 1-1h1c-.2 0 0 0 0 0l2 2s0 .2 0 0v1l-1 1ZM4 18h16v2H4v-2Z" fill-rule="evenodd"/></svg>',
'link': '<svg width="24" height="24"><path d="M6.2 12.3a1 1 0 0 1 1.4 1.4l-2 2a2 2 0 1 0 2.6 2.8l4.8-4.8a1 1 0 0 0 0-1.4 1 1 0 1 1 1.4-1.3 2.9 2.9 0 0 1 0 4L9.6 20a3.9 3.9 0 0 1-5.5-5.5l2-2Zm11.6-.6a1 1 0 0 1-1.4-1.4l2-2a2 2 0 1 0-2.6-2.8L11 10.3a1 1 0 0 0 0 1.4A1 1 0 1 1 9.6 13a2.9 2.9 0 0 1 0-4L14.4 4a3.9 3.9 0 0 1 5.5 5.5l-2 2Z" fill-rule="nonzero"/></svg>',
'list-bull-circle': '<svg width="48" height="48"><g fill-rule="evenodd"><path d="M11 16a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6ZM11 26a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6ZM11 36a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z" fill-rule="nonzero"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',
'list-bull-default': '<svg width="48" height="48"><g fill-rule="evenodd"><circle cx="11" cy="14" r="3"/><circle cx="11" cy="24" r="3"/><circle cx="11" cy="34" r="3"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',
'list-bull-square': '<svg width="48" height="48"><g fill-rule="evenodd"><path d="M8 11h6v6H8zM8 21h6v6H8zM8 31h6v6H8z"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',
'list-num-default-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M37.4 17v-4.8h-.1l-1.5 1v-1.1l1.6-1.1h1.2v6zM33.3 17.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm1.7 5.7c0-1.2 1-2 2.2-2 1.3 0 2.1.8 2.1 1.8 0 .7-.3 1.2-1.3 2.2l-1.2 1v.2h2.6v1h-4.3v-.9l2-1.9c.8-.8 1-1.1 1-1.5 0-.5-.4-.8-1-.8-.5 0-.9.3-.9.9H35zm-1.7 4.3c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm3.2 7.3v-1h.7c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7s-1 .3-1 .8H35c0-1.1 1-1.8 2.2-1.8 1.2 0 2.1.6 2.1 1.6 0 .7-.4 1.2-1 1.3v.1c.7.1 1.3.7 1.3 1.4 0 1-1 1.9-2.4 1.9-1.3 0-2.2-.8-2.3-2h1.2c0 .6.5 1 1.1 1 .6 0 1-.4 1-1 0-.5-.3-.8-1-.8h-.7zm-3.3 2.7c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7z"/></g></svg>',
'list-num-default': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10 17v-4.8l-1.5 1v-1.1l1.6-1h1.2V17h-1.2Zm3.6.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7Zm-5 5.7c0-1.2.8-2 2.1-2s2.1.8 2.1 1.8c0 .7-.3 1.2-1.4 2.2l-1.1 1v.2h2.6v1H8.6v-.9l2-1.9c.8-.8 1-1.1 1-1.5 0-.5-.4-.8-1-.8-.5 0-.9.3-.9.9H8.5Zm6.3 4.3c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7ZM10 34.4v-1h.7c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7s-1 .3-1 .8H8.6c0-1.1 1-1.8 2.2-1.8 1.3 0 2.1.6 2.1 1.6 0 .7-.4 1.2-1 1.3v.1c.8.1 1.3.7 1.3 1.4 0 1-1 1.9-2.4 1.9-1.3 0-2.2-.8-2.3-2h1.2c0 .6.5 1 1.1 1 .7 0 1-.4 1-1 0-.5-.3-.8-1-.8h-.7Zm4.7 2.7c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7Z"/></g></svg>',
'list-num-lower-alpha-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M36.5 16c-.9 0-1.5-.5-1.5-1.3s.6-1.3 1.8-1.4h1v-.4c0-.4-.2-.6-.7-.6-.4 0-.7.1-.8.4h-1.1c0-.8.8-1.4 2-1.4S39 12 39 13V16h-1.2v-.6c-.3.4-.8.7-1.4.7Zm.4-.8c.6 0 1-.4 1-.9V14h-1c-.5.1-.7.3-.7.6 0 .4.3.6.7.6ZM33.1 16.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7ZM37.7 26c-.7 0-1.2-.2-1.5-.7v.7H35v-6.3h1.2v2.5c.3-.5.8-.9 1.5-.9 1.1 0 1.8 1 1.8 2.4 0 1.5-.7 2.4-1.8 2.4Zm-.5-3.6c-.6 0-1 .5-1 1.3s.4 1.4 1 1.4c.7 0 1-.6 1-1.4 0-.8-.3-1.3-1-1.3ZM33.2 26.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7zm6 7h-1c-.1-.5-.4-.8-1-.8s-1 .5-1 1.4c0 1 .4 1.4 1 1.4.5 0 .9-.2 1-.7h1c0 1-.8 1.7-2 1.7-1.4 0-2.2-.9-2.2-2.4s.8-2.4 2.2-2.4c1.2 0 2 .7 2 1.7zm-6.1 3c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7z"/></g></svg>',
'list-num-lower-alpha': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10.3 15.2c.5 0 1-.4 1-.9V14h-1c-.5.1-.8.3-.8.6 0 .4.3.6.8.6Zm-.4.9c-1 0-1.5-.6-1.5-1.4 0-.8.6-1.3 1.7-1.4h1.1v-.4c0-.4-.2-.6-.7-.6-.5 0-.8.1-.9.4h-1c0-.8.8-1.4 2-1.4 1.1 0 1.8.6 1.8 1.6V16h-1.1v-.6h-.1c-.2.4-.7.7-1.3.7Zm4.6 0c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm-3.2 10c-.6 0-1.2-.3-1.4-.8v.7H8.5v-6.3H10v2.5c.3-.5.8-.9 1.4-.9 1.2 0 1.9 1 1.9 2.4 0 1.5-.7 2.4-1.9 2.4Zm-.4-3.7c-.7 0-1 .5-1 1.3s.3 1.4 1 1.4c.6 0 1-.6 1-1.4 0-.8-.4-1.3-1-1.3Zm4 3.7c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm-2.2 7h-1.2c0-.5-.4-.8-.9-.8-.6 0-1 .5-1 1.4 0 1 .4 1.4 1 1.4.5 0 .8-.2 1-.7h1c0 1-.8 1.7-2 1.7-1.4 0-2.2-.9-2.2-2.4s.8-2.4 2.2-2.4c1.2 0 2 .7 2 1.7Zm1.8 3c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',
'list-num-lower-greek-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M37.4 16c-1.2 0-2-.8-2-2.3 0-1.5.8-2.4 2-2.4.6 0 1 .4 1.3 1v-.9H40v3.2c0 .4.1.5.4.5h.2v.9h-.6c-.6 0-1-.2-1-.7h-.2c-.2.4-.7.8-1.3.8Zm.3-1c.6 0 1-.5 1-1.3s-.4-1.3-1-1.3-1 .5-1 1.3.4 1.4 1 1.4ZM33.3 16.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7ZM36 21.9c0-1.5.8-2.3 2.1-2.3 1.2 0 2 .6 2 1.6 0 .6-.3 1-.9 1.3.9.3 1.3.8 1.3 1.7 0 1.2-.7 1.9-1.8 1.9-.6 0-1.1-.3-1.4-.8v2.2H36V22Zm1.8 1.2v-1h.3c.5 0 .9-.2.9-.7 0-.5-.3-.8-.9-.8-.5 0-.8.3-.8 1v2.2c0 .8.4 1.3 1 1.3s1-.4 1-1-.4-1-1.2-1h-.3ZM33.3 26.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7ZM37.1 34.6 34.8 30h1.4l1.7 3.5 1.7-3.5h1.1l-2.2 4.6v.1c.5.8.7 1.4.7 1.8 0 .4-.2.8-.4 1-.2.2-.6.3-1 .3-.9 0-1.3-.4-1.3-1.2 0-.5.2-1 .5-1.7l.1-.2Zm.7 1a2 2 0 0 0-.4.9c0 .3.1.4.4.4.3 0 .4-.1.4-.4 0-.2-.1-.6-.4-1ZM33.3 36.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',
'list-num-lower-greek': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10.5 15c.7 0 1-.5 1-1.3s-.3-1.3-1-1.3c-.5 0-.9.5-.9 1.3s.4 1.4 1 1.4Zm-.3 1c-1.1 0-1.8-.8-1.8-2.3 0-1.5.7-2.4 1.8-2.4.7 0 1.1.4 1.3 1h.1v-.9h1.2v3.2c0 .4.1.5.4.5h.2v.9h-.6c-.6 0-1-.2-1.1-.7h-.1c-.2.4-.7.8-1.4.8Zm5 .1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7Zm-4.9 7v-1h.3c.6 0 1-.2 1-.7 0-.5-.4-.8-1-.8-.5 0-.8.3-.8 1v2.2c0 .8.4 1.3 1.1 1.3.6 0 1-.4 1-1s-.5-1-1.3-1h-.3ZM8.6 22c0-1.5.7-2.3 2-2.3 1.2 0 2 .6 2 1.6 0 .6-.3 1-.8 1.3.8.3 1.3.8 1.3 1.7 0 1.2-.8 1.9-1.9 1.9-.6 0-1.1-.3-1.3-.8v2.2H8.5V22Zm6.2 4.2c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7Zm-4.5 8.5L8 30h1.4l1.7 3.5 1.7-3.5h1.1l-2.2 4.6v.1c.5.8.7 1.4.7 1.8 0 .4-.1.8-.4 1-.2.2-.6.3-1 .3-.9 0-1.3-.4-1.3-1.2 0-.5.2-1 .5-1.7l.1-.2Zm.7 1a2 2 0 0 0-.4.9c0 .3.1.4.4.4.3 0 .4-.1.4-.4 0-.2-.1-.6-.4-1Zm4.5.5c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',
'list-num-lower-roman-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M32.9 16v-1.2h-1.3V16H33Zm0 10v-1.2h-1.3V26H33Zm0 10v-1.2h-1.3V36H33Z"/><path fill-rule="nonzero" d="M36 21h-1.5v5H36zM36 31h-1.5v5H36zM39 21h-1.5v5H39zM39 31h-1.5v5H39zM42 31h-1.5v5H42zM36 11h-1.5v5H36zM36 19h-1.5v1H36zM36 29h-1.5v1H36zM39 19h-1.5v1H39zM39 29h-1.5v1H39zM42 29h-1.5v1H42zM36 9h-1.5v1H36z"/></g></svg>',
'list-num-lower-roman': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M15.1 16v-1.2h1.3V16H15Zm0 10v-1.2h1.3V26H15Zm0 10v-1.2h1.3V36H15Z"/><path fill-rule="nonzero" d="M12 21h1.5v5H12zM12 31h1.5v5H12zM9 21h1.5v5H9zM9 31h1.5v5H9zM6 31h1.5v5H6zM12 11h1.5v5H12zM12 19h1.5v1H12zM12 29h1.5v1H12zM9 19h1.5v1H9zM9 29h1.5v1H9zM6 29h1.5v1H6zM12 9h1.5v1H12z"/></g></svg>',
'list-num-upper-alpha-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="m39.3 17-.5-1.4h-2l-.5 1.4H35l2-6h1.6l2 6h-1.3Zm-1.6-4.7-.7 2.3h1.6l-.8-2.3ZM33.4 17c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7Zm4.7 9.9h-2.7v-6H38c1.2 0 1.9.6 1.9 1.5 0 .6-.5 1.2-1 1.3.7.1 1.3.7 1.3 1.5 0 1-.8 1.7-2 1.7Zm-1.4-5v1.5h1c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7h-1Zm0 4h1.1c.7 0 1.1-.3 1.1-.8 0-.6-.4-.9-1.1-.9h-1.1V26ZM33 27.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm4.9 10c-1.8 0-2.8-1.1-2.8-3.1s1-3.1 2.8-3.1c1.4 0 2.5.9 2.6 2.2h-1.3c0-.7-.6-1.1-1.3-1.1-1 0-1.6.7-1.6 2s.6 2 1.6 2c.7 0 1.2-.4 1.4-1h1.2c-.1 1.3-1.2 2.2-2.6 2.2Zm-4.5 0c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',
'list-num-upper-alpha': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="m12.6 17-.5-1.4h-2L9.5 17H8.3l2-6H12l2 6h-1.3ZM11 12.3l-.7 2.3h1.6l-.8-2.3Zm4.7 4.8c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7ZM11.4 27H8.7v-6h2.6c1.2 0 1.9.6 1.9 1.5 0 .6-.5 1.2-1 1.3.7.1 1.3.7 1.3 1.5 0 1-.8 1.7-2 1.7ZM10 22v1.5h1c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7h-1Zm0 4H11c.7 0 1.1-.3 1.1-.8 0-.6-.4-.9-1.1-.9H10V26Zm5.4 1.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm-4.1 10c-1.8 0-2.8-1.1-2.8-3.1s1-3.1 2.8-3.1c1.4 0 2.5.9 2.6 2.2h-1.3c0-.7-.6-1.1-1.3-1.1-1 0-1.6.7-1.6 2s.6 2 1.6 2c.7 0 1.2-.4 1.4-1h1.2c-.1 1.3-1.2 2.2-2.6 2.2Zm4.5 0c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',
'list-num-upper-roman-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M31.6 17v-1.2H33V17h-1.3Zm0 10v-1.2H33V27h-1.3Zm0 10v-1.2H33V37h-1.3Z"/><path fill-rule="nonzero" d="M34.5 20H36v7h-1.5zM34.5 30H36v7h-1.5zM37.5 20H39v7h-1.5zM37.5 30H39v7h-1.5zM40.5 30H42v7h-1.5zM34.5 10H36v7h-1.5z"/></g></svg>',
'list-num-upper-roman': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M15.1 17v-1.2h1.3V17H15Zm0 10v-1.2h1.3V27H15Zm0 10v-1.2h1.3V37H15Z"/><path fill-rule="nonzero" d="M12 20h1.5v7H12zM12 30h1.5v7H12zM9 20h1.5v7H9zM9 30h1.5v7H9zM6 30h1.5v7H6zM12 10h1.5v7H12z"/></g></svg>',
'lock': '<svg width="24" height="24"><path d="M16.3 11c.2 0 .3 0 .5.2l.2.6v7.4c0 .3 0 .4-.2.6l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6v-7.4c0-.3 0-.4.2-.6l.5-.2H8V8c0-.8.3-1.5.9-2.1.6-.6 1.3-.9 2.1-.9h2c.8 0 1.5.3 2.1.9.6.6.9 1.3.9 2.1v3h.3ZM10 8v3h4V8a1 1 0 0 0-.3-.7A1 1 0 0 0 13 7h-2a1 1 0 0 0-.7.3 1 1 0 0 0-.3.7Z" fill-rule="evenodd"/></svg>',
'ltr': '<svg width="24" height="24"><path d="M11 5h7a1 1 0 0 1 0 2h-1v11a1 1 0 0 1-2 0V7h-2v11a1 1 0 0 1-2 0v-6c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 7.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L11 5ZM4.4 16.2 6.2 15l-1.8-1.2a1 1 0 0 1 1.2-1.6l3 2a1 1 0 0 1 0 1.6l-3 2a1 1 0 1 1-1.2-1.6Z" fill-rule="evenodd"/></svg>',
'more-drawer': '<svg width="24" height="24"><path d="M6 10a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm12 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm-6 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Z" fill-rule="nonzero"/></svg>',
'new-document': '<svg width="24" height="24"><path d="M14.4 3H7a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h10a2 2 0 0 0 2-2V7.6L14.4 3ZM17 19H7V5h6v4h4v10Z" fill-rule="nonzero"/></svg>',
'new-tab': '<svg width="24" height="24"><path d="m15 13 2-2v8H5V7h8l-2 2H7v8h8v-4Zm4-8v5.5l-2-2-5.6 5.5H10v-1.4L15.5 7l-2-2H19Z" fill-rule="evenodd"/></svg>',
'non-breaking': '<svg width="24" height="24"><path d="M11 11H8a1 1 0 1 1 0-2h3V6c0-.6.4-1 1-1s1 .4 1 1v3h3c.6 0 1 .4 1 1s-.4 1-1 1h-3v3c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-3Zm10 4v5H3v-5c0-.6.4-1 1-1s1 .4 1 1v3h14v-3c0-.6.4-1 1-1s1 .4 1 1Z" fill-rule="evenodd"/></svg>',
'notice': '<svg width="24" height="24"><path d="M15.5 4 20 8.5v7L15.5 20h-7L4 15.5v-7L8.5 4h7ZM13 17v-2h-2v2h2Zm0-4V7h-2v6h2Z" fill-rule="evenodd" clip-rule="evenodd"/></svg>',
'ordered-list-rtl': '<svg width="24" height="24"><path d="M6 17h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2Zm0-6h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2Zm0-6h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2Zm13-1v3.5a.5.5 0 1 1-1 0V5h-.5a.5.5 0 1 1 0-1H19Zm-1 8.8.2.2h1.3a.5.5 0 1 1 0 1h-1.6a1 1 0 0 1-.9-1V13c0-.4.3-.8.6-1l1.2-.4.2-.3a.2.2 0 0 0-.2-.2h-1.3a.5.5 0 0 1-.5-.5c0-.3.2-.5.5-.5h1.6c.5 0 .9.4.9 1v.1c0 .4-.3.8-.6 1l-1.2.4-.2.3Zm2 4.2v2c0 .6-.4 1-1 1h-1.5a.5.5 0 0 1 0-1h1.2a.3.3 0 1 0 0-.6h-1.3a.4.4 0 1 1 0-.8h1.3a.3.3 0 0 0 0-.6h-1.2a.5.5 0 1 1 0-1H19c.6 0 1 .4 1 1Z" fill-rule="evenodd"/></svg>',
'ordered-list': '<svg width="24" height="24"><path d="M10 17h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 1 1 0-2ZM6 4v3.5c0 .3-.2.5-.5.5a.5.5 0 0 1-.5-.5V5h-.5a.5.5 0 0 1 0-1H6Zm-1 8.8.2.2h1.3c.3 0 .5.2.5.5s-.2.5-.5.5H4.9a1 1 0 0 1-.9-1V13c0-.4.3-.8.6-1l1.2-.4.2-.3a.2.2 0 0 0-.2-.2H4.5a.5.5 0 0 1-.5-.5c0-.3.2-.5.5-.5h1.6c.5 0 .9.4.9 1v.1c0 .4-.3.8-.6 1l-1.2.4-.2.3ZM7 17v2c0 .6-.4 1-1 1H4.5a.5.5 0 0 1 0-1h1.2c.2 0 .3-.1.3-.3 0-.2-.1-.3-.3-.3H4.4a.4.4 0 1 1 0-.8h1.3c.2 0 .3-.1.3-.3 0-.2-.1-.3-.3-.3H4.5a.5.5 0 1 1 0-1H6c.6 0 1 .4 1 1Z" fill-rule="evenodd"/></svg>',
'orientation': '<svg width="24" height="24"><path d="M7.3 6.4 1 13l6.4 6.5 6.5-6.5-6.5-6.5ZM3.7 13l3.6-3.7L11 13l-3.7 3.7-3.6-3.7ZM12 6l2.8 2.7c.3.3.3.8 0 1-.3.4-.9.4-1.2 0L9.2 5.7a.8.8 0 0 1 0-1.2L13.6.2c.3-.3.9-.3 1.2 0 .3.3.3.8 0 1.1L12 4h1a9 9 0 1 1-4.3 16.9l1.5-1.5A7 7 0 1 0 13 6h-1Z" fill-rule="nonzero"/></svg>',
'outdent': '<svg width="24" height="24"><path d="M7 5h12c.6 0 1 .4 1 1s-.4 1-1 1H7a1 1 0 1 1 0-2Zm5 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm0 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm-5 4h12a1 1 0 0 1 0 2H7a1 1 0 0 1 0-2Zm1.6-3.8a1 1 0 0 1-1.2 1.6l-3-2a1 1 0 0 1 0-1.6l3-2a1 1 0 0 1 1.2 1.6L6.8 12l1.8 1.2Z" fill-rule="evenodd"/></svg>',
'page-break': '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M5 11c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h1c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Zm4 0c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h1c.6 0 1 .4 1 1s-.4 1-1 1h-1a1 1 0 0 1 0-2Zm4 0c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2ZM7 3v5h10V3c0-.6.4-1 1-1s1 .4 1 1v7H5V3c0-.6.4-1 1-1s1 .4 1 1ZM6 22a1 1 0 0 1-1-1v-7h14v7c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-5H7v5c0 .6-.4 1-1 1Z"/></g></svg>',
'paragraph': '<svg width="24" height="24"><path fill-rule="evenodd" d="M10 5h7a1 1 0 0 1 0 2h-1v11a1 1 0 0 1-2 0V7h-2v11a1 1 0 0 1-2 0v-6c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 6.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L10 5Z"/></svg>',
'paste-column-after': '<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V7h-2V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h7v2H6c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm8 7v12h-6V8h6Zm-1.5 1.5h-3v9h3v-9ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',
'paste-column-before': '<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V18c0 1-.8 2-1.9 2H11v-2h7V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v2H4V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm-2 7v12H4V8h6ZM8.5 9.5h-3v9h3v-9ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',
'paste-row-after': '<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V11h-2V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h14c0 1-.8 2-1.9 2H6c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm10 11v5H8v-5h14Zm-1.5 1.5h-11v2h11v-2ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',
'paste-row-before': '<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V7h-2V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h12v-4h2v4c0 1-.8 2-1.9 2H6c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm10 7v5H8V8h14Zm-1.5 1.5h-11v2h11v-2ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',
'paste-text': '<svg width="24" height="24"><path d="M18 9V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h3V9h9ZM9 20H6a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.2A3 3 0 0 1 12 1a3 3 0 0 1 2.8 2H18a2 2 0 0 1 2 2v4h1v12H9v-1Zm1.5-9.5v9h9v-9h-9ZM12 3a1 1 0 0 0-1 1c0 .5.4 1 1 1s1-.5 1-1-.4-1-1-1Zm0 9h6v2h-.5l-.5-1h-1v4h.8v1h-3.6v-1h.8v-4h-1l-.5 1H12v-2Z" fill-rule="nonzero"/></svg>',
'paste': '<svg width="24" height="24"><path d="M18 9V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h3V9h9ZM9 20H6a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.2A3 3 0 0 1 12 1a3 3 0 0 1 2.8 2H18a2 2 0 0 1 2 2v4h1v12H9v-1Zm1.5-9.5v9h9v-9h-9ZM12 3a1 1 0 0 0-1 1c0 .5.4 1 1 1s1-.5 1-1-.4-1-1-1Z" fill-rule="nonzero"/></svg>',
'permanent-pen': '<svg width="24" height="24"><path d="M10.5 17.5 8 20H3v-3l3.5-3.5a2 2 0 0 1 0-3L14 3l1 1-7.3 7.3a1 1 0 0 0 0 1.4l3.6 3.6c.4.4 1 .4 1.4 0L20 9l1 1-7.6 7.6a2 2 0 0 1-2.8 0l-.1-.1Z" fill-rule="nonzero"/></svg>',
'plus': '<svg width="24" height="24"><path d="M12 4c.5 0 1 .4 1 .9V11h6a1 1 0 0 1 .1 2H13v6a1 1 0 0 1-2 .1V13H5a1 1 0 0 1-.1-2H11V5c0-.6.4-1 1-1Z"/></svg>',
'preferences': '<svg width="24" height="24"><path d="m20.1 13.5-1.9.2a5.8 5.8 0 0 1-.6 1.5l1.2 1.5c.4.4.3 1 0 1.4l-.7.7a1 1 0 0 1-1.4 0l-1.5-1.2a6.2 6.2 0 0 1-1.5.6l-.2 1.9c0 .5-.5.9-1 .9h-1a1 1 0 0 1-1-.9l-.2-1.9a5.8 5.8 0 0 1-1.5-.6l-1.5 1.2a1 1 0 0 1-1.4 0l-.7-.7a1 1 0 0 1 0-1.4l1.2-1.5a6.2 6.2 0 0 1-.6-1.5l-1.9-.2a1 1 0 0 1-.9-1v-1c0-.5.4-1 .9-1l1.9-.2a5.8 5.8 0 0 1 .6-1.5L5.2 7.3a1 1 0 0 1 0-1.4l.7-.7a1 1 0 0 1 1.4 0l1.5 1.2a6.2 6.2 0 0 1 1.5-.6l.2-1.9c0-.5.5-.9 1-.9h1c.5 0 1 .4 1 .9l.2 1.9a5.8 5.8 0 0 1 1.5.6l1.5-1.2a1 1 0 0 1 1.4 0l.7.7c.3.4.4 1 0 1.4l-1.2 1.5a6.2 6.2 0 0 1 .6 1.5l1.9.2c.5 0 .9.5.9 1v1c0 .5-.4 1-.9 1ZM12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" fill-rule="evenodd"/></svg>',
'preview': '<svg width="24" height="24"><path d="M3.5 12.5c.5.8 1.1 1.6 1.8 2.3 2 2 4.2 3.2 6.7 3.2s4.7-1.2 6.7-3.2a16.2 16.2 0 0 0 2.1-2.8 15.7 15.7 0 0 0-2.1-2.8c-2-2-4.2-3.2-6.7-3.2a9.3 9.3 0 0 0-6.7 3.2A16.2 16.2 0 0 0 3.2 12c0 .2.2.3.3.5Zm-2.4-1 .7-1.2L4 7.8C6.2 5.4 8.9 4 12 4c3 0 5.8 1.4 8.1 3.8a18.2 18.2 0 0 1 2.8 3.7v1l-.7 1.2-2.1 2.5c-2.3 2.4-5 3.8-8.1 3.8-3 0-5.8-1.4-8.1-3.8a18.2 18.2 0 0 1-2.8-3.7 1 1 0 0 1 0-1Zm12-3.3a2 2 0 1 0 2.7 2.6 4 4 0 1 1-2.6-2.6Z" fill-rule="nonzero"/></svg>',
'print': '<svg width="24" height="24"><path d="M18 8H6a3 3 0 0 0-3 3v6h2v3h14v-3h2v-6a3 3 0 0 0-3-3Zm-1 10H7v-4h10v4Zm.5-5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5Zm.5-8H6v2h12V5Z" fill-rule="nonzero"/></svg>',
'quote': '<svg width="24" height="24"><path d="M7.5 17h.9c.4 0 .7-.2.9-.6L11 13V8c0-.6-.4-1-1-1H6a1 1 0 0 0-1 1v4c0 .6.4 1 1 1h2l-1.3 2.7a1 1 0 0 0 .8 1.3Zm8 0h.9c.4 0 .7-.2.9-.6L19 13V8c0-.6-.4-1-1-1h-4a1 1 0 0 0-1 1v4c0 .6.4 1 1 1h2l-1.3 2.7a1 1 0 0 0 .8 1.3Z" fill-rule="nonzero"/></svg>',
'redo': '<svg width="24" height="24"><path d="M17.6 10H12c-2.8 0-4.4 1.4-4.9 3.5-.4 2 .3 4 1.4 4.6a1 1 0 1 1-1 1.8c-2-1.2-2.9-4.1-2.3-6.8.6-3 3-5.1 6.8-5.1h5.6l-3.3-3.3a1 1 0 1 1 1.4-1.4l5 5a1 1 0 0 1 0 1.4l-5 5a1 1 0 0 1-1.4-1.4l3.3-3.3Z" fill-rule="nonzero"/></svg>',
'reload': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="m5 22.1-1.2-4.7v-.2a1 1 0 0 1 1-1l5 .4a1 1 0 1 1-.2 2l-2.2-.2a7.8 7.8 0 0 0 8.4.2 7.5 7.5 0 0 0 3.5-6.4 1 1 0 1 1 2 0 9.5 9.5 0 0 1-4.5 8 9.9 9.9 0 0 1-10.2 0l.4 1.4a1 1 0 1 1-2 .5ZM13.6 7.4c0-.5.5-1 1-.9l2.8.2a8 8 0 0 0-9.5-1 7.5 7.5 0 0 0-3.6 7 1 1 0 0 1-2 0 9.5 9.5 0 0 1 4.5-8.6 10 10 0 0 1 10.9.3l-.3-1a1 1 0 0 1 2-.5l1.1 4.8a1 1 0 0 1-1 1.2l-5-.4a1 1 0 0 1-.9-1Z"/></g></svg>',
'remove-formatting': '<svg width="24" height="24"><path d="M13.2 6a1 1 0 0 1 0 .2l-2.6 10a1 1 0 0 1-1 .8h-.2a.8.8 0 0 1-.8-1l2.6-10H8a1 1 0 1 1 0-2h9a1 1 0 0 1 0 2h-3.8ZM5 18h7a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Zm13 1.5L16.5 18 15 19.5a.7.7 0 0 1-1-1l1.5-1.5-1.5-1.5a.7.7 0 0 1 1-1l1.5 1.5 1.5-1.5a.7.7 0 0 1 1 1L17.5 17l1.5 1.5a.7.7 0 0 1-1 1Z" fill-rule="evenodd"/></svg>',
'remove': '<svg width="24" height="24"><path d="M16 7h3a1 1 0 0 1 0 2h-1v9a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V9H5a1 1 0 1 1 0-2h3V6a3 3 0 0 1 3-3h2a3 3 0 0 1 3 3v1Zm-2 0V6c0-.6-.4-1-1-1h-2a1 1 0 0 0-1 1v1h4Zm2 2H8v9c0 .6.4 1 1 1h6c.6 0 1-.4 1-1V9Zm-7 3a1 1 0 0 1 2 0v4a1 1 0 0 1-2 0v-4Zm4 0a1 1 0 0 1 2 0v4a1 1 0 0 1-2 0v-4Z" fill-rule="nonzero"/></svg>',
'resize-handle': '<svg width="10" height="10"><g fill-rule="nonzero"><path d="M8.1 1.1A.5.5 0 1 1 9 2l-7 7A.5.5 0 1 1 1 8l7-7ZM8.1 5.1A.5.5 0 1 1 9 6l-3 3A.5.5 0 1 1 5 8l3-3Z"/></g></svg>',
'resize': '<svg width="24" height="24"><path d="M4 5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h6c.3 0 .5.1.7.3.2.2.3.4.3.7 0 .3-.1.5-.3.7a1 1 0 0 1-.7.3H7.4L18 16.6V13c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3.3 0 .5.1.7.3.2.2.3.4.3.7v6c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-6a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h3.6L6 7.4V11c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.7-.3A1 1 0 0 1 4 11V5Z" fill-rule="evenodd"/></svg>',
'restore-draft': '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M17 13c0 .6-.4 1-1 1h-4V8c0-.6.4-1 1-1s1 .4 1 1v4h2c.6 0 1 .4 1 1Z"/><path d="M4.7 10H9a1 1 0 0 1 0 2H3a1 1 0 0 1-1-1V5a1 1 0 1 1 2 0v3l2.5-2.4a9.2 9.2 0 0 1 10.8-1.5A9 9 0 0 1 13.4 21c-2.4.1-4.7-.7-6.5-2.2a1 1 0 1 1 1.3-1.5 7.2 7.2 0 0 0 11.6-3.7 7 7 0 0 0-3.5-7.7A7.2 7.2 0 0 0 8 7L4.7 10Z" fill-rule="nonzero"/></g></svg>',
'rotate-left': '<svg width="24" height="24"><path d="M4.7 10H9a1 1 0 0 1 0 2H3a1 1 0 0 1-1-1V5a1 1 0 1 1 2 0v3l2.5-2.4a9.2 9.2 0 0 1 10.8-1.5A9 9 0 0 1 13.4 21c-2.4.1-4.7-.7-6.5-2.2a1 1 0 1 1 1.3-1.5 7.2 7.2 0 0 0 11.6-3.7 7 7 0 0 0-3.5-7.7A7.2 7.2 0 0 0 8 7L4.7 10Z" fill-rule="nonzero"/></svg>',
'rotate-right': '<svg width="24" height="24"><path d="M20 8V5a1 1 0 0 1 2 0v6c0 .6-.4 1-1 1h-6a1 1 0 0 1 0-2h4.3L16 7A7.2 7.2 0 0 0 7.7 6a7 7 0 0 0 3 13.1c1.9.1 3.7-.5 5-1.7a1 1 0 0 1 1.4 1.5A9.2 9.2 0 0 1 2.2 14c-.9-3.9 1-8 4.5-9.9 3.5-1.9 8-1.3 10.8 1.5L20 8Z" fill-rule="nonzero"/></svg>',
'rtl': '<svg width="24" height="24"><path d="M8 5h8v2h-2v12h-2V7h-2v12H8v-7c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 4.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L8 5Zm12 11.2a1 1 0 1 1-1 1.6l-3-2a1 1 0 0 1 0-1.6l3-2a1 1 0 1 1 1 1.6L18.4 15l1.8 1.2Z" fill-rule="evenodd"/></svg>',
'save': '<svg width="24" height="24"><path d="M5 16h14a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2c0-1.1.9-2 2-2Zm0 2v2h14v-2H5Zm10 0h2v2h-2v-2Zm-4-6.4L8.7 9.3a1 1 0 1 0-1.4 1.4l4 4c.4.4 1 .4 1.4 0l4-4a1 1 0 1 0-1.4-1.4L13 11.6V4a1 1 0 0 0-2 0v7.6Z" fill-rule="nonzero"/></svg>',
'search': '<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3Zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12Z" fill-rule="nonzero"/></svg>',
'select-all': '<svg width="24" height="24"><path d="M3 5h2V3a2 2 0 0 0-2 2Zm0 8h2v-2H3v2Zm4 8h2v-2H7v2ZM3 9h2V7H3v2Zm10-6h-2v2h2V3Zm6 0v2h2a2 2 0 0 0-2-2ZM5 21v-2H3c0 1.1.9 2 2 2Zm-2-4h2v-2H3v2ZM9 3H7v2h2V3Zm2 18h2v-2h-2v2Zm8-8h2v-2h-2v2Zm0 8a2 2 0 0 0 2-2h-2v2Zm0-12h2V7h-2v2Zm0 8h2v-2h-2v2Zm-4 4h2v-2h-2v2Zm0-16h2V3h-2v2ZM7 17h10V7H7v10Zm2-8h6v6H9V9Z" fill-rule="nonzero"/></svg>',
'selected': '<svg width="24" height="24"><path fill-rule="nonzero" d="M6 4h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2Zm3.6 10.9L7 12.3a.7.7 0 0 0-1 1L9.6 17 18 8.6a.7.7 0 0 0 0-1 .7.7 0 0 0-1 0l-7.4 7.3Z"/></svg>',
'settings': '<svg width="24" height="24"><path d="M11 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8v.3c0 .2 0 .3-.2.5l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V8H5a1 1 0 1 1 0-2h2v-.3c0-.2 0-.3.2-.5l.5-.2h2.5c.3 0 .4 0 .6.2l.2.5V6ZM8 8h2V6H8v2Zm9 2.8v.2h2c.6 0 1 .4 1 1s-.4 1-1 1h-2v.3c0 .2 0 .3-.2.5l-.6.2h-2.4c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V13H5a1 1 0 0 1 0-2h8v-.3c0-.2 0-.3.2-.5l.6-.2h2.4c.3 0 .4 0 .6.2l.2.6ZM14 13h2v-2h-2v2Zm-3 2.8v.2h8c.6 0 1 .4 1 1s-.4 1-1 1h-8v.3c0 .2 0 .3-.2.5l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V18H5a1 1 0 0 1 0-2h2v-.3c0-.2 0-.3.2-.5l.5-.2h2.5c.3 0 .4 0 .6.2l.2.6ZM8 18h2v-2H8v2Z" fill-rule="evenodd"/></svg>',
'sharpen': '<svg width="24" height="24"><path d="m16 6 4 4-8 9-8-9 4-4h8Zm-4 10.2 5.5-6.2-.1-.1H12v-.3h5.1l-.2-.2H12V9h4.6l-.2-.2H12v-.3h4.1l-.2-.2H12V8h3.6l-.2-.2H8.7L6.5 10l.1.1H12v.3H6.9l.2.2H12v.3H7.3l.2.2H12v.3H7.7l.3.2h4v.3H8.2l.2.2H12v.3H8.6l.3.2H12v.3H9l.3.2H12v.3H9.5l.2.2H12v.3h-2l.2.2H12v.3h-1.6l.2.2H12v.3h-1.1l.2.2h.9v.3h-.7l.2.2h.5v.3h-.3l.3.2Z" fill-rule="evenodd"/></svg>',
'sourcecode': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M9.8 15.7c.3.3.3.8 0 1-.3.4-.9.4-1.2 0l-4.4-4.1a.8.8 0 0 1 0-1.2l4.4-4.2c.3-.3.9-.3 1.2 0 .3.3.3.8 0 1.1L6 12l3.8 3.7ZM14.2 15.7c-.3.3-.3.8 0 1 .4.4.9.4 1.2 0l4.4-4.1c.3-.3.3-.9 0-1.2l-4.4-4.2a.8.8 0 0 0-1.2 0c-.3.3-.3.8 0 1.1L18 12l-3.8 3.7Z"/></g></svg>',
'spell-check': '<svg width="24" height="24"><path d="M6 8v3H5V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h2c.3 0 .5.1.7.3.2.2.3.4.3.7v6H8V8H6Zm0-3v2h2V5H6Zm13 0h-3v5h3v1h-3a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h3v1Zm-5 1.5-.1.7c-.1.2-.3.3-.6.3.3 0 .5.1.6.3l.1.7V10c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-3V4h3c.3 0 .5.1.7.3.2.2.3.4.3.7v1.5ZM13 10V8h-2v2h2Zm0-3V5h-2v2h2Zm3 5 1 1-6.5 7L7 15.5l1.3-1 2.2 2.2L16 12Z" fill-rule="evenodd"/></svg>',
'strike-through': '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M15.6 8.5c-.5-.7-1-1.1-1.3-1.3-.6-.4-1.3-.6-2-.6-2.7 0-2.8 1.7-2.8 2.1 0 1.6 1.8 2 3.2 2.3 4.4.9 4.6 2.8 4.6 3.9 0 1.4-.7 4.1-5 4.1A6.2 6.2 0 0 1 7 16.4l1.5-1.1c.4.6 1.6 2 3.7 2 1.6 0 2.5-.4 3-1.2.4-.8.3-2-.8-2.6-.7-.4-1.6-.7-2.9-1-1-.2-3.9-.8-3.9-3.6C7.6 6 10.3 5 12.4 5c2.9 0 4.2 1.6 4.7 2.4l-1.5 1.1Z"/><path d="M5 11h14a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z" fill-rule="nonzero"/></g></svg>',
'subscript': '<svg width="24" height="24"><path d="m10.4 10 4.6 4.6-1.4 1.4L9 11.4 4.4 16 3 14.6 7.6 10 3 5.4 4.4 4 9 8.6 13.6 4 15 5.4 10.4 10ZM21 19h-5v-1l1-.8 1.7-1.6c.3-.4.5-.8.5-1.2 0-.3 0-.6-.2-.7-.2-.2-.5-.3-.9-.3a2 2 0 0 0-.8.2l-.7.3-.4-1.1 1-.6 1.2-.2c.8 0 1.4.3 1.8.7.4.4.6.9.6 1.5s-.2 1.1-.5 1.6a8 8 0 0 1-1.3 1.3l-.6.6h2.6V19Z" fill-rule="nonzero"/></svg>',
'superscript': '<svg width="24" height="24"><path d="M15 9.4 10.4 14l4.6 4.6-1.4 1.4L9 15.4 4.4 20 3 18.6 7.6 14 3 9.4 4.4 8 9 12.6 13.6 8 15 9.4Zm5.9 1.6h-5v-1l1-.8 1.7-1.6c.3-.5.5-.9.5-1.3 0-.3 0-.5-.2-.7-.2-.2-.5-.3-.9-.3l-.8.2-.7.4-.4-1.2c.2-.2.5-.4 1-.5.3-.2.8-.2 1.2-.2.8 0 1.4.2 1.8.6.4.4.6 1 .6 1.6 0 .5-.2 1-.5 1.5l-1.3 1.4-.6.5h2.6V11Z" fill-rule="nonzero"/></svg>',
'table-caption': '<svg width="24" height="24"><g fill-rule="nonzero"><rect width="12" height="2" x="3" y="4" rx="1"/><path d="M19 8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-8c0-1.1.9-2 2-2h14ZM5 15v3h6v-3H5Zm14 0h-6v3h6v-3Zm0-5h-6v3h6v-3ZM5 13h6v-3H5v3Z"/></g></svg>',
'table-cell-classes': '<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M13 4v9H3V6c0-1.1.9-2 2-2h8Zm-2 2H5v5h6V6Z"/><path fill-rule="nonzero" d="M13 4h6a2 2 0 0 1 2 2v7h-8v-2h6V6h-6V4Z" opacity=".2"/><path d="m18 20-2.6 1.6.7-3-2.4-2 3.1-.2 1.2-2.9 1.2 2.9 3.1.2-2.4 2 .7 3z"/><path fill-rule="nonzero" d="M3 13v5c0 1.1.9 2 2 2h8v-7h-2v5H5v-5H3Z" opacity=".2"/></g></svg>',
'table-cell-properties': '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 9H5v5h6v-5Zm8 0h-6v5h6v-5Zm-8-7H5v5h6V6Z"/></svg>',
'table-cell-select-all': '<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 2H5v12h14V6Z"/><path d="M13 6v5h6v2h-6v5h-2v-5H5v-2h6V6h2Z" opacity=".2"/></g></svg>',
'table-cell-select-inner': '<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 2H5v12h14V6Z" opacity=".2"/><path d="M13 6v5h6v2h-6v5h-2v-5H5v-2h6V6h2Z"/></g></svg>',
'table-classes': '<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v7h-8v7H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 9H5v5h6v-5Zm8-7h-6v5h6V6Zm-8 0H5v5h6V6Z"/><path d="m18 20-2.6 1.6.7-3-2.4-2 3.1-.2 1.2-2.9 1.2 2.9 3.1.2-2.4 2 .7 3z"/></g></svg>',
'table-delete-column': '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-4 4h-2V6h-2v2H9V6H5v12h4v-2h2v2h2v-2h2v2h4V6h-4v2Zm.3.5 1 1.2-3 2.3 3 2.3-1 1.2L12 13l-3.3 2.6-1-1.2 3-2.3-3-2.3 1-1.2L12 11l3.3-2.5Z"/></svg>',
'table-delete-row': '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 2H5v3h2.5v2H5v2h2.5v2H5v3h14v-3h-2.5v-2H19v-2h-2.5V9H19V6Zm-4.7 1.8 1.2 1L13 12l2.6 3.3-1.2 1-2.3-3-2.3 3-1.2-1L11 12 8.5 8.7l1.2-1 2.3 3 2.3-3Z"/></svg>',
'table-delete-table': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 6v12h14V6H5Z"/><path d="m14.4 8.6 1.1 1-2.4 2.4 2.4 2.4-1.1 1.1-2.4-2.4-2.4 2.4-1-1.1 2.3-2.4-2.3-2.4 1-1 2.4 2.3z"/></g></svg>',
'table-insert-column-after': '<svg width="24" height="24"><path fill-rule="nonzero" d="M20 4c.6 0 1 .4 1 1v2a1 1 0 0 1-2 0V6h-8v12h8v-1a1 1 0 0 1 2 0v2c0 .5-.4 1-.9 1H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h15ZM9 13H5v5h4v-5Zm7-5c.5 0 1 .4 1 .9V11h2a1 1 0 0 1 .1 2H17v2a1 1 0 0 1-2 .1V13h-2a1 1 0 0 1-.1-2H15V9c0-.6.4-1 1-1ZM9 6H5v5h4V6Z"/></svg>',
'table-insert-column-before': '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a1 1 0 0 1-1-1v-2a1 1 0 0 1 2 0v1h8V6H5v1a1 1 0 1 1-2 0V5c0-.6.4-1 1-1h15Zm0 9h-4v5h4v-5ZM8 8c.5 0 1 .4 1 .9V11h2a1 1 0 0 1 .1 2H9v2a1 1 0 0 1-2 .1V13H5a1 1 0 0 1-.1-2H7V9c0-.6.4-1 1-1Zm11-2h-4v5h4V6Z"/></svg>',
'table-insert-row-above': '<svg width="24" height="24"><path fill-rule="nonzero" d="M6 4a1 1 0 1 1 0 2H5v6h14V6h-1a1 1 0 0 1 0-2h2c.6 0 1 .4 1 1v13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5c0-.6.4-1 1-1h2Zm5 10H5v4h6v-4Zm8 0h-6v4h6v-4ZM12 3c.5 0 1 .4 1 .9V6h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 .1V8H9a1 1 0 0 1 0-2h2V4c0-.6.4-1 1-1Z"/></svg>',
'table-insert-row-after': '<svg width="24" height="24"><path fill-rule="nonzero" d="M12 13c.5 0 1 .4 1 .9V16h2a1 1 0 0 1 .1 2H13v2a1 1 0 0 1-2 .1V18H9a1 1 0 0 1-.1-2H11v-2c0-.6.4-1 1-1Zm6 7a1 1 0 0 1 0-2h1v-6H5v6h1a1 1 0 0 1 0 2H4a1 1 0 0 1-1-1V6c0-1.1.9-2 2-2h14a2 2 0 0 1 2 2v13c0 .5-.4 1-.9 1H18ZM11 6H5v4h6V6Zm8 0h-6v4h6V6Z"/></svg>',
'table-left-header': '<svg width="24" height="24"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 9h-4v5h4v-5Zm-6 0H9v5h4v-5Zm0-7H9v5h4V6Zm6 0h-4v5h4V6Z"/></svg>',
'table-merge-cells': '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 15.5V18h3v-2.5H5Zm14-5h-9V18h9v-7.5ZM19 6h-4v2.5h4V6ZM8 6H5v2.5h3V6Zm5 0h-3v2.5h3V6Zm-8 7.5h3v-3H5v3Z"/></svg>',
'table-row-numbering-rtl': '<svg width="24" height="24"><path d="M6 4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6Zm0 12h8v3H6v-3Zm11 0c.6 0 1 .4 1 1v1a1 1 0 0 1-2 0v-1c0-.6.4-1 1-1ZM6 11h8v3H6v-3Zm11 0c.6 0 1 .4 1 1v1a1 1 0 0 1-2 0v-1c0-.6.4-1 1-1ZM6 6h8v3H6V6Zm11 0c.6 0 1 .4 1 1v1a1 1 0 1 1-2 0V7c0-.6.4-1 1-1Z"/></svg>',
'table-row-numbering': '<svg width="24" height="24"><path d="M18 4a2 2 0 0 1 2 2v13a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h12Zm0 12h-8v3h8v-3ZM7 16a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1c0-.6-.4-1-1-1Zm11-5h-8v3h8v-3ZM7 11a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1c0-.6-.4-1-1-1Zm11-5h-8v3h8V6ZM7 6a1 1 0 0 0-1 1v1a1 1 0 1 0 2 0V7c0-.6-.4-1-1-1Z"/></svg>',
'table-row-properties': '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 15v3h6v-3H5Zm14 0h-6v3h6v-3Zm0-9h-6v3h6V6ZM5 9h6V6H5v3Z"/></svg>',
'table-split-cells': '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM8 15.5H5V18h3v-2.5Zm11-5h-9V18h9v-7.5Zm-2.5 1 1 1-2 2 2 2-1 1-2-2-2 2-1-1 2-2-2-2 1-1 2 2 2-2Zm-8.5-1H5v3h3v-3ZM19 6h-4v2.5h4V6ZM8 6H5v2.5h3V6Zm5 0h-3v2.5h3V6Z"/></svg>',
'table-top-header': '<svg width="24" height="24"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 11H5v3h6v-3Zm8 0h-6v3h6v-3Zm0-5h-6v3h6v-3ZM5 13h6v-3H5v3Z"/></svg>',
'table': '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 14v4h6v-4H5Zm14 0h-6v4h6v-4Zm0-6h-6v4h6V8ZM5 12h6V8H5v4Z"/></svg>',
'template': '<svg width="24" height="24"><path d="M19 19v-1H5v1h14ZM9 16v-4a5 5 0 1 1 6 0v4h4a2 2 0 0 1 2 2v3H3v-3c0-1.1.9-2 2-2h4Zm4 0v-5l.8-.6a3 3 0 1 0-3.6 0l.8.6v5h2Z" fill-rule="nonzero"/></svg>',
'temporary-placeholder': '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M9 7.6V6h2.5V4.5a.5.5 0 1 1 1 0V6H15v1.6a8 8 0 1 1-6 0Zm-2.6 5.3a.5.5 0 0 0 .3.6c.3 0 .6 0 .6-.3l.1-.2a5 5 0 0 1 3.3-2.8c.3-.1.4-.4.4-.6-.1-.3-.4-.5-.6-.4a6 6 0 0 0-4.1 3.7Z"/><circle cx="14" cy="4" r="1"/><circle cx="12" cy="2" r="1"/><circle cx="10" cy="4" r="1"/></g></svg>',
'text-color': '<svg width="24" height="24"><g fill-rule="evenodd"><path id="tox-icon-text-color__color" d="M3 18h18v3H3z"/><path d="M8.7 16h-.8a.5.5 0 0 1-.5-.6l2.7-9c.1-.3.3-.4.5-.4h2.8c.2 0 .4.1.5.4l2.7 9a.5.5 0 0 1-.5.6h-.8a.5.5 0 0 1-.4-.4l-.7-2.2c0-.3-.3-.4-.5-.4h-3.4c-.2 0-.4.1-.5.4l-.7 2.2c0 .3-.2.4-.4.4Zm2.6-7.6-.6 2a.5.5 0 0 0 .5.6h1.6a.5.5 0 0 0 .5-.6l-.6-2c0-.3-.3-.4-.5-.4h-.4c-.2 0-.4.1-.5.4Z"/></g></svg>',
'toc': '<svg width="24" height="24"><path d="M5 5c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 1 1 0-2Zm3 0h11c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 1 1 0-2Zm-3 8c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h11c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Zm0-4c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 1 1 0-2Zm3 0h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm-3 8c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
'translate': '<svg width="24" height="24"><path d="m12.7 14.3-.3.7-.4.7-2.2-2.2-3.1 3c-.3.4-.8.4-1 0a.7.7 0 0 1 0-1l3.1-3A12.4 12.4 0 0 1 6.7 9H8a10.1 10.1 0 0 0 1.7 2.4c.5-.5 1-1.1 1.4-1.8l.9-2H4.7a.7.7 0 1 1 0-1.5h4.4v-.7c0-.4.3-.8.7-.8.4 0 .7.4.7.8v.7H15c.4 0 .8.3.8.7 0 .4-.4.8-.8.8h-1.4a12.3 12.3 0 0 1-1 2.4 13.5 13.5 0 0 1-1.7 2.3l1.9 1.8Zm4.3-3 2.7 7.3a.5.5 0 0 1-.4.7 1 1 0 0 1-1-.7l-.6-1.5h-3.4l-.6 1.5a1 1 0 0 1-1 .7.5.5 0 0 1-.4-.7l2.7-7.4a1 1 0 0 1 2 0Zm-2.2 4.4h2.4L16 12.5l-1.2 3.2Z" fill-rule="evenodd"/></svg>',
'typography': '<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M17 5a1 1 0 1 1 0 2h-4v11a1 1 0 1 1-2 0V7H7a1 1 0 0 1 0-2h10Z"/><path d="m17.5 14 .8-1.7 1.7-.8-1.7-.8-.8-1.7-.8 1.7-1.7.8 1.7.8.8 1.7ZM7 14l1 2 2 1-2 1-1 2-1-2-2-1 2-1 1-2Z"/></svg>',
'underline': '<svg width="24" height="24"><path d="M16 5c.6 0 1 .4 1 1v5.5a4 4 0 0 1-.4 1.8l-1 1.4a5.3 5.3 0 0 1-5.5 1 5 5 0 0 1-1.6-1c-.5-.4-.8-.9-1.1-1.4a4 4 0 0 1-.4-1.8V6c0-.6.4-1 1-1s1 .4 1 1v5.5c0 .3 0 .6.2 1l.6.7a3.3 3.3 0 0 0 2.2.8 3.4 3.4 0 0 0 2.2-.8c.3-.2.4-.5.6-.8l.2-.9V6c0-.6.4-1 1-1ZM8 17h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
'undo': '<svg width="24" height="24"><path d="M6.4 8H12c3.7 0 6.2 2 6.8 5.1.6 2.7-.4 5.6-2.3 6.8a1 1 0 0 1-1-1.8c1.1-.6 1.8-2.7 1.4-4.6-.5-2.1-2.1-3.5-4.9-3.5H6.4l3.3 3.3a1 1 0 1 1-1.4 1.4l-5-5a1 1 0 0 1 0-1.4l5-5a1 1 0 0 1 1.4 1.4L6.4 8Z" fill-rule="nonzero"/></svg>',
'unlink': '<svg width="24" height="24"><path d="M6.2 12.3a1 1 0 0 1 1.4 1.4l-2 2a2 2 0 1 0 2.6 2.8l4.8-4.8a1 1 0 0 0 0-1.4 1 1 0 1 1 1.4-1.3 2.9 2.9 0 0 1 0 4L9.6 20a3.9 3.9 0 0 1-5.5-5.5l2-2Zm11.6-.6a1 1 0 0 1-1.4-1.4l2.1-2a2 2 0 1 0-2.7-2.8L11 10.3a1 1 0 0 0 0 1.4A1 1 0 1 1 9.6 13a2.9 2.9 0 0 1 0-4L14.4 4a3.9 3.9 0 0 1 5.5 5.5l-2 2ZM7.6 6.3a.8.8 0 0 1-1 1.1L3.3 4.2a.7.7 0 1 1 1-1l3.2 3.1ZM5.1 8.6a.8.8 0 0 1 0 1.5H3a.8.8 0 0 1 0-1.5H5Zm5-3.5a.8.8 0 0 1-1.5 0V3a.8.8 0 0 1 1.5 0V5Zm6 11.8a.8.8 0 0 1 1-1l3.2 3.2a.8.8 0 0 1-1 1L16 17Zm-2.2 2a.8.8 0 0 1 1.5 0V21a.8.8 0 0 1-1.5 0V19Zm5-3.5a.7.7 0 1 1 0-1.5H21a.8.8 0 0 1 0 1.5H19Z" fill-rule="nonzero"/></svg>',
'unlock': '<svg width="24" height="24"><path d="M16 5c.8 0 1.5.3 2.1.9.6.6.9 1.3.9 2.1v3h-2V8a1 1 0 0 0-.3-.7A1 1 0 0 0 16 7h-2a1 1 0 0 0-.7.3 1 1 0 0 0-.3.7v3h.3c.2 0 .3 0 .5.2l.2.6v7.4c0 .3 0 .4-.2.6l-.6.2H4.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6v-7.4c0-.3 0-.4.2-.6l.5-.2H11V8c0-.8.3-1.5.9-2.1.6-.6 1.3-.9 2.1-.9h2Z" fill-rule="evenodd"/></svg>',
'unordered-list': '<svg width="24" height="24"><path d="M11 5h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2ZM4.5 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1Zm0 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1Zm0 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1Z" fill-rule="evenodd"/></svg>',
'unselected': '<svg width="24" height="24"><path fill-rule="nonzero" d="M6 4h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2Zm0 1a1 1 0 0 0-1 1v12c0 .6.4 1 1 1h12c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H6Z"/></svg>',
'upload': '<svg width="24" height="24"><path d="M18 19v-2a1 1 0 0 1 2 0v3c0 .6-.4 1-1 1H5a1 1 0 0 1-1-1v-3a1 1 0 0 1 2 0v2h12ZM11 6.4 8.7 8.7a1 1 0 0 1-1.4-1.4l4-4a1 1 0 0 1 1.4 0l4 4a1 1 0 1 1-1.4 1.4L13 6.4V16a1 1 0 0 1-2 0V6.4Z" fill-rule="nonzero"/></svg>',
'user': '<svg width="24" height="24"><path d="M12 24a12 12 0 1 1 0-24 12 12 0 0 1 0 24Zm-8.7-5.3a11 11 0 0 0 17.4 0C19.4 16.3 14.6 15 12 15c-2.6 0-7.4 1.3-8.7 3.7ZM12 13c2.2 0 4-2 4-4.5S14.2 4 12 4 8 6 8 8.5 9.8 13 12 13Z" fill-rule="nonzero"/></svg>',
'vertical-align': '<svg width="24" height="24"><g fill-rule="nonzero"><rect width="18" height="2" x="3" y="11" rx="1"/><path d="M12 2c.6 0 1 .4 1 1v4l2-1.3a1 1 0 0 1 1.2 1.5l-.1.1-4.1 3-4-3a1 1 0 0 1 1-1.7l2 1.5V3c0-.6.4-1 1-1zm0 11.8 4 2.9a1 1 0 0 1-1 1.7l-2-1.5V21c0 .5-.4 1-.9 1H12a1 1 0 0 1-1-1v-4l-2 1.3a1 1 0 0 1-1.2-.1l-.1-.1a1 1 0 0 1 .1-1.3l.1-.1 4.1-3z"/></g></svg>',
'visualblocks': '<svg width="24" height="24"><path d="M9 19v2H7v-2h2Zm-4 0v2a2 2 0 0 1-2-2h2Zm8 0v2h-2v-2h2Zm8 0a2 2 0 0 1-2 2v-2h2Zm-4 0v2h-2v-2h2ZM15 7a1 1 0 0 1 0 2v7a1 1 0 0 1-2 0V9h-1v7a1 1 0 0 1-2 0v-4a2.5 2.5 0 0 1-.2-5H15ZM5 15v2H3v-2h2Zm16 0v2h-2v-2h2ZM5 11v2H3v-2h2Zm16 0v2h-2v-2h2ZM5 7v2H3V7h2Zm16 0v2h-2V7h2ZM5 3v2H3c0-1.1.9-2 2-2Zm8 0v2h-2V3h2Zm6 0a2 2 0 0 1 2 2h-2V3ZM9 3v2H7V3h2Zm8 0v2h-2V3h2Z" fill-rule="evenodd"/></svg>',
'visualchars': '<svg width="24" height="24"><path d="M10 5h7a1 1 0 0 1 0 2h-1v11a1 1 0 0 1-2 0V7h-2v11a1 1 0 0 1-2 0v-6c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 6.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L10 5Z" fill-rule="evenodd"/></svg>',
'warning': '<svg width="24" height="24"><path d="M19.8 18.3c.2.5.3.9 0 1.2-.1.3-.5.5-1 .5H5.2c-.5 0-.9-.2-1-.5-.3-.3-.2-.7 0-1.2L11 4.7l.5-.5.5-.2c.2 0 .3 0 .5.2.2 0 .3.3.5.5l6.8 13.6ZM12 18c.3 0 .5-.1.7-.3.2-.2.3-.4.3-.7a1 1 0 0 0-.3-.7 1 1 0 0 0-.7-.3 1 1 0 0 0-.7.3 1 1 0 0 0-.3.7c0 .3.1.5.3.7.2.2.4.3.7.3Zm.7-3 .3-4a1 1 0 0 0-.3-.7 1 1 0 0 0-.7-.3 1 1 0 0 0-.7.3 1 1 0 0 0-.3.7l.3 4h1.4Z" fill-rule="evenodd"/></svg>',
'zoom-in': '<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3Zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12Zm-1-9a1 1 0 0 1 2 0v6a1 1 0 0 1-2 0V8Zm-2 4a1 1 0 0 1 0-2h6a1 1 0 0 1 0 2H8Z" fill-rule="nonzero"/></svg>',
'zoom-out': '<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3Zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12Zm-3-5a1 1 0 0 1 0-2h6a1 1 0 0 1 0 2H8Z" fill-rule="nonzero"/></svg>',
}
});
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
This is where language files should be placed.
Please DO NOT translate these directly use this service: https://www.transifex.com/projects/p/tinymce/
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Ephox Corporation DBA Tiny Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,253 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager');
const applyListFormat = (editor, listName, styleValue) => {
const cmd = listName === 'UL' ? 'InsertUnorderedList' : 'InsertOrderedList';
editor.execCommand(cmd, false, styleValue === false ? null : { 'list-style-type': styleValue });
};
const register$2 = editor => {
editor.addCommand('ApplyUnorderedListStyle', (ui, value) => {
applyListFormat(editor, 'UL', value['list-style-type']);
});
editor.addCommand('ApplyOrderedListStyle', (ui, value) => {
applyListFormat(editor, 'OL', value['list-style-type']);
});
};
const option = name => editor => editor.options.get(name);
const register$1 = editor => {
const registerOption = editor.options.register;
registerOption('advlist_number_styles', {
processor: 'string[]',
default: 'default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman'.split(',')
});
registerOption('advlist_bullet_styles', {
processor: 'string[]',
default: 'default,circle,square'.split(',')
});
};
const getNumberStyles = option('advlist_number_styles');
const getBulletStyles = option('advlist_bullet_styles');
const isNullable = a => a === null || a === undefined;
const isNonNullable = a => !isNullable(a);
var global = tinymce.util.Tools.resolve('tinymce.util.Tools');
class Optional {
constructor(tag, value) {
this.tag = tag;
this.value = value;
}
static some(value) {
return new Optional(true, value);
}
static none() {
return Optional.singletonNone;
}
fold(onNone, onSome) {
if (this.tag) {
return onSome(this.value);
} else {
return onNone();
}
}
isSome() {
return this.tag;
}
isNone() {
return !this.tag;
}
map(mapper) {
if (this.tag) {
return Optional.some(mapper(this.value));
} else {
return Optional.none();
}
}
bind(binder) {
if (this.tag) {
return binder(this.value);
} else {
return Optional.none();
}
}
exists(predicate) {
return this.tag && predicate(this.value);
}
forall(predicate) {
return !this.tag || predicate(this.value);
}
filter(predicate) {
if (!this.tag || predicate(this.value)) {
return this;
} else {
return Optional.none();
}
}
getOr(replacement) {
return this.tag ? this.value : replacement;
}
or(replacement) {
return this.tag ? this : replacement;
}
getOrThunk(thunk) {
return this.tag ? this.value : thunk();
}
orThunk(thunk) {
return this.tag ? this : thunk();
}
getOrDie(message) {
if (!this.tag) {
throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
} else {
return this.value;
}
}
static from(value) {
return isNonNullable(value) ? Optional.some(value) : Optional.none();
}
getOrNull() {
return this.tag ? this.value : null;
}
getOrUndefined() {
return this.value;
}
each(worker) {
if (this.tag) {
worker(this.value);
}
}
toArray() {
return this.tag ? [this.value] : [];
}
toString() {
return this.tag ? `some(${ this.value })` : 'none()';
}
}
Optional.singletonNone = new Optional(false);
const isChildOfBody = (editor, elm) => {
return editor.dom.isChildOf(elm, editor.getBody());
};
const isTableCellNode = node => {
return isNonNullable(node) && /^(TH|TD)$/.test(node.nodeName);
};
const isListNode = editor => node => {
return isNonNullable(node) && /^(OL|UL|DL)$/.test(node.nodeName) && isChildOfBody(editor, node);
};
const getSelectedStyleType = editor => {
const listElm = editor.dom.getParent(editor.selection.getNode(), 'ol,ul');
const style = editor.dom.getStyle(listElm, 'listStyleType');
return Optional.from(style);
};
const isWithinNonEditable = (editor, element) => element !== null && editor.dom.getContentEditableParent(element) === 'false';
const isWithinNonEditableList = (editor, element) => {
const parentList = editor.dom.getParent(element, 'ol,ul,dl');
return isWithinNonEditable(editor, parentList);
};
const findIndex = (list, predicate) => {
for (let index = 0; index < list.length; index++) {
const element = list[index];
if (predicate(element)) {
return index;
}
}
return -1;
};
const styleValueToText = styleValue => {
return styleValue.replace(/\-/g, ' ').replace(/\b\w/g, chr => {
return chr.toUpperCase();
});
};
const normalizeStyleValue = styleValue => isNullable(styleValue) || styleValue === 'default' ? '' : styleValue;
const isWithinList = (editor, e, nodeName) => {
const tableCellIndex = findIndex(e.parents, isTableCellNode);
const parents = tableCellIndex !== -1 ? e.parents.slice(0, tableCellIndex) : e.parents;
const lists = global.grep(parents, isListNode(editor));
return lists.length > 0 && lists[0].nodeName === nodeName;
};
const makeSetupHandler = (editor, nodeName) => api => {
const nodeChangeHandler = e => {
api.setActive(isWithinList(editor, e, nodeName));
api.setEnabled(!isWithinNonEditableList(editor, e.element));
};
editor.on('NodeChange', nodeChangeHandler);
return () => editor.off('NodeChange', nodeChangeHandler);
};
const addSplitButton = (editor, id, tooltip, cmd, nodeName, styles) => {
editor.ui.registry.addSplitButton(id, {
tooltip,
icon: nodeName === 'OL' ? 'ordered-list' : 'unordered-list',
presets: 'listpreview',
columns: 3,
fetch: callback => {
const items = global.map(styles, styleValue => {
const iconStyle = nodeName === 'OL' ? 'num' : 'bull';
const iconName = styleValue === 'disc' || styleValue === 'decimal' ? 'default' : styleValue;
const itemValue = normalizeStyleValue(styleValue);
const displayText = styleValueToText(styleValue);
return {
type: 'choiceitem',
value: itemValue,
icon: 'list-' + iconStyle + '-' + iconName,
text: displayText
};
});
callback(items);
},
onAction: () => editor.execCommand(cmd),
onItemAction: (_splitButtonApi, value) => {
applyListFormat(editor, nodeName, value);
},
select: value => {
const listStyleType = getSelectedStyleType(editor);
return listStyleType.map(listStyle => value === listStyle).getOr(false);
},
onSetup: makeSetupHandler(editor, nodeName)
});
};
const addButton = (editor, id, tooltip, cmd, nodeName, styleValue) => {
editor.ui.registry.addToggleButton(id, {
active: false,
tooltip,
icon: nodeName === 'OL' ? 'ordered-list' : 'unordered-list',
onSetup: makeSetupHandler(editor, nodeName),
onAction: () => editor.queryCommandState(cmd) || styleValue === '' ? editor.execCommand(cmd) : applyListFormat(editor, nodeName, styleValue)
});
};
const addControl = (editor, id, tooltip, cmd, nodeName, styles) => {
if (styles.length > 1) {
addSplitButton(editor, id, tooltip, cmd, nodeName, styles);
} else {
addButton(editor, id, tooltip, cmd, nodeName, normalizeStyleValue(styles[0]));
}
};
const register = editor => {
addControl(editor, 'numlist', 'Numbered list', 'InsertOrderedList', 'OL', getNumberStyles(editor));
addControl(editor, 'bullist', 'Bullet list', 'InsertUnorderedList', 'UL', getBulletStyles(editor));
};
var Plugin = () => {
global$1.add('advlist', editor => {
if (editor.hasPlugin('lists')) {
register$1(editor);
register(editor);
register$2(editor);
} else {
console.error('Please use the Lists plugin together with the Advanced List plugin.');
}
});
};
Plugin();
})();
+4
View File
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=(t,e,r)=>{const s="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(s,!1,!1===r?null:{"list-style-type":r})},r=t=>e=>e.options.get(t),s=r("advlist_number_styles"),n=r("advlist_bullet_styles"),l=t=>null==t,i=t=>!l(t);var o=tinymce.util.Tools.resolve("tinymce.util.Tools");class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return i(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=t=>i(t)&&/^(TH|TD)$/.test(t.nodeName),d=t=>l(t)||"default"===t?"":t,g=(t,e)=>r=>{const s=s=>{r.setActive(((t,e,r)=>{const s=((t,e)=>{for(let r=0;r<t.length;r++)if(e(t[r]))return r;return-1})(e.parents,u),n=-1!==s?e.parents.slice(0,s):e.parents,l=o.grep(n,(t=>e=>i(e)&&/^(OL|UL|DL)$/.test(e.nodeName)&&((t,e)=>t.dom.isChildOf(e,t.getBody()))(t,e))(t));return l.length>0&&l[0].nodeName===r})(t,s,e)),r.setEnabled(!((t,e)=>{const r=t.dom.getParent(e,"ol,ul,dl");return((t,e)=>null!==e&&"false"===t.dom.getContentEditableParent(e))(t,r)})(t,s.element))};return t.on("NodeChange",s),()=>t.off("NodeChange",s)},h=(t,r,s,n,l,i)=>{i.length>1?((t,r,s,n,l,i)=>{t.ui.registry.addSplitButton(r,{tooltip:s,icon:"OL"===l?"ordered-list":"unordered-list",presets:"listpreview",columns:3,fetch:t=>{t(o.map(i,(t=>{const e="OL"===l?"num":"bull",r="disc"===t||"decimal"===t?"default":t,s=d(t),n=(t=>t.replace(/\-/g," ").replace(/\b\w/g,(t=>t.toUpperCase())))(t);return{type:"choiceitem",value:s,icon:"list-"+e+"-"+r,text:n}})))},onAction:()=>t.execCommand(n),onItemAction:(r,s)=>{e(t,l,s)},select:e=>{const r=(t=>{const e=t.dom.getParent(t.selection.getNode(),"ol,ul"),r=t.dom.getStyle(e,"listStyleType");return a.from(r)})(t);return r.map((t=>e===t)).getOr(!1)},onSetup:g(t,l)})})(t,r,s,n,l,i):((t,r,s,n,l,i)=>{t.ui.registry.addToggleButton(r,{active:!1,tooltip:s,icon:"OL"===l?"ordered-list":"unordered-list",onSetup:g(t,l),onAction:()=>t.queryCommandState(n)||""===i?t.execCommand(n):e(t,l,i)})})(t,r,s,n,l,d(i[0]))};t.add("advlist",(t=>{t.hasPlugin("lists")?((t=>{const e=t.options.register;e("advlist_number_styles",{processor:"string[]",default:"default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")}),e("advlist_bullet_styles",{processor:"string[]",default:"default,circle,square".split(",")})})(t),(t=>{h(t,"numlist","Numbered list","InsertOrderedList","OL",s(t)),h(t,"bullist","Bullet list","InsertUnorderedList","UL",n(t))})(t),(t=>{t.addCommand("ApplyUnorderedListStyle",((r,s)=>{e(t,"UL",s["list-style-type"])})),t.addCommand("ApplyOrderedListStyle",((r,s)=>{e(t,"OL",s["list-style-type"])}))})(t)):console.error("Please use the Lists plugin together with the Advanced List plugin.")}))}();
@@ -0,0 +1,196 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$2 = tinymce.util.Tools.resolve('tinymce.PluginManager');
var global$1 = tinymce.util.Tools.resolve('tinymce.dom.RangeUtils');
var global = tinymce.util.Tools.resolve('tinymce.util.Tools');
const option = name => editor => editor.options.get(name);
const register$2 = editor => {
const registerOption = editor.options.register;
registerOption('allow_html_in_named_anchor', {
processor: 'boolean',
default: false
});
};
const allowHtmlInNamedAnchor = option('allow_html_in_named_anchor');
const namedAnchorSelector = 'a:not([href])';
const isEmptyString = str => !str;
const getIdFromAnchor = elm => {
const id = elm.getAttribute('id') || elm.getAttribute('name');
return id || '';
};
const isAnchor = elm => elm.nodeName.toLowerCase() === 'a';
const isNamedAnchor = elm => isAnchor(elm) && !elm.getAttribute('href') && getIdFromAnchor(elm) !== '';
const isEmptyNamedAnchor = elm => isNamedAnchor(elm) && !elm.firstChild;
const removeEmptyNamedAnchorsInSelection = editor => {
const dom = editor.dom;
global$1(dom).walk(editor.selection.getRng(), nodes => {
global.each(nodes, node => {
if (isEmptyNamedAnchor(node)) {
dom.remove(node, false);
}
});
});
};
const isValidId = id => /^[A-Za-z][A-Za-z0-9\-:._]*$/.test(id);
const getNamedAnchor = editor => editor.dom.getParent(editor.selection.getStart(), namedAnchorSelector);
const getId = editor => {
const anchor = getNamedAnchor(editor);
if (anchor) {
return getIdFromAnchor(anchor);
} else {
return '';
}
};
const createAnchor = (editor, id) => {
editor.undoManager.transact(() => {
if (!allowHtmlInNamedAnchor(editor)) {
editor.selection.collapse(true);
}
if (editor.selection.isCollapsed()) {
editor.insertContent(editor.dom.createHTML('a', { id }));
} else {
removeEmptyNamedAnchorsInSelection(editor);
editor.formatter.remove('namedAnchor', undefined, undefined, true);
editor.formatter.apply('namedAnchor', { value: id });
editor.addVisual();
}
});
};
const updateAnchor = (editor, id, anchorElement) => {
anchorElement.removeAttribute('name');
anchorElement.id = id;
editor.addVisual();
editor.undoManager.add();
};
const insert = (editor, id) => {
const anchor = getNamedAnchor(editor);
if (anchor) {
updateAnchor(editor, id, anchor);
} else {
createAnchor(editor, id);
}
editor.focus();
};
const insertAnchor = (editor, newId) => {
if (!isValidId(newId)) {
editor.windowManager.alert('ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.');
return false;
} else {
insert(editor, newId);
return true;
}
};
const open = editor => {
const currentId = getId(editor);
editor.windowManager.open({
title: 'Anchor',
size: 'normal',
body: {
type: 'panel',
items: [{
name: 'id',
type: 'input',
label: 'ID',
placeholder: 'example'
}]
},
buttons: [
{
type: 'cancel',
name: 'cancel',
text: 'Cancel'
},
{
type: 'submit',
name: 'save',
text: 'Save',
primary: true
}
],
initialData: { id: currentId },
onSubmit: api => {
if (insertAnchor(editor, api.getData().id)) {
api.close();
}
}
});
};
const register$1 = editor => {
editor.addCommand('mceAnchor', () => {
open(editor);
});
};
const isNamedAnchorNode = node => isEmptyString(node.attr('href')) && !isEmptyString(node.attr('id') || node.attr('name'));
const isEmptyNamedAnchorNode = node => isNamedAnchorNode(node) && !node.firstChild;
const setContentEditable = state => nodes => {
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (isEmptyNamedAnchorNode(node)) {
node.attr('contenteditable', state);
}
}
};
const setup = editor => {
editor.on('PreInit', () => {
editor.parser.addNodeFilter('a', setContentEditable('false'));
editor.serializer.addNodeFilter('a', setContentEditable(null));
});
};
const registerFormats = editor => {
editor.formatter.register('namedAnchor', {
inline: 'a',
selector: namedAnchorSelector,
remove: 'all',
split: true,
deep: true,
attributes: { id: '%value' },
onmatch: (node, _fmt, _itemName) => {
return isNamedAnchor(node);
}
});
};
const register = editor => {
const onAction = () => editor.execCommand('mceAnchor');
editor.ui.registry.addToggleButton('anchor', {
icon: 'bookmark',
tooltip: 'Anchor',
onAction,
onSetup: buttonApi => editor.selection.selectorChangedWithUnbind('a:not([href])', buttonApi.setActive).unbind
});
editor.ui.registry.addMenuItem('anchor', {
icon: 'bookmark',
text: 'Anchor...',
onAction
});
};
var Plugin = () => {
global$2.add('anchor', editor => {
register$2(editor);
setup(editor);
register$1(editor);
register(editor);
editor.on('PreInit', () => {
registerFormats(editor);
});
});
};
Plugin();
})();
+4
View File
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=("allow_html_in_named_anchor",e=>e.options.get("allow_html_in_named_anchor"));const a="a:not([href])",r=e=>!e,i=e=>e.getAttribute("id")||e.getAttribute("name")||"",l=e=>(e=>"a"===e.nodeName.toLowerCase())(e)&&!e.getAttribute("href")&&""!==i(e),s=e=>e.dom.getParent(e.selection.getStart(),a),d=(e,a)=>{const r=s(e);r?((e,t,o)=>{o.removeAttribute("name"),o.id=t,e.addVisual(),e.undoManager.add()})(e,a,r):((e,a)=>{e.undoManager.transact((()=>{n(e)||e.selection.collapse(!0),e.selection.isCollapsed()?e.insertContent(e.dom.createHTML("a",{id:a})):((e=>{const n=e.dom;t(n).walk(e.selection.getRng(),(e=>{o.each(e,(e=>{var t;l(t=e)&&!t.firstChild&&n.remove(e,!1)}))}))})(e),e.formatter.remove("namedAnchor",void 0,void 0,!0),e.formatter.apply("namedAnchor",{value:a}),e.addVisual())}))})(e,a),e.focus()},c=e=>(e=>r(e.attr("href"))&&!r(e.attr("id")||e.attr("name")))(e)&&!e.firstChild,m=e=>t=>{for(let o=0;o<t.length;o++){const n=t[o];c(n)&&n.attr("contenteditable",e)}};e.add("anchor",(e=>{(e=>{(0,e.options.register)("allow_html_in_named_anchor",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreInit",(()=>{e.parser.addNodeFilter("a",m("false")),e.serializer.addNodeFilter("a",m(null))}))})(e),(e=>{e.addCommand("mceAnchor",(()=>{(e=>{const t=(e=>{const t=s(e);return t?i(t):""})(e);e.windowManager.open({title:"Anchor",size:"normal",body:{type:"panel",items:[{name:"id",type:"input",label:"ID",placeholder:"example"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{id:t},onSubmit:t=>{((e,t)=>/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(t)?(d(e,t),!0):(e.windowManager.alert("ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."),!1))(e,t.getData().id)&&t.close()}})})(e)}))})(e),(e=>{const t=()=>e.execCommand("mceAnchor");e.ui.registry.addToggleButton("anchor",{icon:"bookmark",tooltip:"Anchor",onAction:t,onSetup:t=>e.selection.selectorChangedWithUnbind("a:not([href])",t.setActive).unbind}),e.ui.registry.addMenuItem("anchor",{icon:"bookmark",text:"Anchor...",onAction:t})})(e),e.on("PreInit",(()=>{(e=>{e.formatter.register("namedAnchor",{inline:"a",selector:a,remove:"all",split:!0,deep:!0,attributes:{id:"%value"},onmatch:(e,t,o)=>l(e)})})(e)}))}))}();
@@ -0,0 +1,228 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager');
const link = () => /(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g;
const option = name => editor => editor.options.get(name);
const register = editor => {
const registerOption = editor.options.register;
registerOption('autolink_pattern', {
processor: 'regexp',
default: new RegExp('^' + link().source + '$', 'i')
});
registerOption('link_default_target', { processor: 'string' });
registerOption('link_default_protocol', {
processor: 'string',
default: 'https'
});
};
const getAutoLinkPattern = option('autolink_pattern');
const getDefaultLinkTarget = option('link_default_target');
const getDefaultLinkProtocol = option('link_default_protocol');
const allowUnsafeLinkTarget = option('allow_unsafe_link_target');
const hasProto = (v, constructor, predicate) => {
var _a;
if (predicate(v, constructor.prototype)) {
return true;
} else {
return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
}
};
const typeOf = x => {
const t = typeof x;
if (x === null) {
return 'null';
} else if (t === 'object' && Array.isArray(x)) {
return 'array';
} else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
return 'string';
} else {
return t;
}
};
const isType = type => value => typeOf(value) === type;
const eq = t => a => t === a;
const isString = isType('string');
const isUndefined = eq(undefined);
const isNullable = a => a === null || a === undefined;
const isNonNullable = a => !isNullable(a);
const not = f => t => !f(t);
const hasOwnProperty = Object.hasOwnProperty;
const has = (obj, key) => hasOwnProperty.call(obj, key);
const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
const contains = (str, substr, start = 0, end) => {
const idx = str.indexOf(substr, start);
if (idx !== -1) {
return isUndefined(end) ? true : idx + substr.length <= end;
} else {
return false;
}
};
const startsWith = (str, prefix) => {
return checkRange(str, prefix, 0);
};
const zeroWidth = '\uFEFF';
const isZwsp = char => char === zeroWidth;
const removeZwsp = s => s.replace(/\uFEFF/g, '');
var global = tinymce.util.Tools.resolve('tinymce.dom.TextSeeker');
const isTextNode = node => node.nodeType === 3;
const isElement = node => node.nodeType === 1;
const isBracketOrSpace = char => /^[(\[{ \u00a0]$/.test(char);
const hasProtocol = url => /^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(url);
const isPunctuation = char => /[?!,.;:]/.test(char);
const findChar = (text, index, predicate) => {
for (let i = index - 1; i >= 0; i--) {
const char = text.charAt(i);
if (!isZwsp(char) && predicate(char)) {
return i;
}
}
return -1;
};
const freefallRtl = (container, offset) => {
let tempNode = container;
let tempOffset = offset;
while (isElement(tempNode) && tempNode.childNodes[tempOffset]) {
tempNode = tempNode.childNodes[tempOffset];
tempOffset = isTextNode(tempNode) ? tempNode.data.length : tempNode.childNodes.length;
}
return {
container: tempNode,
offset: tempOffset
};
};
const parseCurrentLine = (editor, offset) => {
var _a;
const voidElements = editor.schema.getVoidElements();
const autoLinkPattern = getAutoLinkPattern(editor);
const {dom, selection} = editor;
if (dom.getParent(selection.getNode(), 'a[href]') !== null) {
return null;
}
const rng = selection.getRng();
const textSeeker = global(dom, node => {
return dom.isBlock(node) || has(voidElements, node.nodeName.toLowerCase()) || dom.getContentEditable(node) === 'false';
});
const {
container: endContainer,
offset: endOffset
} = freefallRtl(rng.endContainer, rng.endOffset);
const root = (_a = dom.getParent(endContainer, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot();
const endSpot = textSeeker.backwards(endContainer, endOffset + offset, (node, offset) => {
const text = node.data;
const idx = findChar(text, offset, not(isBracketOrSpace));
return idx === -1 || isPunctuation(text[idx]) ? idx : idx + 1;
}, root);
if (!endSpot) {
return null;
}
let lastTextNode = endSpot.container;
const startSpot = textSeeker.backwards(endSpot.container, endSpot.offset, (node, offset) => {
lastTextNode = node;
const idx = findChar(node.data, offset, isBracketOrSpace);
return idx === -1 ? idx : idx + 1;
}, root);
const newRng = dom.createRng();
if (!startSpot) {
newRng.setStart(lastTextNode, 0);
} else {
newRng.setStart(startSpot.container, startSpot.offset);
}
newRng.setEnd(endSpot.container, endSpot.offset);
const rngText = removeZwsp(newRng.toString());
const matches = rngText.match(autoLinkPattern);
if (matches) {
let url = matches[0];
if (startsWith(url, 'www.')) {
const protocol = getDefaultLinkProtocol(editor);
url = protocol + '://' + url;
} else if (contains(url, '@') && !hasProtocol(url)) {
url = 'mailto:' + url;
}
return {
rng: newRng,
url
};
} else {
return null;
}
};
const convertToLink = (editor, result) => {
const {dom, selection} = editor;
const {rng, url} = result;
const bookmark = selection.getBookmark();
selection.setRng(rng);
const command = 'createlink';
const args = {
command,
ui: false,
value: url
};
const beforeExecEvent = editor.dispatch('BeforeExecCommand', args);
if (!beforeExecEvent.isDefaultPrevented()) {
editor.getDoc().execCommand(command, false, url);
editor.dispatch('ExecCommand', args);
const defaultLinkTarget = getDefaultLinkTarget(editor);
if (isString(defaultLinkTarget)) {
const anchor = selection.getNode();
dom.setAttrib(anchor, 'target', defaultLinkTarget);
if (defaultLinkTarget === '_blank' && !allowUnsafeLinkTarget(editor)) {
dom.setAttrib(anchor, 'rel', 'noopener');
}
}
}
selection.moveToBookmark(bookmark);
editor.nodeChanged();
};
const handleSpacebar = editor => {
const result = parseCurrentLine(editor, -1);
if (isNonNullable(result)) {
convertToLink(editor, result);
}
};
const handleBracket = handleSpacebar;
const handleEnter = editor => {
const result = parseCurrentLine(editor, 0);
if (isNonNullable(result)) {
convertToLink(editor, result);
}
};
const setup = editor => {
editor.on('keydown', e => {
if (e.keyCode === 13 && !e.isDefaultPrevented()) {
handleEnter(editor);
}
});
editor.on('keyup', e => {
if (e.keyCode === 32) {
handleSpacebar(editor);
} else if (e.keyCode === 48 && e.shiftKey || e.keyCode === 221) {
handleBracket(editor);
}
});
};
var Plugin = () => {
global$1.add('autolink', editor => {
register(editor);
setup(editor);
});
};
Plugin();
})();
+4
View File
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),n=t("autolink_pattern"),o=t("link_default_target"),r=t("link_default_protocol"),a=t("allow_unsafe_link_target"),s=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(a=o.constructor)||void 0===a?void 0:a.name)===r.name)?"string":t;var n,o,r,a})(e));const l=(void 0,e=>undefined===e);const i=e=>!(e=>null==e)(e),c=Object.hasOwnProperty,d=e=>"\ufeff"===e;var u=tinymce.util.Tools.resolve("tinymce.dom.TextSeeker");const f=e=>/^[(\[{ \u00a0]$/.test(e),g=(e,t,n)=>{for(let o=t-1;o>=0;o--){const t=e.charAt(o);if(!d(t)&&n(t))return o}return-1},m=(e,t)=>{var o;const a=e.schema.getVoidElements(),s=n(e),{dom:i,selection:d}=e;if(null!==i.getParent(d.getNode(),"a[href]"))return null;const m=d.getRng(),k=u(i,(e=>{return i.isBlock(e)||(t=a,n=e.nodeName.toLowerCase(),c.call(t,n))||"false"===i.getContentEditable(e);var t,n})),{container:p,offset:y}=((e,t)=>{let n=e,o=t;for(;1===n.nodeType&&n.childNodes[o];)n=n.childNodes[o],o=3===n.nodeType?n.data.length:n.childNodes.length;return{container:n,offset:o}})(m.endContainer,m.endOffset),h=null!==(o=i.getParent(p,i.isBlock))&&void 0!==o?o:i.getRoot(),w=k.backwards(p,y+t,((e,t)=>{const n=e.data,o=g(n,t,(r=f,e=>!r(e)));var r,a;return-1===o||(a=n[o],/[?!,.;:]/.test(a))?o:o+1}),h);if(!w)return null;let v=w.container;const _=k.backwards(w.container,w.offset,((e,t)=>{v=e;const n=g(e.data,t,f);return-1===n?n:n+1}),h),A=i.createRng();_?A.setStart(_.container,_.offset):A.setStart(v,0),A.setEnd(w.container,w.offset);const C=A.toString().replace(/\uFEFF/g,"").match(s);if(C){let t=C[0];return $="www.",(b=t).length>=$.length&&b.substr(0,0+$.length)===$?t=r(e)+"://"+t:((e,t,n=0,o)=>{const r=e.indexOf(t,n);return-1!==r&&(!!l(o)||r+t.length<=o)})(t,"@")&&!(e=>/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(e))(t)&&(t="mailto:"+t),{rng:A,url:t}}var b,$;return null},k=(e,t)=>{const{dom:n,selection:r}=e,{rng:l,url:i}=t,c=r.getBookmark();r.setRng(l);const d="createlink",u={command:d,ui:!1,value:i};if(!e.dispatch("BeforeExecCommand",u).isDefaultPrevented()){e.getDoc().execCommand(d,!1,i),e.dispatch("ExecCommand",u);const t=o(e);if(s(t)){const o=r.getNode();n.setAttrib(o,"target",t),"_blank"!==t||a(e)||n.setAttrib(o,"rel","noopener")}}r.moveToBookmark(c),e.nodeChanged()},p=e=>{const t=m(e,-1);i(t)&&k(e,t)},y=p;e.add("autolink",(e=>{(e=>{const t=e.options.register;t("autolink_pattern",{processor:"regexp",default:new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i")}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"})})(e),(e=>{e.on("keydown",(t=>{13!==t.keyCode||t.isDefaultPrevented()||(e=>{const t=m(e,0);i(t)&&k(e,t)})(e)})),e.on("keyup",(t=>{32===t.keyCode?p(e):(48===t.keyCode&&t.shiftKey||221===t.keyCode)&&y(e)}))})(e)}))}();
@@ -0,0 +1,157 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
const Cell = initial => {
let value = initial;
const get = () => {
return value;
};
const set = v => {
value = v;
};
return {
get,
set
};
};
var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager');
var global = tinymce.util.Tools.resolve('tinymce.Env');
const fireResizeEditor = editor => editor.dispatch('ResizeEditor');
const option = name => editor => editor.options.get(name);
const register$1 = editor => {
const registerOption = editor.options.register;
registerOption('autoresize_overflow_padding', {
processor: 'number',
default: 1
});
registerOption('autoresize_bottom_margin', {
processor: 'number',
default: 50
});
};
const getMinHeight = option('min_height');
const getMaxHeight = option('max_height');
const getAutoResizeOverflowPadding = option('autoresize_overflow_padding');
const getAutoResizeBottomMargin = option('autoresize_bottom_margin');
const isFullscreen = editor => editor.plugins.fullscreen && editor.plugins.fullscreen.isFullscreen();
const toggleScrolling = (editor, state) => {
const body = editor.getBody();
if (body) {
body.style.overflowY = state ? '' : 'hidden';
if (!state) {
body.scrollTop = 0;
}
}
};
const parseCssValueToInt = (dom, elm, name, computed) => {
var _a;
const value = parseInt((_a = dom.getStyle(elm, name, computed)) !== null && _a !== void 0 ? _a : '', 10);
return isNaN(value) ? 0 : value;
};
const shouldScrollIntoView = trigger => {
if ((trigger === null || trigger === void 0 ? void 0 : trigger.type.toLowerCase()) === 'setcontent') {
const setContentEvent = trigger;
return setContentEvent.selection === true || setContentEvent.paste === true;
} else {
return false;
}
};
const resize = (editor, oldSize, trigger) => {
var _a;
const dom = editor.dom;
const doc = editor.getDoc();
if (!doc) {
return;
}
if (isFullscreen(editor)) {
toggleScrolling(editor, true);
return;
}
const docEle = doc.documentElement;
const resizeBottomMargin = getAutoResizeBottomMargin(editor);
const minHeight = (_a = getMinHeight(editor)) !== null && _a !== void 0 ? _a : editor.getElement().offsetHeight;
let resizeHeight = minHeight;
const marginTop = parseCssValueToInt(dom, docEle, 'margin-top', true);
const marginBottom = parseCssValueToInt(dom, docEle, 'margin-bottom', true);
let contentHeight = docEle.offsetHeight + marginTop + marginBottom + resizeBottomMargin;
if (contentHeight < 0) {
contentHeight = 0;
}
const containerHeight = editor.getContainer().offsetHeight;
const contentAreaHeight = editor.getContentAreaContainer().offsetHeight;
const chromeHeight = containerHeight - contentAreaHeight;
if (contentHeight + chromeHeight > minHeight) {
resizeHeight = contentHeight + chromeHeight;
}
const maxHeight = getMaxHeight(editor);
if (maxHeight && resizeHeight > maxHeight) {
resizeHeight = maxHeight;
toggleScrolling(editor, true);
} else {
toggleScrolling(editor, false);
}
if (resizeHeight !== oldSize.get()) {
const deltaSize = resizeHeight - oldSize.get();
dom.setStyle(editor.getContainer(), 'height', resizeHeight + 'px');
oldSize.set(resizeHeight);
fireResizeEditor(editor);
if (global.browser.isSafari() && (global.os.isMacOS() || global.os.isiOS())) {
const win = editor.getWin();
win.scrollTo(win.pageXOffset, win.pageYOffset);
}
if (editor.hasFocus() && shouldScrollIntoView(trigger)) {
editor.selection.scrollIntoView();
}
if ((global.browser.isSafari() || global.browser.isChromium()) && deltaSize < 0) {
resize(editor, oldSize, trigger);
}
}
};
const setup = (editor, oldSize) => {
editor.on('init', () => {
const overflowPadding = getAutoResizeOverflowPadding(editor);
const dom = editor.dom;
dom.setStyles(editor.getDoc().documentElement, { height: 'auto' });
dom.setStyles(editor.getBody(), {
'paddingLeft': overflowPadding,
'paddingRight': overflowPadding,
'min-height': 0
});
});
editor.on('NodeChange SetContent keyup FullscreenStateChanged ResizeContent', e => {
resize(editor, oldSize, e);
});
};
const register = (editor, oldSize) => {
editor.addCommand('mceAutoResize', () => {
resize(editor, oldSize);
});
};
var Plugin = () => {
global$1.add('autoresize', editor => {
register$1(editor);
if (!editor.options.isSet('resize')) {
editor.options.set('resize', false);
}
if (!editor.inline) {
const oldSize = Cell(0);
register(editor, oldSize);
setup(editor, oldSize);
}
});
};
Plugin();
})();
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env");const o=e=>t=>t.options.get(e),n=o("min_height"),s=o("max_height"),i=o("autoresize_overflow_padding"),r=o("autoresize_bottom_margin"),l=(e,t)=>{const o=e.getBody();o&&(o.style.overflowY=t?"":"hidden",t||(o.scrollTop=0))},a=(e,t,o,n)=>{var s;const i=parseInt(null!==(s=e.getStyle(t,o,n))&&void 0!==s?s:"",10);return isNaN(i)?0:i},g=(e,o,i)=>{var c;const u=e.dom,d=e.getDoc();if(!d)return;if((e=>e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen())(e))return void l(e,!0);const f=d.documentElement,m=r(e),p=null!==(c=n(e))&&void 0!==c?c:e.getElement().offsetHeight;let h=p;const v=a(u,f,"margin-top",!0),y=a(u,f,"margin-bottom",!0);let C=f.offsetHeight+v+y+m;C<0&&(C=0);const S=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight;C+S>p&&(h=C+S);const z=s(e);if(z&&h>z?(h=z,l(e,!0)):l(e,!1),h!==o.get()){const n=h-o.get();if(u.setStyle(e.getContainer(),"height",h+"px"),o.set(h),(e=>{e.dispatch("ResizeEditor")})(e),t.browser.isSafari()&&(t.os.isMacOS()||t.os.isiOS())){const t=e.getWin();t.scrollTo(t.pageXOffset,t.pageYOffset)}e.hasFocus()&&(e=>{if("setcontent"===(null==e?void 0:e.type.toLowerCase())){const t=e;return!0===t.selection||!0===t.paste}return!1})(i)&&e.selection.scrollIntoView(),(t.browser.isSafari()||t.browser.isChromium())&&n<0&&g(e,o,i)}};e.add("autoresize",(e=>{if((e=>{const t=e.options.register;t("autoresize_overflow_padding",{processor:"number",default:1}),t("autoresize_bottom_margin",{processor:"number",default:50})})(e),e.options.isSet("resize")||e.options.set("resize",!1),!e.inline){const t=(e=>{let t=0;return{get:()=>t,set:e=>{t=e}}})();((e,t)=>{e.addCommand("mceAutoResize",(()=>{g(e,t)}))})(e,t),((e,t)=>{e.on("init",(()=>{const t=i(e),o=e.dom;o.setStyles(e.getDoc().documentElement,{height:"auto"}),o.setStyles(e.getBody(),{paddingLeft:t,paddingRight:t,"min-height":0})})),e.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",(o=>{g(e,t,o)}))})(e,t)}}))}();
@@ -0,0 +1,233 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$4 = tinymce.util.Tools.resolve('tinymce.PluginManager');
const hasProto = (v, constructor, predicate) => {
var _a;
if (predicate(v, constructor.prototype)) {
return true;
} else {
return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
}
};
const typeOf = x => {
const t = typeof x;
if (x === null) {
return 'null';
} else if (t === 'object' && Array.isArray(x)) {
return 'array';
} else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
return 'string';
} else {
return t;
}
};
const isType = type => value => typeOf(value) === type;
const eq = t => a => t === a;
const isString = isType('string');
const isUndefined = eq(undefined);
var global$3 = tinymce.util.Tools.resolve('tinymce.util.Delay');
var global$2 = tinymce.util.Tools.resolve('tinymce.util.LocalStorage');
var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
const fireRestoreDraft = editor => editor.dispatch('RestoreDraft');
const fireStoreDraft = editor => editor.dispatch('StoreDraft');
const fireRemoveDraft = editor => editor.dispatch('RemoveDraft');
const parse = timeString => {
const multiples = {
s: 1000,
m: 60000
};
const parsedTime = /^(\d+)([ms]?)$/.exec(timeString);
return (parsedTime && parsedTime[2] ? multiples[parsedTime[2]] : 1) * parseInt(timeString, 10);
};
const option = name => editor => editor.options.get(name);
const register$1 = editor => {
const registerOption = editor.options.register;
const timeProcessor = value => {
const valid = isString(value);
if (valid) {
return {
value: parse(value),
valid
};
} else {
return {
valid: false,
message: 'Must be a string.'
};
}
};
registerOption('autosave_ask_before_unload', {
processor: 'boolean',
default: true
});
registerOption('autosave_prefix', {
processor: 'string',
default: 'tinymce-autosave-{path}{query}{hash}-{id}-'
});
registerOption('autosave_restore_when_empty', {
processor: 'boolean',
default: false
});
registerOption('autosave_interval', {
processor: timeProcessor,
default: '30s'
});
registerOption('autosave_retention', {
processor: timeProcessor,
default: '20m'
});
};
const shouldAskBeforeUnload = option('autosave_ask_before_unload');
const shouldRestoreWhenEmpty = option('autosave_restore_when_empty');
const getAutoSaveInterval = option('autosave_interval');
const getAutoSaveRetention = option('autosave_retention');
const getAutoSavePrefix = editor => {
const location = document.location;
return editor.options.get('autosave_prefix').replace(/{path}/g, location.pathname).replace(/{query}/g, location.search).replace(/{hash}/g, location.hash).replace(/{id}/g, editor.id);
};
const isEmpty = (editor, html) => {
if (isUndefined(html)) {
return editor.dom.isEmpty(editor.getBody());
} else {
const trimmedHtml = global$1.trim(html);
if (trimmedHtml === '') {
return true;
} else {
const fragment = new DOMParser().parseFromString(trimmedHtml, 'text/html');
return editor.dom.isEmpty(fragment);
}
}
};
const hasDraft = editor => {
var _a;
const time = parseInt((_a = global$2.getItem(getAutoSavePrefix(editor) + 'time')) !== null && _a !== void 0 ? _a : '0', 10) || 0;
if (new Date().getTime() - time > getAutoSaveRetention(editor)) {
removeDraft(editor, false);
return false;
}
return true;
};
const removeDraft = (editor, fire) => {
const prefix = getAutoSavePrefix(editor);
global$2.removeItem(prefix + 'draft');
global$2.removeItem(prefix + 'time');
if (fire !== false) {
fireRemoveDraft(editor);
}
};
const storeDraft = editor => {
const prefix = getAutoSavePrefix(editor);
if (!isEmpty(editor) && editor.isDirty()) {
global$2.setItem(prefix + 'draft', editor.getContent({
format: 'raw',
no_events: true
}));
global$2.setItem(prefix + 'time', new Date().getTime().toString());
fireStoreDraft(editor);
}
};
const restoreDraft = editor => {
var _a;
const prefix = getAutoSavePrefix(editor);
if (hasDraft(editor)) {
editor.setContent((_a = global$2.getItem(prefix + 'draft')) !== null && _a !== void 0 ? _a : '', { format: 'raw' });
fireRestoreDraft(editor);
}
};
const startStoreDraft = editor => {
const interval = getAutoSaveInterval(editor);
global$3.setEditorInterval(editor, () => {
storeDraft(editor);
}, interval);
};
const restoreLastDraft = editor => {
editor.undoManager.transact(() => {
restoreDraft(editor);
removeDraft(editor);
});
editor.focus();
};
const get = editor => ({
hasDraft: () => hasDraft(editor),
storeDraft: () => storeDraft(editor),
restoreDraft: () => restoreDraft(editor),
removeDraft: fire => removeDraft(editor, fire),
isEmpty: html => isEmpty(editor, html)
});
var global = tinymce.util.Tools.resolve('tinymce.EditorManager');
const setup = editor => {
editor.editorManager.on('BeforeUnload', e => {
let msg;
global$1.each(global.get(), editor => {
if (editor.plugins.autosave) {
editor.plugins.autosave.storeDraft();
}
if (!msg && editor.isDirty() && shouldAskBeforeUnload(editor)) {
msg = editor.translate('You have unsaved changes are you sure you want to navigate away?');
}
});
if (msg) {
e.preventDefault();
e.returnValue = msg;
}
});
};
const makeSetupHandler = editor => api => {
api.setEnabled(hasDraft(editor));
const editorEventCallback = () => api.setEnabled(hasDraft(editor));
editor.on('StoreDraft RestoreDraft RemoveDraft', editorEventCallback);
return () => editor.off('StoreDraft RestoreDraft RemoveDraft', editorEventCallback);
};
const register = editor => {
startStoreDraft(editor);
const onAction = () => {
restoreLastDraft(editor);
};
editor.ui.registry.addButton('restoredraft', {
tooltip: 'Restore last draft',
icon: 'restore-draft',
onAction,
onSetup: makeSetupHandler(editor)
});
editor.ui.registry.addMenuItem('restoredraft', {
text: 'Restore last draft',
icon: 'restore-draft',
onAction,
onSetup: makeSetupHandler(editor)
});
};
var Plugin = () => {
global$4.add('autosave', editor => {
register$1(editor);
setup(editor);
register(editor);
editor.on('init', () => {
if (shouldRestoreWhenEmpty(editor) && editor.dom.isEmpty(editor.getBody())) {
restoreDraft(editor);
}
});
return get(editor);
});
};
Plugin();
})();
+4
View File
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=("string",t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(r=o=t,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":e;var r,o,a,s})(t));const r=(void 0,t=>undefined===t);var o=tinymce.util.Tools.resolve("tinymce.util.Delay"),a=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),s=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=t=>{const e=/^(\d+)([ms]?)$/.exec(t);return(e&&e[2]?{s:1e3,m:6e4}[e[2]]:1)*parseInt(t,10)},i=t=>e=>e.options.get(t),u=i("autosave_ask_before_unload"),l=i("autosave_restore_when_empty"),c=i("autosave_interval"),d=i("autosave_retention"),m=t=>{const e=document.location;return t.options.get("autosave_prefix").replace(/{path}/g,e.pathname).replace(/{query}/g,e.search).replace(/{hash}/g,e.hash).replace(/{id}/g,t.id)},v=(t,e)=>{if(r(e))return t.dom.isEmpty(t.getBody());{const r=s.trim(e);if(""===r)return!0;{const e=(new DOMParser).parseFromString(r,"text/html");return t.dom.isEmpty(e)}}},f=t=>{var e;const r=parseInt(null!==(e=a.getItem(m(t)+"time"))&&void 0!==e?e:"0",10)||0;return!((new Date).getTime()-r>d(t)&&(p(t,!1),1))},p=(t,e)=>{const r=m(t);a.removeItem(r+"draft"),a.removeItem(r+"time"),!1!==e&&(t=>{t.dispatch("RemoveDraft")})(t)},g=t=>{const e=m(t);!v(t)&&t.isDirty()&&(a.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),a.setItem(e+"time",(new Date).getTime().toString()),(t=>{t.dispatch("StoreDraft")})(t))},y=t=>{var e;const r=m(t);f(t)&&(t.setContent(null!==(e=a.getItem(r+"draft"))&&void 0!==e?e:"",{format:"raw"}),(t=>{t.dispatch("RestoreDraft")})(t))};var D=tinymce.util.Tools.resolve("tinymce.EditorManager");const h=t=>e=>{e.setEnabled(f(t));const r=()=>e.setEnabled(f(t));return t.on("StoreDraft RestoreDraft RemoveDraft",r),()=>t.off("StoreDraft RestoreDraft RemoveDraft",r)};t.add("autosave",(t=>((t=>{const r=t.options.register,o=t=>{const r=e(t);return r?{value:n(t),valid:r}:{valid:!1,message:"Must be a string."}};r("autosave_ask_before_unload",{processor:"boolean",default:!0}),r("autosave_prefix",{processor:"string",default:"tinymce-autosave-{path}{query}{hash}-{id}-"}),r("autosave_restore_when_empty",{processor:"boolean",default:!1}),r("autosave_interval",{processor:o,default:"30s"}),r("autosave_retention",{processor:o,default:"20m"})})(t),(t=>{t.editorManager.on("BeforeUnload",(t=>{let e;s.each(D.get(),(t=>{t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&u(t)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))})),e&&(t.preventDefault(),t.returnValue=e)}))})(t),(t=>{(t=>{const e=c(t);o.setEditorInterval(t,(()=>{g(t)}),e)})(t);const e=()=>{(t=>{t.undoManager.transact((()=>{y(t),p(t)})),t.focus()})(t)};t.ui.registry.addButton("restoredraft",{tooltip:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)}),t.ui.registry.addMenuItem("restoredraft",{text:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)})})(t),t.on("init",(()=>{l(t)&&t.dom.isEmpty(t.getBody())&&y(t)})),(t=>({hasDraft:()=>f(t),storeDraft:()=>g(t),restoreDraft:()=>y(t),removeDraft:e=>p(t,e),isEmpty:e=>v(t,e)}))(t))))}();
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,85 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
const setContent = (editor, html) => {
editor.focus();
editor.undoManager.transact(() => {
editor.setContent(html);
});
editor.selection.setCursorLocation();
editor.nodeChanged();
};
const getContent = editor => {
return editor.getContent({ source_view: true });
};
const open = editor => {
const editorContent = getContent(editor);
editor.windowManager.open({
title: 'Source Code',
size: 'large',
body: {
type: 'panel',
items: [{
type: 'textarea',
name: 'code'
}]
},
buttons: [
{
type: 'cancel',
name: 'cancel',
text: 'Cancel'
},
{
type: 'submit',
name: 'save',
text: 'Save',
primary: true
}
],
initialData: { code: editorContent },
onSubmit: api => {
setContent(editor, api.getData().code);
api.close();
}
});
};
const register$1 = editor => {
editor.addCommand('mceCodeEditor', () => {
open(editor);
});
};
const register = editor => {
const onAction = () => editor.execCommand('mceCodeEditor');
editor.ui.registry.addButton('code', {
icon: 'sourcecode',
tooltip: 'Source code',
onAction
});
editor.ui.registry.addMenuItem('code', {
icon: 'sourcecode',
text: 'Source code',
onAction
});
};
var Plugin = () => {
global.add('code', editor => {
register$1(editor);
register(editor);
return {};
});
};
Plugin();
})();
+4
View File
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const o=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:o},onSubmit:o=>{((e,o)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(o)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,o.getData().code),o.close()}})})(e)}))})(e),(e=>{const o=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:o}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:o})})(e),{})))}();
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,384 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
const hasProto = (v, constructor, predicate) => {
var _a;
if (predicate(v, constructor.prototype)) {
return true;
} else {
return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
}
};
const typeOf = x => {
const t = typeof x;
if (x === null) {
return 'null';
} else if (t === 'object' && Array.isArray(x)) {
return 'array';
} else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
return 'string';
} else {
return t;
}
};
const isType$1 = type => value => typeOf(value) === type;
const isSimpleType = type => value => typeof value === type;
const isString = isType$1('string');
const isBoolean = isSimpleType('boolean');
const isNullable = a => a === null || a === undefined;
const isNonNullable = a => !isNullable(a);
const isFunction = isSimpleType('function');
const isNumber = isSimpleType('number');
const compose1 = (fbc, fab) => a => fbc(fab(a));
const constant = value => {
return () => {
return value;
};
};
const never = constant(false);
class Optional {
constructor(tag, value) {
this.tag = tag;
this.value = value;
}
static some(value) {
return new Optional(true, value);
}
static none() {
return Optional.singletonNone;
}
fold(onNone, onSome) {
if (this.tag) {
return onSome(this.value);
} else {
return onNone();
}
}
isSome() {
return this.tag;
}
isNone() {
return !this.tag;
}
map(mapper) {
if (this.tag) {
return Optional.some(mapper(this.value));
} else {
return Optional.none();
}
}
bind(binder) {
if (this.tag) {
return binder(this.value);
} else {
return Optional.none();
}
}
exists(predicate) {
return this.tag && predicate(this.value);
}
forall(predicate) {
return !this.tag || predicate(this.value);
}
filter(predicate) {
if (!this.tag || predicate(this.value)) {
return this;
} else {
return Optional.none();
}
}
getOr(replacement) {
return this.tag ? this.value : replacement;
}
or(replacement) {
return this.tag ? this : replacement;
}
getOrThunk(thunk) {
return this.tag ? this.value : thunk();
}
orThunk(thunk) {
return this.tag ? this : thunk();
}
getOrDie(message) {
if (!this.tag) {
throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
} else {
return this.value;
}
}
static from(value) {
return isNonNullable(value) ? Optional.some(value) : Optional.none();
}
getOrNull() {
return this.tag ? this.value : null;
}
getOrUndefined() {
return this.value;
}
each(worker) {
if (this.tag) {
worker(this.value);
}
}
toArray() {
return this.tag ? [this.value] : [];
}
toString() {
return this.tag ? `some(${ this.value })` : 'none()';
}
}
Optional.singletonNone = new Optional(false);
const map = (xs, f) => {
const len = xs.length;
const r = new Array(len);
for (let i = 0; i < len; i++) {
const x = xs[i];
r[i] = f(x, i);
}
return r;
};
const each = (xs, f) => {
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
f(x, i);
}
};
const filter = (xs, pred) => {
const r = [];
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (pred(x, i)) {
r.push(x);
}
}
return r;
};
const DOCUMENT = 9;
const DOCUMENT_FRAGMENT = 11;
const ELEMENT = 1;
const TEXT = 3;
const fromHtml = (html, scope) => {
const doc = scope || document;
const div = doc.createElement('div');
div.innerHTML = html;
if (!div.hasChildNodes() || div.childNodes.length > 1) {
const message = 'HTML does not have a single root node';
console.error(message, html);
throw new Error(message);
}
return fromDom(div.childNodes[0]);
};
const fromTag = (tag, scope) => {
const doc = scope || document;
const node = doc.createElement(tag);
return fromDom(node);
};
const fromText = (text, scope) => {
const doc = scope || document;
const node = doc.createTextNode(text);
return fromDom(node);
};
const fromDom = node => {
if (node === null || node === undefined) {
throw new Error('Node cannot be null or undefined');
}
return { dom: node };
};
const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
const SugarElement = {
fromHtml,
fromTag,
fromText,
fromDom,
fromPoint
};
const is = (element, selector) => {
const dom = element.dom;
if (dom.nodeType !== ELEMENT) {
return false;
} else {
const elem = dom;
if (elem.matches !== undefined) {
return elem.matches(selector);
} else if (elem.msMatchesSelector !== undefined) {
return elem.msMatchesSelector(selector);
} else if (elem.webkitMatchesSelector !== undefined) {
return elem.webkitMatchesSelector(selector);
} else if (elem.mozMatchesSelector !== undefined) {
return elem.mozMatchesSelector(selector);
} else {
throw new Error('Browser lacks native selectors');
}
}
};
typeof window !== 'undefined' ? window : Function('return this;')();
const name = element => {
const r = element.dom.nodeName;
return r.toLowerCase();
};
const type = element => element.dom.nodeType;
const isType = t => element => type(element) === t;
const isElement = isType(ELEMENT);
const isText = isType(TEXT);
const isDocument = isType(DOCUMENT);
const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
const isTag = tag => e => isElement(e) && name(e) === tag;
const owner = element => SugarElement.fromDom(element.dom.ownerDocument);
const documentOrOwner = dos => isDocument(dos) ? dos : owner(dos);
const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
const children$2 = element => map(element.dom.childNodes, SugarElement.fromDom);
const rawSet = (dom, key, value) => {
if (isString(value) || isBoolean(value) || isNumber(value)) {
dom.setAttribute(key, value + '');
} else {
console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
throw new Error('Attribute value was not simple');
}
};
const set = (element, key, value) => {
rawSet(element.dom, key, value);
};
const remove = (element, key) => {
element.dom.removeAttribute(key);
};
const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
const getShadowRoot = e => {
const r = getRootNode(e);
return isShadowRoot(r) ? Optional.some(r) : Optional.none();
};
const getShadowHost = e => SugarElement.fromDom(e.dom.host);
const inBody = element => {
const dom = isText(element) ? element.dom.parentNode : element.dom;
if (dom === undefined || dom === null || dom.ownerDocument === null) {
return false;
}
const doc = dom.ownerDocument;
return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
};
const ancestor$1 = (scope, predicate, isRoot) => {
let element = scope.dom;
const stop = isFunction(isRoot) ? isRoot : never;
while (element.parentNode) {
element = element.parentNode;
const el = SugarElement.fromDom(element);
if (predicate(el)) {
return Optional.some(el);
} else if (stop(el)) {
break;
}
}
return Optional.none();
};
const ancestor = (scope, selector, isRoot) => ancestor$1(scope, e => is(e, selector), isRoot);
const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
const get = (element, property) => {
const dom = element.dom;
const styles = window.getComputedStyle(dom);
const r = styles.getPropertyValue(property);
return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
};
const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : '';
const getDirection = element => get(element, 'direction') === 'rtl' ? 'rtl' : 'ltr';
const children$1 = (scope, predicate) => filter(children$2(scope), predicate);
const children = (scope, selector) => children$1(scope, e => is(e, selector));
const getParentElement = element => parent(element).filter(isElement);
const getNormalizedBlock = (element, isListItem) => {
const normalizedElement = isListItem ? ancestor(element, 'ol,ul') : Optional.some(element);
return normalizedElement.getOr(element);
};
const isListItem = isTag('li');
const setDir = (editor, dir) => {
const selectedBlocks = editor.selection.getSelectedBlocks();
if (selectedBlocks.length > 0) {
each(selectedBlocks, block => {
const blockElement = SugarElement.fromDom(block);
const isBlockElementListItem = isListItem(blockElement);
const normalizedBlock = getNormalizedBlock(blockElement, isBlockElementListItem);
const normalizedBlockParent = getParentElement(normalizedBlock);
normalizedBlockParent.each(parent => {
const parentDirection = getDirection(parent);
if (parentDirection !== dir) {
set(normalizedBlock, 'dir', dir);
} else if (getDirection(normalizedBlock) !== dir) {
remove(normalizedBlock, 'dir');
}
if (isBlockElementListItem) {
const listItems = children(normalizedBlock, 'li[dir]');
each(listItems, listItem => remove(listItem, 'dir'));
}
});
});
editor.nodeChanged();
}
};
const register$1 = editor => {
editor.addCommand('mceDirectionLTR', () => {
setDir(editor, 'ltr');
});
editor.addCommand('mceDirectionRTL', () => {
setDir(editor, 'rtl');
});
};
const getNodeChangeHandler = (editor, dir) => api => {
const nodeChangeHandler = e => {
const element = SugarElement.fromDom(e.element);
api.setActive(getDirection(element) === dir);
};
editor.on('NodeChange', nodeChangeHandler);
return () => editor.off('NodeChange', nodeChangeHandler);
};
const register = editor => {
editor.ui.registry.addToggleButton('ltr', {
tooltip: 'Left to right',
icon: 'ltr',
onAction: () => editor.execCommand('mceDirectionLTR'),
onSetup: getNodeChangeHandler(editor, 'ltr')
});
editor.ui.registry.addToggleButton('rtl', {
tooltip: 'Right to left',
icon: 'rtl',
onAction: () => editor.execCommand('mceDirectionRTL'),
onSetup: getNodeChangeHandler(editor, 'rtl')
});
};
var Plugin = () => {
global.add('directionality', editor => {
register$1(editor);
register(editor);
});
};
Plugin();
})();
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>typeof e===t,o=t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(o=r=t,(n=String).prototype.isPrototypeOf(o)||(null===(i=r.constructor)||void 0===i?void 0:i.name)===n.name)?"string":e;var o,r,n,i})(t),r=e("boolean"),n=t=>!(t=>null==t)(t),i=e("function"),s=e("number"),l=(!1,()=>false);class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return n(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=(t,e)=>{for(let o=0,r=t.length;o<r;o++)e(t[o],o)},c=t=>{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},d=c,h=(t,e)=>{const o=t.dom;if(1!==o.nodeType)return!1;{const t=o;if(void 0!==t.matches)return t.matches(e);if(void 0!==t.msMatchesSelector)return t.msMatchesSelector(e);if(void 0!==t.webkitMatchesSelector)return t.webkitMatchesSelector(e);if(void 0!==t.mozMatchesSelector)return t.mozMatchesSelector(e);throw new Error("Browser lacks native selectors")}};"undefined"!=typeof window?window:Function("return this;")();const m=t=>e=>(t=>t.dom.nodeType)(e)===t,g=m(1),f=m(3),v=m(9),p=m(11),y=(t,e)=>{t.dom.removeAttribute(e)},w=i(Element.prototype.attachShadow)&&i(Node.prototype.getRootNode)?t=>d(t.dom.getRootNode()):t=>v(t)?t:d(t.dom.ownerDocument),N=t=>d(t.dom.host),b=t=>{const e=f(t)?t.dom.parentNode:t.dom;if(null==e||null===e.ownerDocument)return!1;const o=e.ownerDocument;return(t=>{const e=w(t);return p(o=e)&&n(o.dom.host)?a.some(e):a.none();var o})(d(e)).fold((()=>o.body.contains(e)),(r=b,i=N,t=>r(i(t))));var r,i},S=t=>"rtl"===((t,e)=>{const o=t.dom,r=window.getComputedStyle(o).getPropertyValue(e);return""!==r||b(t)?r:((t,e)=>(t=>void 0!==t.style&&i(t.style.getPropertyValue))(t)?t.style.getPropertyValue(e):"")(o,e)})(t,"direction")?"rtl":"ltr",A=(t,e)=>((t,o)=>((t,e)=>{const o=[];for(let r=0,n=t.length;r<n;r++){const n=t[r];e(n,r)&&o.push(n)}return o})(((t,e)=>{const o=t.length,r=new Array(o);for(let n=0;n<o;n++){const o=t[n];r[n]=e(o,n)}return r})(t.dom.childNodes,d),(t=>h(t,e))))(t),T=("li",t=>g(t)&&"li"===t.dom.nodeName.toLowerCase());const C=(t,e)=>{const n=t.selection.getSelectedBlocks();n.length>0&&(u(n,(t=>{const n=d(t),c=T(n),m=((t,e)=>{return(e?(o=t,r="ol,ul",((t,e,o)=>{let n=t.dom;const s=i(o)?o:l;for(;n.parentNode;){n=n.parentNode;const t=d(n);if(h(t,r))return a.some(t);if(s(t))break}return a.none()})(o,0,n)):a.some(t)).getOr(t);var o,r,n})(n,c);var f;(f=m,(t=>a.from(t.dom.parentNode).map(d))(f).filter(g)).each((t=>{if(S(t)!==e?((t,e,n)=>{((t,e,n)=>{if(!(o(n)||r(n)||s(n)))throw console.error("Invalid call to Attribute.set. Key ",e,":: Value ",n,":: Element ",t),new Error("Attribute value was not simple");t.setAttribute(e,n+"")})(t.dom,e,n)})(m,"dir",e):S(m)!==e&&y(m,"dir"),c){const t=A(m,"li[dir]");u(t,(t=>y(t,"dir")))}}))})),t.nodeChanged())},D=(t,e)=>o=>{const r=t=>{const r=d(t.element);o.setActive(S(r)===e)};return t.on("NodeChange",r),()=>t.off("NodeChange",r)};t.add("directionality",(t=>{(t=>{t.addCommand("mceDirectionLTR",(()=>{C(t,"ltr")})),t.addCommand("mceDirectionRTL",(()=>{C(t,"rtl")}))})(t),(t=>{t.ui.registry.addToggleButton("ltr",{tooltip:"Left to right",icon:"ltr",onAction:()=>t.execCommand("mceDirectionLTR"),onSetup:D(t,"ltr")}),t.ui.registry.addToggleButton("rtl",{tooltip:"Right to left",icon:"rtl",onAction:()=>t.execCommand("mceDirectionRTL"),onSetup:D(t,"rtl")})})(t)}))}();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,583 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager');
const eq = t => a => t === a;
const isNull = eq(null);
const isUndefined = eq(undefined);
const isNullable = a => a === null || a === undefined;
const isNonNullable = a => !isNullable(a);
const noop = () => {
};
const constant = value => {
return () => {
return value;
};
};
const never = constant(false);
class Optional {
constructor(tag, value) {
this.tag = tag;
this.value = value;
}
static some(value) {
return new Optional(true, value);
}
static none() {
return Optional.singletonNone;
}
fold(onNone, onSome) {
if (this.tag) {
return onSome(this.value);
} else {
return onNone();
}
}
isSome() {
return this.tag;
}
isNone() {
return !this.tag;
}
map(mapper) {
if (this.tag) {
return Optional.some(mapper(this.value));
} else {
return Optional.none();
}
}
bind(binder) {
if (this.tag) {
return binder(this.value);
} else {
return Optional.none();
}
}
exists(predicate) {
return this.tag && predicate(this.value);
}
forall(predicate) {
return !this.tag || predicate(this.value);
}
filter(predicate) {
if (!this.tag || predicate(this.value)) {
return this;
} else {
return Optional.none();
}
}
getOr(replacement) {
return this.tag ? this.value : replacement;
}
or(replacement) {
return this.tag ? this : replacement;
}
getOrThunk(thunk) {
return this.tag ? this.value : thunk();
}
orThunk(thunk) {
return this.tag ? this : thunk();
}
getOrDie(message) {
if (!this.tag) {
throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
} else {
return this.value;
}
}
static from(value) {
return isNonNullable(value) ? Optional.some(value) : Optional.none();
}
getOrNull() {
return this.tag ? this.value : null;
}
getOrUndefined() {
return this.value;
}
each(worker) {
if (this.tag) {
worker(this.value);
}
}
toArray() {
return this.tag ? [this.value] : [];
}
toString() {
return this.tag ? `some(${ this.value })` : 'none()';
}
}
Optional.singletonNone = new Optional(false);
const exists = (xs, pred) => {
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (pred(x, i)) {
return true;
}
}
return false;
};
const map$1 = (xs, f) => {
const len = xs.length;
const r = new Array(len);
for (let i = 0; i < len; i++) {
const x = xs[i];
r[i] = f(x, i);
}
return r;
};
const each$1 = (xs, f) => {
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
f(x, i);
}
};
const Cell = initial => {
let value = initial;
const get = () => {
return value;
};
const set = v => {
value = v;
};
return {
get,
set
};
};
const last = (fn, rate) => {
let timer = null;
const cancel = () => {
if (!isNull(timer)) {
clearTimeout(timer);
timer = null;
}
};
const throttle = (...args) => {
cancel();
timer = setTimeout(() => {
timer = null;
fn.apply(null, args);
}, rate);
};
return {
cancel,
throttle
};
};
const insertEmoticon = (editor, ch) => {
editor.insertContent(ch);
};
const keys = Object.keys;
const hasOwnProperty = Object.hasOwnProperty;
const each = (obj, f) => {
const props = keys(obj);
for (let k = 0, len = props.length; k < len; k++) {
const i = props[k];
const x = obj[i];
f(x, i);
}
};
const map = (obj, f) => {
return tupleMap(obj, (x, i) => ({
k: i,
v: f(x, i)
}));
};
const tupleMap = (obj, f) => {
const r = {};
each(obj, (x, i) => {
const tuple = f(x, i);
r[tuple.k] = tuple.v;
});
return r;
};
const has = (obj, key) => hasOwnProperty.call(obj, key);
const shallow = (old, nu) => {
return nu;
};
const baseMerge = merger => {
return (...objects) => {
if (objects.length === 0) {
throw new Error(`Can't merge zero objects`);
}
const ret = {};
for (let j = 0; j < objects.length; j++) {
const curObject = objects[j];
for (const key in curObject) {
if (has(curObject, key)) {
ret[key] = merger(ret[key], curObject[key]);
}
}
}
return ret;
};
};
const merge = baseMerge(shallow);
const singleton = doRevoke => {
const subject = Cell(Optional.none());
const revoke = () => subject.get().each(doRevoke);
const clear = () => {
revoke();
subject.set(Optional.none());
};
const isSet = () => subject.get().isSome();
const get = () => subject.get();
const set = s => {
revoke();
subject.set(Optional.some(s));
};
return {
clear,
isSet,
get,
set
};
};
const value = () => {
const subject = singleton(noop);
const on = f => subject.get().each(f);
return {
...subject,
on
};
};
const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
const contains = (str, substr, start = 0, end) => {
const idx = str.indexOf(substr, start);
if (idx !== -1) {
return isUndefined(end) ? true : idx + substr.length <= end;
} else {
return false;
}
};
const startsWith = (str, prefix) => {
return checkRange(str, prefix, 0);
};
var global = tinymce.util.Tools.resolve('tinymce.Resource');
const DEFAULT_ID = 'tinymce.plugins.emoticons';
const option = name => editor => editor.options.get(name);
const register$2 = (editor, pluginUrl) => {
const registerOption = editor.options.register;
registerOption('emoticons_database', {
processor: 'string',
default: 'emojis'
});
registerOption('emoticons_database_url', {
processor: 'string',
default: `${ pluginUrl }/js/${ getEmojiDatabase(editor) }${ editor.suffix }.js`
});
registerOption('emoticons_database_id', {
processor: 'string',
default: DEFAULT_ID
});
registerOption('emoticons_append', {
processor: 'object',
default: {}
});
registerOption('emoticons_images_url', {
processor: 'string',
default: 'https://twemoji.maxcdn.com/v/13.0.1/72x72/'
});
};
const getEmojiDatabase = option('emoticons_database');
const getEmojiDatabaseUrl = option('emoticons_database_url');
const getEmojiDatabaseId = option('emoticons_database_id');
const getAppendedEmoji = option('emoticons_append');
const getEmojiImageUrl = option('emoticons_images_url');
const ALL_CATEGORY = 'All';
const categoryNameMap = {
symbols: 'Symbols',
people: 'People',
animals_and_nature: 'Animals and Nature',
food_and_drink: 'Food and Drink',
activity: 'Activity',
travel_and_places: 'Travel and Places',
objects: 'Objects',
flags: 'Flags',
user: 'User Defined'
};
const translateCategory = (categories, name) => has(categories, name) ? categories[name] : name;
const getUserDefinedEmoji = editor => {
const userDefinedEmoticons = getAppendedEmoji(editor);
return map(userDefinedEmoticons, value => ({
keywords: [],
category: 'user',
...value
}));
};
const initDatabase = (editor, databaseUrl, databaseId) => {
const categories = value();
const all = value();
const emojiImagesUrl = getEmojiImageUrl(editor);
const getEmoji = lib => {
if (startsWith(lib.char, '<img')) {
return lib.char.replace(/src="([^"]+)"/, (match, url) => `src="${ emojiImagesUrl }${ url }"`);
} else {
return lib.char;
}
};
const processEmojis = emojis => {
const cats = {};
const everything = [];
each(emojis, (lib, title) => {
const entry = {
title,
keywords: lib.keywords,
char: getEmoji(lib),
category: translateCategory(categoryNameMap, lib.category)
};
const current = cats[entry.category] !== undefined ? cats[entry.category] : [];
cats[entry.category] = current.concat([entry]);
everything.push(entry);
});
categories.set(cats);
all.set(everything);
};
editor.on('init', () => {
global.load(databaseId, databaseUrl).then(emojis => {
const userEmojis = getUserDefinedEmoji(editor);
processEmojis(merge(emojis, userEmojis));
}, err => {
console.log(`Failed to load emojis: ${ err }`);
categories.set({});
all.set([]);
});
});
const listCategory = category => {
if (category === ALL_CATEGORY) {
return listAll();
}
return categories.get().bind(cats => Optional.from(cats[category])).getOr([]);
};
const listAll = () => all.get().getOr([]);
const listCategories = () => [ALL_CATEGORY].concat(keys(categories.get().getOr({})));
const waitForLoad = () => {
if (hasLoaded()) {
return Promise.resolve(true);
} else {
return new Promise((resolve, reject) => {
let numRetries = 15;
const interval = setInterval(() => {
if (hasLoaded()) {
clearInterval(interval);
resolve(true);
} else {
numRetries--;
if (numRetries < 0) {
console.log('Could not load emojis from url: ' + databaseUrl);
clearInterval(interval);
reject(false);
}
}
}, 100);
});
}
};
const hasLoaded = () => categories.isSet() && all.isSet();
return {
listCategories,
hasLoaded,
waitForLoad,
listAll,
listCategory
};
};
const emojiMatches = (emoji, lowerCasePattern) => contains(emoji.title.toLowerCase(), lowerCasePattern) || exists(emoji.keywords, k => contains(k.toLowerCase(), lowerCasePattern));
const emojisFrom = (list, pattern, maxResults) => {
const matches = [];
const lowerCasePattern = pattern.toLowerCase();
const reachedLimit = maxResults.fold(() => never, max => size => size >= max);
for (let i = 0; i < list.length; i++) {
if (pattern.length === 0 || emojiMatches(list[i], lowerCasePattern)) {
matches.push({
value: list[i].char,
text: list[i].title,
icon: list[i].char
});
if (reachedLimit(matches.length)) {
break;
}
}
}
return matches;
};
const patternName = 'pattern';
const open = (editor, database) => {
const initialState = {
pattern: '',
results: emojisFrom(database.listAll(), '', Optional.some(300))
};
const currentTab = Cell(ALL_CATEGORY);
const scan = dialogApi => {
const dialogData = dialogApi.getData();
const category = currentTab.get();
const candidates = database.listCategory(category);
const results = emojisFrom(candidates, dialogData[patternName], category === ALL_CATEGORY ? Optional.some(300) : Optional.none());
dialogApi.setData({ results });
};
const updateFilter = last(dialogApi => {
scan(dialogApi);
}, 200);
const searchField = {
label: 'Search',
type: 'input',
name: patternName
};
const resultsField = {
type: 'collection',
name: 'results'
};
const getInitialState = () => {
const body = {
type: 'tabpanel',
tabs: map$1(database.listCategories(), cat => ({
title: cat,
name: cat,
items: [
searchField,
resultsField
]
}))
};
return {
title: 'Emojis',
size: 'normal',
body,
initialData: initialState,
onTabChange: (dialogApi, details) => {
currentTab.set(details.newTabName);
updateFilter.throttle(dialogApi);
},
onChange: updateFilter.throttle,
onAction: (dialogApi, actionData) => {
if (actionData.name === 'results') {
insertEmoticon(editor, actionData.value);
dialogApi.close();
}
},
buttons: [{
type: 'cancel',
text: 'Close',
primary: true
}]
};
};
const dialogApi = editor.windowManager.open(getInitialState());
dialogApi.focus(patternName);
if (!database.hasLoaded()) {
dialogApi.block('Loading emojis...');
database.waitForLoad().then(() => {
dialogApi.redial(getInitialState());
updateFilter.throttle(dialogApi);
dialogApi.focus(patternName);
dialogApi.unblock();
}).catch(_err => {
dialogApi.redial({
title: 'Emojis',
body: {
type: 'panel',
items: [{
type: 'alertbanner',
level: 'error',
icon: 'warning',
text: 'Could not load emojis'
}]
},
buttons: [{
type: 'cancel',
text: 'Close',
primary: true
}],
initialData: {
pattern: '',
results: []
}
});
dialogApi.focus(patternName);
dialogApi.unblock();
});
}
};
const register$1 = (editor, database) => {
editor.addCommand('mceEmoticons', () => open(editor, database));
};
const setup = editor => {
editor.on('PreInit', () => {
editor.parser.addAttributeFilter('data-emoticon', nodes => {
each$1(nodes, node => {
node.attr('data-mce-resize', 'false');
node.attr('data-mce-placeholder', '1');
});
});
});
};
const init = (editor, database) => {
editor.ui.registry.addAutocompleter('emoticons', {
trigger: ':',
columns: 'auto',
minChars: 2,
fetch: (pattern, maxResults) => database.waitForLoad().then(() => {
const candidates = database.listAll();
return emojisFrom(candidates, pattern, Optional.some(maxResults));
}),
onAction: (autocompleteApi, rng, value) => {
editor.selection.setRng(rng);
editor.insertContent(value);
autocompleteApi.hide();
}
});
};
const register = editor => {
const onAction = () => editor.execCommand('mceEmoticons');
editor.ui.registry.addButton('emoticons', {
tooltip: 'Emojis',
icon: 'emoji',
onAction
});
editor.ui.registry.addMenuItem('emoticons', {
text: 'Emojis...',
icon: 'emoji',
onAction
});
};
var Plugin = () => {
global$1.add('emoticons', (editor, pluginUrl) => {
register$2(editor, pluginUrl);
const databaseUrl = getEmojiDatabaseUrl(editor);
const databaseId = getEmojiDatabaseId(editor);
const database = initDatabase(editor, databaseUrl, databaseId);
register$1(editor, database);
register(editor);
init(editor, database);
setup(editor);
});
};
Plugin();
})();
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,931 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
const Cell = initial => {
let value = initial;
const get = () => {
return value;
};
const set = v => {
value = v;
};
return {
get,
set
};
};
var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager');
let unique = 0;
const generate = prefix => {
const date = new Date();
const time = date.getTime();
const random = Math.floor(Math.random() * 1000000000);
unique++;
return prefix + '_' + random + unique + String(time);
};
const get$1 = customTabs => {
const addTab = spec => {
var _a;
const name = (_a = spec.name) !== null && _a !== void 0 ? _a : generate('tab-name');
const currentCustomTabs = customTabs.get();
currentCustomTabs[name] = spec;
customTabs.set(currentCustomTabs);
};
return { addTab };
};
const register$2 = (editor, dialogOpener) => {
editor.addCommand('mceHelp', dialogOpener);
};
const option = name => editor => editor.options.get(name);
const register$1 = editor => {
const registerOption = editor.options.register;
registerOption('help_tabs', { processor: 'array' });
};
const getHelpTabs = option('help_tabs');
const getForcedPlugins = option('forced_plugins');
const register = (editor, dialogOpener) => {
editor.ui.registry.addButton('help', {
icon: 'help',
tooltip: 'Help',
onAction: dialogOpener
});
editor.ui.registry.addMenuItem('help', {
text: 'Help',
icon: 'help',
shortcut: 'Alt+0',
onAction: dialogOpener
});
};
const hasProto = (v, constructor, predicate) => {
var _a;
if (predicate(v, constructor.prototype)) {
return true;
} else {
return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
}
};
const typeOf = x => {
const t = typeof x;
if (x === null) {
return 'null';
} else if (t === 'object' && Array.isArray(x)) {
return 'array';
} else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
return 'string';
} else {
return t;
}
};
const isType = type => value => typeOf(value) === type;
const isSimpleType = type => value => typeof value === type;
const eq = t => a => t === a;
const isString = isType('string');
const isUndefined = eq(undefined);
const isNullable = a => a === null || a === undefined;
const isNonNullable = a => !isNullable(a);
const isFunction = isSimpleType('function');
const constant = value => {
return () => {
return value;
};
};
const never = constant(false);
class Optional {
constructor(tag, value) {
this.tag = tag;
this.value = value;
}
static some(value) {
return new Optional(true, value);
}
static none() {
return Optional.singletonNone;
}
fold(onNone, onSome) {
if (this.tag) {
return onSome(this.value);
} else {
return onNone();
}
}
isSome() {
return this.tag;
}
isNone() {
return !this.tag;
}
map(mapper) {
if (this.tag) {
return Optional.some(mapper(this.value));
} else {
return Optional.none();
}
}
bind(binder) {
if (this.tag) {
return binder(this.value);
} else {
return Optional.none();
}
}
exists(predicate) {
return this.tag && predicate(this.value);
}
forall(predicate) {
return !this.tag || predicate(this.value);
}
filter(predicate) {
if (!this.tag || predicate(this.value)) {
return this;
} else {
return Optional.none();
}
}
getOr(replacement) {
return this.tag ? this.value : replacement;
}
or(replacement) {
return this.tag ? this : replacement;
}
getOrThunk(thunk) {
return this.tag ? this.value : thunk();
}
orThunk(thunk) {
return this.tag ? this : thunk();
}
getOrDie(message) {
if (!this.tag) {
throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
} else {
return this.value;
}
}
static from(value) {
return isNonNullable(value) ? Optional.some(value) : Optional.none();
}
getOrNull() {
return this.tag ? this.value : null;
}
getOrUndefined() {
return this.value;
}
each(worker) {
if (this.tag) {
worker(this.value);
}
}
toArray() {
return this.tag ? [this.value] : [];
}
toString() {
return this.tag ? `some(${ this.value })` : 'none()';
}
}
Optional.singletonNone = new Optional(false);
const nativeSlice = Array.prototype.slice;
const nativeIndexOf = Array.prototype.indexOf;
const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
const contains = (xs, x) => rawIndexOf(xs, x) > -1;
const map = (xs, f) => {
const len = xs.length;
const r = new Array(len);
for (let i = 0; i < len; i++) {
const x = xs[i];
r[i] = f(x, i);
}
return r;
};
const filter = (xs, pred) => {
const r = [];
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (pred(x, i)) {
r.push(x);
}
}
return r;
};
const findUntil = (xs, pred, until) => {
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (pred(x, i)) {
return Optional.some(x);
} else if (until(x, i)) {
break;
}
}
return Optional.none();
};
const find = (xs, pred) => {
return findUntil(xs, pred, never);
};
const sort = (xs, comparator) => {
const copy = nativeSlice.call(xs, 0);
copy.sort(comparator);
return copy;
};
const keys = Object.keys;
const hasOwnProperty = Object.hasOwnProperty;
const get = (obj, key) => {
return has(obj, key) ? Optional.from(obj[key]) : Optional.none();
};
const has = (obj, key) => hasOwnProperty.call(obj, key);
const cat = arr => {
const r = [];
const push = x => {
r.push(x);
};
for (let i = 0; i < arr.length; i++) {
arr[i].each(push);
}
return r;
};
const description = `<h1>Editor UI keyboard navigation</h1>
<h2>Activating keyboard navigation</h2>
<p>The sections of the outer UI of the editor - the menubar, toolbar, sidebar and footer - are all keyboard navigable. As such, there are multiple ways to activate keyboard navigation:</p>
<ul>
<li>Focus the menubar: Alt + F9 (Windows) or &#x2325;F9 (MacOS)</li>
<li>Focus the toolbar: Alt + F10 (Windows) or &#x2325;F10 (MacOS)</li>
<li>Focus the footer: Alt + F11 (Windows) or &#x2325;F11 (MacOS)</li>
</ul>
<p>Focusing the menubar or toolbar will start keyboard navigation at the first item in the menubar or toolbar, which will be highlighted with a gray background. Focusing the footer will start keyboard navigation at the first item in the element path, which will be highlighted with an underline. </p>
<h2>Moving between UI sections</h2>
<p>When keyboard navigation is active, pressing tab will move the focus to the next major section of the UI, where applicable. These sections are:</p>
<ul>
<li>the menubar</li>
<li>each group of the toolbar </li>
<li>the sidebar</li>
<li>the element path in the footer </li>
<li>the wordcount toggle button in the footer </li>
<li>the branding link in the footer </li>
<li>the editor resize handle in the footer</li>
</ul>
<p>Pressing shift + tab will move backwards through the same sections, except when moving from the footer to the toolbar. Focusing the element path then pressing shift + tab will move focus to the first toolbar group, not the last.</p>
<h2>Moving within UI sections</h2>
<p>Keyboard navigation within UI sections can usually be achieved using the left and right arrow keys. This includes:</p>
<ul>
<li>moving between menus in the menubar</li>
<li>moving between buttons in a toolbar group</li>
<li>moving between items in the element path</li>
</ul>
<p>In all these UI sections, keyboard navigation will cycle within the section. For example, focusing the last button in a toolbar group then pressing right arrow will move focus to the first item in the same toolbar group. </p>
<h1>Executing buttons</h1>
<p>To execute a button, navigate the selection to the desired button and hit space or enter.</p>
<h1>Opening, navigating and closing menus</h1>
<p>When focusing a menubar button or a toolbar button with a menu, pressing space, enter or down arrow will open the menu. When the menu opens the first item will be selected. To move up or down the menu, press the up or down arrow key respectively. This is the same for submenus, which can also be opened and closed using the left and right arrow keys.</p>
<p>To close any active menu, hit the escape key. When a menu is closed the selection will be restored to its previous selection. This also works for closing submenus.</p>
<h1>Context toolbars and menus</h1>
<p>To focus an open context toolbar such as the table context toolbar, press Ctrl + F9 (Windows) or &#x2303;F9 (MacOS).</p>
<p>Context toolbar navigation is the same as toolbar navigation, and context menu navigation is the same as standard menu navigation.</p>
<h1>Dialog navigation</h1>
<p>There are two types of dialog UIs in TinyMCE: tabbed dialogs and non-tabbed dialogs.</p>
<p>When a non-tabbed dialog is opened, the first interactive component in the dialog will be focused. Users can navigate between interactive components by pressing tab. This includes any footer buttons. Navigation will cycle back to the first dialog component if tab is pressed while focusing the last component in the dialog. Pressing shift + tab will navigate backwards.</p>
<p>When a tabbed dialog is opened, the first button in the tab menu is focused. Pressing tab will navigate to the first interactive component in that tab, and will cycle through the tab\u2019s components, the footer buttons, then back to the tab button. To switch to another tab, focus the tab button for the current tab, then use the arrow keys to cycle through the tab buttons.</p>`;
const tab$3 = () => {
const body = {
type: 'htmlpanel',
presets: 'document',
html: description
};
return {
name: 'keyboardnav',
title: 'Keyboard Navigation',
items: [body]
};
};
var global$2 = tinymce.util.Tools.resolve('tinymce.Env');
const convertText = source => {
const isMac = global$2.os.isMacOS() || global$2.os.isiOS();
const mac = {
alt: '&#x2325;',
ctrl: '&#x2303;',
shift: '&#x21E7;',
meta: '&#x2318;',
access: '&#x2303;&#x2325;'
};
const other = {
meta: 'Ctrl ',
access: 'Shift + Alt '
};
const replace = isMac ? mac : other;
const shortcut = source.split('+');
const updated = map(shortcut, segment => {
const search = segment.toLowerCase().trim();
return has(replace, search) ? replace[search] : segment;
});
return isMac ? updated.join('').replace(/\s/, '') : updated.join('+');
};
const shortcuts = [
{
shortcuts: ['Meta + B'],
action: 'Bold'
},
{
shortcuts: ['Meta + I'],
action: 'Italic'
},
{
shortcuts: ['Meta + U'],
action: 'Underline'
},
{
shortcuts: ['Meta + A'],
action: 'Select all'
},
{
shortcuts: [
'Meta + Y',
'Meta + Shift + Z'
],
action: 'Redo'
},
{
shortcuts: ['Meta + Z'],
action: 'Undo'
},
{
shortcuts: ['Access + 1'],
action: 'Heading 1'
},
{
shortcuts: ['Access + 2'],
action: 'Heading 2'
},
{
shortcuts: ['Access + 3'],
action: 'Heading 3'
},
{
shortcuts: ['Access + 4'],
action: 'Heading 4'
},
{
shortcuts: ['Access + 5'],
action: 'Heading 5'
},
{
shortcuts: ['Access + 6'],
action: 'Heading 6'
},
{
shortcuts: ['Access + 7'],
action: 'Paragraph'
},
{
shortcuts: ['Access + 8'],
action: 'Div'
},
{
shortcuts: ['Access + 9'],
action: 'Address'
},
{
shortcuts: ['Alt + 0'],
action: 'Open help dialog'
},
{
shortcuts: ['Alt + F9'],
action: 'Focus to menubar'
},
{
shortcuts: ['Alt + F10'],
action: 'Focus to toolbar'
},
{
shortcuts: ['Alt + F11'],
action: 'Focus to element path'
},
{
shortcuts: ['Ctrl + F9'],
action: 'Focus to contextual toolbar'
},
{
shortcuts: ['Shift + Enter'],
action: 'Open popup menu for split buttons'
},
{
shortcuts: ['Meta + K'],
action: 'Insert link (if link plugin activated)'
},
{
shortcuts: ['Meta + S'],
action: 'Save (if save plugin activated)'
},
{
shortcuts: ['Meta + F'],
action: 'Find (if searchreplace plugin activated)'
},
{
shortcuts: ['Meta + Shift + F'],
action: 'Switch to or from fullscreen mode'
}
];
const tab$2 = () => {
const shortcutList = map(shortcuts, shortcut => {
const shortcutText = map(shortcut.shortcuts, convertText).join(' or ');
return [
shortcut.action,
shortcutText
];
});
const tablePanel = {
type: 'table',
header: [
'Action',
'Shortcut'
],
cells: shortcutList
};
return {
name: 'shortcuts',
title: 'Handy Shortcuts',
items: [tablePanel]
};
};
var global$1 = tinymce.util.Tools.resolve('tinymce.util.I18n');
const urls = map([
{
key: 'advlist',
name: 'Advanced List'
},
{
key: 'anchor',
name: 'Anchor'
},
{
key: 'autolink',
name: 'Autolink'
},
{
key: 'autoresize',
name: 'Autoresize'
},
{
key: 'autosave',
name: 'Autosave'
},
{
key: 'charmap',
name: 'Character Map'
},
{
key: 'code',
name: 'Code'
},
{
key: 'codesample',
name: 'Code Sample'
},
{
key: 'colorpicker',
name: 'Color Picker'
},
{
key: 'directionality',
name: 'Directionality'
},
{
key: 'emoticons',
name: 'Emoticons'
},
{
key: 'fullscreen',
name: 'Full Screen'
},
{
key: 'help',
name: 'Help'
},
{
key: 'image',
name: 'Image'
},
{
key: 'importcss',
name: 'Import CSS'
},
{
key: 'insertdatetime',
name: 'Insert Date/Time'
},
{
key: 'link',
name: 'Link'
},
{
key: 'lists',
name: 'Lists'
},
{
key: 'media',
name: 'Media'
},
{
key: 'nonbreaking',
name: 'Nonbreaking'
},
{
key: 'pagebreak',
name: 'Page Break'
},
{
key: 'preview',
name: 'Preview'
},
{
key: 'quickbars',
name: 'Quick Toolbars'
},
{
key: 'save',
name: 'Save'
},
{
key: 'searchreplace',
name: 'Search and Replace'
},
{
key: 'table',
name: 'Table'
},
{
key: 'template',
name: 'Template'
},
{
key: 'textcolor',
name: 'Text Color'
},
{
key: 'visualblocks',
name: 'Visual Blocks'
},
{
key: 'visualchars',
name: 'Visual Characters'
},
{
key: 'wordcount',
name: 'Word Count'
},
{
key: 'a11ychecker',
name: 'Accessibility Checker',
type: 'premium'
},
{
key: 'advcode',
name: 'Advanced Code Editor',
type: 'premium'
},
{
key: 'advtable',
name: 'Advanced Tables',
type: 'premium'
},
{
key: 'casechange',
name: 'Case Change',
type: 'premium'
},
{
key: 'checklist',
name: 'Checklist',
type: 'premium'
},
{
key: 'editimage',
name: 'Enhanced Image Editing',
type: 'premium'
},
{
key: 'footnotes',
name: 'Footnotes',
type: 'premium'
},
{
key: 'typography',
name: 'Advanced Typography',
type: 'premium'
},
{
key: 'mediaembed',
name: 'Enhanced Media Embed',
type: 'premium',
slug: 'introduction-to-mediaembed'
},
{
key: 'export',
name: 'Export',
type: 'premium'
},
{
key: 'formatpainter',
name: 'Format Painter',
type: 'premium'
},
{
key: 'inlinecss',
name: 'Inline CSS',
type: 'premium'
},
{
key: 'linkchecker',
name: 'Link Checker',
type: 'premium'
},
{
key: 'mentions',
name: 'Mentions',
type: 'premium'
},
{
key: 'mergetags',
name: 'Merge Tags',
type: 'premium'
},
{
key: 'pageembed',
name: 'Page Embed',
type: 'premium'
},
{
key: 'permanentpen',
name: 'Permanent Pen',
type: 'premium'
},
{
key: 'powerpaste',
name: 'PowerPaste',
type: 'premium',
slug: 'introduction-to-powerpaste'
},
{
key: 'rtc',
name: 'Real-Time Collaboration',
type: 'premium',
slug: 'rtc-introduction'
},
{
key: 'tinymcespellchecker',
name: 'Spell Checker Pro',
type: 'premium',
slug: 'introduction-to-tiny-spellchecker'
},
{
key: 'autocorrect',
name: 'Spelling Autocorrect',
type: 'premium'
},
{
key: 'tableofcontents',
name: 'Table of Contents',
type: 'premium'
},
{
key: 'tinycomments',
name: 'Tiny Comments',
type: 'premium',
slug: 'introduction-to-tiny-comments'
},
{
key: 'tinydrive',
name: 'Tiny Drive',
type: 'premium',
slug: 'tinydrive-introduction'
}
], item => ({
...item,
type: item.type || 'opensource',
slug: item.slug || item.key
}));
const tab$1 = editor => {
const availablePlugins = () => {
const premiumPlugins = filter(urls, ({type}) => {
return type === 'premium';
});
const sortedPremiumPlugins = sort(map(premiumPlugins, p => p.name), (s1, s2) => s1.localeCompare(s2));
const premiumPluginList = map(sortedPremiumPlugins, pluginName => `<li>${ pluginName }</li>`).join('');
return '<div data-mce-tabstop="1" tabindex="-1">' + '<p><b>' + global$1.translate('Premium plugins:') + '</b></p>' + '<ul>' + premiumPluginList + '<li class="tox-help__more-link" "><a href="https://www.tiny.cloud/pricing/?utm_campaign=editor_referral&utm_medium=help_dialog&utm_source=tinymce" rel="noopener" target="_blank">' + global$1.translate('Learn more...') + '</a></li>' + '</ul>' + '</div>';
};
const makeLink = p => `<a href="${ p.url }" target="_blank" rel="noopener">${ p.name }</a>`;
const identifyUnknownPlugin = (editor, key) => {
const getMetadata = editor.plugins[key].getMetadata;
if (isFunction(getMetadata)) {
const metadata = getMetadata();
return {
name: metadata.name,
html: makeLink(metadata)
};
} else {
return {
name: key,
html: key
};
}
};
const getPluginData = (editor, key) => find(urls, x => {
return x.key === key;
}).fold(() => {
return identifyUnknownPlugin(editor, key);
}, x => {
const name = x.type === 'premium' ? `${ x.name }*` : x.name;
const html = makeLink({
name,
url: `https://www.tiny.cloud/docs/tinymce/6/${ x.slug }/`
});
return {
name,
html
};
});
const getPluginKeys = editor => {
const keys$1 = keys(editor.plugins);
const forcedPlugins = getForcedPlugins(editor);
return isUndefined(forcedPlugins) ? keys$1 : filter(keys$1, k => !contains(forcedPlugins, k));
};
const pluginLister = editor => {
const pluginKeys = getPluginKeys(editor);
const sortedPluginData = sort(map(pluginKeys, k => getPluginData(editor, k)), (pd1, pd2) => pd1.name.localeCompare(pd2.name));
const pluginLis = map(sortedPluginData, key => {
return '<li>' + key.html + '</li>';
});
const count = pluginLis.length;
const pluginsString = pluginLis.join('');
const html = '<p><b>' + global$1.translate([
'Plugins installed ({0}):',
count
]) + '</b></p>' + '<ul>' + pluginsString + '</ul>';
return html;
};
const installedPlugins = editor => {
if (editor == null) {
return '';
}
return '<div data-mce-tabstop="1" tabindex="-1">' + pluginLister(editor) + '</div>';
};
const htmlPanel = {
type: 'htmlpanel',
presets: 'document',
html: [
installedPlugins(editor),
availablePlugins()
].join('')
};
return {
name: 'plugins',
title: 'Plugins',
items: [htmlPanel]
};
};
var global = tinymce.util.Tools.resolve('tinymce.EditorManager');
const tab = () => {
const getVersion = (major, minor) => major.indexOf('@') === 0 ? 'X.X.X' : major + '.' + minor;
const version = getVersion(global.majorVersion, global.minorVersion);
const changeLogLink = '<a href="https://www.tiny.cloud/docs/tinymce/6/changelog/?utm_campaign=editor_referral&utm_medium=help_dialog&utm_source=tinymce" rel="noopener" target="_blank">TinyMCE ' + version + '</a>';
const htmlPanel = {
type: 'htmlpanel',
html: '<p>' + global$1.translate([
'You are using {0}',
changeLogLink
]) + '</p>',
presets: 'document'
};
return {
name: 'versions',
title: 'Version',
items: [htmlPanel]
};
};
const parseHelpTabsSetting = (tabsFromSettings, tabs) => {
const newTabs = {};
const names = map(tabsFromSettings, t => {
var _a;
if (isString(t)) {
if (has(tabs, t)) {
newTabs[t] = tabs[t];
}
return t;
} else {
const name = (_a = t.name) !== null && _a !== void 0 ? _a : generate('tab-name');
newTabs[name] = t;
return name;
}
});
return {
tabs: newTabs,
names
};
};
const getNamesFromTabs = tabs => {
const names = keys(tabs);
const idx = names.indexOf('versions');
if (idx !== -1) {
names.splice(idx, 1);
names.push('versions');
}
return {
tabs,
names
};
};
const parseCustomTabs = (editor, customTabs) => {
const shortcuts = tab$2();
const nav = tab$3();
const plugins = tab$1(editor);
const versions = tab();
const tabs = {
[shortcuts.name]: shortcuts,
[nav.name]: nav,
[plugins.name]: plugins,
[versions.name]: versions,
...customTabs.get()
};
return Optional.from(getHelpTabs(editor)).fold(() => getNamesFromTabs(tabs), tabsFromSettings => parseHelpTabsSetting(tabsFromSettings, tabs));
};
const init = (editor, customTabs) => () => {
const {tabs, names} = parseCustomTabs(editor, customTabs);
const foundTabs = map(names, name => get(tabs, name));
const dialogTabs = cat(foundTabs);
const body = {
type: 'tabpanel',
tabs: dialogTabs
};
editor.windowManager.open({
title: 'Help',
size: 'medium',
body,
buttons: [{
type: 'cancel',
name: 'close',
text: 'Close',
primary: true
}],
initialData: {}
});
};
var Plugin = () => {
global$3.add('help', editor => {
const customTabs = Cell({});
const api = get$1(customTabs);
register$1(editor);
const dialogOpener = init(editor, customTabs);
register(editor, dialogOpener);
register$2(editor, dialogOpener);
editor.shortcuts.add('Alt+0', 'Open help dialog', 'mceHelp');
return api;
});
};
Plugin();
})();
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,344 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$4 = tinymce.util.Tools.resolve('tinymce.PluginManager');
const hasProto = (v, constructor, predicate) => {
var _a;
if (predicate(v, constructor.prototype)) {
return true;
} else {
return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
}
};
const typeOf = x => {
const t = typeof x;
if (x === null) {
return 'null';
} else if (t === 'object' && Array.isArray(x)) {
return 'array';
} else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
return 'string';
} else {
return t;
}
};
const isType = type => value => typeOf(value) === type;
const isSimpleType = type => value => typeof value === type;
const isString = isType('string');
const isObject = isType('object');
const isArray = isType('array');
const isFunction = isSimpleType('function');
var global$3 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
var global$2 = tinymce.util.Tools.resolve('tinymce.EditorManager');
var global$1 = tinymce.util.Tools.resolve('tinymce.Env');
var global = tinymce.util.Tools.resolve('tinymce.util.Tools');
const option = name => editor => editor.options.get(name);
const register = editor => {
const registerOption = editor.options.register;
const filterProcessor = value => isString(value) || isFunction(value) || isObject(value);
registerOption('importcss_merge_classes', {
processor: 'boolean',
default: true
});
registerOption('importcss_exclusive', {
processor: 'boolean',
default: true
});
registerOption('importcss_selector_converter', { processor: 'function' });
registerOption('importcss_selector_filter', { processor: filterProcessor });
registerOption('importcss_file_filter', { processor: filterProcessor });
registerOption('importcss_groups', { processor: 'object[]' });
registerOption('importcss_append', {
processor: 'boolean',
default: false
});
};
const shouldMergeClasses = option('importcss_merge_classes');
const shouldImportExclusive = option('importcss_exclusive');
const getSelectorConverter = option('importcss_selector_converter');
const getSelectorFilter = option('importcss_selector_filter');
const getCssGroups = option('importcss_groups');
const shouldAppend = option('importcss_append');
const getFileFilter = option('importcss_file_filter');
const getSkin = option('skin');
const getSkinUrl = option('skin_url');
const nativePush = Array.prototype.push;
const map = (xs, f) => {
const len = xs.length;
const r = new Array(len);
for (let i = 0; i < len; i++) {
const x = xs[i];
r[i] = f(x, i);
}
return r;
};
const flatten = xs => {
const r = [];
for (let i = 0, len = xs.length; i < len; ++i) {
if (!isArray(xs[i])) {
throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
}
nativePush.apply(r, xs[i]);
}
return r;
};
const bind = (xs, f) => flatten(map(xs, f));
const generate = () => {
const ungroupedOrder = [];
const groupOrder = [];
const groups = {};
const addItemToGroup = (groupTitle, itemInfo) => {
if (groups[groupTitle]) {
groups[groupTitle].push(itemInfo);
} else {
groupOrder.push(groupTitle);
groups[groupTitle] = [itemInfo];
}
};
const addItem = itemInfo => {
ungroupedOrder.push(itemInfo);
};
const toFormats = () => {
const groupItems = bind(groupOrder, g => {
const items = groups[g];
return items.length === 0 ? [] : [{
title: g,
items
}];
});
return groupItems.concat(ungroupedOrder);
};
return {
addItemToGroup,
addItem,
toFormats
};
};
const internalEditorStyle = /^\.(?:ephox|tiny-pageembed|mce)(?:[.-]+\w+)+$/;
const removeCacheSuffix = url => {
const cacheSuffix = global$1.cacheSuffix;
if (isString(url)) {
url = url.replace('?' + cacheSuffix, '').replace('&' + cacheSuffix, '');
}
return url;
};
const isSkinContentCss = (editor, href) => {
const skin = getSkin(editor);
if (skin) {
const skinUrlBase = getSkinUrl(editor);
const skinUrl = skinUrlBase ? editor.documentBaseURI.toAbsolute(skinUrlBase) : global$2.baseURL + '/skins/ui/' + skin;
const contentSkinUrlPart = global$2.baseURL + '/skins/content/';
return href === skinUrl + '/content' + (editor.inline ? '.inline' : '') + '.min.css' || href.indexOf(contentSkinUrlPart) !== -1;
}
return false;
};
const compileFilter = filter => {
if (isString(filter)) {
return value => {
return value.indexOf(filter) !== -1;
};
} else if (filter instanceof RegExp) {
return value => {
return filter.test(value);
};
}
return filter;
};
const isCssImportRule = rule => rule.styleSheet;
const isCssPageRule = rule => rule.selectorText;
const getSelectors = (editor, doc, fileFilter) => {
const selectors = [];
const contentCSSUrls = {};
const append = (styleSheet, imported) => {
let href = styleSheet.href;
let rules;
href = removeCacheSuffix(href);
if (!href || fileFilter && !fileFilter(href, imported) || isSkinContentCss(editor, href)) {
return;
}
global.each(styleSheet.imports, styleSheet => {
append(styleSheet, true);
});
try {
rules = styleSheet.cssRules || styleSheet.rules;
} catch (e) {
}
global.each(rules, cssRule => {
if (isCssImportRule(cssRule)) {
append(cssRule.styleSheet, true);
} else if (isCssPageRule(cssRule)) {
global.each(cssRule.selectorText.split(','), selector => {
selectors.push(global.trim(selector));
});
}
});
};
global.each(editor.contentCSS, url => {
contentCSSUrls[url] = true;
});
if (!fileFilter) {
fileFilter = (href, imported) => {
return imported || contentCSSUrls[href];
};
}
try {
global.each(doc.styleSheets, styleSheet => {
append(styleSheet);
});
} catch (e) {
}
return selectors;
};
const defaultConvertSelectorToFormat = (editor, selectorText) => {
let format = {};
const selector = /^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(selectorText);
if (!selector) {
return;
}
const elementName = selector[1];
const classes = selector[2].substr(1).split('.').join(' ');
const inlineSelectorElements = global.makeMap('a,img');
if (selector[1]) {
format = { title: selectorText };
if (editor.schema.getTextBlockElements()[elementName]) {
format.block = elementName;
} else if (editor.schema.getBlockElements()[elementName] || inlineSelectorElements[elementName.toLowerCase()]) {
format.selector = elementName;
} else {
format.inline = elementName;
}
} else if (selector[2]) {
format = {
inline: 'span',
title: selectorText.substr(1),
classes
};
}
if (shouldMergeClasses(editor)) {
format.classes = classes;
} else {
format.attributes = { class: classes };
}
return format;
};
const getGroupsBySelector = (groups, selector) => {
return global.grep(groups, group => {
return !group.filter || group.filter(selector);
});
};
const compileUserDefinedGroups = groups => {
return global.map(groups, group => {
return global.extend({}, group, {
original: group,
selectors: {},
filter: compileFilter(group.filter)
});
});
};
const isExclusiveMode = (editor, group) => {
return group === null || shouldImportExclusive(editor);
};
const isUniqueSelector = (editor, selector, group, globallyUniqueSelectors) => {
return !(isExclusiveMode(editor, group) ? selector in globallyUniqueSelectors : selector in group.selectors);
};
const markUniqueSelector = (editor, selector, group, globallyUniqueSelectors) => {
if (isExclusiveMode(editor, group)) {
globallyUniqueSelectors[selector] = true;
} else {
group.selectors[selector] = true;
}
};
const convertSelectorToFormat = (editor, plugin, selector, group) => {
let selectorConverter;
const converter = getSelectorConverter(editor);
if (group && group.selector_converter) {
selectorConverter = group.selector_converter;
} else if (converter) {
selectorConverter = converter;
} else {
selectorConverter = () => {
return defaultConvertSelectorToFormat(editor, selector);
};
}
return selectorConverter.call(plugin, selector, group);
};
const setup = editor => {
editor.on('init', () => {
const model = generate();
const globallyUniqueSelectors = {};
const selectorFilter = compileFilter(getSelectorFilter(editor));
const groups = compileUserDefinedGroups(getCssGroups(editor));
const processSelector = (selector, group) => {
if (isUniqueSelector(editor, selector, group, globallyUniqueSelectors)) {
markUniqueSelector(editor, selector, group, globallyUniqueSelectors);
const format = convertSelectorToFormat(editor, editor.plugins.importcss, selector, group);
if (format) {
const formatName = format.name || global$3.DOM.uniqueId();
editor.formatter.register(formatName, format);
return {
title: format.title,
format: formatName
};
}
}
return null;
};
global.each(getSelectors(editor, editor.getDoc(), compileFilter(getFileFilter(editor))), selector => {
if (!internalEditorStyle.test(selector)) {
if (!selectorFilter || selectorFilter(selector)) {
const selectorGroups = getGroupsBySelector(groups, selector);
if (selectorGroups.length > 0) {
global.each(selectorGroups, group => {
const menuItem = processSelector(selector, group);
if (menuItem) {
model.addItemToGroup(group.title, menuItem);
}
});
} else {
const menuItem = processSelector(selector, null);
if (menuItem) {
model.addItem(menuItem);
}
}
}
}
});
const items = model.toFormats();
editor.dispatch('addStyleModifications', {
items,
replace: !shouldAppend(editor)
});
});
};
const get = editor => {
const convertSelectorToFormat = selectorText => {
return defaultConvertSelectorToFormat(editor, selectorText);
};
return { convertSelectorToFormat };
};
var Plugin = () => {
global$4.add('importcss', editor => {
register(editor);
setup(editor);
return get(editor);
});
};
Plugin();
})();
+4
View File
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(s=r=e,(o=String).prototype.isPrototypeOf(s)||(null===(n=r.constructor)||void 0===n?void 0:n.name)===o.name)?"string":t;var s,r,o,n})(t)===e,s=t("string"),r=t("object"),o=t("array"),n=("function",e=>"function"==typeof e);var c=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),i=tinymce.util.Tools.resolve("tinymce.EditorManager"),l=tinymce.util.Tools.resolve("tinymce.Env"),a=tinymce.util.Tools.resolve("tinymce.util.Tools");const p=e=>t=>t.options.get(e),u=p("importcss_merge_classes"),m=p("importcss_exclusive"),f=p("importcss_selector_converter"),y=p("importcss_selector_filter"),d=p("importcss_groups"),h=p("importcss_append"),_=p("importcss_file_filter"),g=p("skin"),v=p("skin_url"),b=Array.prototype.push,x=/^\.(?:ephox|tiny-pageembed|mce)(?:[.-]+\w+)+$/,T=e=>s(e)?t=>-1!==t.indexOf(e):e instanceof RegExp?t=>e.test(t):e,S=(e,t)=>{let s={};const r=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(t);if(!r)return;const o=r[1],n=r[2].substr(1).split(".").join(" "),c=a.makeMap("a,img");return r[1]?(s={title:t},e.schema.getTextBlockElements()[o]?s.block=o:e.schema.getBlockElements()[o]||c[o.toLowerCase()]?s.selector=o:s.inline=o):r[2]&&(s={inline:"span",title:t.substr(1),classes:n}),u(e)?s.classes=n:s.attributes={class:n},s},k=(e,t)=>null===t||m(e),w=e=>{e.on("init",(()=>{const t=(()=>{const e=[],t=[],s={};return{addItemToGroup:(e,r)=>{s[e]?s[e].push(r):(t.push(e),s[e]=[r])},addItem:t=>{e.push(t)},toFormats:()=>{return(r=t,n=e=>{const t=s[e];return 0===t.length?[]:[{title:e,items:t}]},(e=>{const t=[];for(let s=0,r=e.length;s<r;++s){if(!o(e[s]))throw new Error("Arr.flatten item "+s+" was not an array, input: "+e);b.apply(t,e[s])}return t})(((e,t)=>{const s=e.length,r=new Array(s);for(let o=0;o<s;o++){const s=e[o];r[o]=t(s,o)}return r})(r,n))).concat(e);var r,n}}})(),r={},n=T(y(e)),p=(e=>a.map(e,(e=>a.extend({},e,{original:e,selectors:{},filter:T(e.filter)}))))(d(e)),u=(t,s)=>{if(((e,t,s,r)=>!(k(e,s)?t in r:t in s.selectors))(e,t,s,r)){((e,t,s,r)=>{k(e,s)?r[t]=!0:s.selectors[t]=!0})(e,t,s,r);const o=((e,t,s,r)=>{let o;const n=f(e);return o=r&&r.selector_converter?r.selector_converter:n||(()=>S(e,s)),o.call(t,s,r)})(e,e.plugins.importcss,t,s);if(o){const t=o.name||c.DOM.uniqueId();return e.formatter.register(t,o),{title:o.title,format:t}}}return null};a.each(((e,t,r)=>{const o=[],n={},c=(t,n)=>{let p,u=t.href;if(u=(e=>{const t=l.cacheSuffix;return s(e)&&(e=e.replace("?"+t,"").replace("&"+t,"")),e})(u),u&&(!r||r(u,n))&&!((e,t)=>{const s=g(e);if(s){const r=v(e),o=r?e.documentBaseURI.toAbsolute(r):i.baseURL+"/skins/ui/"+s,n=i.baseURL+"/skins/content/";return t===o+"/content"+(e.inline?".inline":"")+".min.css"||-1!==t.indexOf(n)}return!1})(e,u)){a.each(t.imports,(e=>{c(e,!0)}));try{p=t.cssRules||t.rules}catch(e){}a.each(p,(e=>{e.styleSheet?c(e.styleSheet,!0):e.selectorText&&a.each(e.selectorText.split(","),(e=>{o.push(a.trim(e))}))}))}};a.each(e.contentCSS,(e=>{n[e]=!0})),r||(r=(e,t)=>t||n[e]);try{a.each(t.styleSheets,(e=>{c(e)}))}catch(e){}return o})(e,e.getDoc(),T(_(e))),(e=>{if(!x.test(e)&&(!n||n(e))){const s=((e,t)=>a.grep(e,(e=>!e.filter||e.filter(t))))(p,e);if(s.length>0)a.each(s,(s=>{const r=u(e,s);r&&t.addItemToGroup(s.title,r)}));else{const s=u(e,null);s&&t.addItem(s)}}}));const m=t.toFormats();e.dispatch("addStyleModifications",{items:m,replace:!h(e)})}))};e.add("importcss",(e=>((e=>{const t=e.options.register,o=e=>s(e)||n(e)||r(e);t("importcss_merge_classes",{processor:"boolean",default:!0}),t("importcss_exclusive",{processor:"boolean",default:!0}),t("importcss_selector_converter",{processor:"function"}),t("importcss_selector_filter",{processor:o}),t("importcss_file_filter",{processor:o}),t("importcss_groups",{processor:"object[]"}),t("importcss_append",{processor:"boolean",default:!1})})(e),w(e),(e=>({convertSelectorToFormat:t=>S(e,t)}))(e))))}();
@@ -0,0 +1,175 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager');
const option = name => editor => editor.options.get(name);
const register$2 = editor => {
const registerOption = editor.options.register;
registerOption('insertdatetime_dateformat', {
processor: 'string',
default: editor.translate('%Y-%m-%d')
});
registerOption('insertdatetime_timeformat', {
processor: 'string',
default: editor.translate('%H:%M:%S')
});
registerOption('insertdatetime_formats', {
processor: 'string[]',
default: [
'%H:%M:%S',
'%Y-%m-%d',
'%I:%M:%S %p',
'%D'
]
});
registerOption('insertdatetime_element', {
processor: 'boolean',
default: false
});
};
const getDateFormat = option('insertdatetime_dateformat');
const getTimeFormat = option('insertdatetime_timeformat');
const getFormats = option('insertdatetime_formats');
const shouldInsertTimeElement = option('insertdatetime_element');
const getDefaultDateTime = editor => {
const formats = getFormats(editor);
return formats.length > 0 ? formats[0] : getTimeFormat(editor);
};
const daysShort = 'Sun Mon Tue Wed Thu Fri Sat Sun'.split(' ');
const daysLong = 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday'.split(' ');
const monthsShort = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');
const monthsLong = 'January February March April May June July August September October November December'.split(' ');
const addZeros = (value, len) => {
value = '' + value;
if (value.length < len) {
for (let i = 0; i < len - value.length; i++) {
value = '0' + value;
}
}
return value;
};
const getDateTime = (editor, fmt, date = new Date()) => {
fmt = fmt.replace('%D', '%m/%d/%Y');
fmt = fmt.replace('%r', '%I:%M:%S %p');
fmt = fmt.replace('%Y', '' + date.getFullYear());
fmt = fmt.replace('%y', '' + date.getYear());
fmt = fmt.replace('%m', addZeros(date.getMonth() + 1, 2));
fmt = fmt.replace('%d', addZeros(date.getDate(), 2));
fmt = fmt.replace('%H', '' + addZeros(date.getHours(), 2));
fmt = fmt.replace('%M', '' + addZeros(date.getMinutes(), 2));
fmt = fmt.replace('%S', '' + addZeros(date.getSeconds(), 2));
fmt = fmt.replace('%I', '' + ((date.getHours() + 11) % 12 + 1));
fmt = fmt.replace('%p', '' + (date.getHours() < 12 ? 'AM' : 'PM'));
fmt = fmt.replace('%B', '' + editor.translate(monthsLong[date.getMonth()]));
fmt = fmt.replace('%b', '' + editor.translate(monthsShort[date.getMonth()]));
fmt = fmt.replace('%A', '' + editor.translate(daysLong[date.getDay()]));
fmt = fmt.replace('%a', '' + editor.translate(daysShort[date.getDay()]));
fmt = fmt.replace('%%', '%');
return fmt;
};
const updateElement = (editor, timeElm, computerTime, userTime) => {
const newTimeElm = editor.dom.create('time', { datetime: computerTime }, userTime);
editor.dom.replace(newTimeElm, timeElm);
editor.selection.select(newTimeElm, true);
editor.selection.collapse(false);
};
const insertDateTime = (editor, format) => {
if (shouldInsertTimeElement(editor)) {
const userTime = getDateTime(editor, format);
let computerTime;
if (/%[HMSIp]/.test(format)) {
computerTime = getDateTime(editor, '%Y-%m-%dT%H:%M');
} else {
computerTime = getDateTime(editor, '%Y-%m-%d');
}
const timeElm = editor.dom.getParent(editor.selection.getStart(), 'time');
if (timeElm) {
updateElement(editor, timeElm, computerTime, userTime);
} else {
editor.insertContent('<time datetime="' + computerTime + '">' + userTime + '</time>');
}
} else {
editor.insertContent(getDateTime(editor, format));
}
};
const register$1 = editor => {
editor.addCommand('mceInsertDate', (_ui, value) => {
insertDateTime(editor, value !== null && value !== void 0 ? value : getDateFormat(editor));
});
editor.addCommand('mceInsertTime', (_ui, value) => {
insertDateTime(editor, value !== null && value !== void 0 ? value : getTimeFormat(editor));
});
};
const Cell = initial => {
let value = initial;
const get = () => {
return value;
};
const set = v => {
value = v;
};
return {
get,
set
};
};
var global = tinymce.util.Tools.resolve('tinymce.util.Tools');
const register = editor => {
const formats = getFormats(editor);
const defaultFormat = Cell(getDefaultDateTime(editor));
const insertDateTime = format => editor.execCommand('mceInsertDate', false, format);
editor.ui.registry.addSplitButton('insertdatetime', {
icon: 'insert-time',
tooltip: 'Insert date/time',
select: value => value === defaultFormat.get(),
fetch: done => {
done(global.map(formats, format => ({
type: 'choiceitem',
text: getDateTime(editor, format),
value: format
})));
},
onAction: _api => {
insertDateTime(defaultFormat.get());
},
onItemAction: (_api, value) => {
defaultFormat.set(value);
insertDateTime(value);
}
});
const makeMenuItemHandler = format => () => {
defaultFormat.set(format);
insertDateTime(format);
};
editor.ui.registry.addNestedMenuItem('insertdatetime', {
icon: 'insert-time',
text: 'Date/time',
getSubmenuItems: () => global.map(formats, format => ({
type: 'menuitem',
text: getDateTime(editor, format),
onAction: makeMenuItemHandler(format)
}))
});
};
var Plugin = () => {
global$1.add('insertdatetime', editor => {
register$2(editor);
register$1(editor);
register(editor);
});
};
Plugin();
})();
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),a=t("insertdatetime_dateformat"),r=t("insertdatetime_timeformat"),n=t("insertdatetime_formats"),s=t("insertdatetime_element"),i="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),o="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),l="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),m="January February March April May June July August September October November December".split(" "),c=(e,t)=>{if((e=""+e).length<t)for(let a=0;a<t-e.length;a++)e="0"+e;return e},d=(e,t,a=new Date)=>(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=t.replace("%D","%m/%d/%Y")).replace("%r","%I:%M:%S %p")).replace("%Y",""+a.getFullYear())).replace("%y",""+a.getYear())).replace("%m",c(a.getMonth()+1,2))).replace("%d",c(a.getDate(),2))).replace("%H",""+c(a.getHours(),2))).replace("%M",""+c(a.getMinutes(),2))).replace("%S",""+c(a.getSeconds(),2))).replace("%I",""+((a.getHours()+11)%12+1))).replace("%p",a.getHours()<12?"AM":"PM")).replace("%B",""+e.translate(m[a.getMonth()]))).replace("%b",""+e.translate(l[a.getMonth()]))).replace("%A",""+e.translate(o[a.getDay()]))).replace("%a",""+e.translate(i[a.getDay()]))).replace("%%","%"),u=(e,t)=>{if(s(e)){const a=d(e,t);let r;r=/%[HMSIp]/.test(t)?d(e,"%Y-%m-%dT%H:%M"):d(e,"%Y-%m-%d");const n=e.dom.getParent(e.selection.getStart(),"time");n?((e,t,a,r)=>{const n=e.dom.create("time",{datetime:a},r);e.dom.replace(n,t),e.selection.select(n,!0),e.selection.collapse(!1)})(e,n,r,a):e.insertContent('<time datetime="'+r+'">'+a+"</time>")}else e.insertContent(d(e,t))};var p=tinymce.util.Tools.resolve("tinymce.util.Tools");e.add("insertdatetime",(e=>{(e=>{const t=e.options.register;t("insertdatetime_dateformat",{processor:"string",default:e.translate("%Y-%m-%d")}),t("insertdatetime_timeformat",{processor:"string",default:e.translate("%H:%M:%S")}),t("insertdatetime_formats",{processor:"string[]",default:["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"]}),t("insertdatetime_element",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mceInsertDate",((t,r)=>{u(e,null!=r?r:a(e))})),e.addCommand("mceInsertTime",((t,a)=>{u(e,null!=a?a:r(e))}))})(e),(e=>{const t=n(e),a=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})((e=>{const t=n(e);return t.length>0?t[0]:r(e)})(e)),s=t=>e.execCommand("mceInsertDate",!1,t);e.ui.registry.addSplitButton("insertdatetime",{icon:"insert-time",tooltip:"Insert date/time",select:e=>e===a.get(),fetch:a=>{a(p.map(t,(t=>({type:"choiceitem",text:d(e,t),value:t}))))},onAction:e=>{s(a.get())},onItemAction:(e,t)=>{a.set(t),s(t)}});const i=e=>()=>{a.set(e),s(e)};e.ui.registry.addNestedMenuItem("insertdatetime",{icon:"insert-time",text:"Date/time",getSubmenuItems:()=>p.map(t,(t=>({type:"menuitem",text:d(e,t),onAction:i(t)})))})})(e)}))}();
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,111 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager');
const isSimpleType = type => value => typeof value === type;
const isBoolean = isSimpleType('boolean');
const isNumber = isSimpleType('number');
const option = name => editor => editor.options.get(name);
const register$2 = editor => {
const registerOption = editor.options.register;
registerOption('nonbreaking_force_tab', {
processor: value => {
if (isBoolean(value)) {
return {
value: value ? 3 : 0,
valid: true
};
} else if (isNumber(value)) {
return {
value,
valid: true
};
} else {
return {
valid: false,
message: 'Must be a boolean or number.'
};
}
},
default: false
});
registerOption('nonbreaking_wrap', {
processor: 'boolean',
default: true
});
};
const getKeyboardSpaces = option('nonbreaking_force_tab');
const wrapNbsps = option('nonbreaking_wrap');
const stringRepeat = (string, repeats) => {
let str = '';
for (let index = 0; index < repeats; index++) {
str += string;
}
return str;
};
const isVisualCharsEnabled = editor => editor.plugins.visualchars ? editor.plugins.visualchars.isEnabled() : false;
const insertNbsp = (editor, times) => {
const classes = () => isVisualCharsEnabled(editor) ? 'mce-nbsp-wrap mce-nbsp' : 'mce-nbsp-wrap';
const nbspSpan = () => `<span class="${ classes() }" contenteditable="false">${ stringRepeat('&nbsp;', times) }</span>`;
const shouldWrap = wrapNbsps(editor);
const html = shouldWrap || editor.plugins.visualchars ? nbspSpan() : stringRepeat('&nbsp;', times);
editor.undoManager.transact(() => editor.insertContent(html));
};
const register$1 = editor => {
editor.addCommand('mceNonBreaking', () => {
insertNbsp(editor, 1);
});
};
var global = tinymce.util.Tools.resolve('tinymce.util.VK');
const setup = editor => {
const spaces = getKeyboardSpaces(editor);
if (spaces > 0) {
editor.on('keydown', e => {
if (e.keyCode === global.TAB && !e.isDefaultPrevented()) {
if (e.shiftKey) {
return;
}
e.preventDefault();
e.stopImmediatePropagation();
insertNbsp(editor, spaces);
}
});
}
};
const register = editor => {
const onAction = () => editor.execCommand('mceNonBreaking');
editor.ui.registry.addButton('nonbreaking', {
icon: 'non-breaking',
tooltip: 'Nonbreaking space',
onAction
});
editor.ui.registry.addMenuItem('nonbreaking', {
icon: 'non-breaking',
text: 'Nonbreaking space',
onAction
});
};
var Plugin = () => {
global$1.add('nonbreaking', editor => {
register$2(editor);
register$1(editor);
register(editor);
setup(editor);
});
};
Plugin();
})();
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=n=>e=>typeof e===n,a=e("boolean"),o=e("number"),t=n=>e=>e.options.get(n),i=t("nonbreaking_force_tab"),r=t("nonbreaking_wrap"),s=(n,e)=>{let a="";for(let o=0;o<e;o++)a+=n;return a},c=(n,e)=>{const a=r(n)||n.plugins.visualchars?`<span class="${(n=>!!n.plugins.visualchars&&n.plugins.visualchars.isEnabled())(n)?"mce-nbsp-wrap mce-nbsp":"mce-nbsp-wrap"}" contenteditable="false">${s("&nbsp;",e)}</span>`:s("&nbsp;",e);n.undoManager.transact((()=>n.insertContent(a)))};var l=tinymce.util.Tools.resolve("tinymce.util.VK");n.add("nonbreaking",(n=>{(n=>{const e=n.options.register;e("nonbreaking_force_tab",{processor:n=>a(n)?{value:n?3:0,valid:!0}:o(n)?{value:n,valid:!0}:{valid:!1,message:"Must be a boolean or number."},default:!1}),e("nonbreaking_wrap",{processor:"boolean",default:!0})})(n),(n=>{n.addCommand("mceNonBreaking",(()=>{c(n,1)}))})(n),(n=>{const e=()=>n.execCommand("mceNonBreaking");n.ui.registry.addButton("nonbreaking",{icon:"non-breaking",tooltip:"Nonbreaking space",onAction:e}),n.ui.registry.addMenuItem("nonbreaking",{icon:"non-breaking",text:"Nonbreaking space",onAction:e})})(n),(n=>{const e=i(n);e>0&&n.on("keydown",(a=>{if(a.keyCode===l.TAB&&!a.isDefaultPrevented()){if(a.shiftKey)return;a.preventDefault(),a.stopImmediatePropagation(),c(n,e)}}))})(n)}))}();
@@ -0,0 +1,105 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager');
var global = tinymce.util.Tools.resolve('tinymce.Env');
const option = name => editor => editor.options.get(name);
const register$2 = editor => {
const registerOption = editor.options.register;
registerOption('pagebreak_separator', {
processor: 'string',
default: '<!-- pagebreak -->'
});
registerOption('pagebreak_split_block', {
processor: 'boolean',
default: false
});
};
const getSeparatorHtml = option('pagebreak_separator');
const shouldSplitBlock = option('pagebreak_split_block');
const pageBreakClass = 'mce-pagebreak';
const getPlaceholderHtml = shouldSplitBlock => {
const html = `<img src="${ global.transparentSrc }" class="${ pageBreakClass }" data-mce-resize="false" data-mce-placeholder />`;
return shouldSplitBlock ? `<p>${ html }</p>` : html;
};
const setup$1 = editor => {
const separatorHtml = getSeparatorHtml(editor);
const shouldSplitBlock$1 = () => shouldSplitBlock(editor);
const pageBreakSeparatorRegExp = new RegExp(separatorHtml.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g, a => {
return '\\' + a;
}), 'gi');
editor.on('BeforeSetContent', e => {
e.content = e.content.replace(pageBreakSeparatorRegExp, getPlaceholderHtml(shouldSplitBlock$1()));
});
editor.on('PreInit', () => {
editor.serializer.addNodeFilter('img', nodes => {
let i = nodes.length, node, className;
while (i--) {
node = nodes[i];
className = node.attr('class');
if (className && className.indexOf(pageBreakClass) !== -1) {
const parentNode = node.parent;
if (parentNode && editor.schema.getBlockElements()[parentNode.name] && shouldSplitBlock$1()) {
parentNode.type = 3;
parentNode.value = separatorHtml;
parentNode.raw = true;
node.remove();
continue;
}
node.type = 3;
node.value = separatorHtml;
node.raw = true;
}
}
});
});
};
const register$1 = editor => {
editor.addCommand('mcePageBreak', () => {
editor.insertContent(getPlaceholderHtml(shouldSplitBlock(editor)));
});
};
const setup = editor => {
editor.on('ResolveName', e => {
if (e.target.nodeName === 'IMG' && editor.dom.hasClass(e.target, pageBreakClass)) {
e.name = 'pagebreak';
}
});
};
const register = editor => {
const onAction = () => editor.execCommand('mcePageBreak');
editor.ui.registry.addButton('pagebreak', {
icon: 'page-break',
tooltip: 'Page break',
onAction
});
editor.ui.registry.addMenuItem('pagebreak', {
text: 'Page break',
icon: 'page-break',
onAction
});
};
var Plugin = () => {
global$1.add('pagebreak', editor => {
register$2(editor);
register$1(editor);
register(editor);
setup$1(editor);
setup(editor);
});
};
Plugin();
})();
+4
View File
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.Env");const t=e=>a=>a.options.get(e),r=t("pagebreak_separator"),n=t("pagebreak_split_block"),o="mce-pagebreak",s=e=>{const t=`<img src="${a.transparentSrc}" class="mce-pagebreak" data-mce-resize="false" data-mce-placeholder />`;return e?`<p>${t}</p>`:t};e.add("pagebreak",(e=>{(e=>{const a=e.options.register;a("pagebreak_separator",{processor:"string",default:"\x3c!-- pagebreak --\x3e"}),a("pagebreak_split_block",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mcePageBreak",(()=>{e.insertContent(s(n(e)))}))})(e),(e=>{const a=()=>e.execCommand("mcePageBreak");e.ui.registry.addButton("pagebreak",{icon:"page-break",tooltip:"Page break",onAction:a}),e.ui.registry.addMenuItem("pagebreak",{text:"Page break",icon:"page-break",onAction:a})})(e),(e=>{const a=r(e),t=()=>n(e),c=new RegExp(a.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,(e=>"\\"+e)),"gi");e.on("BeforeSetContent",(e=>{e.content=e.content.replace(c,s(t()))})),e.on("PreInit",(()=>{e.serializer.addNodeFilter("img",(r=>{let n,s,c=r.length;for(;c--;)if(n=r[c],s=n.attr("class"),s&&-1!==s.indexOf(o)){const r=n.parent;if(r&&e.schema.getBlockElements()[r.name]&&t()){r.type=3,r.value=a,r.raw=!0,n.remove();continue}n.type=3,n.value=a,n.raw=!0}}))}))})(e),(e=>{e.on("ResolveName",(a=>{"IMG"===a.target.nodeName&&e.dom.hasClass(a.target,o)&&(a.name="pagebreak")}))})(e)}))}();
@@ -0,0 +1,97 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$2 = tinymce.util.Tools.resolve('tinymce.PluginManager');
var global$1 = tinymce.util.Tools.resolve('tinymce.Env');
var global = tinymce.util.Tools.resolve('tinymce.util.Tools');
const option = name => editor => editor.options.get(name);
const getContentStyle = option('content_style');
const shouldUseContentCssCors = option('content_css_cors');
const getBodyClass = option('body_class');
const getBodyId = option('body_id');
const getPreviewHtml = editor => {
var _a;
let headHtml = '';
const encode = editor.dom.encode;
const contentStyle = (_a = getContentStyle(editor)) !== null && _a !== void 0 ? _a : '';
headHtml += '<base href="' + encode(editor.documentBaseURI.getURI()) + '">';
const cors = shouldUseContentCssCors(editor) ? ' crossorigin="anonymous"' : '';
global.each(editor.contentCSS, url => {
headHtml += '<link type="text/css" rel="stylesheet" href="' + encode(editor.documentBaseURI.toAbsolute(url)) + '"' + cors + '>';
});
if (contentStyle) {
headHtml += '<style type="text/css">' + contentStyle + '</style>';
}
const bodyId = getBodyId(editor);
const bodyClass = getBodyClass(editor);
const isMetaKeyPressed = global$1.os.isMacOS() || global$1.os.isiOS() ? 'e.metaKey' : 'e.ctrlKey && !e.altKey';
const preventClicksOnLinksScript = '<script>' + 'document.addEventListener && document.addEventListener("click", function(e) {' + 'for (var elm = e.target; elm; elm = elm.parentNode) {' + 'if (elm.nodeName === "A" && !(' + isMetaKeyPressed + ')) {' + 'e.preventDefault();' + '}' + '}' + '}, false);' + '</script> ';
const directionality = editor.getBody().dir;
const dirAttr = directionality ? ' dir="' + encode(directionality) + '"' : '';
const previewHtml = '<!DOCTYPE html>' + '<html>' + '<head>' + headHtml + '</head>' + '<body id="' + encode(bodyId) + '" class="mce-content-body ' + encode(bodyClass) + '"' + dirAttr + '>' + editor.getContent() + preventClicksOnLinksScript + '</body>' + '</html>';
return previewHtml;
};
const open = editor => {
const content = getPreviewHtml(editor);
const dataApi = editor.windowManager.open({
title: 'Preview',
size: 'large',
body: {
type: 'panel',
items: [{
name: 'preview',
type: 'iframe',
sandboxed: true,
transparent: false
}]
},
buttons: [{
type: 'cancel',
name: 'close',
text: 'Close',
primary: true
}],
initialData: { preview: content }
});
dataApi.focus('close');
};
const register$1 = editor => {
editor.addCommand('mcePreview', () => {
open(editor);
});
};
const register = editor => {
const onAction = () => editor.execCommand('mcePreview');
editor.ui.registry.addButton('preview', {
icon: 'preview',
tooltip: 'Preview',
onAction
});
editor.ui.registry.addMenuItem('preview', {
icon: 'preview',
text: 'Preview',
onAction
});
};
var Plugin = () => {
global$2.add('preview', editor => {
register$1(editor);
register(editor);
});
};
Plugin();
})();
+4
View File
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=e=>t=>t.options.get(e),i=n("content_style"),s=n("content_css_cors"),c=n("body_class"),r=n("body_id");e.add("preview",(e=>{(e=>{e.addCommand("mcePreview",(()=>{(e=>{const n=(e=>{var n;let l="";const a=e.dom.encode,d=null!==(n=i(e))&&void 0!==n?n:"";l+='<base href="'+a(e.documentBaseURI.getURI())+'">';const m=s(e)?' crossorigin="anonymous"':"";o.each(e.contentCSS,(t=>{l+='<link type="text/css" rel="stylesheet" href="'+a(e.documentBaseURI.toAbsolute(t))+'"'+m+">"})),d&&(l+='<style type="text/css">'+d+"</style>");const y=r(e),u=c(e),v='<script>document.addEventListener && document.addEventListener("click", function(e) {for (var elm = e.target; elm; elm = elm.parentNode) {if (elm.nodeName === "A" && !('+(t.os.isMacOS()||t.os.isiOS()?"e.metaKey":"e.ctrlKey && !e.altKey")+")) {e.preventDefault();}}}, false);<\/script> ",p=e.getBody().dir,w=p?' dir="'+a(p)+'"':"";return"<!DOCTYPE html><html><head>"+l+'</head><body id="'+a(y)+'" class="mce-content-body '+a(u)+'"'+w+">"+e.getContent()+v+"</body></html>"})(e);e.windowManager.open({title:"Preview",size:"large",body:{type:"panel",items:[{name:"preview",type:"iframe",sandboxed:!0,transparent:!1}]},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{preview:n}}).focus("close")})(e)}))})(e),(e=>{const t=()=>e.execCommand("mcePreview");e.ui.registry.addButton("preview",{icon:"preview",tooltip:"Preview",onAction:t}),e.ui.registry.addMenuItem("preview",{icon:"preview",text:"Preview",onAction:t})})(e)}))}();
@@ -0,0 +1,429 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$2 = tinymce.util.Tools.resolve('tinymce.PluginManager');
const hasProto = (v, constructor, predicate) => {
var _a;
if (predicate(v, constructor.prototype)) {
return true;
} else {
return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
}
};
const typeOf = x => {
const t = typeof x;
if (x === null) {
return 'null';
} else if (t === 'object' && Array.isArray(x)) {
return 'array';
} else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
return 'string';
} else {
return t;
}
};
const isType = type => value => typeOf(value) === type;
const isSimpleType = type => value => typeof value === type;
const isString = isType('string');
const isBoolean = isSimpleType('boolean');
const isNullable = a => a === null || a === undefined;
const isNonNullable = a => !isNullable(a);
const isFunction = isSimpleType('function');
const option = name => editor => editor.options.get(name);
const register = editor => {
const registerOption = editor.options.register;
const toolbarProcessor = defaultValue => value => {
const valid = isBoolean(value) || isString(value);
if (valid) {
if (isBoolean(value)) {
return {
value: value ? defaultValue : '',
valid
};
} else {
return {
value: value.trim(),
valid
};
}
} else {
return {
valid: false,
message: 'Must be a boolean or string.'
};
}
};
const defaultSelectionToolbar = 'bold italic | quicklink h2 h3 blockquote';
registerOption('quickbars_selection_toolbar', {
processor: toolbarProcessor(defaultSelectionToolbar),
default: defaultSelectionToolbar
});
const defaultInsertToolbar = 'quickimage quicktable';
registerOption('quickbars_insert_toolbar', {
processor: toolbarProcessor(defaultInsertToolbar),
default: defaultInsertToolbar
});
const defaultImageToolbar = 'alignleft aligncenter alignright';
registerOption('quickbars_image_toolbar', {
processor: toolbarProcessor(defaultImageToolbar),
default: defaultImageToolbar
});
};
const getTextSelectionToolbarItems = option('quickbars_selection_toolbar');
const getInsertToolbarItems = option('quickbars_insert_toolbar');
const getImageToolbarItems = option('quickbars_image_toolbar');
let unique = 0;
const generate = prefix => {
const date = new Date();
const time = date.getTime();
const random = Math.floor(Math.random() * 1000000000);
unique++;
return prefix + '_' + random + unique + String(time);
};
const insertTable = (editor, columns, rows) => {
editor.execCommand('mceInsertTable', false, {
rows,
columns
});
};
const insertBlob = (editor, base64, blob) => {
const blobCache = editor.editorUpload.blobCache;
const blobInfo = blobCache.create(generate('mceu'), blob, base64);
blobCache.add(blobInfo);
editor.insertContent(editor.dom.createHTML('img', { src: blobInfo.blobUri() }));
};
const blobToBase64 = blob => {
return new Promise(resolve => {
const reader = new FileReader();
reader.onloadend = () => {
resolve(reader.result.split(',')[1]);
};
reader.readAsDataURL(blob);
});
};
var global$1 = tinymce.util.Tools.resolve('tinymce.Env');
var global = tinymce.util.Tools.resolve('tinymce.util.Delay');
const pickFile = editor => new Promise(resolve => {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = 'image/*';
fileInput.style.position = 'fixed';
fileInput.style.left = '0';
fileInput.style.top = '0';
fileInput.style.opacity = '0.001';
document.body.appendChild(fileInput);
const changeHandler = e => {
resolve(Array.prototype.slice.call(e.target.files));
};
fileInput.addEventListener('change', changeHandler);
const cancelHandler = e => {
const cleanup = () => {
var _a;
resolve([]);
(_a = fileInput.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(fileInput);
};
if (global$1.os.isAndroid() && e.type !== 'remove') {
global.setEditorTimeout(editor, cleanup, 0);
} else {
cleanup();
}
editor.off('focusin remove', cancelHandler);
};
editor.on('focusin remove', cancelHandler);
fileInput.click();
});
const setupButtons = editor => {
editor.ui.registry.addButton('quickimage', {
icon: 'image',
tooltip: 'Insert image',
onAction: () => {
pickFile(editor).then(files => {
if (files.length > 0) {
const blob = files[0];
blobToBase64(blob).then(base64 => {
insertBlob(editor, base64, blob);
});
}
});
}
});
editor.ui.registry.addButton('quicktable', {
icon: 'table',
tooltip: 'Insert table',
onAction: () => {
insertTable(editor, 2, 2);
}
});
};
const constant = value => {
return () => {
return value;
};
};
const never = constant(false);
class Optional {
constructor(tag, value) {
this.tag = tag;
this.value = value;
}
static some(value) {
return new Optional(true, value);
}
static none() {
return Optional.singletonNone;
}
fold(onNone, onSome) {
if (this.tag) {
return onSome(this.value);
} else {
return onNone();
}
}
isSome() {
return this.tag;
}
isNone() {
return !this.tag;
}
map(mapper) {
if (this.tag) {
return Optional.some(mapper(this.value));
} else {
return Optional.none();
}
}
bind(binder) {
if (this.tag) {
return binder(this.value);
} else {
return Optional.none();
}
}
exists(predicate) {
return this.tag && predicate(this.value);
}
forall(predicate) {
return !this.tag || predicate(this.value);
}
filter(predicate) {
if (!this.tag || predicate(this.value)) {
return this;
} else {
return Optional.none();
}
}
getOr(replacement) {
return this.tag ? this.value : replacement;
}
or(replacement) {
return this.tag ? this : replacement;
}
getOrThunk(thunk) {
return this.tag ? this.value : thunk();
}
orThunk(thunk) {
return this.tag ? this : thunk();
}
getOrDie(message) {
if (!this.tag) {
throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
} else {
return this.value;
}
}
static from(value) {
return isNonNullable(value) ? Optional.some(value) : Optional.none();
}
getOrNull() {
return this.tag ? this.value : null;
}
getOrUndefined() {
return this.value;
}
each(worker) {
if (this.tag) {
worker(this.value);
}
}
toArray() {
return this.tag ? [this.value] : [];
}
toString() {
return this.tag ? `some(${ this.value })` : 'none()';
}
}
Optional.singletonNone = new Optional(false);
typeof window !== 'undefined' ? window : Function('return this;')();
const ELEMENT = 1;
const name = element => {
const r = element.dom.nodeName;
return r.toLowerCase();
};
const has = (element, key) => {
const dom = element.dom;
return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
};
var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
if (is(scope, a)) {
return Optional.some(scope);
} else if (isFunction(isRoot) && isRoot(scope)) {
return Optional.none();
} else {
return ancestor(scope, a, isRoot);
}
};
const fromHtml = (html, scope) => {
const doc = scope || document;
const div = doc.createElement('div');
div.innerHTML = html;
if (!div.hasChildNodes() || div.childNodes.length > 1) {
const message = 'HTML does not have a single root node';
console.error(message, html);
throw new Error(message);
}
return fromDom(div.childNodes[0]);
};
const fromTag = (tag, scope) => {
const doc = scope || document;
const node = doc.createElement(tag);
return fromDom(node);
};
const fromText = (text, scope) => {
const doc = scope || document;
const node = doc.createTextNode(text);
return fromDom(node);
};
const fromDom = node => {
if (node === null || node === undefined) {
throw new Error('Node cannot be null or undefined');
}
return { dom: node };
};
const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
const SugarElement = {
fromHtml,
fromTag,
fromText,
fromDom,
fromPoint
};
const is = (element, selector) => {
const dom = element.dom;
if (dom.nodeType !== ELEMENT) {
return false;
} else {
const elem = dom;
if (elem.matches !== undefined) {
return elem.matches(selector);
} else if (elem.msMatchesSelector !== undefined) {
return elem.msMatchesSelector(selector);
} else if (elem.webkitMatchesSelector !== undefined) {
return elem.webkitMatchesSelector(selector);
} else if (elem.mozMatchesSelector !== undefined) {
return elem.mozMatchesSelector(selector);
} else {
throw new Error('Browser lacks native selectors');
}
}
};
const ancestor$1 = (scope, predicate, isRoot) => {
let element = scope.dom;
const stop = isFunction(isRoot) ? isRoot : never;
while (element.parentNode) {
element = element.parentNode;
const el = SugarElement.fromDom(element);
if (predicate(el)) {
return Optional.some(el);
} else if (stop(el)) {
break;
}
}
return Optional.none();
};
const closest$2 = (scope, predicate, isRoot) => {
const is = (s, test) => test(s);
return ClosestOrAncestor(is, ancestor$1, scope, predicate, isRoot);
};
const closest$1 = (scope, predicate, isRoot) => closest$2(scope, predicate, isRoot).isSome();
const ancestor = (scope, selector, isRoot) => ancestor$1(scope, e => is(e, selector), isRoot);
const closest = (scope, selector, isRoot) => {
const is$1 = (element, selector) => is(element, selector);
return ClosestOrAncestor(is$1, ancestor, scope, selector, isRoot);
};
const addToEditor$1 = editor => {
const insertToolbarItems = getInsertToolbarItems(editor);
if (insertToolbarItems.length > 0) {
editor.ui.registry.addContextToolbar('quickblock', {
predicate: node => {
const sugarNode = SugarElement.fromDom(node);
const textBlockElementsMap = editor.schema.getTextBlockElements();
const isRoot = elem => elem.dom === editor.getBody();
return !has(sugarNode, 'data-mce-bogus') && closest(sugarNode, 'table,[data-mce-bogus="all"]', isRoot).fold(() => closest$1(sugarNode, elem => name(elem) in textBlockElementsMap && editor.dom.isEmpty(elem.dom), isRoot), never);
},
items: insertToolbarItems,
position: 'line',
scope: 'editor'
});
}
};
const addToEditor = editor => {
const isEditable = node => editor.dom.getContentEditableParent(node) !== 'false';
const isImage = node => node.nodeName === 'IMG' || node.nodeName === 'FIGURE' && /image/i.test(node.className);
const imageToolbarItems = getImageToolbarItems(editor);
if (imageToolbarItems.length > 0) {
editor.ui.registry.addContextToolbar('imageselection', {
predicate: isImage,
items: imageToolbarItems,
position: 'node'
});
}
const textToolbarItems = getTextSelectionToolbarItems(editor);
if (textToolbarItems.length > 0) {
editor.ui.registry.addContextToolbar('textselection', {
predicate: node => !isImage(node) && !editor.selection.isCollapsed() && isEditable(node),
items: textToolbarItems,
position: 'selection',
scope: 'editor'
});
}
};
var Plugin = () => {
global$2.add('quickbars', editor => {
register(editor);
setupButtons(editor);
addToEditor$1(editor);
addToEditor(editor);
});
};
Plugin();
})();
File diff suppressed because one or more lines are too long
@@ -0,0 +1,118 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$2 = tinymce.util.Tools.resolve('tinymce.PluginManager');
const isSimpleType = type => value => typeof value === type;
const isFunction = isSimpleType('function');
var global$1 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
var global = tinymce.util.Tools.resolve('tinymce.util.Tools');
const option = name => editor => editor.options.get(name);
const register$2 = editor => {
const registerOption = editor.options.register;
registerOption('save_enablewhendirty', {
processor: 'boolean',
default: true
});
registerOption('save_onsavecallback', { processor: 'function' });
registerOption('save_oncancelcallback', { processor: 'function' });
};
const enableWhenDirty = option('save_enablewhendirty');
const getOnSaveCallback = option('save_onsavecallback');
const getOnCancelCallback = option('save_oncancelcallback');
const displayErrorMessage = (editor, message) => {
editor.notificationManager.open({
text: message,
type: 'error'
});
};
const save = editor => {
const formObj = global$1.DOM.getParent(editor.id, 'form');
if (enableWhenDirty(editor) && !editor.isDirty()) {
return;
}
editor.save();
const onSaveCallback = getOnSaveCallback(editor);
if (isFunction(onSaveCallback)) {
onSaveCallback.call(editor, editor);
editor.nodeChanged();
return;
}
if (formObj) {
editor.setDirty(false);
if (!formObj.onsubmit || formObj.onsubmit()) {
if (typeof formObj.submit === 'function') {
formObj.submit();
} else {
displayErrorMessage(editor, 'Error: Form submit field collision.');
}
}
editor.nodeChanged();
} else {
displayErrorMessage(editor, 'Error: No form element found.');
}
};
const cancel = editor => {
const h = global.trim(editor.startContent);
const onCancelCallback = getOnCancelCallback(editor);
if (isFunction(onCancelCallback)) {
onCancelCallback.call(editor, editor);
return;
}
editor.resetContent(h);
};
const register$1 = editor => {
editor.addCommand('mceSave', () => {
save(editor);
});
editor.addCommand('mceCancel', () => {
cancel(editor);
});
};
const stateToggle = editor => api => {
const handler = () => {
api.setEnabled(!enableWhenDirty(editor) || editor.isDirty());
};
handler();
editor.on('NodeChange dirty', handler);
return () => editor.off('NodeChange dirty', handler);
};
const register = editor => {
editor.ui.registry.addButton('save', {
icon: 'save',
tooltip: 'Save',
enabled: false,
onAction: () => editor.execCommand('mceSave'),
onSetup: stateToggle(editor)
});
editor.ui.registry.addButton('cancel', {
icon: 'cancel',
tooltip: 'Cancel',
enabled: false,
onAction: () => editor.execCommand('mceCancel'),
onSetup: stateToggle(editor)
});
editor.addShortcut('Meta+S', '', 'mceSave');
};
var Plugin = () => {
global$2.add('save', editor => {
register$2(editor);
register(editor);
register$1(editor);
});
};
Plugin();
})();
+4
View File
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const n=("function",e=>"function"==typeof e);var o=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),t=tinymce.util.Tools.resolve("tinymce.util.Tools");const a=e=>n=>n.options.get(e),c=a("save_enablewhendirty"),i=a("save_onsavecallback"),s=a("save_oncancelcallback"),r=(e,n)=>{e.notificationManager.open({text:n,type:"error"})},l=e=>n=>{const o=()=>{n.setEnabled(!c(e)||e.isDirty())};return o(),e.on("NodeChange dirty",o),()=>e.off("NodeChange dirty",o)};e.add("save",(e=>{(e=>{const n=e.options.register;n("save_enablewhendirty",{processor:"boolean",default:!0}),n("save_onsavecallback",{processor:"function"}),n("save_oncancelcallback",{processor:"function"})})(e),(e=>{e.ui.registry.addButton("save",{icon:"save",tooltip:"Save",enabled:!1,onAction:()=>e.execCommand("mceSave"),onSetup:l(e)}),e.ui.registry.addButton("cancel",{icon:"cancel",tooltip:"Cancel",enabled:!1,onAction:()=>e.execCommand("mceCancel"),onSetup:l(e)}),e.addShortcut("Meta+S","","mceSave")})(e),(e=>{e.addCommand("mceSave",(()=>{(e=>{const t=o.DOM.getParent(e.id,"form");if(c(e)&&!e.isDirty())return;e.save();const a=i(e);if(n(a))return a.call(e,e),void e.nodeChanged();t?(e.setDirty(!1),t.onsubmit&&!t.onsubmit()||("function"==typeof t.submit?t.submit():r(e,"Error: Form submit field collision.")),e.nodeChanged()):r(e,"Error: No form element found.")})(e)})),e.addCommand("mceCancel",(()=>{(e=>{const o=t.trim(e.startContent),a=s(e);n(a)?a.call(e,e):e.resetContent(o)})(e)}))})(e)}))}();
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,551 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$2 = tinymce.util.Tools.resolve('tinymce.PluginManager');
const hasProto = (v, constructor, predicate) => {
var _a;
if (predicate(v, constructor.prototype)) {
return true;
} else {
return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
}
};
const typeOf = x => {
const t = typeof x;
if (x === null) {
return 'null';
} else if (t === 'object' && Array.isArray(x)) {
return 'array';
} else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
return 'string';
} else {
return t;
}
};
const isType = type => value => typeOf(value) === type;
const isSimpleType = type => value => typeof value === type;
const isString = isType('string');
const isObject = isType('object');
const isArray = isType('array');
const isNullable = a => a === null || a === undefined;
const isNonNullable = a => !isNullable(a);
const isFunction = isSimpleType('function');
const isArrayOf = (value, pred) => {
if (isArray(value)) {
for (let i = 0, len = value.length; i < len; ++i) {
if (!pred(value[i])) {
return false;
}
}
return true;
}
return false;
};
const constant = value => {
return () => {
return value;
};
};
function curry(fn, ...initialArgs) {
return (...restArgs) => {
const all = initialArgs.concat(restArgs);
return fn.apply(null, all);
};
}
const never = constant(false);
const escape = text => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
const option = name => editor => editor.options.get(name);
const register$2 = editor => {
const registerOption = editor.options.register;
registerOption('template_cdate_classes', {
processor: 'string',
default: 'cdate'
});
registerOption('template_mdate_classes', {
processor: 'string',
default: 'mdate'
});
registerOption('template_selected_content_classes', {
processor: 'string',
default: 'selcontent'
});
registerOption('template_preview_replace_values', { processor: 'object' });
registerOption('template_replace_values', { processor: 'object' });
registerOption('templates', {
processor: value => isString(value) || isArrayOf(value, isObject) || isFunction(value),
default: []
});
registerOption('template_cdate_format', {
processor: 'string',
default: editor.translate('%Y-%m-%d')
});
registerOption('template_mdate_format', {
processor: 'string',
default: editor.translate('%Y-%m-%d')
});
};
const getCreationDateClasses = option('template_cdate_classes');
const getModificationDateClasses = option('template_mdate_classes');
const getSelectedContentClasses = option('template_selected_content_classes');
const getPreviewReplaceValues = option('template_preview_replace_values');
const getTemplateReplaceValues = option('template_replace_values');
const getTemplates = option('templates');
const getCdateFormat = option('template_cdate_format');
const getMdateFormat = option('template_mdate_format');
const getContentStyle = option('content_style');
const shouldUseContentCssCors = option('content_css_cors');
const getBodyClass = option('body_class');
const addZeros = (value, len) => {
value = '' + value;
if (value.length < len) {
for (let i = 0; i < len - value.length; i++) {
value = '0' + value;
}
}
return value;
};
const getDateTime = (editor, fmt, date = new Date()) => {
const daysShort = 'Sun Mon Tue Wed Thu Fri Sat Sun'.split(' ');
const daysLong = 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday'.split(' ');
const monthsShort = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');
const monthsLong = 'January February March April May June July August September October November December'.split(' ');
fmt = fmt.replace('%D', '%m/%d/%Y');
fmt = fmt.replace('%r', '%I:%M:%S %p');
fmt = fmt.replace('%Y', '' + date.getFullYear());
fmt = fmt.replace('%y', '' + date.getYear());
fmt = fmt.replace('%m', addZeros(date.getMonth() + 1, 2));
fmt = fmt.replace('%d', addZeros(date.getDate(), 2));
fmt = fmt.replace('%H', '' + addZeros(date.getHours(), 2));
fmt = fmt.replace('%M', '' + addZeros(date.getMinutes(), 2));
fmt = fmt.replace('%S', '' + addZeros(date.getSeconds(), 2));
fmt = fmt.replace('%I', '' + ((date.getHours() + 11) % 12 + 1));
fmt = fmt.replace('%p', '' + (date.getHours() < 12 ? 'AM' : 'PM'));
fmt = fmt.replace('%B', '' + editor.translate(monthsLong[date.getMonth()]));
fmt = fmt.replace('%b', '' + editor.translate(monthsShort[date.getMonth()]));
fmt = fmt.replace('%A', '' + editor.translate(daysLong[date.getDay()]));
fmt = fmt.replace('%a', '' + editor.translate(daysShort[date.getDay()]));
fmt = fmt.replace('%%', '%');
return fmt;
};
class Optional {
constructor(tag, value) {
this.tag = tag;
this.value = value;
}
static some(value) {
return new Optional(true, value);
}
static none() {
return Optional.singletonNone;
}
fold(onNone, onSome) {
if (this.tag) {
return onSome(this.value);
} else {
return onNone();
}
}
isSome() {
return this.tag;
}
isNone() {
return !this.tag;
}
map(mapper) {
if (this.tag) {
return Optional.some(mapper(this.value));
} else {
return Optional.none();
}
}
bind(binder) {
if (this.tag) {
return binder(this.value);
} else {
return Optional.none();
}
}
exists(predicate) {
return this.tag && predicate(this.value);
}
forall(predicate) {
return !this.tag || predicate(this.value);
}
filter(predicate) {
if (!this.tag || predicate(this.value)) {
return this;
} else {
return Optional.none();
}
}
getOr(replacement) {
return this.tag ? this.value : replacement;
}
or(replacement) {
return this.tag ? this : replacement;
}
getOrThunk(thunk) {
return this.tag ? this.value : thunk();
}
orThunk(thunk) {
return this.tag ? this : thunk();
}
getOrDie(message) {
if (!this.tag) {
throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
} else {
return this.value;
}
}
static from(value) {
return isNonNullable(value) ? Optional.some(value) : Optional.none();
}
getOrNull() {
return this.tag ? this.value : null;
}
getOrUndefined() {
return this.value;
}
each(worker) {
if (this.tag) {
worker(this.value);
}
}
toArray() {
return this.tag ? [this.value] : [];
}
toString() {
return this.tag ? `some(${ this.value })` : 'none()';
}
}
Optional.singletonNone = new Optional(false);
const exists = (xs, pred) => {
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (pred(x, i)) {
return true;
}
}
return false;
};
const map = (xs, f) => {
const len = xs.length;
const r = new Array(len);
for (let i = 0; i < len; i++) {
const x = xs[i];
r[i] = f(x, i);
}
return r;
};
const findUntil = (xs, pred, until) => {
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (pred(x, i)) {
return Optional.some(x);
} else if (until(x, i)) {
break;
}
}
return Optional.none();
};
const find = (xs, pred) => {
return findUntil(xs, pred, never);
};
const hasOwnProperty = Object.hasOwnProperty;
const get = (obj, key) => {
return has(obj, key) ? Optional.from(obj[key]) : Optional.none();
};
const has = (obj, key) => hasOwnProperty.call(obj, key);
const entitiesAttr = {
'"': '&quot;',
'<': '&lt;',
'>': '&gt;',
'&': '&amp;',
'\'': '&#039;'
};
const htmlEscape = html => html.replace(/["'<>&]/g, match => get(entitiesAttr, match).getOr(match));
const hasAnyClasses = (dom, n, classes) => exists(classes.split(/\s+/), c => dom.hasClass(n, c));
const createTemplateList = (editor, callback) => {
return () => {
const templateList = getTemplates(editor);
if (isFunction(templateList)) {
templateList(callback);
} else if (isString(templateList)) {
fetch(templateList).then(res => {
if (res.ok) {
res.json().then(callback);
}
});
} else {
callback(templateList);
}
};
};
const replaceTemplateValues = (html, templateValues) => {
global$1.each(templateValues, (v, k) => {
if (isFunction(v)) {
v = v(k);
}
html = html.replace(new RegExp('\\{\\$' + escape(k) + '\\}', 'g'), v);
});
return html;
};
const replaceVals = (editor, scope) => {
const dom = editor.dom, vl = getTemplateReplaceValues(editor);
global$1.each(dom.select('*', scope), e => {
global$1.each(vl, (v, k) => {
if (dom.hasClass(e, k)) {
if (isFunction(v)) {
v(e);
}
}
});
});
};
const insertTemplate = (editor, _ui, html) => {
const dom = editor.dom;
const sel = editor.selection.getContent();
html = replaceTemplateValues(html, getTemplateReplaceValues(editor));
let el = dom.create('div', {}, html);
const n = dom.select('.mceTmpl', el);
if (n && n.length > 0) {
el = dom.create('div');
el.appendChild(n[0].cloneNode(true));
}
global$1.each(dom.select('*', el), n => {
if (hasAnyClasses(dom, n, getCreationDateClasses(editor))) {
n.innerHTML = getDateTime(editor, getCdateFormat(editor));
}
if (hasAnyClasses(dom, n, getModificationDateClasses(editor))) {
n.innerHTML = getDateTime(editor, getMdateFormat(editor));
}
if (hasAnyClasses(dom, n, getSelectedContentClasses(editor))) {
n.innerHTML = sel;
}
});
replaceVals(editor, el);
editor.execCommand('mceInsertContent', false, el.innerHTML);
editor.addVisual();
};
var global = tinymce.util.Tools.resolve('tinymce.Env');
const getPreviewContent = (editor, html) => {
var _a;
if (html.indexOf('<html>') === -1) {
let contentCssEntries = '';
const contentStyle = (_a = getContentStyle(editor)) !== null && _a !== void 0 ? _a : '';
const cors = shouldUseContentCssCors(editor) ? ' crossorigin="anonymous"' : '';
global$1.each(editor.contentCSS, url => {
contentCssEntries += '<link type="text/css" rel="stylesheet" href="' + editor.documentBaseURI.toAbsolute(url) + '"' + cors + '>';
});
if (contentStyle) {
contentCssEntries += '<style type="text/css">' + contentStyle + '</style>';
}
const bodyClass = getBodyClass(editor);
const encode = editor.dom.encode;
const isMetaKeyPressed = global.os.isMacOS() || global.os.isiOS() ? 'e.metaKey' : 'e.ctrlKey && !e.altKey';
const preventClicksOnLinksScript = '<script>' + 'document.addEventListener && document.addEventListener("click", function(e) {' + 'for (var elm = e.target; elm; elm = elm.parentNode) {' + 'if (elm.nodeName === "A" && !(' + isMetaKeyPressed + ')) {' + 'e.preventDefault();' + '}' + '}' + '}, false);' + '</script> ';
const directionality = editor.getBody().dir;
const dirAttr = directionality ? ' dir="' + encode(directionality) + '"' : '';
html = '<!DOCTYPE html>' + '<html>' + '<head>' + '<base href="' + encode(editor.documentBaseURI.getURI()) + '">' + contentCssEntries + preventClicksOnLinksScript + '</head>' + '<body class="' + encode(bodyClass) + '"' + dirAttr + '>' + html + '</body>' + '</html>';
}
return replaceTemplateValues(html, getPreviewReplaceValues(editor));
};
const open = (editor, templateList) => {
const createTemplates = () => {
if (!templateList || templateList.length === 0) {
const message = editor.translate('No templates defined.');
editor.notificationManager.open({
text: message,
type: 'info'
});
return Optional.none();
}
return Optional.from(global$1.map(templateList, (template, index) => {
const isUrlTemplate = t => t.url !== undefined;
return {
selected: index === 0,
text: template.title,
value: {
url: isUrlTemplate(template) ? Optional.from(template.url) : Optional.none(),
content: !isUrlTemplate(template) ? Optional.from(template.content) : Optional.none(),
description: template.description
}
};
}));
};
const createSelectBoxItems = templates => map(templates, t => ({
text: t.text,
value: t.text
}));
const findTemplate = (templates, templateTitle) => find(templates, t => t.text === templateTitle);
const loadFailedAlert = api => {
editor.windowManager.alert('Could not load the specified template.', () => api.focus('template'));
};
const getTemplateContent = t => t.value.url.fold(() => Promise.resolve(t.value.content.getOr('')), url => fetch(url).then(res => res.ok ? res.text() : Promise.reject()));
const onChange = (templates, updateDialog) => (api, change) => {
if (change.name === 'template') {
const newTemplateTitle = api.getData().template;
findTemplate(templates, newTemplateTitle).each(t => {
api.block('Loading...');
getTemplateContent(t).then(previewHtml => {
updateDialog(api, t, previewHtml);
}).catch(() => {
updateDialog(api, t, '');
api.setEnabled('save', false);
loadFailedAlert(api);
});
});
}
};
const onSubmit = templates => api => {
const data = api.getData();
findTemplate(templates, data.template).each(t => {
getTemplateContent(t).then(previewHtml => {
editor.execCommand('mceInsertTemplate', false, previewHtml);
api.close();
}).catch(() => {
api.setEnabled('save', false);
loadFailedAlert(api);
});
});
};
const openDialog = templates => {
const selectBoxItems = createSelectBoxItems(templates);
const buildDialogSpec = (bodyItems, initialData) => ({
title: 'Insert Template',
size: 'large',
body: {
type: 'panel',
items: bodyItems
},
initialData,
buttons: [
{
type: 'cancel',
name: 'cancel',
text: 'Cancel'
},
{
type: 'submit',
name: 'save',
text: 'Save',
primary: true
}
],
onSubmit: onSubmit(templates),
onChange: onChange(templates, updateDialog)
});
const updateDialog = (dialogApi, template, previewHtml) => {
const content = getPreviewContent(editor, previewHtml);
const bodyItems = [
{
type: 'selectbox',
name: 'template',
label: 'Templates',
items: selectBoxItems
},
{
type: 'htmlpanel',
html: `<p aria-live="polite">${ htmlEscape(template.value.description) }</p>`
},
{
label: 'Preview',
type: 'iframe',
name: 'preview',
sandboxed: false,
transparent: false
}
];
const initialData = {
template: template.text,
preview: content
};
dialogApi.unblock();
dialogApi.redial(buildDialogSpec(bodyItems, initialData));
dialogApi.focus('template');
};
const dialogApi = editor.windowManager.open(buildDialogSpec([], {
template: '',
preview: ''
}));
dialogApi.block('Loading...');
getTemplateContent(templates[0]).then(previewHtml => {
updateDialog(dialogApi, templates[0], previewHtml);
}).catch(() => {
updateDialog(dialogApi, templates[0], '');
dialogApi.setEnabled('save', false);
loadFailedAlert(dialogApi);
});
};
const optTemplates = createTemplates();
optTemplates.each(openDialog);
};
const showDialog = editor => templates => {
open(editor, templates);
};
const register$1 = editor => {
editor.addCommand('mceInsertTemplate', curry(insertTemplate, editor));
editor.addCommand('mceTemplate', createTemplateList(editor, showDialog(editor)));
};
const setup = editor => {
editor.on('PreProcess', o => {
const dom = editor.dom, dateFormat = getMdateFormat(editor);
global$1.each(dom.select('div', o.node), e => {
if (dom.hasClass(e, 'mceTmpl')) {
global$1.each(dom.select('*', e), e => {
if (hasAnyClasses(dom, e, getModificationDateClasses(editor))) {
e.innerHTML = getDateTime(editor, dateFormat);
}
});
replaceVals(editor, e);
}
});
});
};
const register = editor => {
const onAction = () => editor.execCommand('mceTemplate');
editor.ui.registry.addButton('template', {
icon: 'template',
tooltip: 'Insert template',
onAction
});
editor.ui.registry.addMenuItem('template', {
icon: 'template',
text: 'Insert template...',
onAction
});
};
var Plugin = () => {
global$2.add('template', editor => {
register$2(editor);
register(editor);
register$1(editor);
setup(editor);
});
};
Plugin();
})();
File diff suppressed because one or more lines are too long
@@ -0,0 +1,98 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
const Cell = initial => {
let value = initial;
const get = () => {
return value;
};
const set = v => {
value = v;
};
return {
get,
set
};
};
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
const fireVisualBlocks = (editor, state) => {
editor.dispatch('VisualBlocks', { state });
};
const toggleVisualBlocks = (editor, pluginUrl, enabledState) => {
const dom = editor.dom;
dom.toggleClass(editor.getBody(), 'mce-visualblocks');
enabledState.set(!enabledState.get());
fireVisualBlocks(editor, enabledState.get());
};
const register$2 = (editor, pluginUrl, enabledState) => {
editor.addCommand('mceVisualBlocks', () => {
toggleVisualBlocks(editor, pluginUrl, enabledState);
});
};
const option = name => editor => editor.options.get(name);
const register$1 = editor => {
const registerOption = editor.options.register;
registerOption('visualblocks_default_state', {
processor: 'boolean',
default: false
});
};
const isEnabledByDefault = option('visualblocks_default_state');
const setup = (editor, pluginUrl, enabledState) => {
editor.on('PreviewFormats AfterPreviewFormats', e => {
if (enabledState.get()) {
editor.dom.toggleClass(editor.getBody(), 'mce-visualblocks', e.type === 'afterpreviewformats');
}
});
editor.on('init', () => {
if (isEnabledByDefault(editor)) {
toggleVisualBlocks(editor, pluginUrl, enabledState);
}
});
};
const toggleActiveState = (editor, enabledState) => api => {
api.setActive(enabledState.get());
const editorEventCallback = e => api.setActive(e.state);
editor.on('VisualBlocks', editorEventCallback);
return () => editor.off('VisualBlocks', editorEventCallback);
};
const register = (editor, enabledState) => {
const onAction = () => editor.execCommand('mceVisualBlocks');
editor.ui.registry.addToggleButton('visualblocks', {
icon: 'visualblocks',
tooltip: 'Show blocks',
onAction,
onSetup: toggleActiveState(editor, enabledState)
});
editor.ui.registry.addToggleMenuItem('visualblocks', {
text: 'Show blocks',
icon: 'visualblocks',
onAction,
onSetup: toggleActiveState(editor, enabledState)
});
};
var Plugin = () => {
global.add('visualblocks', (editor, pluginUrl) => {
register$1(editor);
const enabledState = Cell(false);
register$2(editor, pluginUrl, enabledState);
register(editor, enabledState);
setup(editor, pluginUrl, enabledState);
});
};
Plugin();
})();
@@ -0,0 +1,4 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const s=(t,s,o)=>{t.dom.toggleClass(t.getBody(),"mce-visualblocks"),o.set(!o.get()),((t,s)=>{t.dispatch("VisualBlocks",{state:s})})(t,o.get())},o=("visualblocks_default_state",t=>t.options.get("visualblocks_default_state"));const e=(t,s)=>o=>{o.setActive(s.get());const e=t=>o.setActive(t.state);return t.on("VisualBlocks",e),()=>t.off("VisualBlocks",e)};t.add("visualblocks",((t,l)=>{(t=>{(0,t.options.register)("visualblocks_default_state",{processor:"boolean",default:!1})})(t);const a=(t=>{let s=!1;return{get:()=>s,set:t=>{s=t}}})();((t,o,e)=>{t.addCommand("mceVisualBlocks",(()=>{s(t,0,e)}))})(t,0,a),((t,s)=>{const o=()=>t.execCommand("mceVisualBlocks");t.ui.registry.addToggleButton("visualblocks",{icon:"visualblocks",tooltip:"Show blocks",onAction:o,onSetup:e(t,s)}),t.ui.registry.addToggleMenuItem("visualblocks",{text:"Show blocks",icon:"visualblocks",onAction:o,onSetup:e(t,s)})})(t,a),((t,e,l)=>{t.on("PreviewFormats AfterPreviewFormats",(s=>{l.get()&&t.dom.toggleClass(t.getBody(),"mce-visualblocks","afterpreviewformats"===s.type)})),t.on("init",(()=>{o(t)&&s(t,0,l)}))})(t,0,a)}))}();
@@ -0,0 +1,509 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
const Cell = initial => {
let value = initial;
const get = () => {
return value;
};
const set = v => {
value = v;
};
return {
get,
set
};
};
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
const get$2 = toggleState => {
const isEnabled = () => {
return toggleState.get();
};
return { isEnabled };
};
const fireVisualChars = (editor, state) => {
return editor.dispatch('VisualChars', { state });
};
const hasProto = (v, constructor, predicate) => {
var _a;
if (predicate(v, constructor.prototype)) {
return true;
} else {
return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
}
};
const typeOf = x => {
const t = typeof x;
if (x === null) {
return 'null';
} else if (t === 'object' && Array.isArray(x)) {
return 'array';
} else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
return 'string';
} else {
return t;
}
};
const isType$1 = type => value => typeOf(value) === type;
const isSimpleType = type => value => typeof value === type;
const eq = t => a => t === a;
const isString = isType$1('string');
const isNull = eq(null);
const isBoolean = isSimpleType('boolean');
const isNullable = a => a === null || a === undefined;
const isNonNullable = a => !isNullable(a);
const isNumber = isSimpleType('number');
class Optional {
constructor(tag, value) {
this.tag = tag;
this.value = value;
}
static some(value) {
return new Optional(true, value);
}
static none() {
return Optional.singletonNone;
}
fold(onNone, onSome) {
if (this.tag) {
return onSome(this.value);
} else {
return onNone();
}
}
isSome() {
return this.tag;
}
isNone() {
return !this.tag;
}
map(mapper) {
if (this.tag) {
return Optional.some(mapper(this.value));
} else {
return Optional.none();
}
}
bind(binder) {
if (this.tag) {
return binder(this.value);
} else {
return Optional.none();
}
}
exists(predicate) {
return this.tag && predicate(this.value);
}
forall(predicate) {
return !this.tag || predicate(this.value);
}
filter(predicate) {
if (!this.tag || predicate(this.value)) {
return this;
} else {
return Optional.none();
}
}
getOr(replacement) {
return this.tag ? this.value : replacement;
}
or(replacement) {
return this.tag ? this : replacement;
}
getOrThunk(thunk) {
return this.tag ? this.value : thunk();
}
orThunk(thunk) {
return this.tag ? this : thunk();
}
getOrDie(message) {
if (!this.tag) {
throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
} else {
return this.value;
}
}
static from(value) {
return isNonNullable(value) ? Optional.some(value) : Optional.none();
}
getOrNull() {
return this.tag ? this.value : null;
}
getOrUndefined() {
return this.value;
}
each(worker) {
if (this.tag) {
worker(this.value);
}
}
toArray() {
return this.tag ? [this.value] : [];
}
toString() {
return this.tag ? `some(${ this.value })` : 'none()';
}
}
Optional.singletonNone = new Optional(false);
const map = (xs, f) => {
const len = xs.length;
const r = new Array(len);
for (let i = 0; i < len; i++) {
const x = xs[i];
r[i] = f(x, i);
}
return r;
};
const each$1 = (xs, f) => {
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
f(x, i);
}
};
const filter = (xs, pred) => {
const r = [];
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (pred(x, i)) {
r.push(x);
}
}
return r;
};
const keys = Object.keys;
const each = (obj, f) => {
const props = keys(obj);
for (let k = 0, len = props.length; k < len; k++) {
const i = props[k];
const x = obj[i];
f(x, i);
}
};
typeof window !== 'undefined' ? window : Function('return this;')();
const TEXT = 3;
const type = element => element.dom.nodeType;
const value = element => element.dom.nodeValue;
const isType = t => element => type(element) === t;
const isText = isType(TEXT);
const rawSet = (dom, key, value) => {
if (isString(value) || isBoolean(value) || isNumber(value)) {
dom.setAttribute(key, value + '');
} else {
console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
throw new Error('Attribute value was not simple');
}
};
const set = (element, key, value) => {
rawSet(element.dom, key, value);
};
const get$1 = (element, key) => {
const v = element.dom.getAttribute(key);
return v === null ? undefined : v;
};
const remove$3 = (element, key) => {
element.dom.removeAttribute(key);
};
const read = (element, attr) => {
const value = get$1(element, attr);
return value === undefined || value === '' ? [] : value.split(' ');
};
const add$2 = (element, attr, id) => {
const old = read(element, attr);
const nu = old.concat([id]);
set(element, attr, nu.join(' '));
return true;
};
const remove$2 = (element, attr, id) => {
const nu = filter(read(element, attr), v => v !== id);
if (nu.length > 0) {
set(element, attr, nu.join(' '));
} else {
remove$3(element, attr);
}
return false;
};
const supports = element => element.dom.classList !== undefined;
const get = element => read(element, 'class');
const add$1 = (element, clazz) => add$2(element, 'class', clazz);
const remove$1 = (element, clazz) => remove$2(element, 'class', clazz);
const add = (element, clazz) => {
if (supports(element)) {
element.dom.classList.add(clazz);
} else {
add$1(element, clazz);
}
};
const cleanClass = element => {
const classList = supports(element) ? element.dom.classList : get(element);
if (classList.length === 0) {
remove$3(element, 'class');
}
};
const remove = (element, clazz) => {
if (supports(element)) {
const classList = element.dom.classList;
classList.remove(clazz);
} else {
remove$1(element, clazz);
}
cleanClass(element);
};
const fromHtml = (html, scope) => {
const doc = scope || document;
const div = doc.createElement('div');
div.innerHTML = html;
if (!div.hasChildNodes() || div.childNodes.length > 1) {
const message = 'HTML does not have a single root node';
console.error(message, html);
throw new Error(message);
}
return fromDom(div.childNodes[0]);
};
const fromTag = (tag, scope) => {
const doc = scope || document;
const node = doc.createElement(tag);
return fromDom(node);
};
const fromText = (text, scope) => {
const doc = scope || document;
const node = doc.createTextNode(text);
return fromDom(node);
};
const fromDom = node => {
if (node === null || node === undefined) {
throw new Error('Node cannot be null or undefined');
}
return { dom: node };
};
const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
const SugarElement = {
fromHtml,
fromTag,
fromText,
fromDom,
fromPoint
};
const charMap = {
'\xA0': 'nbsp',
'\xAD': 'shy'
};
const charMapToRegExp = (charMap, global) => {
let regExp = '';
each(charMap, (_value, key) => {
regExp += key;
});
return new RegExp('[' + regExp + ']', global ? 'g' : '');
};
const charMapToSelector = charMap => {
let selector = '';
each(charMap, value => {
if (selector) {
selector += ',';
}
selector += 'span.mce-' + value;
});
return selector;
};
const regExp = charMapToRegExp(charMap);
const regExpGlobal = charMapToRegExp(charMap, true);
const selector = charMapToSelector(charMap);
const nbspClass = 'mce-nbsp';
const wrapCharWithSpan = value => '<span data-mce-bogus="1" class="mce-' + charMap[value] + '">' + value + '</span>';
const isMatch = n => {
const value$1 = value(n);
return isText(n) && isString(value$1) && regExp.test(value$1);
};
const filterDescendants = (scope, predicate) => {
let result = [];
const dom = scope.dom;
const children = map(dom.childNodes, SugarElement.fromDom);
each$1(children, x => {
if (predicate(x)) {
result = result.concat([x]);
}
result = result.concat(filterDescendants(x, predicate));
});
return result;
};
const findParentElm = (elm, rootElm) => {
while (elm.parentNode) {
if (elm.parentNode === rootElm) {
return rootElm;
}
elm = elm.parentNode;
}
return undefined;
};
const replaceWithSpans = text => text.replace(regExpGlobal, wrapCharWithSpan);
const isWrappedNbsp = node => node.nodeName.toLowerCase() === 'span' && node.classList.contains('mce-nbsp-wrap');
const show = (editor, rootElm) => {
const dom = editor.dom;
const nodeList = filterDescendants(SugarElement.fromDom(rootElm), isMatch);
each$1(nodeList, n => {
var _a;
const parent = n.dom.parentNode;
if (isWrappedNbsp(parent)) {
add(SugarElement.fromDom(parent), nbspClass);
} else {
const withSpans = replaceWithSpans(dom.encode((_a = value(n)) !== null && _a !== void 0 ? _a : ''));
const div = dom.create('div', {}, withSpans);
let node;
while (node = div.lastChild) {
dom.insertAfter(node, n.dom);
}
editor.dom.remove(n.dom);
}
});
};
const hide = (editor, rootElm) => {
const nodeList = editor.dom.select(selector, rootElm);
each$1(nodeList, node => {
if (isWrappedNbsp(node)) {
remove(SugarElement.fromDom(node), nbspClass);
} else {
editor.dom.remove(node, true);
}
});
};
const toggle = editor => {
const body = editor.getBody();
const bookmark = editor.selection.getBookmark();
let parentNode = findParentElm(editor.selection.getNode(), body);
parentNode = parentNode !== undefined ? parentNode : body;
hide(editor, parentNode);
show(editor, parentNode);
editor.selection.moveToBookmark(bookmark);
};
const applyVisualChars = (editor, toggleState) => {
fireVisualChars(editor, toggleState.get());
const body = editor.getBody();
if (toggleState.get() === true) {
show(editor, body);
} else {
hide(editor, body);
}
};
const toggleVisualChars = (editor, toggleState) => {
toggleState.set(!toggleState.get());
const bookmark = editor.selection.getBookmark();
applyVisualChars(editor, toggleState);
editor.selection.moveToBookmark(bookmark);
};
const register$2 = (editor, toggleState) => {
editor.addCommand('mceVisualChars', () => {
toggleVisualChars(editor, toggleState);
});
};
const option = name => editor => editor.options.get(name);
const register$1 = editor => {
const registerOption = editor.options.register;
registerOption('visualchars_default_state', {
processor: 'boolean',
default: false
});
};
const isEnabledByDefault = option('visualchars_default_state');
const setup$1 = (editor, toggleState) => {
editor.on('init', () => {
applyVisualChars(editor, toggleState);
});
};
const first = (fn, rate) => {
let timer = null;
const cancel = () => {
if (!isNull(timer)) {
clearTimeout(timer);
timer = null;
}
};
const throttle = (...args) => {
if (isNull(timer)) {
timer = setTimeout(() => {
timer = null;
fn.apply(null, args);
}, rate);
}
};
return {
cancel,
throttle
};
};
const setup = (editor, toggleState) => {
const debouncedToggle = first(() => {
toggle(editor);
}, 300);
editor.on('keydown', e => {
if (toggleState.get() === true) {
e.keyCode === 13 ? toggle(editor) : debouncedToggle.throttle();
}
});
editor.on('remove', debouncedToggle.cancel);
};
const toggleActiveState = (editor, enabledStated) => api => {
api.setActive(enabledStated.get());
const editorEventCallback = e => api.setActive(e.state);
editor.on('VisualChars', editorEventCallback);
return () => editor.off('VisualChars', editorEventCallback);
};
const register = (editor, toggleState) => {
const onAction = () => editor.execCommand('mceVisualChars');
editor.ui.registry.addToggleButton('visualchars', {
tooltip: 'Show invisible characters',
icon: 'visualchars',
onAction,
onSetup: toggleActiveState(editor, toggleState)
});
editor.ui.registry.addToggleMenuItem('visualchars', {
text: 'Show invisible characters',
icon: 'visualchars',
onAction,
onSetup: toggleActiveState(editor, toggleState)
});
};
var Plugin = () => {
global.add('visualchars', editor => {
register$1(editor);
const toggleState = Cell(isEnabledByDefault(editor));
register$2(editor, toggleState);
register(editor, toggleState);
setup(editor, toggleState);
setup$1(editor, toggleState);
return get$2(toggleState);
});
};
Plugin();
})();
File diff suppressed because one or more lines are too long
@@ -0,0 +1,405 @@
/**
* TinyMCE version 6.3.1 (2022-12-06)
*/
(function () {
'use strict';
var global$2 = tinymce.util.Tools.resolve('tinymce.PluginManager');
const eq = t => a => t === a;
const isNull = eq(null);
const identity = x => {
return x;
};
const zeroWidth = '\uFEFF';
const removeZwsp$1 = s => s.replace(/\uFEFF/g, '');
const map = (xs, f) => {
const len = xs.length;
const r = new Array(len);
for (let i = 0; i < len; i++) {
const x = xs[i];
r[i] = f(x, i);
}
return r;
};
const punctuationStr = '[!-#%-*,-\\/:;?@\\[-\\]_{}\xA1\xAB\xB7\xBB\xBF;\xB7\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1361-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u3008\u3009\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30\u2E31\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uff3f\uFF5B\uFF5D\uFF5F-\uFF65]';
const regExps = {
aletter: '[A-Za-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05F3\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u10a0-\u10c5\u10d0-\u10fa\u10fc\u1100-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1a00-\u1a16\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bc0-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u24B6-\u24E9\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2d00-\u2d25\u2d30-\u2d65\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005\u303b\u303c\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790\ua791\ua7a0-\ua7a9\ua7fa-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uffa0-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]',
midnumlet: `[-'\\.\u2018\u2019\u2024\uFE52\uFF07\uFF0E]`,
midletter: '[:\xB7\xB7\u05F4\u2027\uFE13\uFE55\uFF1A]',
midnum: '[\xB1+*/,;;\u0589\u060C\u060D\u066C\u07F8\u2044\uFE10\uFE14\uFE50\uFE54\uFF0C\uFF1B]',
numeric: '[0-9\u0660-\u0669\u066B\u06f0-\u06f9\u07c0-\u07c9\u0966-\u096f\u09e6-\u09ef\u0a66-\u0a6f\u0ae6-\u0aef\u0b66-\u0b6f\u0be6-\u0bef\u0c66-\u0c6f\u0ce6-\u0cef\u0d66-\u0d6f\u0e50-\u0e59\u0ed0-\u0ed9\u0f20-\u0f29\u1040-\u1049\u1090-\u1099\u17e0-\u17e9\u1810-\u1819\u1946-\u194f\u19d0-\u19d9\u1a80-\u1a89\u1a90-\u1a99\u1b50-\u1b59\u1bb0-\u1bb9\u1c40-\u1c49\u1c50-\u1c59\ua620-\ua629\ua8d0-\ua8d9\ua900-\ua909\ua9d0-\ua9d9\uaa50-\uaa59\uabf0-\uabf9]',
cr: '\\r',
lf: '\\n',
newline: '[\x0B\f\x85\u2028\u2029]',
extend: '[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065f\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0c01-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d02\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f\u109a-\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b6-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u192b\u1930-\u193b\u19b0-\u19c0\u19c8\u19c9\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f\u1b00-\u1b04\u1b34-\u1b44\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1baa\u1be6-\u1bf3\u1c24-\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2\u1dc0-\u1de6\u1dfc-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\uA672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa7b\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe3-\uabea\uabec\uabed\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]',
format: '[\xAD\u0600-\u0603\u06DD\u070F\u17b4\u17b5\u200E\u200F\u202A-\u202E\u2060-\u2064\u206A-\u206F\uFEFF\uFFF9-\uFFFB]',
katakana: '[\u3031-\u3035\u309B\u309C\u30A0-\u30fa\u30fc-\u30ff\u31f0-\u31ff\u32D0-\u32FE\u3300-\u3357\uff66-\uff9d]',
extendnumlet: '[=_\u203f\u2040\u2054\ufe33\ufe34\ufe4d-\ufe4f\uff3f\u2200-\u22FF<>]',
punctuation: punctuationStr
};
const characterIndices = {
ALETTER: 0,
MIDNUMLET: 1,
MIDLETTER: 2,
MIDNUM: 3,
NUMERIC: 4,
CR: 5,
LF: 6,
NEWLINE: 7,
EXTEND: 8,
FORMAT: 9,
KATAKANA: 10,
EXTENDNUMLET: 11,
AT: 12,
OTHER: 13
};
const SETS$1 = [
new RegExp(regExps.aletter),
new RegExp(regExps.midnumlet),
new RegExp(regExps.midletter),
new RegExp(regExps.midnum),
new RegExp(regExps.numeric),
new RegExp(regExps.cr),
new RegExp(regExps.lf),
new RegExp(regExps.newline),
new RegExp(regExps.extend),
new RegExp(regExps.format),
new RegExp(regExps.katakana),
new RegExp(regExps.extendnumlet),
new RegExp('@')
];
const EMPTY_STRING$1 = '';
const PUNCTUATION$1 = new RegExp('^' + regExps.punctuation + '$');
const WHITESPACE$1 = /^\s+$/;
const SETS = SETS$1;
const OTHER = characterIndices.OTHER;
const getType = char => {
let type = OTHER;
const setsLength = SETS.length;
for (let j = 0; j < setsLength; ++j) {
const set = SETS[j];
if (set && set.test(char)) {
type = j;
break;
}
}
return type;
};
const memoize = func => {
const cache = {};
return char => {
if (cache[char]) {
return cache[char];
} else {
const result = func(char);
cache[char] = result;
return result;
}
};
};
const classify = characters => {
const memoized = memoize(getType);
return map(characters, memoized);
};
const isWordBoundary = (map, index) => {
const type = map[index];
const nextType = map[index + 1];
if (index < 0 || index > map.length - 1 && index !== 0) {
return false;
}
if (type === characterIndices.ALETTER && nextType === characterIndices.ALETTER) {
return false;
}
const nextNextType = map[index + 2];
if (type === characterIndices.ALETTER && (nextType === characterIndices.MIDLETTER || nextType === characterIndices.MIDNUMLET || nextType === characterIndices.AT) && nextNextType === characterIndices.ALETTER) {
return false;
}
const prevType = map[index - 1];
if ((type === characterIndices.MIDLETTER || type === characterIndices.MIDNUMLET || nextType === characterIndices.AT) && nextType === characterIndices.ALETTER && prevType === characterIndices.ALETTER) {
return false;
}
if ((type === characterIndices.NUMERIC || type === characterIndices.ALETTER) && (nextType === characterIndices.NUMERIC || nextType === characterIndices.ALETTER)) {
return false;
}
if ((type === characterIndices.MIDNUM || type === characterIndices.MIDNUMLET) && nextType === characterIndices.NUMERIC && prevType === characterIndices.NUMERIC) {
return false;
}
if (type === characterIndices.NUMERIC && (nextType === characterIndices.MIDNUM || nextType === characterIndices.MIDNUMLET) && nextNextType === characterIndices.NUMERIC) {
return false;
}
if (type === characterIndices.EXTEND || type === characterIndices.FORMAT || prevType === characterIndices.EXTEND || prevType === characterIndices.FORMAT || nextType === characterIndices.EXTEND || nextType === characterIndices.FORMAT) {
return false;
}
if (type === characterIndices.CR && nextType === characterIndices.LF) {
return false;
}
if (type === characterIndices.NEWLINE || type === characterIndices.CR || type === characterIndices.LF) {
return true;
}
if (nextType === characterIndices.NEWLINE || nextType === characterIndices.CR || nextType === characterIndices.LF) {
return true;
}
if (type === characterIndices.KATAKANA && nextType === characterIndices.KATAKANA) {
return false;
}
if (nextType === characterIndices.EXTENDNUMLET && (type === characterIndices.ALETTER || type === characterIndices.NUMERIC || type === characterIndices.KATAKANA || type === characterIndices.EXTENDNUMLET)) {
return false;
}
if (type === characterIndices.EXTENDNUMLET && (nextType === characterIndices.ALETTER || nextType === characterIndices.NUMERIC || nextType === characterIndices.KATAKANA)) {
return false;
}
if (type === characterIndices.AT) {
return false;
}
return true;
};
const EMPTY_STRING = EMPTY_STRING$1;
const WHITESPACE = WHITESPACE$1;
const PUNCTUATION = PUNCTUATION$1;
const isProtocol = str => str === 'http' || str === 'https';
const findWordEnd = (characters, startIndex) => {
let i;
for (i = startIndex; i < characters.length; i++) {
if (WHITESPACE.test(characters[i])) {
break;
}
}
return i;
};
const findUrlEnd = (characters, startIndex) => {
const endIndex = findWordEnd(characters, startIndex + 1);
const peakedWord = characters.slice(startIndex + 1, endIndex).join(EMPTY_STRING);
return peakedWord.substr(0, 3) === '://' ? endIndex : startIndex;
};
const findWords = (chars, sChars, characterMap, options) => {
const words = [];
let word = [];
for (let i = 0; i < characterMap.length; ++i) {
word.push(chars[i]);
if (isWordBoundary(characterMap, i)) {
const ch = sChars[i];
if ((options.includeWhitespace || !WHITESPACE.test(ch)) && (options.includePunctuation || !PUNCTUATION.test(ch))) {
const startOfWord = i - word.length + 1;
const endOfWord = i + 1;
const str = sChars.slice(startOfWord, endOfWord).join(EMPTY_STRING);
if (isProtocol(str)) {
const endOfUrl = findUrlEnd(sChars, i);
const url = chars.slice(endOfWord, endOfUrl);
Array.prototype.push.apply(word, url);
i = endOfUrl;
}
words.push(word);
}
word = [];
}
}
return words;
};
const getDefaultOptions = () => ({
includeWhitespace: false,
includePunctuation: false
});
const getWords$1 = (chars, extract, options) => {
options = {
...getDefaultOptions(),
...options
};
const filteredChars = [];
const extractedChars = [];
for (let i = 0; i < chars.length; i++) {
const ch = extract(chars[i]);
if (ch !== zeroWidth) {
filteredChars.push(chars[i]);
extractedChars.push(ch);
}
}
const characterMap = classify(extractedChars);
return findWords(filteredChars, extractedChars, characterMap, options);
};
const getWords = getWords$1;
var global$1 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
const getText = (node, schema) => {
const blockElements = schema.getBlockElements();
const voidElements = schema.getVoidElements();
const isNewline = node => blockElements[node.nodeName] || voidElements[node.nodeName];
const textBlocks = [];
let txt = '';
const treeWalker = new global$1(node, node);
let tempNode;
while (tempNode = treeWalker.next()) {
if (tempNode.nodeType === 3) {
txt += removeZwsp$1(tempNode.data);
} else if (isNewline(tempNode) && txt.length) {
textBlocks.push(txt);
txt = '';
}
}
if (txt.length) {
textBlocks.push(txt);
}
return textBlocks;
};
const removeZwsp = text => text.replace(/\u200B/g, '');
const strLen = str => str.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '_').length;
const countWords = (node, schema) => {
const text = removeZwsp(getText(node, schema).join('\n'));
return getWords(text.split(''), identity).length;
};
const countCharacters = (node, schema) => {
const text = getText(node, schema).join('');
return strLen(text);
};
const countCharactersWithoutSpaces = (node, schema) => {
const text = getText(node, schema).join('').replace(/\s/g, '');
return strLen(text);
};
const createBodyCounter = (editor, count) => () => count(editor.getBody(), editor.schema);
const createSelectionCounter = (editor, count) => () => count(editor.selection.getRng().cloneContents(), editor.schema);
const createBodyWordCounter = editor => createBodyCounter(editor, countWords);
const get = editor => ({
body: {
getWordCount: createBodyWordCounter(editor),
getCharacterCount: createBodyCounter(editor, countCharacters),
getCharacterCountWithoutSpaces: createBodyCounter(editor, countCharactersWithoutSpaces)
},
selection: {
getWordCount: createSelectionCounter(editor, countWords),
getCharacterCount: createSelectionCounter(editor, countCharacters),
getCharacterCountWithoutSpaces: createSelectionCounter(editor, countCharactersWithoutSpaces)
},
getCount: createBodyWordCounter(editor)
});
const open = (editor, api) => {
editor.windowManager.open({
title: 'Word Count',
body: {
type: 'panel',
items: [{
type: 'table',
header: [
'Count',
'Document',
'Selection'
],
cells: [
[
'Words',
String(api.body.getWordCount()),
String(api.selection.getWordCount())
],
[
'Characters (no spaces)',
String(api.body.getCharacterCountWithoutSpaces()),
String(api.selection.getCharacterCountWithoutSpaces())
],
[
'Characters',
String(api.body.getCharacterCount()),
String(api.selection.getCharacterCount())
]
]
}]
},
buttons: [{
type: 'cancel',
name: 'close',
text: 'Close',
primary: true
}]
});
};
const register$1 = (editor, api) => {
editor.addCommand('mceWordCount', () => open(editor, api));
};
const first = (fn, rate) => {
let timer = null;
const cancel = () => {
if (!isNull(timer)) {
clearTimeout(timer);
timer = null;
}
};
const throttle = (...args) => {
if (isNull(timer)) {
timer = setTimeout(() => {
timer = null;
fn.apply(null, args);
}, rate);
}
};
return {
cancel,
throttle
};
};
var global = tinymce.util.Tools.resolve('tinymce.util.Delay');
const fireWordCountUpdate = (editor, api) => {
editor.dispatch('wordCountUpdate', {
wordCount: {
words: api.body.getWordCount(),
characters: api.body.getCharacterCount(),
charactersWithoutSpaces: api.body.getCharacterCountWithoutSpaces()
}
});
};
const updateCount = (editor, api) => {
fireWordCountUpdate(editor, api);
};
const setup = (editor, api, delay) => {
const debouncedUpdate = first(() => updateCount(editor, api), delay);
editor.on('init', () => {
updateCount(editor, api);
global.setEditorTimeout(editor, () => {
editor.on('SetContent BeforeAddUndo Undo Redo ViewUpdate keyup', debouncedUpdate.throttle);
}, 0);
editor.on('remove', debouncedUpdate.cancel);
});
};
const register = editor => {
const onAction = () => editor.execCommand('mceWordCount');
editor.ui.registry.addButton('wordcount', {
tooltip: 'Word count',
icon: 'character-count',
onAction
});
editor.ui.registry.addMenuItem('wordcount', {
text: 'Word count',
icon: 'character-count',
onAction
});
};
var Plugin = (delay = 300) => {
global$2.add('wordcount', editor => {
const api = get(editor);
register$1(editor, api);
register(editor);
setup(editor, api, delay);
return api;
});
};
Plugin();
})();

Some files were not shown because too many files have changed in this diff Show More