Add global music player, invoicing/payment system, account subpages, mail account admin, and the qualityiron.vegas Jet 2.0 port

Jet interpreter (Tag.cpp, __call.cpp, __imap*.cpp/h, __smtpsend.cpp/h,
__imapemptyfolder.cpp/h - new): assorted parser/tag fixes found across
this work - a stray literal-tag-in-comment and backslash-quote parser
corruption class, a dangling-pointer fix, a __call.cpp fd leak, IMAP
folder-management tags, multi-account/per-host IMAP support, and a
smtpsend Message-ID fix.

barant.com site (jetc/barant-site/):
- A site-wide persistent music player (header band, playlist/queue,
  stereo FFT EQ, session-persisted state) fed by new library/
  ianslibrary/music song-list subpages.
- /account split into info/phones/invoices subpages; a full invoicing
  and Square payment system (create/edit/copy/pay/email invoice);
  admin invoice management and mail-account management subpages.
- /services split into overview/hosting/siptrunking/documents
  subpages, retiring the old standalone pages.
- SIPPHONE.tag: a Jet 2.0 WebRTC softphone tag.
- main.css/spa.js/email.js: the SPA loading indicator, the music
  player band styling, and assorted fixes accumulated alongside this
  work.

qualityiron-site/: the qualityiron.vegas job/contractor/customer/
document management app, ported from its original Jet 1.4 codebase to
Jet 2.0 as barant.coms APIServers second multi-tenant site.

wcwc/wcwc.jet: the WCWC site Jet source (wcwc.jtc build output not
included).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Brad ArantandClaude Sonnet 5 committed 2026-10-06 17:42:01 +00:00
1 parent 905fbafa5a
commit b8f7793773
406 files changed
+15739 -523

No files matched your search

+70 -5
View File
@@ -11,6 +11,7 @@
#include "__imapmessage.h" #include "__imapmessage.h"
#include "__imapflag.h" #include "__imapflag.h"
#include "__imapdelete.h" #include "__imapdelete.h"
#include "__imapemptyfolder.h"
#include "__imapmove.h" #include "__imapmove.h"
#include "__imapfolders.h" #include "__imapfolders.h"
#include "__imapsearch.h" #include "__imapsearch.h"
@@ -215,9 +216,33 @@ namespace jet {
// matches the same unconsumed <catch> on every subsequent // matches the same unconsumed <catch> on every subsequent
// iteration forever. Build the real expected delimiter // iteration forever. Build the real expected delimiter
// from splitTagName itself so it works for any split tag. // from splitTagName itself so it works for any split tag.
coreutils::MString splitOpenTag; in.ifNext("<");
splitOpenTag << "<" << splitTagName << ">"; in.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
in.ifNextIgnoreCase(splitOpenTag); while(!in.eod()) {
in.skipWhitespace();
if(in.ifNext(">"))
break;
else if(in.getTokenExclude("=").getLength() != 0) {
bool dq = in.ifNext("=\"");
bool sq = !dq && in.ifNext("='");
if(dq || sq) {
while(1) {
if(in.ifNext(dq ? "\"" : "'"))
break;
in.nextChar();
}
} else {
in.nextChar();
while(!in.eod()) {
char c = in.charAt(0);
if(c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '>' || c == '/')
break;
in.nextChar();
}
}
} else
break;
}
start = in.getCursor(); start = in.getCursor();
} else if(ifNested(in)) { } else if(ifNested(in)) {
} else } else
@@ -477,6 +502,9 @@ namespace jet {
} else if(ifTagName(in, "imapdelete")) { } else if(ifTagName(in, "imapdelete")) {
__imapdelete _imapdelete(in, out, global, this, local); __imapdelete _imapdelete(in, out, global, this, local);
continue; continue;
} else if(ifTagName(in, "imapemptyfolder")) {
__imapemptyfolder _imapemptyfolder(in, out, global, this, local);
continue;
} else if(ifTagName(in, "imapmove")) { } else if(ifTagName(in, "imapmove")) {
__imapmove _imapmove(in, out, global, this, local); __imapmove _imapmove(in, out, global, this, local);
continue; continue;
@@ -737,11 +765,48 @@ namespace jet {
bool Tag::ifSplitTagName(coreutils::ZString &in) { bool Tag::ifSplitTagName(coreutils::ZString &in) {
in.push(); in.push();
if(in.ifNext("<")) if(in.ifNext("<")) {
if(coreutils::MString(in.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_")).toLower() == coreutils::MString(splitTagName).toLower()) { if(coreutils::MString(in.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_")).toLower() == coreutils::MString(splitTagName).toLower()) {
if(in.ifNext(">")) // Tolerate attributes on the split-tag marker itself (e.g.
// <try>'s own <catch name="_imaperr">) rather than requiring
// '>' to land immediately after the tag name - every
// splitTagName="else" caller writes a bare <else> so this
// never mattered for them, but <catch name="..."> is the
// universal convention everywhere it's used. Previously this
// whole check was a single unbraced
// if(...){in.pop();return true;} where the missing braces
// meant "return true" executed unconditionally, leaving the
// cursor in a half-advanced, never-popped state on the
// attributed-tag path - confirmed live via a real /email/list
// failure whose caught error text leaked
// "name=\"_imaperr\">" into the JSON response.
while(!in.eod()) {
in.skipWhitespace();
if(in.ifNext(">")) {
in.pop(); in.pop();
return true; return true;
} else if(in.getTokenExclude("=").getLength() != 0) {
bool dq = in.ifNext("=\"");
bool sq = !dq && in.ifNext("='");
if(dq || sq) {
while(1) {
if(in.ifNext(dq ? "\"" : "'"))
break;
in.nextChar();
}
} else {
in.nextChar();
while(!in.eod()) {
char c = in.charAt(0);
if(c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '>' || c == '/')
break;
in.nextChar();
}
}
} else
break;
}
}
} }
in.pop(); in.pop();
return false; return false;
+57 -10
View File
@@ -7,6 +7,8 @@
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <cerrno>
#include <cstring>
#include <filesystem> #include <filesystem>
namespace jet { namespace jet {
@@ -35,36 +37,69 @@ namespace jet {
} else } else
break; break;
} }
pipe(fdo); // pipe()/fork() both used to go unchecked here - on failure (most
// realistically pipe() hitting the process's open-file-descriptor
// limit, see below) fdo[] is left holding whatever garbage was
// already on the stack/in this member array, and every use of it
// after this point (close(), read(), and - for a failed fork() -
// waitpid(-1, ...), which has the special POSIX meaning "wait for
// ANY child" rather than "wait for none") operates on that garbage
// or on an unrelated process instead of safely no-oping. That's a
// real, confirmed mechanism for exactly the kind of sporadic
// memory corruption this codebase has seen: closing/reading a
// stale fd that coincidentally matches another subsystem's live
// socket, or reaping a concurrent request's own child out from
// under it.
if(pipe(fdo) != 0)
throw coreutils::Exception("call: pipe() failed - " + std::string(strerror(errno)), __FILE__, __LINE__, 500);
pid = fork(); pid = fork();
if(pid < 0) {
close(fdo[0]);
close(fdo[1]);
throw coreutils::Exception("call: fork() failed - " + std::string(strerror(errno)), __FILE__, __LINE__, 500);
}
if(pid == 0) { if(pid == 0) {
close(fdo[0]); close(fdo[0]);
dup2(fdo[1], 1); dup2(fdo[1], 1);
if(hasContainer) { if(hasContainer) {
pipe(fdi); if(pipe(fdi) == 0) {
if(fork() == 0) { pid_t innerPid = fork();
if(innerPid == 0) {
close(fdi[0]); close(fdi[0]);
write(fdi[1], container.getData(), container.getLength()); write(fdi[1], container.getData(), container.getLength());
close(fdi[1]); close(fdi[1]);
exit(0); _exit(0);
} } else if(innerPid > 0) {
close(fdi[1]); close(fdi[1]);
dup2(fdi[0], 0); dup2(fdi[0], 0);
close(fdi[0]);
} else {
close(fdi[0]);
close(fdi[1]);
}
}
} else if(keywordDefined("input")) { } else if(keywordDefined("input")) {
coreutils::MString input(resolveKeyword("input")); coreutils::MString input(resolveKeyword("input"));
pipe(fdi); if(pipe(fdi) == 0) {
if(fork() == 0) { pid_t innerPid = fork();
if(innerPid == 0) {
close(fdi[0]); close(fdi[0]);
write(fdi[1], input.getData(), input.getLength()); write(fdi[1], input.getData(), input.getLength());
close(fdi[1]); close(fdi[1]);
exit(0); _exit(0);
} } else if(innerPid > 0) {
close(fdi[1]); close(fdi[1]);
dup2(fdi[0], 0); dup2(fdi[0], 0);
close(fdi[0]);
} else {
close(fdi[0]);
close(fdi[1]);
}
}
} }
rc = execvpe(argv[0], argv, global.envp); rc = execvpe(argv[0], argv, global.envp);
close(fdo[1]); close(fdo[1]);
exit(errno); _exit(errno);
} }
close(fdo[1]); close(fdo[1]);
if(keywordDefined("name")) { if(keywordDefined("name")) {
@@ -73,6 +108,18 @@ namespace jet {
storeVariable(resolveKeyword("name"), value, resolveKeyword("scope")); storeVariable(resolveKeyword("name"), value, resolveKeyword("scope"));
} else } else
out.read(fdo[0]); out.read(fdo[0]);
// fdo[0] (the read end, still open in this - the parent - process)
// was never closed here before, leaking one file descriptor on
// every single <call> invocation for the life of the process.
// Harmless-looking for an occasional <call>, but <call> is used
// throughout this codebase (jq/curl parsing, mailcreate, this
// session's own per-line-item JS-escaping on the invoice editor,
// which alone can issue a double-digit number of calls per page
// load) - repeated, routine use was slowly accumulating leaked
// fds for as long as this process stayed up, eventually hitting
// the real open-files limit and turning into exactly the pipe()
// failures (and the undefined behavior above) this fix addresses.
close(fdo[0]);
waitpid(pid, &status, 0); waitpid(pid, &status, 0);
if(keywordDefined("error")) { if(keywordDefined("error")) {
global.variables[resolveKeyword("error")] = (status >> 8 & 255); global.variables[resolveKeyword("error")] = (status >> 8 & 255);
+27 -2
View File
@@ -559,8 +559,15 @@ namespace jet {
coreutils::MString passwordVal = resolveKeyword("password"); coreutils::MString passwordVal = resolveKeyword("password");
coreutils::JFile config(configPath); coreutils::JFile config(configPath);
std::string host = config.getString("host"); // host/port keywords override the config file's own values when
long port = (long)config.getNumber("port"); // present - lets a caller reuse one config file (still needed for
// caCertificate/smtpPort) across many accounts that each live on
// a different mail server, rather than requiring a separate config
// file per server. Every existing caller omits these keywords, so
// behavior is unchanged for them - config's own host/port is still
// the only thing read in that case.
std::string host = keywordDefined("host") ? resolveKeyword("host").str() : config.getString("host");
long port = keywordDefined("port") ? strtol(resolveKeyword("port").str().c_str(), nullptr, 10) : (long)config.getNumber("port");
if (port <= 0) if (port <= 0)
port = 993; port = 993;
@@ -1034,6 +1041,24 @@ namespace jet {
return coreutils::MString(std::string("{\"ok\":") + (ok ? "true" : "false") + "}"); return coreutils::MString(std::string("{\"ok\":") + (ok ? "true" : "false") + "}");
} }
coreutils::MString __imap::emptyFolder(const std::string &folder) {
if (!selectFolderIfNeeded(folder))
throw coreutils::Exception("imap: could not select folder " + folder, __FILE__, __LINE__, 502);
std::string tag = nextTag();
sendLine(tag + " UID STORE 1:* +FLAGS (\\Deleted)");
auto lines = readUntilTagged(tag);
bool ok1 = taggedOk(lines, tag);
std::string tag2 = nextTag();
sendLine(tag2 + " EXPUNGE");
auto lines2 = readUntilTagged(tag2);
bool ok2 = taggedOk(lines2, tag2);
bool ok = ok1 && ok2;
return coreutils::MString(std::string("{\"ok\":") + (ok ? "true" : "false") + "}");
}
// BARANTMail (see __IMAP_COPY.cpp) implements COPY but not the // BARANTMail (see __IMAP_COPY.cpp) implements COPY but not the
// RFC 6851 MOVE extension - not surprising, since the whole point // RFC 6851 MOVE extension - not surprising, since the whole point
// of that extension was standardizing what every real-world client // of that extension was standardizing what every real-world client
+9
View File
@@ -63,6 +63,15 @@ namespace jet {
coreutils::MString setFlag(const std::string &folder, uint32_t uid, const std::string &flag, bool add); coreutils::MString setFlag(const std::string &folder, uint32_t uid, const std::string &flag, bool add);
coreutils::MString deleteMessage(const std::string &folder, uint32_t uid); coreutils::MString deleteMessage(const std::string &folder, uint32_t uid);
coreutils::MString moveMessage(const std::string &folder, uint32_t uid, const std::string &destFolder); coreutils::MString moveMessage(const std::string &folder, uint32_t uid, const std::string &destFolder);
// Permanently empties an entire folder - every message, not one at
// a time. "1:*" is IMAP's standard UID-range syntax for "every UID
// in the selected mailbox" (well-defined and a no-op, not an error,
// on an already-empty folder - verified directly against
// BARANTMail rather than assumed from the RFC), so this is a
// single mark-all-deleted STORE plus one EXPUNGE, not a loop over
// deleteMessage() - the whole point is one IMAP round trip instead
// of one per message.
coreutils::MString emptyFolder(const std::string &folder);
coreutils::MString folderCounts(); coreutils::MString folderCounts();
coreutils::MString sessionId; coreutils::MString sessionId;
+43 -19
View File
@@ -37,8 +37,8 @@ namespace jet {
return s.substr(start, end - start + 1); return s.substr(start, end - start + 1);
} }
std::vector<std::pair<std::string, std::string>> __imapaccounts::decodeList(const std::string &encodedRaw) { std::vector<__imapaccounts::Account> __imapaccounts::decodeList(const std::string &encodedRaw) {
std::vector<std::pair<std::string, std::string>> entries; std::vector<Account> entries;
coreutils::Base64 base64; coreutils::Base64 base64;
// The list value round-trips through <eval>/<set> template // The list value round-trips through <eval>/<set> template
// captures, which include whatever whitespace/newlines surround // captures, which include whatever whitespace/newlines surround
@@ -56,26 +56,35 @@ namespace jet {
entry = trimWhitespace(entry); entry = trimWhitespace(entry);
if (entry.empty()) if (entry.empty())
continue; continue;
size_t colon = entry.find(':'); size_t colon1 = entry.find(':');
if (colon == std::string::npos) if (colon1 == std::string::npos)
continue; continue;
std::string userB64 = trimWhitespace(entry.substr(0, colon)); size_t colon2 = entry.find(':', colon1 + 1);
std::string passB64 = trimWhitespace(entry.substr(colon + 1)); if (colon2 == std::string::npos)
std::string user = base64.decode(userB64).str(); continue;
std::string password = base64.decode(passB64).str(); std::string hostB64 = trimWhitespace(entry.substr(0, colon1));
entries.push_back(std::make_pair(user, password)); std::string userB64 = trimWhitespace(entry.substr(colon1 + 1, colon2 - colon1 - 1));
std::string passB64 = trimWhitespace(entry.substr(colon2 + 1));
Account account;
account.host = base64.decode(hostB64).str();
account.user = base64.decode(userB64).str();
account.password = base64.decode(passB64).str();
entries.push_back(account);
} }
return entries; return entries;
} }
std::string __imapaccounts::encodeList(const std::vector<std::pair<std::string, std::string>> &entries) { std::string __imapaccounts::encodeList(const std::vector<Account> &entries) {
coreutils::Base64 base64; coreutils::Base64 base64;
std::string result; std::string result;
for (size_t i = 0; i < entries.size(); i++) { for (size_t i = 0; i < entries.size(); i++) {
if (i > 0) if (i > 0)
result += ";"; result += ";";
std::string user = entries[i].first; std::string host = entries[i].host;
std::string password = entries[i].second; std::string user = entries[i].user;
std::string password = entries[i].password;
result += base64.encode(host).str();
result += ":";
result += base64.encode(user).str(); result += base64.encode(user).str();
result += ":"; result += ":";
result += base64.encode(password).str(); result += base64.encode(password).str();
@@ -90,20 +99,25 @@ namespace jet {
auto entries = decodeList(listStr); auto entries = decodeList(listStr);
if (action == "add") { if (action == "add") {
std::string host = trimWhitespace(resolveKeyword("host").str());
std::string user = trimWhitespace(resolveKeyword("user").str()); std::string user = trimWhitespace(resolveKeyword("user").str());
std::string password = trimWhitespace(resolveKeyword("password").str()); std::string password = trimWhitespace(resolveKeyword("password").str());
for (size_t i = 0; i < entries.size(); i++) { for (size_t i = 0; i < entries.size(); i++) {
if (entries[i].first == user) { if (entries[i].user == user) {
entries.erase(entries.begin() + (long)i); entries.erase(entries.begin() + (long)i);
break; break;
} }
} }
entries.push_back(std::make_pair(user, password)); Account account;
account.host = host;
account.user = user;
account.password = password;
entries.push_back(account);
out = coreutils::MString(encodeList(entries)); out = coreutils::MString(encodeList(entries));
} else if (action == "remove") { } else if (action == "remove") {
std::string user = trimWhitespace(resolveKeyword("user").str()); std::string user = trimWhitespace(resolveKeyword("user").str());
for (size_t i = 0; i < entries.size(); i++) { for (size_t i = 0; i < entries.size(); i++) {
if (entries[i].first == user) { if (entries[i].user == user) {
entries.erase(entries.begin() + (long)i); entries.erase(entries.begin() + (long)i);
break; break;
} }
@@ -113,21 +127,31 @@ namespace jet {
std::string user = trimWhitespace(resolveKeyword("user").str()); std::string user = trimWhitespace(resolveKeyword("user").str());
std::string password; std::string password;
for (size_t i = 0; i < entries.size(); i++) { for (size_t i = 0; i < entries.size(); i++) {
if (entries[i].first == user) { if (entries[i].user == user) {
password = entries[i].second; password = entries[i].password;
break; break;
} }
} }
out = coreutils::MString(password); out = coreutils::MString(password);
} else if (action == "gethost") {
std::string user = trimWhitespace(resolveKeyword("user").str());
std::string host;
for (size_t i = 0; i < entries.size(); i++) {
if (entries[i].user == user) {
host = entries[i].host;
break;
}
}
out = coreutils::MString(host);
} else if (action == "firstuser") { } else if (action == "firstuser") {
out = coreutils::MString(entries.empty() ? std::string() : entries[0].first); out = coreutils::MString(entries.empty() ? std::string() : entries[0].user);
} else if (action == "list") { } else if (action == "list") {
std::string active = resolveKeyword("active").str(); std::string active = resolveKeyword("active").str();
std::string json = "{\"accounts\":["; std::string json = "{\"accounts\":[";
for (size_t i = 0; i < entries.size(); i++) { for (size_t i = 0; i < entries.size(); i++) {
if (i > 0) if (i > 0)
json += ","; json += ",";
json += "\"" + jsonEscape(entries[i].first) + "\""; json += "\"" + jsonEscape(entries[i].user) + "\"";
} }
json += "],\"active\":\"" + jsonEscape(active) + "\"}"; json += "],\"active\":\"" + jsonEscape(active) + "\"}";
out = coreutils::MString(json); out = coreutils::MString(json);
+24 -13
View File
@@ -11,8 +11,8 @@
namespace jet { namespace jet {
/// ///
/// <imapaccounts action="add|remove|getpassword|firstuser|list" /// <imapaccounts action="add|remove|getpassword|gethost|firstuser|list"
/// list="$[@_imap_accounts]" user="..." password="..."> /// list="$[@_imap_accounts]" host="..." user="..." password="...">
/// ///
/// Pure list-transform tag (no session-variable access of its own, /// Pure list-transform tag (no session-variable access of its own,
/// no IMAP connection) that manages the multi-account list webmail /// no IMAP connection) that manages the multi-account list webmail
@@ -23,34 +23,45 @@ namespace jet {
/// touches Global's session-variable map directly). /// touches Global's session-variable map directly).
/// ///
/// The list's own on-the-wire encoding (semicolon-separated /// The list's own on-the-wire encoding (semicolon-separated
/// "base64(user):base64(password)" entries) is private to this tag - /// "base64(host):base64(user):base64(password)" entries) is private
/// callers only ever pass the whole `list` value back in verbatim /// to this tag - callers only ever pass the whole `list` value back
/// and use the returned value the same way, so the choice of /// in verbatim and use the returned value the same way, so the
/// delimiter can't collide with any real username or password /// choice of delimiter can't collide with any real username or
/// character. /// password character. Each account can live on its own IMAP server
/// (see the <imap>/<imaplist>/etc. tags' own optional host/port
/// keywords), not just the one fixed host in email.cfg.
/// ///
/// action="add": upserts user/password (removing any existing entry /// action="add": upserts host/user/password (removing any existing
/// for the same user first, so reconnecting with a changed password /// entry for the same user first, so reconnecting with a changed
/// updates it) - returns the updated encoded list. /// password or server updates it) - returns the updated encoded list.
/// action="remove": drops the entry for user, if present - returns /// action="remove": drops the entry for user, if present - returns
/// the updated encoded list. /// the updated encoded list.
/// action="getpassword": returns the stored password for user, or /// action="getpassword": returns the stored password for user, or
/// an empty string if not present. /// an empty string if not present.
/// action="gethost": returns the stored host for user, or an empty
/// string if not present.
/// action="firstuser": returns the first entry's username, or an /// action="firstuser": returns the first entry's username, or an
/// empty string if the list is empty. /// empty string if the list is empty.
/// action="list": returns JSON ({"accounts":[...],"active":"..."}) /// action="list": returns JSON ({"accounts":[...],"active":"..."})
/// - the one client-facing action; "active" echoes the `active` /// - the one client-facing action; "active" echoes the `active`
/// keyword (typically $[@_imap_user]) back verbatim so the sidebar /// keyword (typically $[@_imap_user]) back verbatim so the sidebar
/// can highlight the current one, and never includes any password. /// can highlight the current one, and never includes any password or
/// host (unchanged shape from before per-account hosts existed -
/// nothing client-side needs the host to switch between already-
/// connected accounts).
/// ///
class __imapaccounts : public Tag { class __imapaccounts : public Tag {
struct Account {
std::string host, user, password;
};
public: public:
__imapaccounts(coreutils::ZString &in, coreutils::MString &parentOut, Global &global, Tag *parent, Tag *local); __imapaccounts(coreutils::ZString &in, coreutils::MString &parentOut, Global &global, Tag *parent, Tag *local);
private: private:
static std::vector<std::pair<std::string, std::string>> decodeList(const std::string &encoded); static std::vector<Account> decodeList(const std::string &encoded);
static std::string encodeList(const std::vector<std::pair<std::string, std::string>> &entries); static std::string encodeList(const std::vector<Account> &entries);
static std::string jsonEscape(const std::string &s); static std::string jsonEscape(const std::string &s);
}; };
+26
View File
@@ -0,0 +1,26 @@
#include "__imapemptyfolder.h"
#include "Exception.h"
#include "__imap.h"
namespace jet {
__imapemptyfolder::__imapemptyfolder(coreutils::ZString &in, coreutils::MString &parentOut, Global &global, Tag *parent, Tag *local) : Tag(in, parentOut, global, parent, local) {
coreutils::MString sessionId = resolveKeyword("sessionid");
if (!global.imapSessionExists(sessionId))
throw coreutils::Exception("imap sessionid does not exist.", __FILE__, __LINE__, 502);
// Unlike __imapdelete (one message - low blast radius even on a
// wrong default), this permanently destroys an entire folder's
// contents - no silent "defaults to INBOX" here. A missing/blank
// folder attribute is refused outright rather than risked.
if (!keywordDefined("folder"))
throw coreutils::Exception("imapemptyfolder tag must have folder defined.", __FILE__, __LINE__, 400);
std::string folder = resolveKeyword("folder").str();
if (folder.empty())
throw coreutils::Exception("imapemptyfolder tag must have folder defined.", __FILE__, __LINE__, 400);
out = global.getImapSession(sessionId)->emptyFolder(folder);
}
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef ____imapemptyfolder_h__
# define ____imapemptyfolder_h__
# include "Tag.h"
namespace jet {
///
/// <imapemptyfolder sessionid="" folder="Trash">
///
/// Self-closing tag - permanently deletes every message in the given
/// folder (mark-all-\Deleted + one EXPUNGE, not a per-message loop),
/// writes {"ok":true|false} into `out`. See __imaplist.h's doc
/// comment for how `out` reaches the real response body.
///
class __imapemptyfolder : public Tag {
public:
__imapemptyfolder(coreutils::ZString &in, coreutils::MString &parentOut, Global &global, Tag *parent, Tag *local);
};
}
#endif
+23
View File
@@ -10,6 +10,8 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <ctime> #include <ctime>
#include <iomanip>
#include <sstream>
namespace jet { namespace jet {
@@ -88,10 +90,31 @@ namespace jet {
return std::string(buf); return std::string(buf);
} }
// RFC 5322 3.6.4: Message-ID "SHOULD be present" - in practice
// several real receivers (confirmed live: Gmail) now hard-reject
// anything missing one ("550 5.7.1 Messages missing a valid
// Message-ID header are not accepted") rather than just marking it
// down, so this isn't optional in practice. Domain part is the
// sender's own domain (everything after '@' in `from`), matching
// RFC 5322's own recommendation that it be a name under the
// generating system's control - falls back to the literal `from`
// string in the (should-never-happen) case it has no '@' at all.
std::string __smtpsend::generateMessageId(const std::string &from) {
size_t at = from.find('@');
std::string domainPart = (at == std::string::npos) ? from : from.substr(at + 1);
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
std::ostringstream idStream;
idStream << ts.tv_sec << "." << std::setfill('0') << std::setw(9) << ts.tv_nsec
<< "." << rand() << "@" << domainPart;
return idStream.str();
}
std::string __smtpsend::buildMessage(const std::string &from, const std::string &to, std::string __smtpsend::buildMessage(const std::string &from, const std::string &to,
const std::string &subject, const std::string &html) { const std::string &subject, const std::string &html) {
std::string msg; std::string msg;
msg += "Date: " + rfc2822Date() + "\r\n"; msg += "Date: " + rfc2822Date() + "\r\n";
msg += "Message-ID: <" + generateMessageId(from) + ">\r\n";
msg += "From: " + from + "\r\n"; msg += "From: " + from + "\r\n";
msg += "To: " + to + "\r\n"; msg += "To: " + to + "\r\n";
msg += "Subject: " + subject + "\r\n"; msg += "Subject: " + subject + "\r\n";
+1
View File
@@ -58,6 +58,7 @@ namespace jet {
static std::string base64Encode(const std::string &s); static std::string base64Encode(const std::string &s);
static std::string rfc2822Date(); static std::string rfc2822Date();
static std::string generateMessageId(const std::string &from);
// Builds the full RFC 5322 message (headers + dot-stuffed body) // Builds the full RFC 5322 message (headers + dot-stuffed body)
// handed to SMTP's DATA command. // handed to SMTP's DATA command.
static std::string buildMessage(const std::string &from, const std::string &to, static std::string buildMessage(const std::string &from, const std::string &to,
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 510 KiB

+64 -6
View File
@@ -43,6 +43,13 @@
pageNext: pageNext:
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">' + '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">' +
'<path d="M9 18l6-6-6-6"/>' + '<path d="M9 18l6-6-6-6"/>' +
'</svg>',
emptyFolder:
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">' +
'<path d="M4 7h16"/>' +
'<path d="M9 7V4h6v3"/>' +
'<path d="M6 7l1 13a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2l1-13"/>' +
'<path d="M9.5 12.5l5 5M14.5 12.5l-5 5"/>' +
'</svg>' '</svg>'
}; };
@@ -109,6 +116,15 @@
var links = document.querySelectorAll('.email-folder-link'); var links = document.querySelectorAll('.email-folder-link');
for (var i = 0; i < links.length; i++) for (var i = 0; i < links.length; i++)
links[i].classList.toggle('email-folder-selected', links[i].getAttribute('data-folder') === currentFolder); links[i].classList.toggle('email-folder-selected', links[i].getAttribute('data-folder') === currentFolder);
// Only Spam/Trash ever offer this - emptying Inbox (or any future
// folder) as a single destructive click isn't something any real
// mail client exposes, and the server enforces the exact same
// Spam/Trash-only allowlist independently (see email.jet) - this is
// just keeping the button from ever being visible somewhere it
// would 400 anyway, not the actual safety boundary.
var emptyBtn = document.getElementById('email-empty-folder-btn');
if (emptyBtn)
emptyBtn.hidden = (currentFolder !== 'Spam' && currentFolder !== 'Trash');
} }
function escapeHtml(s) { function escapeHtml(s) {
@@ -158,6 +174,7 @@
'<button type="button" id="email-search-btn" class="icon-btn" title="Search">' + ICONS.search + '</button>' + '<button type="button" id="email-search-btn" class="icon-btn" title="Search">' + ICONS.search + '</button>' +
'</span>' + '</span>' +
'<button type="button" id="email-compose-btn" class="icon-btn" title="New Mail">' + ICONS.compose + '</button>' + '<button type="button" id="email-compose-btn" class="icon-btn" title="New Mail">' + ICONS.compose + '</button>' +
'<button type="button" id="email-empty-folder-btn" class="icon-btn" title="Permanently empty this folder" hidden>' + ICONS.emptyFolder + '</button>' +
'<button type="button" id="email-refresh-btn" class="icon-btn" title="Refresh">' + ICONS.refresh + '</button>' + '<button type="button" id="email-refresh-btn" class="icon-btn" title="Refresh">' + ICONS.refresh + '</button>' +
'</span>' + '</span>' +
'</div>' + '</div>' +
@@ -218,6 +235,7 @@
document.getElementById('email-refresh-btn').addEventListener('click', function() { document.getElementById('email-refresh-btn').addEventListener('click', function() {
loadMessageList(); loadMessageList();
}); });
document.getElementById('email-empty-folder-btn').addEventListener('click', emptyCurrentFolder);
// Matches sender, subject, or body content in whatever folder is // Matches sender, subject, or body content in whatever folder is
// currently open (see __imap.cpp's searchMessages()) - an empty // currently open (see __imap.cpp's searchMessages()) - an empty
@@ -444,6 +462,38 @@
}); });
} }
// Permanently deletes every message in the CURRENT folder (only ever
// reachable while viewing Spam or Trash - see syncActiveFolder()'s own
// button-visibility gate, and email.jet's independent server-side
// allowlist, which is the real enforcement). Unlike trashMessage()
// there's no undo, no "move somewhere" - a real, human-readable confirm()
// is the whole safety net here, matching how Gmail/Outlook both gate
// "Empty Trash now" behind exactly one extra click and nothing fancier.
function emptyCurrentFolder() {
if (currentFolder !== 'Spam' && currentFolder !== 'Trash')
return;
if (!window.confirm('Permanently delete every message in ' + currentFolder + '? This cannot be undone.'))
return;
var btn = document.getElementById('email-empty-folder-btn');
if (btn) btn.disabled = true;
post('/email/emptyfolder', { folder: currentFolder })
.then(function(res) {
if (btn) btn.disabled = false;
if (!res.ok) {
window.alert(res.error || 'Could not empty the folder.');
return;
}
currentUid = null;
document.getElementById('email-reading-pane').innerHTML =
'<div id="email-empty-state">Select a message to read it.</div>';
loadMessageList();
})
.catch(function() {
if (btn) btn.disabled = false;
window.alert('Empty-folder request failed.');
});
}
// Same fade-out/fetch-concurrently/fade-in shape as openMessage() and // Same fade-out/fetch-concurrently/fade-in shape as openMessage() and
// spa.js's own navigate() - every list refresh (folder switch, // spa.js's own navigate() - every list refresh (folder switch,
// refresh button) gets the same smooth transition instead of a flash // refresh button) gets the same smooth transition instead of a flash
@@ -488,8 +538,10 @@
if (!skipFade) if (!skipFade)
list.classList.remove('email-fading'); list.classList.remove('email-fading');
}) })
.catch(function() { .catch(function(err) {
list.innerHTML = '<div id="email-empty-state">Could not load messages.</div>'; console.error('loadMessageList failed:', err);
list.innerHTML = '<div id="email-empty-state">Could not load messages' +
(err && err.message ? ': ' + escapeHtml(err.message) : '.') + '</div>';
if (!skipFade) if (!skipFade)
list.classList.remove('email-fading'); list.classList.remove('email-fading');
}); });
@@ -506,8 +558,10 @@
// cosmetic problem, not worth surfacing as a user-visible failure. // cosmetic problem, not worth surfacing as a user-visible failure.
function loadFolderCounts() { function loadFolderCounts() {
post('/email/folders', {}).then(function(res) { post('/email/folders', {}).then(function(res) {
if (res.error) if (res.error) {
console.error('loadFolderCounts server error:', res.error);
return; return;
}
var folders = ['Inbox', 'Spam', 'Trash']; var folders = ['Inbox', 'Spam', 'Trash'];
for (var i = 0; i < folders.length; i++) { for (var i = 0; i < folders.length; i++) {
var f = folders[i]; var f = folders[i];
@@ -515,7 +569,9 @@
if (span && res[f]) if (span && res[f])
span.textContent = res[f].messages > 0 ? (res[f].unseen + '/' + res[f].messages) : ''; span.textContent = res[f].messages > 0 ? (res[f].unseen + '/' + res[f].messages) : '';
} }
}).catch(function() {}); }).catch(function(err) {
console.error('loadFolderCounts failed:', err);
});
} }
function loadAccounts() { function loadAccounts() {
@@ -756,8 +812,10 @@
} }
pane.classList.remove('email-fading'); pane.classList.remove('email-fading');
}) })
.catch(function() { .catch(function(err) {
pane.innerHTML = '<div id="email-empty-state">Could not load message.</div>'; console.error('openMessage failed:', err);
pane.innerHTML = '<div id="email-empty-state">Could not load message' +
(err && err.message ? ': ' + escapeHtml(err.message) : '.') + '</div>';
pane.classList.remove('email-fading'); pane.classList.remove('email-fading');
}); });
} }
+530 -15
View File
@@ -13,16 +13,16 @@
@font-face { @font-face {
font-family: avenir; font-family: avenir;
src: url('https://barant.com/fonts/AvenirLTStd-Light.ttf'); src: url('https://barant.com/assets/AvenirLTStd-Light.ttf');
} }
@font-face { @font-face {
font-family: source; font-family: source;
src: url('https://barant.com/fonts/jackinput.TTF'); src: url('https://barant.com/assets/jackinput.TTF');
} }
@font-face { @font-face {
font-family: exo2; font-family: exo2;
src: url('https://barant.com/fonts/Exo2-RegularCondensed.otf'); src: url('https://barant.com/assets/Exo2-RegularCondensed.otf');
} }
:root { :root {
@@ -283,7 +283,7 @@ textarea.fieldinputerror {
background: linear-gradient(180deg, #131318, #0d0d10); background: linear-gradient(180deg, #131318, #0d0d10);
border-radius: 5px 5px 0px 0px; border-radius: 5px 5px 0px 0px;
border-bottom: 1px solid var(--bond-line); border-bottom: 1px solid var(--bond-line);
max-height: 80px; max-height: 125px;
} }
.entryform { .entryform {
background: #232330; background: #232330;
@@ -365,24 +365,43 @@ textarea.fieldinputerror {
transition: color 0.2s ease, border-color 0.2s ease; transition: color 0.2s ease, border-color 0.2s ease;
} }
/* The currently-active entry in a page's own sidebar submenu (e.g. /* Every entry in a page's own sidebar submenu (e.g. opensource.menu's
opensource.menu's list of subpages) - a background highlight rather list of subpages) shares this same box model - selected and
than baritemselected's "raised tab" treatment, since these are plain unselected alike - so the only thing that changes when an item
inline links stacked in a list, not tabs sitting on a bar edge. becomes active is its background/border, never its box size or the
Applied server-side (see opensource.menu) by comparing each position of its own text. Giving only the active item padding/margin
linkbutton's own subpage against $[SUBPAGE] - spa.js already (the original approach) made its text visibly shift the moment it
re-renders and swaps this menu's markup on every client-side was selected, since the unselected items sat flush with none. */
navigation (see its #_spa_panelmenu handling), so this stays correct #panelmenu a {
without any script of its own. */ display: block;
padding: 2px 6px;
margin: 2px 0;
}
/* The currently-active entry - a background highlight rather than
baritemselected's "raised tab" treatment, since these are plain
links stacked in a list, not tabs sitting on a bar edge. Applied
server-side (see opensource.menu) by comparing each linkbutton's own
subpage against $[SUBPAGE] - spa.js also applies it instantly client-
side on click (see its #panelmenu click listener) and then
re-confirms it from the server's own #_spa_panelmenu markup once the
fetch resolves, so this stays correct either way. */
.submenuitem-active { .submenuitem-active {
background: var(--bond-panel-2); background: var(--bond-panel-2);
color: var(--bond-gold-bright) !important; color: var(--bond-gold-bright) !important;
padding: 2px 6px;
margin: -2px -6px;
border-radius: 3px; border-radius: 3px;
box-shadow: inset 0 0 0 1px var(--bond-gold); box-shadow: inset 0 0 0 1px var(--bond-gold);
} }
/* Every menu entry's own markup is <linkbutton...></linkbutton><br> - that
<br> was needed to force a line break after an inline link, but every
entry is display:block now (its own implicit line break), so the
trailing <br> doubles up into a blank line for every item, not just
the active one. */
#panelmenu a + br {
display: none;
}
.panel { .panel {
background: var(--bond-panel); background: var(--bond-panel);
margin: 10px; margin: 10px;
@@ -861,3 +880,499 @@ textarea.fieldinputerror {
.filemgr-progress-fill { height: 100%; width: 0%; background: var(--bond-gold-bright); transition: width 0.15s ease; } .filemgr-progress-fill { height: 100%; width: 0%; background: var(--bond-gold-bright); transition: width 0.15s ease; }
.filemgr-item.filemgr-done .filemgr-progress-fill { background: #6c6; } .filemgr-item.filemgr-done .filemgr-progress-fill { background: #6c6; }
.filemgr-item.filemgr-failed .filemgr-progress-fill { background: #c66; } .filemgr-item.filemgr-failed .filemgr-progress-fill { background: #c66; }
/* Fades in during an SPA navigation fetch - lives outside #content (a
content.innerHTML swap would just wipe it out otherwise), positioned
relative to the viewport rather than the resizable content column so
dragging #panelmenu-resizer narrower/wider never throws its centering
off. The transition duration alone (no separate timer) is what keeps
a fast load from ever showing it at a noticeable opacity before the
class comes back off. */
.spa-loading-indicator {
position: fixed;
top: 90px;
left: 50%;
transform: translateX(-50%);
color: var(--bond-text-dim);
font-size: 10pt;
letter-spacing: 1px;
opacity: 0;
transition: opacity 0.6s ease;
pointer-events: none;
z-index: 500;
}
.spa-loading-indicator.spa-loading-visible {
opacity: 1;
}
/* Fades in during an SPA navigation fetch - lives outside #content (a
content.innerHTML swap would just wipe it out otherwise), positioned
relative to the viewport rather than the resizable content column so
dragging #panelmenu-resizer narrower/wider never throws its centering
off. The transition duration alone (no separate timer) is what keeps
a fast load from ever showing it at a noticeable opacity before the
class comes back off. */
.spa-loading-indicator {
position: fixed;
top: 90px;
left: 50%;
transform: translateX(-50%);
color: var(--bond-text-dim);
font-size: 10pt;
letter-spacing: 1px;
opacity: 0;
transition: opacity 0.6s ease;
pointer-events: none;
z-index: 500;
}
.spa-loading-indicator.spa-loading-visible {
opacity: 1;
}
/* Keeps the music/library/ianslibrary subpages pinned to the browser
window's height (footer always visible, no whole-page scroll) while
the song list itself scrolls internally - the exact same pattern
already proven for the email app's own message list
(.pageclass:has(#email-app)), just scoped to this marker instead and
adapted for <sectionframe>'s own heading-then-contents structure
(the heading needs to stay a fixed size above the scrolling list,
not get swept into the same scroll region). height:100% has to be
set explicitly at every level down to .music-song-list itself -
percentage heights only resolve against an ancestor with its own
definite height, and a plain block element's default is auto, which
does not count, so skipping any one level here would silently break
the whole chain. #main-subpage (main.page's generic per-subpage
wrapper, between #content and .sectionframe) is exactly that kind of
skip - missing it let .sectionframe's height:100% resolve to auto,
so .music-song-list sized itself to its full content height instead
of a scrollable box, and the overflow got clipped by .pageclass's
own overflow:hidden with no scrollbar to show for it. */
.pageclass:has(.music-song-list) {
height: calc(100vh - 150px);
overflow: hidden;
}
#content:has(.music-song-list) {
height: 100%;
overflow: hidden;
}
#main-subpage:has(.music-song-list) {
height: 100%;
overflow: hidden;
}
.sectionframe:has(.music-song-list) {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
box-sizing: border-box;
}
.sectionframe:has(.music-song-list) .sectionframecontents {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
overflow: hidden;
}
.music-song-list {
flex: 1;
min-height: 0;
overflow-y: auto;
}
/* Fades in during an SPA navigation fetch - lives outside #content (a
content.innerHTML swap would just wipe it out otherwise), positioned
relative to the viewport rather than the resizable content column so
dragging #panelmenu-resizer narrower/wider never throws its centering
off. The transition duration alone (no separate timer) is what keeps
a fast load from ever showing it at a noticeable opacity before the
class comes back off. */
.spa-loading-indicator {
position: fixed;
top: 90px;
left: 50%;
transform: translateX(-50%);
color: var(--bond-text-dim);
font-size: 10pt;
letter-spacing: 1px;
opacity: 0;
transition: opacity 0.6s ease;
pointer-events: none;
z-index: 500;
}
.spa-loading-indicator.spa-loading-visible {
opacity: 1;
}
/* Global persistent music player band - slides open only while playing */
.globalplayer-band {
max-height: 0;
overflow: hidden;
display: flex;
align-items: center;
gap: 10px;
background: var(--bond-panel);
border-bottom: 1pt solid var(--bond-line);
padding: 0 16px;
box-sizing: border-box;
transition: max-height 0.3s ease, padding 0.3s ease;
}
.globalplayer-band.globalplayer-open {
max-height: 54px;
padding: 10px 16px;
}
.globalplayer-title {
position: relative;
flex: 1;
/* A flex item's default min-width is its content's own min-content
size, not 0 - without this, a long song name would force the whole
LCD panel wider (squeezing the volume slider/buttons) rather than
actually truncating against the space it is given. */
min-width: 0;
display: flex;
flex-direction: column;
justify-content: center;
background: #000;
border: 1px solid #333;
border-radius: 4px;
padding: 4px 10px;
box-sizing: border-box;
box-shadow: inset 0 0 8px rgba(26,143,196,0.12), inset 0 2px 4px rgba(0,0,0,0.8);
}
.globalplayer-duration {
position: absolute;
top: 4px;
right: 8px;
font-family: 'Consolas', 'Courier New', monospace;
font-size: 10pt;
color: #1a8fc4;
text-shadow: 0 0 4px rgba(26,143,196,0.7);
opacity: 0.85;
}
.globalplayer-random-indicator {
position: absolute;
top: 20px;
right: 8px;
font-family: 'Consolas', 'Courier New', monospace;
font-size: 7pt;
letter-spacing: 1px;
color: #1a8fc4;
text-shadow: 0 0 4px rgba(26,143,196,0.7);
opacity: 0.85;
display: none;
}
.globalplayer-random-indicator.globalplayer-random-indicator-visible {
display: block;
}
.globalplayer-title-text {
font-family: 'Consolas', 'Courier New', monospace;
font-size: 20pt;
line-height: 1.1;
color: #1a8fc4;
text-shadow: 0 0 5px rgba(26,143,196,0.8), 0 0 1px rgba(26,143,196,0.9);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.globalplayer-progress {
position: relative;
height: 8px;
width: 100%;
background: rgba(26,143,196,0.15);
border-radius: 4px;
margin-top: 4px;
box-sizing: border-box;
cursor: pointer;
touch-action: none;
}
.globalplayer-progress-fill {
height: 100%;
width: 0%;
background: #1a8fc4;
border-radius: 4px 0 0 4px;
box-shadow: 0 0 4px rgba(26,143,196,0.8);
transition: width 0.2s linear;
pointer-events: none;
}
.globalplayer-progress-handle {
position: absolute;
top: 50%;
left: 0%;
width: 12px;
height: 12px;
border-radius: 50%;
background: radial-gradient(circle at 35% 30%, #fff6d0 0%, #d4af37 55%, #6b5313 100%);
border: 1px solid #5a4410;
box-shadow: 0 1px 3px rgba(0,0,0,0.7);
transform: translate(-50%, -50%);
transition: left 0.2s linear;
pointer-events: none;
}
.globalplayer-progress.globalplayer-progress-dragging .globalplayer-progress-fill,
.globalplayer-progress.globalplayer-progress-dragging .globalplayer-progress-handle {
transition: none;
}
/* Square, touch-tone-style buttons for the player band - same dished
gold-on-black look as the sipphone tag's dialpad keys. */
.globalplayer-btn {
flex-shrink: 0;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
background: radial-gradient(circle at 50% 50%, #8a6a22 0%, #b8903a 32%, #d4af37 55%, #ecce79 80%, #fff6d0 100%);
border: 1px solid #5a4410;
box-shadow:
0 2px 0 #4a3a0f,
0 3px 5px rgba(0,0,0,0.5),
inset 0 3px 5px rgba(0,0,0,0.45),
inset 0 -1px 1px rgba(255,255,255,0.5);
color: #3a2d05;
cursor: pointer;
transition: transform 0.06s ease, box-shadow 0.06s ease;
}
.globalplayer-btn svg { width: 16px; height: 16px; }
.globalplayer-btn:active {
transform: translateY(2px);
box-shadow:
inset 0 4px 8px rgba(0,0,0,0.6),
inset 0 -1px 1px rgba(255,255,255,0.3);
}
.globalplayer-btn-text {
width: auto;
padding: 0 12px;
font-size: 10px;
font-weight: bold;
letter-spacing: 1px;
white-space: nowrap;
}
/* Stereo FFT-style bar graph - left channel above the midline, right
channel below it, drawn directly onto a small canvas. */
.globalplayer-eq {
flex-shrink: 0;
width: 60px;
height: 32px;
background: #000;
border: 1px solid #333;
border-radius: 4px;
}
/* Playlist dropdown - its own independent sliding strip directly below
the player band, NOT nested inside it: the band's own overflow:hidden
(needed for its slide animation) would otherwise clip anything
positioned to pop out below it, which is why this was invisible
before despite the open/close class toggling correctly in JS. */
.globalplayer-queue {
max-height: 0;
overflow: hidden;
background: var(--bond-panel-2);
border-bottom: 1pt solid var(--bond-line);
transition: max-height 0.25s ease;
}
.globalplayer-queue.globalplayer-queue-open {
max-height: 240px;
overflow-y: auto;
}
.globalplayer-queue-item {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin: 6px 10px;
padding: 8px 14px;
border: 1px solid var(--bond-line);
border-radius: 8px;
background: rgba(255,255,255,0.03);
color: var(--bond-text-dim);
}
.globalplayer-queue-name {
font-size: 18pt;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.globalplayer-queue-left {
display: flex;
align-items: center;
gap: 8px;
flex: 1;
min-width: 0;
}
.globalplayer-queue-handle {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
color: var(--bond-text-dim);
cursor: grab;
}
.globalplayer-queue-handle svg {
width: 14px;
height: 14px;
}
.globalplayer-queue-item.globalplayer-queue-dragging {
opacity: 0.4;
}
.globalplayer-queue-item.globalplayer-queue-dragover {
border-top: 2px solid var(--bond-gold-bright);
}
.globalplayer-queue-right {
flex-shrink: 0;
display: flex;
align-items: center;
gap: 8px;
}
.globalplayer-queue-duration {
flex-shrink: 0;
font-size: 9pt;
opacity: 0.75;
}
.globalplayer-queue-remove {
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
padding: 0;
margin: 0;
border-radius: 6px;
border: 1px solid var(--bond-line);
background: linear-gradient(180deg, #1c1c24, #131318);
color: var(--bond-text-dim);
cursor: pointer;
transition: box-shadow 0.2s ease, background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}
.globalplayer-queue-remove svg {
width: 12px;
height: 12px;
display: block;
}
.globalplayer-queue-remove:hover {
border-color: var(--bond-red);
color: var(--bond-red);
box-shadow: 0 0 0.5em rgba(161,58,58,0.35);
background: linear-gradient(180deg, #24242e, #1a1a20);
}
.globalplayer-queue-item.globalplayer-queue-current {
color: var(--bond-gold-bright);
font-weight: 600;
border-color: var(--bond-gold);
background: rgba(212,175,55,0.08);
}
/* Tactile feedback for clicking a song to queue it: an immediate flash
on the row, plus a lasting checkmark so it is clear at a glance which
songs are already in the queue. */
/* Scoped to the name span, not the row itself: the row is a flex
container with justify-content:space-between, and a ::before on it
directly becomes its own flex item - with 3 items instead of 2, the
name ends up looking centered between the checkmark and the duration/
remove group instead of staying left-aligned. Putting it on the name
span keeps it as ordinary inline content inside that one flex item. */
.song-queued .music-song-name::before {
content: "\2713 ";
color: var(--bond-gold-bright);
}
.song-queued-flash {
animation: songQueuedFlash 0.6s ease;
}
@keyframes songQueuedFlash {
0% { background: var(--bond-gold-bright); color: var(--bond-bg); }
100% { background: transparent; }
}
/* Song-picker rows (music/jukebox subpages) - same boxed, rounded-corner
look as the playlist dropdown's own entries, for visual consistency
between "songs you can pick" and "what's in the queue". */
.music-song-row {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 10px;
margin: 4px 0;
padding: 5px 10px;
border: 1px solid var(--bond-line);
border-radius: 8px;
background: rgba(255,255,255,0.03);
color: var(--bond-text-dim);
cursor: pointer;
}
.music-song-row:hover {
border-color: var(--bond-gold);
background: rgba(255,255,255,0.06);
}
.music-song-name {
font-size: 12pt;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.music-song-duration {
flex-shrink: 0;
font-size: 8pt;
opacity: 0.75;
}
/* Volume slider - a small gold knob riding a thin gold-tinted track */
.globalplayer-volume {
-webkit-appearance: none;
appearance: none;
flex-shrink: 0;
width: 70px;
height: 4px;
border-radius: 2px;
background: var(--bond-line);
outline: none;
cursor: pointer;
}
.globalplayer-volume::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 14px;
height: 14px;
border-radius: 50%;
background: radial-gradient(circle at 35% 30%, #fff6d0 0%, #d4af37 55%, #6b5313 100%);
border: 1px solid #5a4410;
box-shadow: 0 1px 2px rgba(0,0,0,0.6);
cursor: pointer;
}
.globalplayer-volume::-moz-range-track {
height: 4px;
border-radius: 2px;
background: var(--bond-line);
}
.globalplayer-volume::-moz-range-thumb {
width: 14px;
height: 14px;
border-radius: 50%;
background: radial-gradient(circle at 35% 30%, #fff6d0 0%, #d4af37 55%, #6b5313 100%);
border: 1px solid #5a4410;
box-shadow: 0 1px 2px rgba(0,0,0,0.6);
cursor: pointer;
}
+28
View File
@@ -1,6 +1,7 @@
(function() { (function() {
var content = document.getElementById('content'); var content = document.getElementById('content');
var form = document.getElementById('mainform'); var form = document.getElementById('mainform');
var loadingIndicator = document.getElementById('spa-loading-indicator');
// Lives outside #content (a sibling in the persistent shell, next to // Lives outside #content (a sibling in the persistent shell, next to
// the menu bar/form) - a fragment swap never touches it on its own, // the menu bar/form) - a fragment swap never touches it on its own,
// so a per-page side menu would otherwise stay frozen on whichever // so a per-page side menu would otherwise stay frozen on whichever
@@ -220,6 +221,12 @@
function navigate(url, push) { function navigate(url, push) {
var sep = url.indexOf('?') === -1 ? '?' : '&'; var sep = url.indexOf('?') === -1 ? '?' : '&';
content.classList.add('spa-fading'); content.classList.add('spa-fading');
// Opacity transition alone (see the CSS) means a fetch that resolves
// quickly never gets the indicator past a barely-visible opacity
// before this removes the class again - exactly the "do not flash
// this for a fast load" behavior wanted, with no separate delay
// timer needed to achieve it.
if (loadingIndicator) loadingIndicator.classList.add('spa-loading-visible');
Promise.all([ Promise.all([
fetch(url + sep + '_fragment=1', { credentials: 'same-origin' }).then(function(r) { return r.text(); }), fetch(url + sep + '_fragment=1', { credentials: 'same-origin' }).then(function(r) { return r.text(); }),
delay(180) delay(180)
@@ -233,6 +240,7 @@
syncActiveTab(finalUrl.split('?')[0]); syncActiveTab(finalUrl.split('?')[0]);
} }
content.classList.remove('spa-fading'); content.classList.remove('spa-fading');
if (loadingIndicator) loadingIndicator.classList.remove('spa-loading-visible');
}); });
} }
@@ -254,6 +262,7 @@
var subpage = fd.get('SUBPAGE') || ''; var subpage = fd.get('SUBPAGE') || '';
var url = formPrefix + '/' + page + (subpage ? '/' + subpage : ''); var url = formPrefix + '/' + page + (subpage ? '/' + subpage : '');
content.classList.add('spa-fading'); content.classList.add('spa-fading');
if (loadingIndicator) loadingIndicator.classList.add('spa-loading-visible');
Promise.all([ Promise.all([
fetch(url + '?_fragment=1', { fetch(url + '?_fragment=1', {
method: 'POST', method: 'POST',
@@ -271,6 +280,7 @@
syncActiveTab(finalUrl.split('?')[0]); syncActiveTab(finalUrl.split('?')[0]);
} }
content.classList.remove('spa-fading'); content.classList.remove('spa-fading');
if (loadingIndicator) loadingIndicator.classList.remove('spa-loading-visible');
}); });
}); });
} }
@@ -279,6 +289,24 @@
navigate(window.location.pathname + window.location.search, false); navigate(window.location.pathname + window.location.search, false);
}); });
// Instant visual feedback on a side-menu click - without this, the
// active-item highlight only updated once applyResponse() swapped in
// the new #_spa_panelmenu markup after the fetch finished, which read
// as unresponsive (the click did nothing visible until the whole
// subpage had already loaded). That server-rendered swap is still the
// authoritative source of truth and will correct this on arrival (e.g.
// if a click ends up redirected somewhere else entirely), so this is
// purely an optimistic bridge, not a second source of truth.
if (panelMenu) {
panelMenu.addEventListener('click', function(e) {
var a = e.target.closest('a');
if (!a || !panelMenu.contains(a)) return;
var current = panelMenu.querySelector('.submenuitem-active');
if (current) current.classList.remove('submenuitem-active');
a.classList.add('submenuitem-active');
});
}
// Drag-to-resize for the side menu (#panelmenu) against the main // Drag-to-resize for the side menu (#panelmenu) against the main
// content column - the resizer bar (#panelmenu-resizer) lives in the // content column - the resizer bar (#panelmenu-resizer) lives in the
// persistent shell right alongside panelMenu itself (see its own // persistent shell right alongside panelMenu itself (see its own
+421
View File
@@ -0,0 +1,421 @@
<tag name="sipphone">
<style>
.sipphone-bond {
width: 360px;
margin: 10px 0 24px 0;
padding: 14px;
border-radius: 16px;
background: linear-gradient(160deg, #1a1a1a 0%, #060606 60%, #000 100%);
border: 1px solid #000;
box-shadow:
0 0 0 2px #2a2a2a,
0 0 0 3px #b8860b,
0 10px 30px rgba(0,0,0,0.6),
inset 0 1px 0 rgba(255,255,255,0.05);
font-family: 'Segoe UI', Arial, sans-serif;
color: #d4af37;
}
.sipphone-bond .sipphone-brand {
text-align: center;
font-size: 10px;
letter-spacing: 4px;
color: #d4af37;
text-shadow: 0 0 6px rgba(212,175,55,0.6);
margin-bottom: 6px;
}
.sipphone-bond .sipphone-lcd {
background: #000;
border: 2px solid #333;
border-radius: 4px;
padding: 8px 10px;
margin-bottom: 10px;
font-family: 'Consolas', 'Courier New', monospace;
color: #39ff6a;
text-shadow: 0 0 5px rgba(57,255,106,0.8), 0 0 1px rgba(57,255,106,0.9);
font-size: 13px;
line-height: 1.5;
min-height: 56px;
box-shadow: inset 0 0 12px rgba(57,255,106,0.15), inset 0 2px 6px rgba(0,0,0,0.8);
position: relative;
overflow: hidden;
}
.sipphone-bond .sipphone-lcd::before {
content: "";
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: repeating-linear-gradient(
to bottom,
rgba(0,0,0,0.15) 0px,
rgba(0,0,0,0.15) 1px,
transparent 1px,
transparent 3px
);
pointer-events: none;
}
.sipphone-bond .sipphone-lcd-line1 { font-size: 30px; font-weight: bold; line-height: 1.2; }
.sipphone-bond .sipphone-lcd-line2 { opacity: 0.85; }
.sipphone-bond .sipphone-video-wrap {
position: relative;
width: 100%;
height: 180px;
background: #000;
border: 1px solid #333;
border-radius: 4px;
margin-bottom: 10px;
overflow: hidden;
display: none;
}
.sipphone-bond .sipphone-video-wrap.active { display: block; }
.sipphone-bond .sipphone-remote-video {
width: 100%;
height: 100%;
object-fit: cover;
background: #000;
}
.sipphone-bond .sipphone-local-video {
position: absolute;
width: 72px;
height: 54px;
right: 6px;
bottom: 6px;
border: 1px solid #d4af37;
border-radius: 3px;
object-fit: cover;
background: #111;
}
.sipphone-bond .sipphone-dialpad {
display: grid;
grid-template-columns: repeat(3, 44px);
justify-content: center;
gap: 8px;
margin-bottom: 10px;
}
.sipphone-bond .sipphone-key {
user-select: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
border-radius: 8px;
font-size: 16px;
font-weight: bold;
color: #3a2d05;
background: radial-gradient(circle at 50% 50%, #8a6a22 0%, #b8903a 32%, #d4af37 55%, #ecce79 80%, #fff6d0 100%);
border: 1px solid #5a4410;
box-shadow:
0 2px 0 #4a3a0f,
0 4px 6px rgba(0,0,0,0.6),
inset 0 3px 5px rgba(0,0,0,0.45),
inset 0 -1px 1px rgba(255,255,255,0.5);
transition: transform 0.06s ease, box-shadow 0.06s ease;
}
.sipphone-bond .sipphone-key:active {
transform: translateY(2px);
box-shadow:
inset 0 4px 8px rgba(0,0,0,0.6),
inset 0 -1px 1px rgba(255,255,255,0.3);
}
.sipphone-bond .sipphone-controls {
display: flex;
gap: 8px;
}
.sipphone-bond .sipphone-btn {
flex: 1;
cursor: pointer;
text-align: center;
padding: 9px 0;
border-radius: 8px;
font-size: 12px;
font-weight: bold;
letter-spacing: 1px;
color: #3a2d05;
background: linear-gradient(180deg, #f3d77a 0%, #d4af37 45%, #9c7a1f 100%);
border: 1px solid #5a4410;
box-shadow: 0 2px 0 #4a3a0f, 0 4px 8px rgba(0,0,0,0.6), inset 0 1px 1px rgba(255,255,255,0.7);
}
.sipphone-bond .sipphone-btn.sipphone-hangup {
background: linear-gradient(180deg, #e06666 0%, #a30000 60%, #6b0000 100%);
color: #2a0000;
border-color: #3a0000;
}
.sipphone-bond .sipphone-btn:active {
transform: translateY(2px);
box-shadow: inset 0 1px 3px rgba(0,0,0,0.5);
}
.sipphone-bond .sipphone-btn.sipphone-btn-disabled {
cursor: default;
opacity: 0.35;
filter: grayscale(70%);
box-shadow: none;
pointer-events: none;
}
.sipphone-bond .sipphone-lcd-status-offline {
color: #ff3b3b;
text-shadow: 0 0 6px rgba(255,59,59,0.8);
}
.sipphone-bond .sipphone-status-dot {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 6px;
background: #666;
box-shadow: 0 0 4px #666;
}
.sipphone-bond .sipphone-status-dot.reg {
background: #39ff6a;
box-shadow: 0 0 6px #39ff6a;
}
.sipphone-bond .sipphone-status-dot.incall {
background: #ffcc00;
box-shadow: 0 0 6px #ffcc00;
}
</style>
<sql>select id, exten, secret from phones.extensions where user_id=$[_login_id] and secret is not null</sql>
<ifrow>
<whilerow>
<div class="sipphone-bond" id="sipphone-$[.id]"
data-sipphone-id="$[.id]"
data-sipphone-exten="$[.exten]"
data-sipphone-secret="$[.secret]"
data-sipphone-domain="barant.com"
data-sipphone-wss="wss://barant.com:8089/ws">
<div class="sipphone-brand">&#9670;&nbsp;B · A · R · A · N · T&nbsp;&#9670;</div>
<div class="sipphone-lcd">
<div class="sipphone-lcd-line1" data-role="lcd-line1">$[.exten]</div>
<div class="sipphone-lcd-line2" data-role="lcd-line2"><span class="sipphone-status-dot" data-role="status-dot"></span><span data-role="lcd-status">OFFLINE</span></div>
</div>
<div class="sipphone-video-wrap" data-role="video-wrap">
<video class="sipphone-remote-video" data-role="remote-video" autoplay playsinline></video>
<video class="sipphone-local-video" data-role="local-video" autoplay playsinline muted></video>
</div>
<div class="sipphone-dialpad" data-role="dialpad">
<div class="sipphone-key" data-digit="1">1</div>
<div class="sipphone-key" data-digit="2">2</div>
<div class="sipphone-key" data-digit="3">3</div>
<div class="sipphone-key" data-digit="4">4</div>
<div class="sipphone-key" data-digit="5">5</div>
<div class="sipphone-key" data-digit="6">6</div>
<div class="sipphone-key" data-digit="7">7</div>
<div class="sipphone-key" data-digit="8">8</div>
<div class="sipphone-key" data-digit="9">9</div>
<div class="sipphone-key" data-digit="*">*</div>
<div class="sipphone-key" data-digit="0">0</div>
<div class="sipphone-key" data-digit="#">#</div>
</div>
<div class="sipphone-controls">
<div class="sipphone-btn" data-role="call-hangup-btn">CALL</div>
<div class="sipphone-btn" data-role="video-toggle-btn">VIDEO: OFF</div>
</div>
</div>
</whilerow>
<script type="module">
import * as SIP from "https://cdn.jsdelivr.net/npm/sip.js@0.21.2/lib/index.min.js";
(function() {
function initSipPhone(root) {
var exten = root.dataset.sipphoneExten;
var secret = root.dataset.sipphoneSecret;
var domain = root.dataset.sipphoneDomain;
var wss = root.dataset.sipphoneWss;
var dialedDigits = "";
var currentSession = null;
var videoEnabled = false;
var isRegistered = false;
var previewStream = null;
var lcdLine1 = root.querySelector('[data-role="lcd-line1"]');
var lcdStatus = root.querySelector('[data-role="lcd-status"]');
var statusDot = root.querySelector('[data-role="status-dot"]');
var videoWrap = root.querySelector('[data-role="video-wrap"]');
var remoteVideo = root.querySelector('[data-role="remote-video"]');
var localVideo = root.querySelector('[data-role="local-video"]');
var callHangupBtn = root.querySelector('[data-role="call-hangup-btn"]');
var videoToggleBtn = root.querySelector('[data-role="video-toggle-btn"]');
function setLcd(line1, status, dotClass) {
if (line1 !== undefined) lcdLine1.textContent = line1;
if (status !== undefined) lcdStatus.textContent = status;
statusDot.className = "sipphone-status-dot" + (dotClass ? (" " + dotClass) : "");
}
function updateCallButton() {
if (currentSession) {
callHangupBtn.textContent = "END";
callHangupBtn.classList.add("sipphone-hangup");
callHangupBtn.classList.remove("sipphone-btn-disabled");
} else {
callHangupBtn.textContent = "CALL";
callHangupBtn.classList.remove("sipphone-hangup");
callHangupBtn.classList.toggle("sipphone-btn-disabled", !isRegistered || !dialedDigits);
}
lcdStatus.classList.toggle("sipphone-lcd-status-offline", !isRegistered);
}
var ua = new SIP.UserAgent({
uri: SIP.UserAgent.makeURI("sip:" + exten + "@" + domain),
transportOptions: { server: wss },
authorizationUsername: exten,
authorizationPassword: secret,
logLevel: "error",
delegate: {
onInvite: function(invitation) {
currentSession = invitation;
updateCallButton();
setLcd("INCOMING CALL", "RINGING", "incall");
attachSessionHandlers(invitation);
invitation.accept({
sessionDescriptionHandlerOptions: {
constraints: { audio: true, video: videoEnabled }
}
}).then(function() {
setLcd(exten, "IN CALL", "incall");
videoWrap.classList.add("active");
attachMedia(invitation);
});
}
}
});
var registerer = new SIP.Registerer(ua);
updateCallButton();
ua.start().then(function() {
return registerer.register();
}).then(function() {
isRegistered = true;
setLcd(exten, "READY", "reg");
updateCallButton();
}).catch(function() {
isRegistered = false;
setLcd(exten, "REG FAILED", "");
updateCallButton();
});
function stopPreview() {
if (previewStream) {
previewStream.getTracks().forEach(function(t) { t.stop(); });
previewStream = null;
}
}
function startPreview() {
if (previewStream || currentSession) return;
navigator.mediaDevices.getUserMedia({ video: true }).then(function(stream) {
if (!videoEnabled || currentSession) {
stream.getTracks().forEach(function(t) { t.stop(); });
return;
}
previewStream = stream;
localVideo.srcObject = stream;
videoWrap.classList.add("active");
}).catch(function() {
videoEnabled = false;
videoToggleBtn.textContent = "VIDEO: OFF";
});
}
function attachMedia(session) {
stopPreview();
var pc = session.sessionDescriptionHandler.peerConnection;
var remoteStream = new MediaStream();
pc.getReceivers().forEach(function(receiver) {
if (receiver.track) remoteStream.addTrack(receiver.track);
});
remoteVideo.srcObject = remoteStream;
var localStream = new MediaStream();
pc.getSenders().forEach(function(sender) {
if (sender.track) localStream.addTrack(sender.track);
});
localVideo.srcObject = localStream;
}
function attachSessionHandlers(session) {
session.stateChange.addListener(function(state) {
if (state === SIP.SessionState.Established) {
setLcd(undefined, "IN CALL", "incall");
videoWrap.classList.add("active");
attachMedia(session);
} else if (state === SIP.SessionState.Terminated) {
setLcd(exten, "READY", "reg");
videoWrap.classList.remove("active");
remoteVideo.srcObject = null;
localVideo.srcObject = null;
currentSession = null;
dialedDigits = "";
updateCallButton();
}
});
}
root.querySelectorAll('[data-digit]').forEach(function(key) {
key.addEventListener('click', function() {
var d = key.dataset.digit;
if (currentSession) {
currentSession.sessionDescriptionHandler.sendDtmf(d);
} else {
dialedDigits += d;
setLcd(dialedDigits || exten, dialedDigits ? "DIALING" : "READY", dialedDigits ? "" : "reg");
updateCallButton();
}
});
});
callHangupBtn.addEventListener('click', function() {
if (!currentSession) {
if (!dialedDigits || !isRegistered) return;
var target = SIP.UserAgent.makeURI("sip:" + dialedDigits + "@" + domain);
var inviter = new SIP.Inviter(ua, target, {
sessionDescriptionHandlerOptions: {
constraints: { audio: true, video: videoEnabled }
}
});
currentSession = inviter;
updateCallButton();
attachSessionHandlers(inviter);
setLcd(dialedDigits, "CALLING...", "incall");
inviter.invite();
} else {
if (currentSession.state === SIP.SessionState.Established) {
currentSession.bye();
} else if (currentSession instanceof SIP.Inviter) {
currentSession.cancel();
} else {
currentSession.reject();
}
}
});
videoToggleBtn.addEventListener('click', function() {
videoEnabled = !videoEnabled;
videoToggleBtn.textContent = "VIDEO: " + (videoEnabled ? "ON" : "OFF");
if (currentSession) return;
if (videoEnabled) {
startPreview();
} else {
stopPreview();
localVideo.srcObject = null;
videoWrap.classList.remove("active");
}
});
}
document.querySelectorAll('.sipphone-bond').forEach(initSipPhone);
})();
</script>
</ifrow>
</tag>
+83
View File
@@ -0,0 +1,83 @@
<sectionframe title="Account Information">
<sql>select * from users where id=$[_login_id]</sql>
<table>
<tr><th class="left">Name:</th><td class="right">$[.name]</td></tr>
<if value1="$[company_name]" value2="" type="ne">
<tr><th class="left">Company Name:</th><td class="right">$[.company_name]</td></tr>
</if>
<tr><th class="left">E-Mail:</th><td class="right">$[.email]</td></tr>
</table>
</sectionframe>
<sql>select * from user_messages where user_id=$[_login_id]</sql>$[sqlerror]
<ifrow>
<sectionframe title="Messages">
<table>
<whilerow>
<tr>
<td>$[.message]</td>
<td>$[.link]</td>
</tr>
</whilerow>
</table>
</sectionframe>
</ifrow>
<sql>select *
from virtual_machines
join products on virtual_machines.sku=products.sku
where user_id=$[_login_id]</sql>
<ifrow>
<sectionframe title="Virtual Machines">
<whilerow>
<div style="margin-bottom: 3px; border: 1pt solid #000; border-radius: 5px;">
<div style="float: left; padding: 2px 5px 0px 5px; vertical-align: middle; display: inline-block;"><img src="$[.image]" width="40"></div>
<div style="float: left; background: #ccf; width: 300px; padding: 0px 0px 0px 0px;"><span style="font-size: 7pt;">Ubuntu Server 22.04 LTE</span>
<br><span style="font-size: 9pt;"><b>barant.com</b></span>
<br><span style="font-size: 7pt;">IP:</span> <span style="font-size: 9pt; font-family: monospace;">74.80.233.78</span></div>
<div style="float: right; padding: 5px;"><img src="/assets/power_on.png" width="32"></div>
<div style="float: right; width: 90px; height: 48px; background: #444;"></div>
<div style="float: right; margin-right: 25px;">3 days 2:10:33<br><br>34% of 40.2GB</div>
<div style="clear: both;"></div>
</div>
</whilerow>
</sectionframe>
</ifrow>
<sql>select *
from files
join products on files.sku=products.sku
where user_id=$[_login_id]</sql>
<ifrow>
<sectionframe title="Downloadable Content">
<p>Content that has been purchased and can be downloaded is displayed
below. Click on the Download button to begin downloading your files.</p>
<whilerow>
<table style="margin: 3px;">
<tr>
<td>
<img src="$[.image]" width="50px"">
</td>
<td style="width: 300px; border: 1pt inset #888">
$[.description]
</td>
<td style="width: 300px;">
<div>$[license_name]</div><div>$[license_key]</div>
</td>
<td>
<a href="/downloadfile.cgi?sku=$[.sku]"><div class="button">Download</div></a>
</td>
</tr>
</table>
</whilerow>
</sectionframe>
</ifrow>
@@ -0,0 +1,18 @@
<sectionframe title="Invoices">
<if value1="$[@_invoice_id]" value2="" type="ne">
<sql>select user_id, status from invoices where id=$[@_invoice_id]</sql>
<ifrow>
<if expr="('$[.user_id]'='$[_login_id]') and ('$[.status]'='OPEN')">
<div style="margin-bottom: 16px;">
<include file="invoice.method">
<include file="payment.method">
</div>
</if>
</ifrow>
</if>
<div>
<showtable process="selectinvoice" name="invoice_id" value="X">
select id as X,id as 'Invoice ID',date_format(created, '%b %D %Y') as 'Date',amount as 'Amount',status as 'Status' from invoices where user_id=$[_login_id] order by created desc
</showtable>
</div>
</sectionframe>
@@ -0,0 +1,4 @@
<include file="phones.section">
<include file="SIPPHONE.tag">
<sipphone>
+17
View File
@@ -0,0 +1,17 @@
<sectionframe title="ACCOUNT">
<if value1="$[SUBPAGE]" value2="" type="eq">
<linkbutton page="account" class="submenuitem-active">ACCOUNT INFORMATION</linkbutton><br>
<else>
<linkbutton page="account">ACCOUNT INFORMATION</linkbutton><br>
</if>
<if value1="$[SUBPAGE]" value2="phones" type="eq">
<linkbutton page="account" subpage="phones" class="submenuitem-active">PHONES</linkbutton><br>
<else>
<linkbutton page="account" subpage="phones">PHONES</linkbutton><br>
</if>
<if value1="$[SUBPAGE]" value2="invoices" type="eq">
<linkbutton page="account" subpage="invoices" class="submenuitem-active">INVOICES</linkbutton><br>
<else>
<linkbutton page="account" subpage="invoices">INVOICES</linkbutton><br>
</if>
</sectionframe>
+9 -101
View File
@@ -4,108 +4,16 @@
<retain name="download_file"> <retain name="download_file">
<retain name="invoice_id"> <retain name="invoice_id">
<sectionframe title="Account Information"> <div id="account-subpage">
<if value1="$[SUBPAGE]" value2="" type="eq">
<sql>select * from users where id=$[_login_id]</sql> <include file="account-info.subpage">
<table> <else>
<tr><th class="left">Name:</th><td class="right">$[.name]</td></tr> <try>
<if value1="$[company_name]" value2="" type="ne"> <include file="account-$[SUBPAGE].subpage">
<tr><th class="left">Company Name:</th><td class="right">$[.company_name]</td></tr> <catch>
</if> <p>That account section doesn't exist.</p>
<tr><th class="left">E-Mail:</th><td class="right">$[.email]</td></tr> </try>
</table>
</sectionframe>
<sql>select * from user_messages where user_id=$[_login_id]</sql>$[sqlerror]
<ifrow>
<sectionframe title="Messages">
<table>
<whilerow>
<tr>
<td>$[.message]</td>
<td>$[.link]</td>
</tr>
</whilerow>
</table>
</sectionframe>
</ifrow>
<sql>select *
from virtual_machines
join products on virtual_machines.sku=products.sku
where user_id=$[_login_id]</sql>
<ifrow>
<sectionframe title="Virtual Machines">
<whilerow>
<div style="margin-bottom: 3px; border: 1pt solid #000; border-radius: 5px;">
<div style="float: left; padding: 2px 5px 0px 5px; vertical-align: middle; display: inline-block;"><img src="$[.image]" width="40"></div>
<div style="float: left; background: #ccf; width: 300px; padding: 0px 0px 0px 0px;"><span style="font-size: 7pt;">Ubuntu Server 22.04 LTE</span>
<br><span style="font-size: 9pt;"><b>barant.com</b></span>
<br><span style="font-size: 7pt;">IP:</span> <span style="font-size: 9pt; font-family: monospace;">74.80.233.78</span></div>
<div style="float: right; padding: 5px;"><img src="/assets/power_on.png" width="32"></div>
<div style="float: right; width: 90px; height: 48px; background: #444;"></div>
<div style="float: right; margin-right: 25px;">3 days 2:10:33<br><br>34% of 40.2GB</div>
<div style="clear: both;"></div>
</div>
</whilerow>
</sectionframe>
</ifrow>
<include file="phones.section">
<sql>select *
from files
join products on files.sku=products.sku
where user_id=$[_login_id]</sql>
<ifrow>
<sectionframe title="Downloadable Content">
<p>Content that has been purchased and can be downloaded is displayed
below. Click on the Download button to begin downloading your files.</p>
<whilerow>
<table style="margin: 3px;">
<tr>
<td>
<img src="$[.image]" width="50px"">
</td>
<td style="width: 300px; border: 1pt inset #888">
$[.description]
</td>
<td style="width: 300px;">
<div>$[license_name]</div><div>$[license_key]</div>
</td>
<td>
<a href="/downloadfile.cgi?sku=$[.sku]"><div class="button">Download</div></a>
</td>
</tr>
</table>
</whilerow>
</sectionframe>
</ifrow>
<sectionframe title="Invoices">
<div style="display: flex;">
<div style="display: inline-block; padding: 0px 10px 0px 0px;">
<showtable process="selectinvoice" name="invoice_id" value="X">
select id as X,id as 'Invoice ID',date_format(created, '%b %D %Y') as 'Date',amount as 'Amount',status as 'Status' from invoices where user_id=$[_login_id]
</showtable>
</div>
<if value1="$[_invoice_id]" value2="" type="ne">
<div>
<include file="invoice.method">
<include file="payment.method">
</div>
</if> </if>
</div> </div>
</sectionframe>
</contents> </contents>
</page> </page>
+13 -1
View File
@@ -93,6 +93,16 @@
box-shadow: 0 0 0.4em rgba(197, 164, 90, 0.25); box-shadow: 0 0 0.4em rgba(197, 164, 90, 0.25);
transition: box-shadow 0.2s ease, background 0.2s ease, transform 0.1s ease; transition: box-shadow 0.2s ease, background 0.2s ease, transform 0.1s ease;
} }
/* .icon-btn's own display:inline-flex is a plain class selector -
same specificity as the browser's own [hidden]{display:none} UA
default, and an author rule always wins that tie regardless of
source order - confirmed as a real, previously-shipped bug on a
different site this same session (a hidden modal that stayed
visible for the exact same reason). Without this, the empty-folder
button's `hidden` attribute would be set correctly but silently
ignored, leaving it visible on every folder instead of only
Spam/Trash. */
.icon-btn[hidden] { display: none; }
.icon-btn svg { width: 16px; height: 16px; display: block; } .icon-btn svg { width: 16px; height: 16px; display: block; }
.icon-btn:hover { .icon-btn:hover {
box-shadow: 0 0 0.8em rgba(197, 164, 90, 0.5), 0 0 0.25em rgba(227, 196, 126, 0.55); box-shadow: 0 0 0.8em rgba(197, 164, 90, 0.5), 0 0 0.25em rgba(227, 196, 126, 0.55);
@@ -118,12 +128,14 @@
<div id="email-client"> <div id="email-client">
<div id="email-toolbar"> <div id="email-toolbar">
<span id="email-connected-as">$[@_imap_user]</span><span id="email-list-count"></span> <span id="email-connected-as">$[@_imap_user]</span><span id="email-list-count"></span>
<span id="email-pagination"></span>
<span id="email-toolbar-actions"> <span id="email-toolbar-actions">
<span id="email-search-box"> <span id="email-search-box">
<input type="text" id="email-search-input" placeholder="Search mail&hellip;"> <input type="text" id="email-search-input" placeholder="Search mail&hellip;">
<button type="button" id="email-search-btn" class="icon-btn" title="Search"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.35-4.35"/></svg></button> <button type="button" id="email-search-btn" class="icon-btn" title="Search"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.35-4.35"/></svg></button>
</span> </span>
<button type="button" id="email-compose-btn" class="icon-btn" title="New Mail"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6h13a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2z"/><path d="M2.5 7.5 12 14l9.5-6.5"/><path d="M18.5 3.5v5M16 6h5"/></svg></button> <button type="button" id="email-compose-btn" class="icon-btn" title="New Mail"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6h13a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2z"/><path d="M2.5 7.5 12 14l9.5-6.5"/><path d="M18.5 3.5v5M16 6h5"/></svg></button>
<button type="button" id="email-empty-folder-btn" class="icon-btn" title="Permanently empty this folder" hidden><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h16"/><path d="M9 7V4h6v3"/><path d="M6 7l1 13a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2l1-13"/><path d="M9.5 12.5l5 5M14.5 12.5l-5 5"/></svg></button>
<button type="button" id="email-refresh-btn" class="icon-btn" title="Refresh"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M20 11a8 8 0 0 0-14.6-4.4M4 4v5h5"/><path d="M4 13a8 8 0 0 0 14.6 4.4M20 20v-5h-5"/></svg></button> <button type="button" id="email-refresh-btn" class="icon-btn" title="Refresh"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M20 11a8 8 0 0 0-14.6-4.4M4 4v5h5"/><path d="M4 13a8 8 0 0 0 14.6 4.4M20 20v-5h-5"/></svg></button>
<button type="button" id="email-disconnect-btn" class="icon-btn" title="Disconnect"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><path d="M16 17l5-5-5-5"/><path d="M21 12H9"/></svg></button> <button type="button" id="email-disconnect-btn" class="icon-btn" title="Disconnect"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><path d="M16 17l5-5-5-5"/><path d="M21 12H9"/></svg></button>
</span> </span>
@@ -135,4 +147,4 @@
</div> </div>
</if> </if>
</div> </div>
<script src="/assets/email.js?v=20260907b"></script> <script src="/assets/email.js?v=20260926a"></script>
@@ -0,0 +1,46 @@
<include file="invoice.method">
<br>
<linkbutton page="editinvoice"><div class="button">Edit Invoice</div></linkbutton>
<div style="margin-top: 10px; display: flex; align-items: center; gap: 6px;">
<input type="email" id="mail_invoice_email" placeholder="recipient@example.com" style="width: 220px;">
<button type="button" id="mail_invoice_btn" class="button">Mail Invoice</button>
<span id="mail_invoice_status" style="font-size: 12px; color: var(--bond-text-dim);"></span>
</div>
<script>
(function() {
var btn = document.getElementById('mail_invoice_btn');
var input = document.getElementById('mail_invoice_email');
var status = document.getElementById('mail_invoice_status');
if (!btn || !input || !status) return;
btn.addEventListener('click', function() {
var email = input.value.trim();
if (!email) {
status.textContent = 'Enter an e-mail address first.';
status.style.color = '#a13a3a';
return;
}
btn.disabled = true;
status.textContent = 'Sending…';
status.style.color = 'var(--bond-text-dim)';
fetch('/admin/mail-invoice', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ email: email }).toString()
}).then(function(r) { return r.json(); }).then(function(res) {
btn.disabled = false;
if (res.ok) {
status.textContent = 'Invoice emailed to ' + email + '.';
status.style.color = '#6fb8c9';
} else {
status.textContent = res.error || 'Could not send the invoice.';
status.style.color = '#a13a3a';
}
}).catch(function() {
btn.disabled = false;
status.textContent = 'Request failed. Please try again.';
status.style.color = '#a13a3a';
});
});
})();
</script>
+118 -3
View File
@@ -1,5 +1,120 @@
<retain name="invoice_id"> <retain name="invoice_id">
<h3>Invoices</h3> <h3>Invoices</h3>
<showtable page="admin_invoice" process="selectinvoice" name="invoice_id" value="X"> <div style="margin-bottom: 10px;">
select invoices.id as X,invoices.id,user_id,name,invoices.created,amount,invoices.status from invoices join users on invoices.user_id=users.id <button type="button" id="new_invoice_toggle" class="button">+ Create New Invoice</button>
</showtable> <div id="new_invoice_form" style="display: none; margin-top: 8px; align-items: center; gap: 6px;">
<select id="new_invoice_user">
<option value="">Select a customer&hellip;</option>
<sql>select id,name,email from users order by name</sql>
<whilerow>
<option value="$[.id]">$[.name] ($[.email])</option>
</whilerow>
</select>
<button type="button" id="new_invoice_create_btn" class="button">Create</button>
<span id="new_invoice_status" style="font-size: 12px; color: var(--bond-text-dim);"></span>
</div>
</div>
<span id="copy_invoice_status" style="font-size: 12px; color: var(--bond-text-dim);"></span>
<table>
<tr>
<th></th>
<th>id</th>
<th>user_id</th>
<th>name</th>
<th>created</th>
<th>amount</th>
<th>status</th>
<th></th>
</tr>
<sql>select invoices.id,user_id,name,invoices.created,amount,invoices.status from invoices join users on invoices.user_id=users.id</sql>
<whilerow>
<tr>
<td><linkbutton page="admin" subpage="invoice" process="selectinvoice" name="invoice_id" value="$[.id]" class="button">Open</linkbutton></td>
<td>$[.id]</td>
<td>$[.user_id]</td>
<td>$[.name]</td>
<td>$[.created]</td>
<td>$[.amount]</td>
<td>$[.status]</td>
<td><button type="button" class="button copy_invoice_btn" data-invoice-id="$[.id]">Copy</button></td>
</tr>
</whilerow>
</table>
<script>
(function() {
var toggle = document.getElementById('new_invoice_toggle');
var form = document.getElementById('new_invoice_form');
var userSelect = document.getElementById('new_invoice_user');
var createBtn = document.getElementById('new_invoice_create_btn');
var status = document.getElementById('new_invoice_status');
if (!toggle || !form || !userSelect || !createBtn || !status) return;
toggle.addEventListener('click', function() {
form.style.display = form.style.display === 'none' ? 'flex' : 'none';
});
createBtn.addEventListener('click', function() {
var userId = userSelect.value;
if (!userId) {
status.textContent = 'Please select a customer.';
status.style.color = '#a13a3a';
return;
}
createBtn.disabled = true;
status.textContent = 'Creating…';
status.style.color = 'var(--bond-text-dim)';
fetch('/admin/create-invoice', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ user_id: userId }).toString()
}).then(function(r) { return r.json(); }).then(function(res) {
if (res.ok) {
window.location.href = '/editinvoice';
} else {
createBtn.disabled = false;
status.textContent = res.error || 'Could not create the invoice.';
status.style.color = '#a13a3a';
}
}).catch(function() {
createBtn.disabled = false;
status.textContent = 'Request failed. Please try again.';
status.style.color = '#a13a3a';
});
});
var copyStatus = document.getElementById('copy_invoice_status');
document.querySelectorAll('.copy_invoice_btn').forEach(function(btn) {
btn.addEventListener('click', function() {
var sourceId = btn.getAttribute('data-invoice-id');
document.querySelectorAll('.copy_invoice_btn').forEach(function(b) { b.disabled = true; });
if (copyStatus) {
copyStatus.textContent = 'Copying…';
copyStatus.style.color = 'var(--bond-text-dim)';
}
fetch('/admin/copy-invoice', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ source_invoice_id: sourceId }).toString()
}).then(function(r) { return r.json(); }).then(function(res) {
if (res.ok) {
window.location.href = '/editinvoice';
} else {
document.querySelectorAll('.copy_invoice_btn').forEach(function(b) { b.disabled = false; });
if (copyStatus) {
copyStatus.textContent = res.error || 'Could not copy the invoice.';
copyStatus.style.color = '#a13a3a';
}
}
}).catch(function() {
document.querySelectorAll('.copy_invoice_btn').forEach(function(b) { b.disabled = false; });
if (copyStatus) {
copyStatus.textContent = 'Request failed. Please try again.';
copyStatus.style.color = '#a13a3a';
}
});
});
});
})();
</script>
@@ -0,0 +1,98 @@
<h3>Mail Accounts</h3>
<div style="margin-bottom: 10px;">
<button type="button" id="new_mailaccount_toggle" class="button">+ Add Mail Account</button>
<div id="new_mailaccount_form" style="display: none; margin-top: 8px; align-items: center; gap: 6px;">
<input type="text" id="new_mailaccount_host" placeholder="Mail Server" value="mail.barant.com">
<input type="text" id="new_mailaccount_email" placeholder="E-Mail Address">
<input type="password" id="new_mailaccount_password" placeholder="Password">
<button type="button" id="new_mailaccount_create_btn" class="button">Add</button>
<span id="new_mailaccount_status" style="font-size: 12px; color: var(--bond-text-dim);"></span>
</div>
</div>
<table>
<tr>
<th>E-Mail</th>
<th>Server</th>
<th>Added</th>
<th></th>
</tr>
<sql>select id,email,host,created from email_accounts where user_id=$[@_login_id] order by email</sql>
<whilerow>
<tr>
<td>$[.email]</td>
<td>$[.host]</td>
<td>$[.created]</td>
<td><button type="button" class="button remove_mailaccount_btn" data-account-id="$[.id]">Remove</button></td>
</tr>
</whilerow>
</table>
<p style="font-size: 12px; color: var(--bond-text-dim);">Saved accounts automatically reconnect the next time you log in.</p>
<script>
(function() {
var toggle = document.getElementById('new_mailaccount_toggle');
var form = document.getElementById('new_mailaccount_form');
var hostInput = document.getElementById('new_mailaccount_host');
var emailInput = document.getElementById('new_mailaccount_email');
var passwordInput = document.getElementById('new_mailaccount_password');
var createBtn = document.getElementById('new_mailaccount_create_btn');
var status = document.getElementById('new_mailaccount_status');
if (!toggle || !form || !hostInput || !emailInput || !passwordInput || !createBtn || !status) return;
toggle.addEventListener('click', function() {
form.style.display = form.style.display === 'none' ? 'flex' : 'none';
});
createBtn.addEventListener('click', function() {
var host = hostInput.value.trim();
var email = emailInput.value.trim();
var password = passwordInput.value;
if (!host || !email || !password) {
status.textContent = 'Please enter a mail server, e-mail address, and password.';
status.style.color = '#a13a3a';
return;
}
createBtn.disabled = true;
status.textContent = 'Connecting…';
status.style.color = 'var(--bond-text-dim)';
fetch('/admin/add-mail-account', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ mail_host: host, mail_email: email, mail_password: password }).toString()
}).then(function(r) { return r.json(); }).then(function(res) {
if (res.ok) {
window.location.href = '/admin/mailaccounts';
} else {
createBtn.disabled = false;
status.textContent = res.error || 'Could not add the account.';
status.style.color = '#a13a3a';
}
}).catch(function() {
createBtn.disabled = false;
status.textContent = 'Request failed. Please try again.';
status.style.color = '#a13a3a';
});
});
document.querySelectorAll('.remove_mailaccount_btn').forEach(function(btn) {
btn.addEventListener('click', function() {
var accountId = btn.getAttribute('data-account-id');
document.querySelectorAll('.remove_mailaccount_btn').forEach(function(b) { b.disabled = true; });
fetch('/admin/remove-mail-account', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ account_id: accountId }).toString()
}).then(function(r) { return r.json(); }).then(function(res) {
if (res.ok) {
window.location.href = '/admin/mailaccounts';
} else {
document.querySelectorAll('.remove_mailaccount_btn').forEach(function(b) { b.disabled = false; });
}
}).catch(function() {
document.querySelectorAll('.remove_mailaccount_btn').forEach(function(b) { b.disabled = false; });
});
});
});
})();
</script>
+21
View File
@@ -1,8 +1,29 @@
<sectionframe title="ADMINISTRATIVE SUPPORT"> <sectionframe title="ADMINISTRATIVE SUPPORT">
<if value1="$[SUBPAGE]" value2="email" type="eq">
<linkbutton page="admin" subpage="email" class="submenuitem-active">EMAIL</linkbutton><br>
<else>
<linkbutton page="admin" subpage="email">EMAIL</linkbutton><br> <linkbutton page="admin" subpage="email">EMAIL</linkbutton><br>
</if>
<if expr="('$[SUBPAGE]'='invoices') or ('$[SUBPAGE]'='invoice')">
<linkbutton page="admin" subpage="invoices" class="submenuitem-active">INVOICES</linkbutton><br>
<else>
<linkbutton page="admin" subpage="invoices">INVOICES</linkbutton><br> <linkbutton page="admin" subpage="invoices">INVOICES</linkbutton><br>
</if>
<if value1="$[SUBPAGE]" value2="products" type="eq">
<linkbutton page="admin" subpage="products" class="submenuitem-active">PRODUCTS</linkbutton><br>
<else>
<linkbutton page="admin" subpage="products">PRODUCTS</linkbutton><br> <linkbutton page="admin" subpage="products">PRODUCTS</linkbutton><br>
</if>
<if value1="$[SUBPAGE]" value2="users" type="eq">
<linkbutton page="admin" subpage="users" class="submenuitem-active">USERS</linkbutton><br>
<else>
<linkbutton page="admin" subpage="users">USERS</linkbutton><br> <linkbutton page="admin" subpage="users">USERS</linkbutton><br>
</if>
<if value1="$[SUBPAGE]" value2="mailaccounts" type="eq">
<linkbutton page="admin" subpage="mailaccounts" class="submenuitem-active">MAIL ACCOUNTS</linkbutton><br>
<else>
<linkbutton page="admin" subpage="mailaccounts">MAIL ACCOUNTS</linkbutton><br>
</if>
</sectionframe> </sectionframe>
<if value1="$[SUBPAGE]" value2="email" type="eq"> <if value1="$[SUBPAGE]" value2="email" type="eq">
<include file="email.menu"> <include file="email.menu">
+24
View File
@@ -2,10 +2,18 @@
<title>ADMINISTRATION</title> <title>ADMINISTRATION</title>
<contents> <contents>
<if value1="$[SUBPAGE]" value2="email" type="eq"> <if value1="$[SUBPAGE]" value2="email" type="eq">
<if expr="('$[_login_type]'='user')">
<p>Requested page is not found.</p>
<else>
<include file="admin-email.subpage"> <include file="admin-email.subpage">
</if>
<else> <else>
<if value1="$[SUBPAGE]" value2="newemail" type="eq"> <if value1="$[SUBPAGE]" value2="newemail" type="eq">
<if expr="('$[_login_type]'='user')">
<p>Requested page is not found.</p>
<else>
<include file="admin-newemail.subpage"> <include file="admin-newemail.subpage">
</if>
<else> <else>
<if value1="$[SUBPAGE]" value2="invoices" type="eq"> <if value1="$[SUBPAGE]" value2="invoices" type="eq">
<if expr="('$[_login_type]'='user')"> <if expr="('$[_login_type]'='user')">
@@ -13,6 +21,13 @@
<else> <else>
<include file="admin-invoices.subpage"> <include file="admin-invoices.subpage">
</if> </if>
<else>
<if value1="$[SUBPAGE]" value2="invoice" type="eq">
<if expr="('$[_login_type]'='user')">
<p>Requested page is not found.</p>
<else>
<include file="admin-invoice.subpage">
</if>
<else> <else>
<if value1="$[SUBPAGE]" value2="users" type="eq"> <if value1="$[SUBPAGE]" value2="users" type="eq">
<if expr="('$[_login_type]'='user')"> <if expr="('$[_login_type]'='user')">
@@ -27,6 +42,13 @@
<else> <else>
<include file="admin-products.subpage"> <include file="admin-products.subpage">
</if> </if>
<else>
<if value1="$[SUBPAGE]" value2="mailaccounts" type="eq">
<if expr="('$[_login_type]'='user')">
<p>Requested page is not found.</p>
<else>
<include file="admin-mailaccounts.subpage">
</if>
<else> <else>
<if expr="('$[_login_type]'='user')"> <if expr="('$[_login_type]'='user')">
<p>Requested page is not found.</p> <p>Requested page is not found.</p>
@@ -41,5 +63,7 @@
</if> </if>
</if> </if>
</if> </if>
</if>
</if>
</contents> </contents>
</page> </page>
-11
View File
@@ -1,11 +0,0 @@
<page secure="yes" admin="true" loggedin="yes">
<title>INVOICE</title>
<contents>
<eval name="_menu">
<include file="adminmenu.section">
</eval>
<include file="invoice.method">
<br>
<linkbutton page="editinvoice"><div class="button">Edit Invoice</div></linkbutton>
</contents>
</page>
+1 -1
View File
@@ -1,4 +1,4 @@
<sectionframe title="Admin Functions"> <sectionframe title="Admin Functions">
<div><linkbutton page="modular1_1_preset_admin">Modular 1 Presets</linkbutton></div> <div><linkbutton page="modular1_1_preset_admin">Modular 1 Presets</linkbutton></div>
<div><linkbutton page="admin_invoices">Invoices</linkbutton></div> <div><linkbutton page="admin" subpage="invoices">Invoices</linkbutton></div>
</sectionframe> </sectionframe>
+2 -2
View File
@@ -95,7 +95,7 @@
</if> </if>
</tag> </tag>
<tag name="showtable" keywords="sessionid page process name value"> <tag name="showtable" keywords="sessionid page subpage process name value">
<sql sessionid="#[sessionid]"><container></sql>$[sqlerror] <sql sessionid="#[sessionid]"><container></sql>$[sqlerror]
<ifrow sessionid="#[sessionid]"> <ifrow sessionid="#[sessionid]">
<table> <table>
@@ -117,7 +117,7 @@
<set name="field" value="$[?$[index]]"> <set name="field" value="$[?$[index]]">
<if value1="$[field]" value2="X" type="eq"> <if value1="$[field]" value2="X" type="eq">
<td> <td>
<linkbutton page="#[page]" process="#[process]" name="#[name]" value="$[#[value]]" class="button">Open</linkbutton> <linkbutton page="#[page]" subpage="#[subpage]" process="#[process]" name="#[name]" value="$[#[value]]" class="button">Open</linkbutton>
</td> </td>
<else> <else>
<if expr="substring('$[field]',1,1)!='_'"> <if expr="substring('$[field]',1,1)!='_'">
+29
View File
@@ -0,0 +1,29 @@
#api POST /admin/copy-invoice
<set name="host" value="localhost">
<set name="database" value="barant">
<set name="user" value="barant">
<set name="password" value="uversa1960">
<database name="$[database]" host="$[host]" user="$[user]" password="$[password]" sessionid="">
<header name="Content-Type" value="application/json">
<if value1="$[@_login_type]" value2="admin" type="ne">
{"ok":false,"error":"Not authorized."}
<else>
<if value1="$[source_invoice_id]" value2="" type="eq">
{"ok":false,"error":"Please select an invoice to copy."}
<else>
<sql>select * from invoices where id=$[source_invoice_id]</sql>
<ifrow>
<sql>insert into invoices set user_id=$[.user_id], created=now(), amount=$[.amount], status="OPEN"</sql>
<sql>select last_insert_id() as new_invoice_id</sql>
<set name="new_invoice_id" value="$[.new_invoice_id]">
<sql>insert into invoices_detail (invoice_id,sku,sku_suffix,quantity,description,text,price,total,tax_amount,type)
select $[new_invoice_id],sku,sku_suffix,quantity,description,text,price,total,tax_amount,type
from invoices_detail where invoice_id=$[source_invoice_id]</sql>
<set name="@_invoice_id" value="$[new_invoice_id]">
{"ok":true,"invoice_id":$[new_invoice_id]}
<else>
{"ok":false,"error":"Invoice not found."}
</ifrow>
</if>
</if>
</database>
+21
View File
@@ -0,0 +1,21 @@
#api POST /admin/create-invoice
<set name="host" value="localhost">
<set name="database" value="barant">
<set name="user" value="barant">
<set name="password" value="uversa1960">
<database name="$[database]" host="$[host]" user="$[user]" password="$[password]" sessionid="">
<header name="Content-Type" value="application/json">
<if value1="$[@_login_type]" value2="admin" type="ne">
{"ok":false,"error":"Not authorized."}
<else>
<if value1="$[user_id]" value2="" type="eq">
{"ok":false,"error":"Please select a user."}
<else>
<sql>insert into invoices set user_id=$[user_id], created=now(), amount=0.00, status="OPEN"</sql>
<sql>select last_insert_id() as new_invoice_id</sql>
<set name="new_invoice_id" value="$[.new_invoice_id]">
<set name="@_invoice_id" value="$[new_invoice_id]">
{"ok":true,"invoice_id":$[new_invoice_id]}
</if>
</if>
</database>
+100 -46
View File
@@ -3,9 +3,6 @@
<contents> <contents>
<database host="$[host]" name="$[database]" user="$[user]" password="$[password]" sessionid="1"> <database host="$[host]" name="$[database]" user="$[user]" password="$[password]" sessionid="1">
<script> <script>
function checkDetail() {
document.getElementById('detail').style.display=(document.getElementById('sku').value=='***')?'block':'none';
}
function totalInvoice() { function totalInvoice() {
const detail_section = document.getElementById('detail_section'); const detail_section = document.getElementById('detail_section');
const totalsum = document.getElementById('totalsum'); const totalsum = document.getElementById('totalsum');
@@ -13,6 +10,7 @@ function totalInvoice() {
var sum = 0; var sum = 0;
var index = 0; var index = 0;
detail_section.childNodes.forEach((child) => { detail_section.childNodes.forEach((child) => {
if (!child.quantity_z) return;
child.quantity_z.setAttribute('name','quantity' + index); child.quantity_z.setAttribute('name','quantity' + index);
child.sku_z.setAttribute('name','sku' + index); child.sku_z.setAttribute('name','sku' + index);
child.description_z.setAttribute('name','description' + index); child.description_z.setAttribute('name','description' + index);
@@ -31,16 +29,18 @@ function totalInvoice() {
} }
function addLine(qty,skuid,descr,text,prc,tax,tot,typ) { function addLine(qty,skuid,descr,text,prc,tax,tot,typ) {
const lineItem = document.createElement('div'); const lineItem = document.createElement('tr');
lineItem.style.border = "padding: 3px;";
column1 = document.createElement('div'); column1 = document.createElement('td');
column1.setAttribute('style','display: inline-block; margin-right: 5px;'); column1.setAttribute('style','text-align: center; vertical-align: top; padding: 6px 4px; border-bottom: 1px solid #000;');
removeButton = document.createElement('button'); removeButton = document.createElement('button');
removeButton.setAttribute('type','button'); removeButton.setAttribute('type','button');
removeButton.setAttribute('class','button');
removeButton.setAttribute('style','padding: 1px 7px 2px 7px; font-size: 11pt; line-height: 1;');
removeButton.innerText = '-'; removeButton.innerText = '-';
removeButton.addEventListener('click', function(e) { removeButton.addEventListener('click', function(e) {
document.getElementById('detail_section').removeChild(lineItem); document.getElementById('detail_section').removeChild(lineItem);
if (lineItem.detailRow) document.getElementById('detail_section').removeChild(lineItem.detailRow);
totalInvoice(); totalInvoice();
}); });
column1.appendChild(removeButton) column1.appendChild(removeButton)
@@ -66,11 +66,10 @@ function addLine(qty,skuid,descr,text,prc,tax,tot,typ) {
lineItem.total_z = total; lineItem.total_z = total;
lineItem.type_z = type; lineItem.type_z = type;
column2 = document.createElement('div'); column2 = document.createElement('td');
column2.setAttribute('style','display: inline-block; margin-right: 5px;'); column2.setAttribute('style','width: 54px; vertical-align: top; padding: 6px 4px; border-bottom: 1px solid #000;');
quantity.setAttribute('type','text'); quantity.setAttribute('type','text');
quantity.setAttribute('size','5'); quantity.setAttribute('style','width: 44px; text-align: center;');
quantity.setAttribute('maxlength','5');
quantity.setAttribute('name','quantity'); quantity.setAttribute('name','quantity');
quantity.setAttribute('value',qty); quantity.setAttribute('value',qty);
quantity.addEventListener('change',(e) => { quantity.addEventListener('change',(e) => {
@@ -83,9 +82,10 @@ function addLine(qty,skuid,descr,text,prc,tax,tot,typ) {
column2.appendChild(quantity); column2.appendChild(quantity);
lineItem.appendChild(column2); lineItem.appendChild(column2);
column3 = document.createElement('div'); column3 = document.createElement('td');
column3.setAttribute('style','display: inline-block; margin-right: 5px;'); column3.setAttribute('style','vertical-align: top; padding: 6px 4px; border-bottom: 1px solid #000;');
sku.setAttribute('name','sku'); sku.setAttribute('name','sku');
sku.setAttribute('style','width: 100%;');
sku.detail = detail; sku.detail = detail;
sku.addEventListener('change', (e) => { sku.addEventListener('change', (e) => {
sku.detail.style.display = sku.value == '***' ? 'block':'none'; sku.detail.style.display = sku.value == '***' ? 'block':'none';
@@ -99,13 +99,16 @@ function addLine(qty,skuid,descr,text,prc,tax,tot,typ) {
}); });
<sql sessionid="1">select * from product_list</sql> <sql sessionid="1">select * from product_list</sql>
<whilerow sessionid="1"> <whilerow sessionid="1">
<call pgm="/bin/sh" arg1="-c" arg2="jq -R -s . | sed 's#/#\\/#g'" input="$[1.description]" name="product_description_js">
<call pgm="/bin/sh" arg1="-c" arg2="jq -R -s . | sed 's#/#\\/#g'" input="$[1.sku]" name="product_sku_js">
<call pgm="/bin/sh" arg1="-c" arg2="jq -R -s . | sed 's#/#\\/#g'" input="$[1.type]" name="product_type_js">
option = document.createElement('option'); option = document.createElement('option');
option.setAttribute('value','$[1.sku]'); option.setAttribute('value',$[product_sku_js]);
option.description = '$[1.description]'; option.description = $[product_description_js];
option.typex = '$[1.type]'; option.typex = $[product_type_js];
option.price = '$[1.price]'; option.price = '$[1.price]';
option.innerText = '$[1.description]'; option.innerText = $[product_description_js];
if(skuid == '$[1.sku]') { if(skuid == $[product_sku_js]) {
option.selected = 'selected'; option.selected = 'selected';
} }
sku.appendChild(option); sku.appendChild(option);
@@ -121,47 +124,52 @@ function addLine(qty,skuid,descr,text,prc,tax,tot,typ) {
type.setAttribute('value', typ); type.setAttribute('value', typ);
lineItem.appendChild(type); lineItem.appendChild(type);
column4 = document.createElement('div'); column4 = document.createElement('td');
column4.setAttribute('style','display: inline-block; margin-right: 5px;'); column4.setAttribute('style','width: 90px; vertical-align: top; padding: 6px 4px; border-bottom: 1px solid #000;');
price.setAttribute('type','text'); price.setAttribute('type','text');
price.setAttribute('size','15'); price.setAttribute('style','width: 80px; text-align: right;');
price.setAttribute('maxlength','15');
price.setAttribute('name','price'); price.setAttribute('name','price');
price.setAttribute('value',prc); price.setAttribute('value',prc);
column4.appendChild(price); column4.appendChild(price);
lineItem.appendChild(column4); lineItem.appendChild(column4);
column5 = document.createElement('div'); column5 = document.createElement('td');
column5.setAttribute('style','display: inline-block; margin-right: 5px;'); column5.setAttribute('style','width: 70px; vertical-align: top; padding: 6px 4px; border-bottom: 1px solid #000;');
taxAmount.setAttribute('type','text'); taxAmount.setAttribute('type','text');
taxAmount.setAttribute('size','15'); taxAmount.setAttribute('style','width: 60px; text-align: right;');
taxAmount.setAttribute('maxlength','15');
taxAmount.setAttribute('name','tax_amount'); taxAmount.setAttribute('name','tax_amount');
taxAmount.setAttribute('value',tax); taxAmount.setAttribute('value',tax);
column5.appendChild(taxAmount); column5.appendChild(taxAmount);
lineItem.appendChild(column5); lineItem.appendChild(column5);
column6 = document.createElement('div'); column6 = document.createElement('td');
column6.setAttribute('style','display: inline-block;'); column6.setAttribute('style','width: 90px; vertical-align: top; padding: 6px 4px; border-bottom: 1px solid #000;');
total.setAttribute('type','text'); total.setAttribute('type','text');
total.setAttribute('size','15'); total.setAttribute('style','width: 80px; text-align: right;');
total.setAttribute('maxlength','15');
total.setAttribute('name','total'); total.setAttribute('name','total');
total.setAttribute('value',tot); total.setAttribute('value',tot);
column6.appendChild(total); column6.appendChild(total);
lineItem.appendChild(column6); lineItem.appendChild(column6);
const detailRow = document.createElement('tr');
const detailCell = document.createElement('td');
detailCell.setAttribute('colspan','6');
detailCell.setAttribute('style','padding: 0 4px 6px 4px; border-bottom: 1px solid #000;');
textarea.setAttribute('name','textarea'); textarea.setAttribute('name','textarea');
textarea.setAttribute('rows','5');
textarea.setAttribute('style','width: 100%; background: #101014; color: #e7e4dc; border: 1px solid rgba(255, 255, 255, 0.07); border-radius: 2px; padding: 6px 8px; font-family: inherit; font-size: 14px;');
textarea.innerHTML = text; textarea.innerHTML = text;
CKEDITOR.replace(textarea);
detail.appendChild(textarea); detail.appendChild(textarea);
lineItem.appendChild(detail); detailCell.appendChild(detail);
detailRow.appendChild(detailCell);
lineItem.detailRow = detailRow;
detail.style.display = sku.value == '***' ? 'block':'none'; detail.style.display = sku.value == '***' ? 'block':'none';
lineItem.total = total.value; lineItem.total = total.value;
document.getElementById('detail_section').appendChild(lineItem); document.getElementById('detail_section').appendChild(lineItem);
document.getElementById('detail_section').appendChild(detailRow);
} }
</script> </script>
<input type="hidden" id="linecount" name="linecount"> <input type="hidden" id="linecount" name="linecount">
@@ -169,12 +177,30 @@ function addLine(qty,skuid,descr,text,prc,tax,tot,typ) {
<eval name="_menu"> <eval name="_menu">
<include file="adminmenu.section"> <include file="adminmenu.section">
</eval> </eval>
<h3>Invoice $[_invoice_id]</h3> <sql>select i.id as invnumber,
<sql>select * from invoices where id=$[_invoice_id]</sql> u.name as name,
<entryform> u.company_name as company_name,
<td>Account</td> u.email as email,
<td> date_format(i.created,'%m/%e/%Y') as invdate,
<select> i.status as status,
i.user_id as user_id
from invoices as i
join users as u on i.user_id=u.id
where i.id=$[@_invoice_id]</sql>
<ifrow>
<div style="width: 760px; max-width: 100%; margin: 0 auto; border: 1px solid rgba(197, 164, 90, 0.28); border-radius: 10px; padding: 20px; background: #0a0a0d; color: #e7e4dc; font-family: Arial, Helvetica, sans-serif; font-size: 14px;">
<table style="width: 100%; border-collapse: collapse;" cellspacing="0" cellpadding="0"><tr>
<td style="vertical-align: middle;"><img style="height: 90px; width: auto;" src="/assets/btglogo.png"></td>
<td style="vertical-align: middle; text-align: right; color: #c5a45a; letter-spacing: 0.5px;">
<div style="font-size: 24px; font-weight: 600;">Invoice: $[.invnumber]</div>
<div style="color: #8d8c92; font-size: 12px; margin-top: 4px;">$[.status]</div>
</td>
</tr></table>
<div style="height: 1px; background: rgba(197, 164, 90, 0.28); margin: 16px 0;"></div>
<table style="border-collapse: collapse; margin-bottom: 16px; font-size: 16px; width: 100%;" cellspacing="0" cellpadding="0">
<tr><td style="color: #8d8c92; text-align: right; padding: 3px 10px 3px 16px; border-bottom: 1px solid #000; width: 150px;">Account:</td>
<td style="padding: 3px 16px 3px 0; border-bottom: 1px solid #000;">
<select name="user_id" style="width: 100%; max-width: 360px;">
<sql sessionid="1">select * from users</sql> <sql sessionid="1">select * from users</sql>
<whilerow sessionid="1"> <whilerow sessionid="1">
<option value="$[1.id]" <option value="$[1.id]"
@@ -183,23 +209,51 @@ function addLine(qty,skuid,descr,text,prc,tax,tot,typ) {
</whilerow> </whilerow>
</select> </select>
</td></tr> </td></tr>
<tr><td colspan="3"> <tr><td style="color: #8d8c92; text-align: right; padding: 3px 10px 3px 16px; border-bottom: 1px solid #000;">Company Name:</td><td style="color: #e7e4dc; text-align: left; padding: 3px 16px 3px 0; border-bottom: 1px solid #000;">$[.company_name]</td></tr>
<div id="detail_section"></div> <tr><td style="color: #8d8c92; text-align: right; padding: 3px 10px 3px 16px; border-bottom: 1px solid #000;">E-Mail:</td><td style="color: #e7e4dc; text-align: left; padding: 3px 16px 3px 0; border-bottom: 1px solid #000;">$[.email]</td></tr>
<sql>select * from invoices_detail where invoice_id=$[_invoice_id]</sql> <tr><td style="color: #8d8c92; text-align: right; padding: 3px 10px 3px 16px;">Invoice Date:</td><td style="color: #e7e4dc; text-align: left; padding: 3px 16px 3px 0;">$[.invdate]</td></tr>
</table>
<table style="width: 100%; border-collapse: collapse; background: #16161c; border-radius: 6px;" cellspacing="0" cellpadding="0">
<thead>
<tr><td style="background-color: #1c1c24; color: #c5a45a; width: 54px; padding: 6px 4px; text-align: center; border-bottom: 1px solid #000;"></td>
<td style="background-color: #1c1c24; color: #c5a45a; width: 54px; padding: 6px 8px; text-align: center; border-bottom: 1px solid #000;">Qty</td>
<td style="background-color: #1c1c24; color: #c5a45a; padding: 6px 8px; border-bottom: 1px solid #000;">Item / Description</td>
<td style="background-color: #1c1c24; color: #c5a45a; width: 90px; padding: 6px 8px; text-align: center; border-bottom: 1px solid #000;">Unit Price</td>
<td style="background-color: #1c1c24; color: #c5a45a; width: 70px; padding: 6px 8px; text-align: center; border-bottom: 1px solid #000;">Tax</td>
<td style="background-color: #1c1c24; color: #c5a45a; width: 90px; padding: 6px 8px; text-align: center; border-bottom: 1px solid #000;">Amount</td>
</tr>
</thead>
<tbody id="detail_section"></tbody>
<tfoot>
<tr><td colspan="5" style="text-align: right; padding: 10px 8px; color: #e3c47e; font-weight: bold;">Invoice Total:</td>
<td id="totalsum" style="text-align: right; padding: 10px 8px; color: #e3c47e; font-weight: bold;"></td>
</tr>
</tfoot>
</table>
<sql>select * from invoices_detail where invoice_id=$[@_invoice_id]</sql>
<whilerow> <whilerow>
<call pgm="/bin/sh" arg1="-c" arg2="jq -R -s . | sed 's#/#\\/#g'" input="$[.sku]" name="detail_sku_js">
<call pgm="/bin/sh" arg1="-c" arg2="jq -R -s . | sed 's#/#\\/#g'" input="$[.description]" name="detail_description_js">
<call pgm="/bin/sh" arg1="-c" arg2="jq -R -s . | sed 's#/#\\/#g'" input="$[.text]" name="detail_text_js">
<call pgm="/bin/sh" arg1="-c" arg2="jq -R -s . | sed 's#/#\\/#g'" input="$[.type]" name="detail_type_js">
<script> <script>
addLine('$[.quantity]','$[.sku]','$[.description]','$[.text]','$[.price]','$[.tax_amount]','$[.total]','$[.type]'); addLine('$[.quantity]',$[detail_sku_js],$[detail_description_js],$[detail_text_js],'$[.price]','$[.tax_amount]','$[.total]',$[detail_type_js]);
</script> </script>
</whilerow> </whilerow>
<button type="button" onclick="addLine('1','','','','0.00','0.00','0.00','');">+</button> <div style="margin-top: 10px;">
<div id="totalsum" style="border: 1pt solid #000f; padding: 3px; width: 100px; text-align: right; float: right;"></div> <button type="button" class="button" onclick="addLine('1','','','','0.00','0.00','0.00','');">+ Add Line</button>
</div>
<script> <script>
totalInvoice(); totalInvoice();
</script> </script>
<buttonbay> <buttonbay style="display: block; margin-top: 18px; text-align: right;">
<linkbutton process="update_invoice"><div class="button">Update Invoice</div></linkbutton> <linkbutton process="update_invoice"><div class="button">Update Invoice</div></linkbutton>
</buttonbay> </buttonbay>
</entryform> </div>
<else>
<div style="width: 760px; max-width: 100%; margin: 40px auto; text-align: center; color: #8d8c92;">Invoice not found.</div>
</ifrow>
<br> <br>
</database> </database>
</contents> </contents>
+46 -22
View File
@@ -4,6 +4,7 @@
#api POST /email/message #api POST /email/message
#api POST /email/flag #api POST /email/flag
#api POST /email/delete #api POST /email/delete
#api POST /email/emptyfolder
#api POST /email/trash #api POST /email/trash
#api POST /email/folders #api POST /email/folders
#api POST /email/search #api POST /email/search
@@ -12,10 +13,15 @@
#api POST /email/switchaccount #api POST /email/switchaccount
<header name="Content-Type" value="application/json"> <header name="Content-Type" value="application/json">
<if value1="$[REQUEST_URI]" value2="/email/connect" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/connect" type="eq">
<if value1="$[host]" value2="" type="eq">
<set name="host" value="mail.barant.com">
</if>
<try> <try>
<imap config="./email.cfg" user="$[user]" password="$[password]" sessionid=""> <imap config="./email.cfg" host="$[host]" user="$[user]" password="$[password]" sessionid="">
<eval name="_imap_accounts"><imapaccounts action="add" list="$[@_imap_accounts]" user="$[user]" password="$[password]"></imapaccounts></eval> <eval name="_imap_accounts"><imapaccounts action="add" list="$[@_imap_accounts]" host="$[host]" user="$[user]" password="$[password]"></imapaccounts></eval>
<set name="@_imap_accounts" value="$[_imap_accounts]"> <set name="@_imap_accounts" value="$[_imap_accounts]">
<set name="_imap_host" value="$[host]">
<set name="@_imap_host" value="$[host]">
<set name="_imap_user" value="$[user]"> <set name="_imap_user" value="$[user]">
<set name="@_imap_user" value="$[user]"> <set name="@_imap_user" value="$[user]">
<set name="_imap_password" value="$[password]"> <set name="_imap_password" value="$[password]">
@@ -24,7 +30,6 @@
</imap> </imap>
<catch name="_imaperr"> <catch name="_imaperr">
{"ok":false,"error":"$[_imaperr]"} {"ok":false,"error":"$[_imaperr]"}
</catch>
</try> </try>
<else> <else>
<if value1="$[REQUEST_URI]" value2="/email/disconnect" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/disconnect" type="eq">
@@ -36,22 +41,25 @@
</if> </if>
<eval name="_next_user"><imapaccounts action="firstuser" list="$[@_imap_accounts]"></imapaccounts></eval> <eval name="_next_user"><imapaccounts action="firstuser" list="$[@_imap_accounts]"></imapaccounts></eval>
<if value1="$[_next_user]" value2="" type="eq"> <if value1="$[_next_user]" value2="" type="eq">
<set name="@_imap_host" value="">
<set name="@_imap_user" value=""> <set name="@_imap_user" value="">
<set name="@_imap_password" value=""> <set name="@_imap_password" value="">
{"ok":true,"active":""} {"ok":true,"active":""}
<else> <else>
<try> <try>
<eval name="_next_host"><imapaccounts action="gethost" list="$[@_imap_accounts]" user="$[_next_user]"></imapaccounts></eval>
<eval name="_next_password"><imapaccounts action="getpassword" list="$[@_imap_accounts]" user="$[_next_user]"></imapaccounts></eval> <eval name="_next_password"><imapaccounts action="getpassword" list="$[@_imap_accounts]" user="$[_next_user]"></imapaccounts></eval>
<imap config="./email.cfg" user="$[_next_user]" password="$[_next_password]" sessionid=""> <imap config="./email.cfg" host="$[_next_host]" user="$[_next_user]" password="$[_next_password]" sessionid="">
<set name="@_imap_host" value="$[_next_host]">
<set name="@_imap_user" value="$[_next_user]"> <set name="@_imap_user" value="$[_next_user]">
<set name="@_imap_password" value="$[_next_password]"> <set name="@_imap_password" value="$[_next_password]">
{"ok":true,"active":"$[_next_user]"} {"ok":true,"active":"$[_next_user]"}
</imap> </imap>
<catch name="_disconnecterr"> <catch name="_disconnecterr">
<set name="@_imap_host" value="">
<set name="@_imap_user" value=""> <set name="@_imap_user" value="">
<set name="@_imap_password" value=""> <set name="@_imap_password" value="">
{"ok":true,"active":""} {"ok":true,"active":""}
</catch>
</try> </try>
</if> </if>
<else> <else>
@@ -63,7 +71,7 @@
</if> </if>
<if value1="$[REQUEST_URI]" value2="/email/list" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/list" type="eq">
<try> <try>
<imap config="./email.cfg" user="$[@_imap_user]" password="$[@_imap_password]" sessionid=""> <imap config="./email.cfg" host="$[@_imap_host]" user="$[@_imap_user]" password="$[@_imap_password]" sessionid="">
<if value1="$[limit]" value2="" type="eq"> <if value1="$[limit]" value2="" type="eq">
<set name="limit" value="50"> <set name="limit" value="50">
</if> </if>
@@ -71,67 +79,82 @@
</imap> </imap>
<catch name="_imaperr"> <catch name="_imaperr">
{"ok":false,"error":"$[_imaperr]"} {"ok":false,"error":"$[_imaperr]"}
</catch>
</try> </try>
<else> <else>
<if value1="$[REQUEST_URI]" value2="/email/message" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/message" type="eq">
<try> <try>
<imap config="./email.cfg" user="$[@_imap_user]" password="$[@_imap_password]" sessionid=""> <imap config="./email.cfg" host="$[@_imap_host]" user="$[@_imap_user]" password="$[@_imap_password]" sessionid="">
<imapmessage sessionid="" folder="$[folder]" uid="$[uid]"> <imapmessage sessionid="" folder="$[folder]" uid="$[uid]">
</imap> </imap>
<catch name="_imaperr"> <catch name="_imaperr">
{"ok":false,"error":"$[_imaperr]"} {"ok":false,"error":"$[_imaperr]"}
</catch>
</try> </try>
<else> <else>
<if value1="$[REQUEST_URI]" value2="/email/flag" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/flag" type="eq">
<try> <try>
<imap config="./email.cfg" user="$[@_imap_user]" password="$[@_imap_password]" sessionid=""> <imap config="./email.cfg" host="$[@_imap_host]" user="$[@_imap_user]" password="$[@_imap_password]" sessionid="">
<imapflag sessionid="" folder="$[folder]" uid="$[uid]" flag="$[flag]" set="$[set]"> <imapflag sessionid="" folder="$[folder]" uid="$[uid]" flag="$[flag]" set="$[set]">
</imap> </imap>
<catch name="_imaperr"> <catch name="_imaperr">
{"ok":false,"error":"$[_imaperr]"} {"ok":false,"error":"$[_imaperr]"}
</catch>
</try> </try>
<else> <else>
<if value1="$[REQUEST_URI]" value2="/email/delete" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/delete" type="eq">
<try> <try>
<imap config="./email.cfg" user="$[@_imap_user]" password="$[@_imap_password]" sessionid=""> <imap config="./email.cfg" host="$[@_imap_host]" user="$[@_imap_user]" password="$[@_imap_password]" sessionid="">
<imapdelete sessionid="" folder="$[folder]" uid="$[uid]"> <imapdelete sessionid="" folder="$[folder]" uid="$[uid]">
</imap> </imap>
<catch name="_imaperr"> <catch name="_imaperr">
{"ok":false,"error":"$[_imaperr]"} {"ok":false,"error":"$[_imaperr]"}
</catch>
</try> </try>
<else>
<if value1="$[REQUEST_URI]" value2="/email/emptyfolder" type="eq">
<if value1="$[folder]" value2="Spam" type="eq">
<set name="_emptyok" value="1">
<else>
<if value1="$[folder]" value2="Trash" type="eq">
<set name="_emptyok" value="1">
<else>
<set name="_emptyok" value="0">
</if>
</if>
<if value1="$[_emptyok]" value2="1" type="eq">
<try>
<imap config="./email.cfg" host="$[@_imap_host]" user="$[@_imap_user]" password="$[@_imap_password]" sessionid="">
<imapemptyfolder sessionid="" folder="$[folder]">
</imap>
<catch name="_imaperr">
{"ok":false,"error":"$[_imaperr]"}
</try>
<else>
{"ok":false,"error":"Only the Spam and Trash folders can be emptied."}
</if>
<else> <else>
<if value1="$[REQUEST_URI]" value2="/email/trash" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/trash" type="eq">
<try> <try>
<imap config="./email.cfg" user="$[@_imap_user]" password="$[@_imap_password]" sessionid=""> <imap config="./email.cfg" host="$[@_imap_host]" user="$[@_imap_user]" password="$[@_imap_password]" sessionid="">
<imapmove sessionid="" folder="$[folder]" uid="$[uid]" destfolder="Trash"> <imapmove sessionid="" folder="$[folder]" uid="$[uid]" destfolder="Trash">
</imap> </imap>
<catch name="_imaperr"> <catch name="_imaperr">
{"ok":false,"error":"$[_imaperr]"} {"ok":false,"error":"$[_imaperr]"}
</catch>
</try> </try>
<else> <else>
<if value1="$[REQUEST_URI]" value2="/email/folders" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/folders" type="eq">
<try> <try>
<imap config="./email.cfg" user="$[@_imap_user]" password="$[@_imap_password]" sessionid=""> <imap config="./email.cfg" host="$[@_imap_host]" user="$[@_imap_user]" password="$[@_imap_password]" sessionid="">
<imapfolders sessionid=""> <imapfolders sessionid="">
</imap> </imap>
<catch name="_imaperr"> <catch name="_imaperr">
{"ok":false,"error":"$[_imaperr]"} {"ok":false,"error":"$[_imaperr]"}
</catch>
</try> </try>
<else> <else>
<if value1="$[REQUEST_URI]" value2="/email/search" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/search" type="eq">
<try> <try>
<imap config="./email.cfg" user="$[@_imap_user]" password="$[@_imap_password]" sessionid=""> <imap config="./email.cfg" host="$[@_imap_host]" user="$[@_imap_user]" password="$[@_imap_password]" sessionid="">
<imapsearch sessionid="" folder="$[folder]" query="$[query]"> <imapsearch sessionid="" folder="$[folder]" query="$[query]">
</imap> </imap>
<catch name="_imaperr"> <catch name="_imaperr">
{"ok":false,"error":"$[_imaperr]"} {"ok":false,"error":"$[_imaperr]"}
</catch>
</try> </try>
<else> <else>
<if value1="$[REQUEST_URI]" value2="/email/send" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/send" type="eq">
@@ -139,7 +162,6 @@
<smtpsend config="./email.cfg" user="$[@_imap_user]" password="$[@_imap_password]" to="$[to]" subject="$[subject]" html="$[body]"> <smtpsend config="./email.cfg" user="$[@_imap_user]" password="$[@_imap_password]" to="$[to]" subject="$[subject]" html="$[body]">
<catch name="_smtperr"> <catch name="_smtperr">
{"ok":false,"error":"$[_smtperr]"} {"ok":false,"error":"$[_smtperr]"}
</catch>
</try> </try>
<else> <else>
<if value1="$[REQUEST_URI]" value2="/email/accounts" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/accounts" type="eq">
@@ -147,11 +169,13 @@
<else> <else>
<if value1="$[REQUEST_URI]" value2="/email/switchaccount" type="eq"> <if value1="$[REQUEST_URI]" value2="/email/switchaccount" type="eq">
<try> <try>
<eval name="_switch_host"><imapaccounts action="gethost" list="$[@_imap_accounts]" user="$[user]"></imapaccounts></eval>
<eval name="_switch_password"><imapaccounts action="getpassword" list="$[@_imap_accounts]" user="$[user]"></imapaccounts></eval> <eval name="_switch_password"><imapaccounts action="getpassword" list="$[@_imap_accounts]" user="$[user]"></imapaccounts></eval>
<if value1="$[_switch_password]" value2="" type="eq"> <if value1="$[_switch_password]" value2="" type="eq">
{"ok":false,"error":"That account is not connected."} {"ok":false,"error":"That account is not connected."}
<else> <else>
<imap config="./email.cfg" user="$[user]" password="$[_switch_password]" sessionid=""> <imap config="./email.cfg" host="$[_switch_host]" user="$[user]" password="$[_switch_password]" sessionid="">
<set name="@_imap_host" value="$[_switch_host]">
<set name="@_imap_user" value="$[user]"> <set name="@_imap_user" value="$[user]">
<set name="@_imap_password" value="$[_switch_password]"> <set name="@_imap_password" value="$[_switch_password]">
{"ok":true} {"ok":true}
@@ -159,7 +183,6 @@
</if> </if>
<catch name="_switcherr"> <catch name="_switcherr">
{"ok":false,"error":"$[_switcherr]"} {"ok":false,"error":"$[_switcherr]"}
</catch>
</try> </try>
<else> <else>
{"ok":false,"error":"Unknown route."} {"ok":false,"error":"Unknown route."}
@@ -176,3 +199,4 @@
</if> </if>
</if> </if>
</if> </if>
</if>
+35 -36
View File
@@ -7,52 +7,51 @@
i.amount as amount i.amount as amount
from invoices as i from invoices as i
join users as u on i.user_id=u.id join users as u on i.user_id=u.id
where i.id=$[_invoice_id]</sql> where i.id=$[@_invoice_id]</sql>
<set name="amount" value="$[.amount]"> <set name="amount" value="$[.amount]">
<div style="width: 500px; border: 1pt solid #000; padding: 3px; background: #fff;"> <set name="invoicestatus" value="$[.status]">
<div><div style="display: inline-block;"><img style="width: 300px;" src="/assets/invoice_logo.png"></div> <div style="width: 600px; max-width: 100%; margin: 0 auto; border: 1px solid rgba(197, 164, 90, 0.28); border-radius: 10px; padding: 20px; background: #0a0a0d; color: #e7e4dc; font-family: Arial, Helvetica, sans-serif; font-size: 14px;">
<div style="display: flex; float: right; align-items: center;"> <table style="width: 100%; border-collapse: collapse;" cellspacing="0" cellpadding="0"><tr>
Invoice: $[.invnumber] $[.status] <td style="vertical-align: middle;"><img style="height: 90px; width: auto;" src="https://barant.com/assets/btglogo.png"></td>
</div> <td style="vertical-align: middle; text-align: right; color: #c5a45a; letter-spacing: 0.5px;">
</div> <div style="font-size: 24px; font-weight: 600;">Invoice: $[.invnumber]</div>
<div style="background: #eee;"> <div style="color: #8d8c92; font-size: 12px; margin-top: 4px;">$[.status]</div>
<div>Name: $[.name]</div> </td>
<div>Company Name: $[.company_name]</div> </tr></table>
<div>E-Mail $[.email]</div> <div style="height: 1px; background: rgba(197, 164, 90, 0.28); margin: 16px 0;"></div>
<div>Invoice Date: $[.invdate]</div> <table style="border-collapse: collapse; margin-bottom: 16px; font-size: 16px;" cellspacing="0" cellpadding="0">
</div> <tr><td style="color: #8d8c92; text-align: right; padding: 3px 10px 3px 16px; border-bottom: 1px solid #000;">Name:</td><td style="color: #e7e4dc; text-align: left; padding: 3px 16px 3px 0; border-bottom: 1px solid #000;">$[.name]</td></tr>
<div style="background: #ddd;"> <tr><td style="color: #8d8c92; text-align: right; padding: 3px 10px 3px 16px; border-bottom: 1px solid #000;">Company Name:</td><td style="color: #e7e4dc; text-align: left; padding: 3px 16px 3px 0; border-bottom: 1px solid #000;">$[.company_name]</td></tr>
<sql>select * from invoices_detail where invoice_id=$[_invoice_id]</sql> <tr><td style="color: #8d8c92; text-align: right; padding: 3px 10px 3px 16px; border-bottom: 1px solid #000;">E-Mail:</td><td style="color: #e7e4dc; text-align: left; padding: 3px 16px 3px 0; border-bottom: 1px solid #000;">$[.email]</td></tr>
<table style="border: 0px;" cellspacing="0"> <tr><td style="color: #8d8c92; text-align: right; padding: 3px 10px 3px 16px;">Invoice Date:</td><td style="color: #e7e4dc; text-align: left; padding: 3px 16px 3px 0;">$[.invdate]</td></tr>
<tr><td style="background-color: #888; color: #fff; width: 50px; padding:3px; text-align: center; border: 1pt solid #ddd;">Qty</td> </table>
<td style="background-color: #888; color: #fff; width: 400px; padding: 3px; border: 1pt solid #ddd;">Description</td> <sql>select * from invoices_detail where invoice_id=$[@_invoice_id]</sql>
<td style="background-color: #888; color: #fff; width: 60px; padding: 3px; text-align: center; border: 1pt solid #ddd;">Unit Price</td> <table style="width: 100%; border-collapse: collapse; background: #16161c; border-radius: 6px;" cellspacing="0" cellpadding="0">
<td style="background-color: #888; color: #fff; width: 60px; padding: 3px; text-align: center; border: 1pt solid #ddd;">Amount</td> <tr><td style="background-color: #1c1c24; color: #c5a45a; width: 50px; padding: 6px 8px; text-align: center; border-bottom: 1px solid #000;">Qty</td>
<td style="background-color: #1c1c24; color: #c5a45a; width: 400px; padding: 6px 8px; border-bottom: 1px solid #000;">Description</td>
<td style="background-color: #1c1c24; color: #c5a45a; width: 60px; padding: 6px 8px; text-align: center; border-bottom: 1px solid #000;">Unit Price</td>
<td style="background-color: #1c1c24; color: #c5a45a; width: 60px; padding: 6px 8px; text-align: center; border-bottom: 1px solid #000;">Amount</td>
</tr> </tr>
<whilerow> <whilerow>
<tr><td style="width: 50px; vertical-align: top; text-align: center; border: 1pt solid #ddd;"> <tr><td style="width: 50px; vertical-align: top; text-align: center; color: #e7e4dc; padding: 6px 8px; border-bottom: 1px solid #000;">
<if value1="$[.sku]" value2="***" type="ne">$[quantity]</if></td> <if value1="$[.sku]" value2="***" type="ne">$[quantity]</if></td>
<td style="width: 400px; border: 1pt solid #ddd;"> <td style="width: 400px; vertical-align: top; color: #e7e4dc; padding: 6px 8px; border-bottom: 1px solid #000;">
<if value1="$[.sku]" value2="***" type="ne">$[description]<br></if> <if value1="$[.sku]" value2="***" type="ne">$[description]<br></if>
$[text]</td> $[text]</td>
<td style="width: 60px; vertical-align: top; text-align: right; border: 1pt solid #ddd;"> <td style="width: 60px; vertical-align: top; text-align: right; color: #e7e4dc; padding: 6px 8px; border-bottom: 1px solid #000;">
<if value1="$[.sku]" value2="***" type="ne">$[price]</if></td> <if value1="$[.sku]" value2="***" type="ne">$[price]</if></td>
<td style="width: 60px; vertical-align: top; text-align: right; border: 1pt solid #ddd;">$[total]</td> <td style="width: 60px; vertical-align: top; text-align: right; color: #e7e4dc; padding: 6px 8px; border-bottom: 1px solid #000;">$[total]</td>
</tr> </tr>
</whilerow> </whilerow>
<tr><td style="width: 50px; border: 0pt solid #000;"></td> <tr><td style="width: 50px;"></td>
<td style="width: 400px; text-align: right; border: 0pt solid #000;" colspan="2">Invoice Total:</td> <td style="width: 400px; text-align: right; padding: 10px 8px; color: #e3c47e; font-weight: bold;" colspan="2">Invoice Total:</td>
<td style="width: 60px; text-align: right; border: 1pt solid #000;">$[amount]</td> <td style="width: 60px; text-align: right; padding: 10px 8px; color: #e3c47e; font-weight: bold;">$[amount]</td>
</tr> </tr>
<tr><td colspan="4" style="width: 50px; border: 0pt solid #000;"><hr></td>
</tr>
<sql>select * from payments where invoice_id=$[_invoice_id]</sql>
<whilerow>
<tr><td style="width: 50px; border: 0pt solid #000;"></td>
<td colspan="2" style="width: 400px; text-align: right; border: 0pt solid #000;">Credit Card: $[.card_brand] ending in $[.last_4_digits] expires on $[.exp_month]/$[.exp_year]</td>
<td style="width: 60px; text-align: right; border: 1pt solid #000;">$[.amount]</td>
</tr>
</whilerow>
</table> </table>
<sql>select * from payments where invoice_id=$[@_invoice_id]</sql>
<whilerow>
<div style="margin-top: 12px; text-align: right; color: #8d8c92; font-size: 12px;">
Credit Card: $[.card_brand] ending in $[.last_4_digits] expires $[.exp_month]/$[.exp_year]
</div> </div>
</whilerow>
</div> </div>
-67
View File
@@ -1,67 +0,0 @@
<page secure="yes" loggedin="no">
<title>JUKEBOX</title>
<contents>
<script>
var index = 0;
const paths = [];
const songs = [];
function onselection(path,selection) {
var name = path + '/' + selection;
var player = document.getElementById('player');
var audio = document.getElementById('audio');
var title = document.getElementById('title');
player.src = name;
title.textContent = selection;
audio.load();
audio.play();
}
function selectNext() {
var index = Math.floor(Math.random()*songs.length) + 1;
onselection(paths[index],songs[index]);
}
</script>
<retain name="download_file">
<div style="display: inline-block;">
<audio id="audio" controls onended="selectNext();">
<source id="player" type="audio/mp3">
</audio>
</div>
<div style="font-size: 20px; display: inline-block;" id="title">Click on a title below</div>
<sectionframe title="Old Library">
<div style="height: 300px; overflow-y: scroll;">
<whiledir name="file" dir="musiclink/library">
<if expr="left('$[file]',1) != '.' ">
<div style="cursor: pointer;" onclick="onselection('musiclink/library','$[file]');">$[file]</div>
<script>
paths[index]='musiclink/library';
songs[index++]='$[file]';
</script>
</if>
</whiledir>
</div>
<script>
</script>
</sectionframe>
<sectionframe title="Ian's Library">
<div style="height: 300px; overflow-y: scroll;">
<whiledir name="file" dir="musiclink/ianslibrary">
<if expr="left('$[file]',1) != '.' ">
<div style="cursor: pointer;" onclick="onselection('musiclink/ianslibrary','$[file]');">$[file]</div>
<script>
paths[index]='musiclink/ianslibrary';
songs[index++]='$[file]';
</script>
</if>
</whiledir>
</div>
</sectionframe>
<script>
function printName(name) {
document.write(name + '\n');
}
//songs.forEach(printName);
</script>
</contents>
</page>
+13
View File
@@ -14,6 +14,19 @@
<setenv name="_login_type">$[login_type]</setenv> <setenv name="_login_type">$[login_type]</setenv>
<setenv name="_login_uuid">$[login_uuid]</setenv> <setenv name="_login_uuid">$[login_uuid]</setenv>
<sql>update users set last_login=now() where id=$[login_id]</sql> <sql>update users set last_login=now() where id=$[login_id]</sql>
<sql>select group_concat(to_base64(host),':',to_base64(email),':',to_base64(password) order by id separator ';') as accounts_list,
(select host from email_accounts where user_id=$[login_id] order by id limit 1) as first_host,
(select email from email_accounts where user_id=$[login_id] order by id limit 1) as first_email,
(select password from email_accounts where user_id=$[login_id] order by id limit 1) as first_password
from email_accounts where user_id=$[login_id]</sql>
<ifrow>
<if value1="$[.accounts_list]" value2="" type="ne">
<set name="@_imap_accounts" value="$[.accounts_list]">
<set name="@_imap_host" value="$[.first_host]">
<set name="@_imap_user" value="$[.first_email]">
<set name="@_imap_password" value="$[.first_password]">
</if>
</ifrow>
<if value1="$[@start]" value2="" type="eq"> <if value1="$[@start]" value2="" type="eq">
<setpage name="account"> <setpage name="account">
<else> <else>
+26
View File
@@ -0,0 +1,26 @@
#api POST /admin/mail-invoice
<set name="host" value="localhost">
<set name="database" value="barant">
<set name="user" value="barant">
<set name="password" value="uversa1960">
<database name="$[database]" host="$[host]" user="$[user]" password="$[password]" sessionid="">
<header name="Content-Type" value="application/json">
<if value1="$[@_login_type]" value2="admin" type="ne">
{"ok":false,"error":"Not authorized."}
<else>
<if value1="$[@_invoice_id]" value2="" type="eq">
{"ok":false,"error":"No invoice selected."}
<else>
<if value1="$[email]" value2="" type="eq">
{"ok":false,"error":"Please enter an e-mail address."}
<else>
<try>
<set name="_invoice_email_override" value="$[email]">
<include file="send_invoice_email.method">{"ok":true}
<catch name="_mailerr">
{"ok":false,"error":"$[_mailerr]"}
</try>
</if>
</if>
</if>
</database>
+43
View File
@@ -0,0 +1,43 @@
#api POST /admin/add-mail-account
#api POST /admin/remove-mail-account
<set name="host" value="localhost">
<set name="database" value="barant">
<set name="user" value="barant">
<set name="password" value="uversa1960">
<database name="$[database]" host="$[host]" user="$[user]" password="$[password]" sessionid="">
<header name="Content-Type" value="application/json">
<if value1="$[@_login_type]" value2="admin" type="ne">
{"ok":false,"error":"Not authorized."}
<else>
<if value1="$[REQUEST_URI]" value2="/admin/add-mail-account" type="eq">
<if value1="$[mail_host]" value2="" type="eq">
{"ok":false,"error":"Please enter a mail server."}
<else>
<if value1="$[mail_email]" value2="" type="eq">
{"ok":false,"error":"Please enter an e-mail address."}
<else>
<if value1="$[mail_password]" value2="" type="eq">
{"ok":false,"error":"Please enter a password."}
<else>
<try>
<imap config="./email.cfg" host="$[mail_host]" user="$[mail_email]" password="$[mail_password]" sessionid="">
</imap>
<sql>insert into email_accounts (user_id,email,host,password) values ($[@_login_id],'$[mail_email]','$[mail_host]','$[mail_password]')
on duplicate key update host='$[mail_host]', password='$[mail_password]'</sql>
{"ok":true}
<catch name="_imaperr">
{"ok":false,"error":"Could not connect with those credentials: $[_imaperr]"}
</try>
</if>
</if>
</if>
<else>
<if value1="$[account_id]" value2="" type="eq">
{"ok":false,"error":"No account specified."}
<else>
<sql>delete from email_accounts where id=$[account_id] and user_id=$[@_login_id]</sql>
{"ok":true}
</if>
</if>
</if>
</database>
@@ -0,0 +1,7 @@
<retain name="download_file">
<sectionframe title="Ian's Library">
<div class="music-song-list" id="music-list-ianslibrary"></div>
</sectionframe>
<script>
__renderMusicFolder('music-list-ianslibrary', 'ianslibrary', '/assets/musiclink/ianslibrary');
</script>
@@ -0,0 +1,7 @@
<retain name="download_file">
<sectionframe title="Old Library">
<div class="music-song-list" id="music-list-library"></div>
</sectionframe>
<script>
__renderMusicFolder('music-list-library', 'library', '/assets/musiclink/library');
</script>
+7
View File
@@ -0,0 +1,7 @@
<retain name="download_file">
<sectionframe title="BARANT Audio Experiments">
<div class="music-song-list" id="music-list-bae"></div>
</sectionframe>
<script>
__renderMusicFolder('music-list-bae', 'bae', '/assets/musiclink/bae');
</script>
@@ -0,0 +1,23 @@
<sectionframe title="Welcome to BARANT Systems">
<div style="width: 48%;">
<p>We are BARANT Technology Group. Contact us for information on how we can
help you with your technical objectives.</p>
<h1>Modular1 VST Synthesizer</h1>
<p>Check out our <a href="/vst">Modular1 VST3
Synthesizer</a> If you appreciate the art of modular analog
synthesizers then you will really enjoy the Modular1 with all the
features of an analog modular synthesizer put into a single VST3
instrument. With the added features of polyphony and patches that
change instantaneously this synthesizer is truly a powerhouse in the
audio toolbox.</p>
<a href="/vst"><img src="/assets/modular1.png" style="width: 200px;" align="left"></a>
<p>Excellent quality and technical performance provide a performance level
instrument for musicians or students who wish to learn sound wave
synthesis techniques or for musicians to enable that old analog sound
in their DAW recording system..</p>
<p>Checkout the product page for more information on the capabilities
of the Modular1 synthesizer.</p>
</div>
</sectionframe>
+24 -2
View File
@@ -1,7 +1,29 @@
<sectionframe title="MAIN">
<if value1="$[SUBPAGE]" value2="" type="eq">
<linkbutton page="main" class="submenuitem-active">OVERVIEW</linkbutton><br>
<else>
<linkbutton page="main">OVERVIEW</linkbutton><br>
</if>
<if value1="$[SUBPAGE]" value2="music" type="eq">
<linkbutton page="main" subpage="music" class="submenuitem-active">MUSIC</linkbutton><br>
<else>
<linkbutton page="main" subpage="music">MUSIC</linkbutton><br>
</if>
<if value1="$[SUBPAGE]" value2="library" type="eq">
<linkbutton page="main" subpage="library" class="submenuitem-active">MATT'S LIBRARY</linkbutton><br>
<else>
<linkbutton page="main" subpage="library">MATT'S LIBRARY</linkbutton><br>
</if>
<if value1="$[SUBPAGE]" value2="ianslibrary" type="eq">
<linkbutton page="main" subpage="ianslibrary" class="submenuitem-active">IAN'S LIBRARY</linkbutton><br>
<else>
<linkbutton page="main" subpage="ianslibrary">IAN'S LIBRARY</linkbutton><br>
</if>
</sectionframe>
<sectionframe title="QUICK LINKS"> <sectionframe title="QUICK LINKS">
<linkbutton page="services">SERVICES</linkbutton><br> <linkbutton page="services">SERVICES</linkbutton><br>
<linkbutton page="hosting">HOSTING</linkbutton><br> <linkbutton page="services" subpage="hosting">HOSTING</linkbutton><br>
<linkbutton page="siptrunk">SIP TRUNKING</linkbutton><br> <linkbutton page="services" subpage="siptrunking">SIP TRUNKING</linkbutton><br>
<linkbutton page="opensource">OPEN SOURCE</linkbutton><br> <linkbutton page="opensource">OPEN SOURCE</linkbutton><br>
<linkbutton page="contact">CONTACT</linkbutton> <linkbutton page="contact">CONTACT</linkbutton>
</sectionframe> </sectionframe>
+10 -22
View File
@@ -2,28 +2,16 @@
<title>BARANT Technology Group</title> <title>BARANT Technology Group</title>
<contents> <contents>
<setenv name="_menubar"></setenv> <setenv name="_menubar"></setenv>
<sectionframe title="Welcome to BARANT Systems"> <div id="main-subpage">
<if value1="$[SUBPAGE]" value2="" type="eq">
<div style="width: 48%;"> <include file="main-overview.subpage">
<p>We are BARANT Technology Group. Contact us for information on how we can <else>
help you with your technical objectives.</p> <try>
<include file="main-$[SUBPAGE].subpage">
<h1>Modular1 VST Synthesizer</h1> <catch>
<p>Check out our <a href="/vst">Modular1 VST3 <p>That page doesn't exist.</p>
Synthesizer</a> If you appreciate the art of modular analog </try>
synthesizers then you will really enjoy the Modular1 with all the </if>
features of an analog modular synthesizer put into a single VST3
instrument. With the added features of polyphony and patches that
change instantaneously this synthesizer is truly a powerhouse in the
audio toolbox.</p>
<a href="/vst"><img src="/assets/modular1.png" style="width: 200px;" align="left"></a>
<p>Excellent quality and technical performance provide a performance level
instrument for musicians or students who wish to learn sound wave
synthesis techniques or for musicians to enable that old analog sound
in their DAW recording system..</p>
<p>Checkout the product page for more information on the capabilities
of the Modular1 synthesizer.</p>
</div> </div>
</sectionframe>
</contents> </contents>
</page> </page>
+747 -6
View File
@@ -72,7 +72,7 @@ $[_BODY]
<html lang="en"> <html lang="en">
<head> <head>
<title>BARANT Technology Group</title> <title>BARANT Technology Group</title>
<link rel="stylesheet" href="/assets/main.css?v=20260908a"> <link rel="stylesheet" href="/assets/main.css?v=20261006a">
<link rel="stylesheet" href="/assets/control.css?v=20260902"> <link rel="stylesheet" href="/assets/control.css?v=20260902">
</head> </head>
<body> <body>
@@ -88,13 +88,753 @@ $[_BODY]
<div class="pageclass"> <div class="pageclass">
<div class="heading"> <div class="heading">
<div style="display: inline-block; width: 500px;"> <div style="display: inline-block; width: 500px;">
<a href="https://barant.com"><img style="width: 60px; height: 60px; margin: 10px; background-color: #000; border-radius: 6px; padding: 4px; box-sizing: border-box;" align="left" src="/assets/btglogo.png"></a> <a href="https://barant.com"><img style="height: 100px; width: auto; margin: 10px; border-radius: 6px; box-sizing: border-box;" align="left" src="/assets/btglogo.png"></a>
<div style="padding-top: 15px;">
<div style="left: 80px; color: #c5a45a; font-size: 20pt; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 600;">BARANT TECHNOLOGY GROUP</div>
</div>
</div> </div>
<div id="loginmenu" style="float: right; text-align: right; margin-right: 10px; margin-top: 5px;"><include file="login.menu"></div> <div id="loginmenu" style="float: right; text-align: right; margin-right: 10px; margin-top: 5px;"><include file="login.menu"></div>
</div> </div>
<div id="globalplayer-band" class="globalplayer-band">
<div id="globalplayer-playpause" class="globalplayer-btn" title="Play/Pause" onclick="__playerTogglePause();">
<svg id="globalplayer-playicon" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
<svg id="globalplayer-pauseicon" viewBox="0 0 24 24" fill="currentColor" style="display:none;"><path d="M6 5h4v14H6zM14 5h4v14h-4z"/></svg>
</div>
<div id="globalplayer-stop" class="globalplayer-btn" title="Stop" onclick="__playerStop();">
<svg viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="6" width="12" height="12"/></svg>
</div>
<div id="globalplayer-skip" class="globalplayer-btn" title="Skip" onclick="__playerAdvance();">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M6 5v14l8-7zM16 5h2v14h-2z"/></svg>
</div>
<div id="globalplayer-title" class="globalplayer-title">
<div id="globalplayer-duration" class="globalplayer-duration"></div>
<div id="globalplayer-random-indicator" class="globalplayer-random-indicator">RANDOM</div>
<div id="globalplayer-title-text" class="globalplayer-title-text">Not Playing</div>
<div id="globalplayer-progress" class="globalplayer-progress"><div id="globalplayer-progress-fill" class="globalplayer-progress-fill"></div><div id="globalplayer-progress-handle" class="globalplayer-progress-handle"></div></div>
</div>
<input type="range" id="globalplayer-volume" class="globalplayer-volume" min="0" max="100" value="<if value1="$[@_player_volume]" value2="" type="eq">100<else>$[@_player_volume]</if>" title="Volume" oninput="__playerSetVolume(this.value);" onchange="__playerPersistVolume(this.value);">
<canvas id="globalplayer-eq" class="globalplayer-eq" width="60" height="32"></canvas>
<div id="globalplayer-queue-toggle" class="globalplayer-btn globalplayer-btn-text" title="Playlist" onclick="__playerToggleQueue();">RANDOM</div>
<audio id="globalaudio" style="display:none;"></audio>
</div>
<script type="application/json" id="globalplayer-saved-state">$[@_player_state]</script>
<div id="globalplayer-queue" class="globalplayer-queue"></div>
<script>
// Global, persistent music player + playlist queue - lives here (outside
// the #content area) specifically so it survives spa.js's per-navigation
// content.innerHTML swap: this whole full-page-load branch of
// mainpagetemplate.jet only ever renders once per real browser
// navigation, never again on a client-side SPA page change (the
// fragment branch further below renders none of this) - so this
// audio element and the playlist array it drives keep running
// uninterrupted across every subsequent in-app page click, exactly
// like the request asked for (as long as you do not leave the domain).
var __playlist = [];
var __currentIndex = -1;
var __isIdle = true;
var __playToken = 0;
// Turned on by clicking RANDOM while nothing is queued, turned back
// off by clicking the same button (now showing HALT) - while on, the
// queue auto-refills with another random pick instead of going idle
// or sitting empty whenever it runs out, rather than that one click
// only ever adding a single song.
var __autoRandomMode = false;
// Display-only - the real audio.src below still uses entry.file in
// full, extension included, since that is what the server actually
// needs to find the right file on disk.
function __stripExtension(filename) {
var dot = filename.lastIndexOf('.');
return dot > 0 ? filename.substring(0, dot) : filename;
}
function __playerLoad(entry) {
var audio = document.getElementById('globalaudio');
var title = document.getElementById('globalplayer-title-text');
document.getElementById('globalplayer-band').classList.add('globalplayer-open');
__setProgress(0);
document.getElementById('globalplayer-duration').textContent = '0:00';
var myToken = ++__playToken;
audio.src = entry.path + '/' + entry.file;
title.textContent = __stripExtension(entry.file);
audio.load();
audio.play().catch(function(err) {
// Same AbortError race already solved once for the old per-page
// player (see the history of main-music.subpage) - a later selection
// already owns recovery if it has since bumped __playToken.
if (myToken === __playToken) __playerAdvance();
});
}
function __goIdle() {
var audio = document.getElementById('globalaudio');
audio.pause();
__isIdle = true;
document.getElementById('globalplayer-band').classList.remove('globalplayer-open');
document.getElementById('globalplayer-title-text').textContent = 'Not Playing';
__setProgress(0);
document.getElementById('globalplayer-duration').textContent = '';
}
// The song-picker row stays marked (checkmark + flash) via addToPlaylist
// for as long as its entry is actually sitting in __playlist - this
// clears that mark once a song is no longer there, whether it finished
// naturally or was deleted via the remove button. Matches by data-path/
// data-file rather than building a CSS attribute-selector string, since
// real filenames can contain quotes/other characters that would need
// escaping to use safely in one.
function __unmarkSongRow(path, file) {
document.querySelectorAll('.music-song-row').forEach(function(row) {
if (row.dataset.path === path && row.dataset.file === file) {
row.classList.remove('song-queued');
row.classList.remove('song-queued-flash');
}
});
}
// Shared by __playerAdvance and __removeFromPlaylist - whichever path
// the queue became empty through, the same rule applies: auto-random
// mode refills it with another pick instead of actually going idle.
function __goIdleOrAutoFill() {
if (__autoRandomMode) {
__isIdle = true;
__playRandomSong();
} else {
__goIdle();
}
}
function __playerAdvance() {
var finished = __playlist[__currentIndex];
if (__currentIndex + 1 < __playlist.length) {
__currentIndex++;
__playerLoad(__playlist[__currentIndex]);
} else {
__goIdleOrAutoFill();
}
if (finished) __unmarkSongRow(finished.path, finished.file);
__renderQueue();
}
// Removing a not-yet-played entry just drops it. Removing the
// CURRENTLY playing one is treated like a skip: splice it out, then
// whatever was queued right behind it has shifted down into this same
// index, so loading __playlist[__currentIndex] again (unchanged value,
// now pointing at a different entry) picks it up - or goes idle if
// that was the last one left. A row for anything already played is
// never rendered in the dropdown in the first place (see __renderQueue
// - it only shows current-and-later), so there is no "delete history"
// case to handle here.
function __removeFromPlaylist(index) {
var removed = __playlist[index];
if (index === __currentIndex) {
__playlist.splice(index, 1);
if (index < __playlist.length) {
__playerLoad(__playlist[__currentIndex]);
} else {
__goIdleOrAutoFill();
}
} else if (index > __currentIndex) {
__playlist.splice(index, 1);
}
if (removed) __unmarkSongRow(removed.path, removed.file);
__renderQueue();
}
// Only ever called with indices from rows actually rendered in the
// dropdown, which (see __renderQueue's own comment) never include the
// currently-playing entry - so this only ever reorders the upcoming
// portion of the queue, never disturbs __currentIndex itself.
function __reorderPlaylist(fromIndex, toIndex) {
if (fromIndex === toIndex) return;
var item = __playlist.splice(fromIndex, 1)[0];
__playlist.splice(toIndex, 0, item);
__renderQueue();
}
function __setProgress(ratio) {
var pct = (Math.max(0, Math.min(1, ratio)) * 100) + '%';
document.getElementById('globalplayer-progress-fill').style.width = pct;
document.getElementById('globalplayer-progress-handle').style.left = pct;
}
function __updateTimeDisplay(current, total) {
document.getElementById('globalplayer-duration').textContent = __formatTime(current) + ' / ' + __formatTime(total);
}
// Shared with the music/jukebox subpages' own song-picker lists (not
// just the playlist dropdown) - a lightweight metadata-only probe so
// each row can show its own track length without needing to play it
// first.
// All duration probes (both this and addToPlaylist's own) funnel
// through one strictly-sequential queue - a song list can easily have
// 100+ rows, and firing a probe per row all at once was saturating the
// browser's per-origin connection limit (6 concurrent, in most
// browsers) with background metadata fetches. A real click to actually
// play something queues up behind whichever of those happened to grab
// a connection first, which is what made selecting a song "not work or
// take a long time" - processing one probe at a time, each starting
// only once the previous finishes, keeps the other 5 connection slots
// free for an actual user-initiated request at all times.
var __durationQueue = [];
var __durationQueueRunning = false;
function __queueDurationProbe(path, file, onReady) {
__durationQueue.push({path: path, file: file, onReady: onReady});
__runDurationQueue();
}
function __runDurationQueue() {
if (__durationQueueRunning || __durationQueue.length === 0) return;
__durationQueueRunning = true;
var item = __durationQueue.shift();
var probe = new Audio();
probe.preload = 'metadata';
function done() {
__durationQueueRunning = false;
__runDurationQueue();
}
probe.addEventListener('loadedmetadata', function() {
item.onReady(probe.duration);
done();
});
probe.addEventListener('error', done);
probe.src = item.path + '/' + item.file;
}
function __loadSongDuration(path, file, el) {
if (!el) return;
__queueDurationProbe(path, file, function(duration) {
el.textContent = __formatTime(duration);
});
}
function __formatTime(seconds) {
if (!seconds || isNaN(seconds) || !isFinite(seconds)) return '0:00';
seconds = Math.floor(seconds);
var h = Math.floor(seconds / 3600);
var m = Math.floor((seconds % 3600) / 60);
var s = seconds % 60;
var sStr = (s < 10 ? '0' : '') + s;
if (h > 0) {
var mStr = (m < 10 ? '0' : '') + m;
return h + ':' + mStr + ':' + sStr;
}
return m + ':' + sStr;
}
function __escapeHtml(s) {
return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
// Builds a music subpage's song list client-side from the fast JSON
// listing route (GET /assets/musiclist/{subfolder}), rather than having
// the server render one row per file via a directory-loop tag - that
// path was genuinely slow for these particular folders (~1200+ files
// each), since every literal HTML element inside a Jet loop body costs
// real, compounding interpreter overhead per iteration. The container
// appears instantly (empty) on navigation; this fills it in shortly
// after via one fetch, in small batches via requestAnimationFrame
// rather than one giant synchronous DOM write, so the list visibly
// populates rather than the page just sitting blank until everything
// is ready at once.
function __renderMusicFolder(containerId, subfolder, basePath) {
var container = document.getElementById(containerId);
if (!container) return;
fetch('/assets/musiclist/' + subfolder)
.then(function(r) { return r.json(); })
.then(function(data) {
var files = data.files || [];
var i = 0;
function appendBatch() {
var end = Math.min(i + 100, files.length);
for (; i < end; i++) {
var file = files[i];
var row = document.createElement('div');
row.className = 'music-song-row';
row.dataset.path = basePath;
row.dataset.file = file;
var nameSpan = document.createElement('span');
nameSpan.className = 'music-song-name';
nameSpan.textContent = __stripExtension(file);
var durSpan = document.createElement('span');
durSpan.className = 'music-song-duration';
row.appendChild(nameSpan);
row.appendChild(durSpan);
row.addEventListener('click', (function(rowEl, path, fname) {
return function() { addToPlaylist(rowEl, path, fname); };
})(row, basePath, file));
container.appendChild(row);
__loadSongDuration(basePath, file, durSpan);
}
if (i < files.length) requestAnimationFrame(appendBatch);
}
appendBatch();
})
.catch(function(err) {
container.textContent = 'Could not load the song list.';
});
}
function __playerSetVolume(val) {
document.getElementById('globalaudio').volume = val / 100;
}
// Only persists on change (slider release), not on every input event
// while dragging, so dragging does not fire a request per pixel moved.
function __playerPersistVolume(val) {
fetch(window.location.pathname, {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'PROCESS=setvolume&volume=' + encodeURIComponent(val)
});
}
// While idle (nothing playing, nothing queued) there is nothing for a
// playlist dropdown to show, so the same button instead offers to pick
// something at random - its label reflects whichever of those two
// things it would actually do right now, recomputed any time the open/
// closed state or __isIdle changes (see __renderQueue's own call to
// this).
function __updateQueueButtonLabel() {
var btn = document.getElementById('globalplayer-queue-toggle');
var queueOpen = document.getElementById('globalplayer-queue').classList.contains('globalplayer-queue-open');
if (queueOpen) {
btn.textContent = 'CLOSE';
} else if (__autoRandomMode) {
btn.textContent = 'HALT';
} else if (!__hasQueuedSongs()) {
btn.textContent = 'RANDOM';
} else {
btn.textContent = 'PLAYLIST';
}
document.getElementById('globalplayer-random-indicator').classList.toggle('globalplayer-random-indicator-visible', __autoRandomMode);
}
function __hasQueuedSongs() {
return !__isIdle && __currentIndex !== -1 && (__currentIndex + 1 < __playlist.length);
}
function __playerToggleQueue() {
// Already in auto-random mode - this button's only job right now is
// to turn it back off (does not stop whatever is currently playing,
// just stops it from auto-refilling once that finishes).
if (__autoRandomMode) {
__autoRandomMode = false;
__updateQueueButtonLabel();
return;
}
// Nothing queued (whether idle or something is already playing) -
// turn auto-random mode on and queue the first pick right away rather
// than making this a one-shot "add one song" click.
if (!__hasQueuedSongs()) {
__autoRandomMode = true;
__playRandomSong();
return;
}
document.getElementById('globalplayer-queue').classList.toggle('globalplayer-queue-open');
__updateQueueButtonLabel();
}
// Picks from whatever song-picker rows happen to be rendered on the
// CURRENT page (music/jukebox's own .music-song-row elements) - there
// is no server-side "list all songs" endpoint to fall back on, so this
// only has songs to choose from when the page you are actually on has
// some. Reuses addToPlaylist exactly as a real click would (same
// element, same path/file), so the row's own checkmark/flash feedback
// and the queue button's label both update exactly as they would for a
// manual click.
function __playRandomSong() {
var rows = document.querySelectorAll('.music-song-row');
if (rows.length === 0) return;
var row = rows[Math.floor(Math.random() * rows.length)];
addToPlaylist(row, row.dataset.path, row.dataset.file, true);
}
// Shows the current song as the first entry, followed by whatever is
// still queued up behind it - not a play history, just now-playing
// plus up-next, rebuilt every time the queue or current position changes.
// The currently-playing entry is deliberately left out of this list -
// it's already shown up in the LCD title/progress bar, so the dropdown
// now only ever shows what's queued up NEXT, not what's already
// playing.
// Session persistence - survives a real full-page navigation/reload
// the same way the volume slider's own session variable already does
// (see setvolume.proc), using one JSON blob (one session variable,
// one .proc) rather than several separate ones so the whole player
// state saves/restores atomically together.
// Runs once, at setup - reads the JSON a real full-page load embedded
// server-side (see the script#globalplayer-saved-state tag, rendered
// from the same session variable setplayerstate.proc writes) and picks
// playback back up from there. A plain text node's content needs none
// of the quote-escaping embedding this directly inside a JS string
// literal would have required, since real song filenames/paths can
// contain characters (quotes, etc.) that would otherwise have to be
// escaped correctly to avoid corrupting the surrounding script.
function __restoreSavedPlayerState() {
var stateEl = document.getElementById('globalplayer-saved-state');
if (!stateEl) return;
var raw = stateEl.textContent.trim();
if (!raw) return;
var saved;
try {
saved = JSON.parse(atob(raw));
} catch (e) {
return;
}
if (!saved || !saved.playlist || !saved.playlist.length) return;
__playlist = saved.playlist.map(function(p) { return {path: p.path, file: p.file, duration: null}; });
__currentIndex = Math.min(Math.max(0, saved.currentIndex || 0), __playlist.length - 1);
__isIdle = false;
__autoRandomMode = !!saved.autoRandomMode;
var entry = __playlist[__currentIndex];
var audio = document.getElementById('globalaudio');
document.getElementById('globalplayer-band').classList.add('globalplayer-open');
document.getElementById('globalplayer-title-text').textContent = __stripExtension(entry.file);
audio.src = entry.path + '/' + entry.file;
audio.load();
function onceReady() {
audio.removeEventListener('loadedmetadata', onceReady);
if (saved.position) audio.currentTime = saved.position;
if (saved.playing) {
// Browsers block unprompted autoplay without a real user gesture -
// if that happens, this just stays loaded and paused at the
// restored position instead of erroring, the same tolerance the
// normal play()-failure handling elsewhere already has.
audio.play().catch(function() {});
}
}
audio.addEventListener('loadedmetadata', onceReady);
}
function __buildPlayerState() {
var audio = document.getElementById('globalaudio');
return {
playlist: __playlist.map(function(p) { return {path: p.path, file: p.file}; }),
currentIndex: __currentIndex,
position: audio.currentTime || 0,
playing: !audio.paused,
autoRandomMode: __autoRandomMode
};
}
// base64-encoded before it ever reaches the server, not just plain
// JSON - the session store is itself JSON-backed (JFile), and a raw
// JSON string containing quote characters round-trips back out of
// the player-state session variable with its quotes re-escaped - the
// text node ends up holding broken, double-escaped JSON rather than
// the original. Base64 has no quote characters to collide with that
// escaping in the first place, so this sidesteps the whole problem
// rather than trying to out-guess exactly how many times to un-escape
// it.
function __persistPlayerState() {
fetch(window.location.pathname, {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'PROCESS=setplayerstate&state=' + encodeURIComponent(btoa(JSON.stringify(__buildPlayerState())))
});
}
function __renderQueue() {
var queue = document.getElementById('globalplayer-queue');
var html = '';
if (!__hasQueuedSongs()) {
// Nothing to show either way (idle, or playing with nothing queued
// behind it) - leave it empty and force it closed rather than
// displaying a placeholder message, matching __playerToggleQueue's
// own refusal to open it in this state.
queue.classList.remove('globalplayer-queue-open');
} else {
for (var i = __currentIndex + 1; i < __playlist.length; i++) {
var name = __escapeHtml(__stripExtension(__playlist[i].file));
var dur = (__playlist[i].duration != null) ? __formatTime(__playlist[i].duration) : '';
html += '<div class="globalplayer-queue-item" draggable="true" data-index="' + i + '">'
+ '<span class="globalplayer-queue-left">'
+ '<span class="globalplayer-queue-handle" title="Drag to reorder"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="M4 7h16M4 12h16M4 17h16"/></svg></span>'
+ '<span class="globalplayer-queue-name">' + name + '</span>'
+ '</span>'
+ '<span class="globalplayer-queue-right">'
+ '<span class="globalplayer-queue-duration">' + dur + '</span>'
+ '<button type="button" class="globalplayer-queue-remove" title="Remove" onclick="__removeFromPlaylist(' + i + ');"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h16"/><path d="M9 7V4h6v3"/><path d="M6 7l1 13a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2l1-13"/><path d="M10 11v6M14 11v6"/></svg></button>'
+ '</span>'
+ '</div>';
}
}
queue.innerHTML = html;
__updateQueueButtonLabel();
__persistPlayerState();
}
function __playerTogglePause() {
if (__isIdle) return;
var audio = document.getElementById('globalaudio');
if (audio.paused) {
audio.play();
} else {
audio.pause();
}
}
// Distinct from pause: pause just halts playback in place with the
// band staying open (see __playerTogglePause/the pause listener's own
// comment) - stop clears the queue entirely and closes the band, a
// genuine "shut the player off" rather than a resumable pause.
function __playerStop() {
__playlist = [];
__currentIndex = -1;
__goIdle();
__renderQueue();
}
// Shared entry point every music/jukebox subpage calls on a song click -
// appends to the queue, and only starts playback immediately if the
// queue was otherwise idle (nothing already playing/queued).
// isAutoRandom is only ever true when __playRandomSong() itself is the
// caller (a manual click on a song-picker row never passes it) -
// picking a specific song yourself is a clear signal you want to take
// back manual control, so that turns auto-random mode back off rather
// than leaving the button stuck on HALT while a real, manually-chosen
// entry sits in the queue underneath it.
function addToPlaylist(el, path, file, isAutoRandom) {
if (!isAutoRandom) __autoRandomMode = false;
var entry = {path: path, file: file, duration: null};
__playlist.push(entry);
// The queue only ever stores path/file - duration is not otherwise
// known until something actually plays it, so a lightweight probe
// (metadata only, not the full file) fetches just enough to learn it
// for the playlist dropdown's own display - shares the same
// one-at-a-time queue the song-picker list's own probes use (see
// __queueDurationProbe's own comment for why that matters).
__queueDurationProbe(path, file, function(duration) {
entry.duration = duration;
__renderQueue();
});
if (__isIdle) {
__isIdle = false;
__currentIndex = __playlist.length - 1;
__playerLoad(__playlist[__currentIndex]);
}
__renderQueue();
if (el) {
el.classList.add('song-queued');
el.classList.remove('song-queued-flash');
// Force a reflow so re-adding the flash class restarts the animation
// even if this same row was already flashed once before.
void el.offsetWidth;
el.classList.add('song-queued-flash');
}
}
(function() {
var audio = document.getElementById('globalaudio');
var band = document.getElementById('globalplayer-band');
var playIcon = document.getElementById('globalplayer-playicon');
var pauseIcon = document.getElementById('globalplayer-pauseicon');
var eqCanvas = document.getElementById('globalplayer-eq');
var progressBar = document.getElementById('globalplayer-progress');
// Delegated on the queue container itself rather than attached per-row,
// since __renderQueue() rebuilds every row's markup via innerHTML on
// every change - listeners bound directly to a row would be destroyed
// and need re-attaching on every single re-render. The container
// element itself is never replaced, only its children, so binding here
// once at setup survives any number of re-renders.
var queueEl = document.getElementById('globalplayer-queue');
var __dragSrcIndex = null;
queueEl.addEventListener('dragstart', function(e) {
var row = e.target.closest('.globalplayer-queue-item');
if (!row || row.dataset.index === undefined) return;
__dragSrcIndex = parseInt(row.dataset.index, 10);
e.dataTransfer.effectAllowed = 'move';
row.classList.add('globalplayer-queue-dragging');
});
queueEl.addEventListener('dragover', function(e) {
var row = e.target.closest('.globalplayer-queue-item');
if (!row || row.dataset.index === undefined) return;
e.preventDefault();
queueEl.querySelectorAll('.globalplayer-queue-dragover').forEach(function(el) {
el.classList.remove('globalplayer-queue-dragover');
});
row.classList.add('globalplayer-queue-dragover');
});
queueEl.addEventListener('dragleave', function(e) {
var row = e.target.closest('.globalplayer-queue-item');
if (row) row.classList.remove('globalplayer-queue-dragover');
});
queueEl.addEventListener('drop', function(e) {
var row = e.target.closest('.globalplayer-queue-item');
e.preventDefault();
if (row && row.dataset.index !== undefined && __dragSrcIndex !== null) {
__reorderPlaylist(__dragSrcIndex, parseInt(row.dataset.index, 10));
}
__dragSrcIndex = null;
});
queueEl.addEventListener('dragend', function() {
queueEl.querySelectorAll('.globalplayer-queue-dragging, .globalplayer-queue-dragover').forEach(function(el) {
el.classList.remove('globalplayer-queue-dragging', 'globalplayer-queue-dragover');
});
__dragSrcIndex = null;
});
// Click-or-drag seeking: setPointerCapture means every subsequent
// move/up for this same pointer keeps routing here even once the
// cursor leaves the bar's own bounds while still held down - the
// standard way a scrubber stays grabbed mid-drag rather than losing
// the gesture the moment the mouse strays off the (thin, 8px) bar.
function seekFromEvent(e) {
if (!audio.duration || isNaN(audio.duration)) return;
var rect = progressBar.getBoundingClientRect();
var ratio = (e.clientX - rect.left) / rect.width;
ratio = Math.max(0, Math.min(1, ratio));
audio.currentTime = ratio * audio.duration;
__setProgress(ratio);
__updateTimeDisplay(audio.currentTime, audio.duration);
}
progressBar.addEventListener('pointerdown', function(e) {
progressBar.classList.add('globalplayer-progress-dragging');
progressBar.setPointerCapture(e.pointerId);
seekFromEvent(e);
});
progressBar.addEventListener('pointermove', function(e) {
if (progressBar.classList.contains('globalplayer-progress-dragging'))
seekFromEvent(e);
});
progressBar.addEventListener('pointerup', function(e) {
progressBar.classList.remove('globalplayer-progress-dragging');
progressBar.releasePointerCapture(e.pointerId);
});
var eqCtx = eqCanvas.getContext('2d');
audio.volume = document.getElementById('globalplayer-volume').value / 100;
audio.addEventListener('ended', function() { __playerAdvance(); });
audio.addEventListener('loadedmetadata', function() {
__updateTimeDisplay(audio.currentTime, audio.duration);
});
var __lastPersistTime = 0;
audio.addEventListener('timeupdate', function() {
if (!progressBar.classList.contains('globalplayer-progress-dragging') && audio.duration && !isNaN(audio.duration)) {
__setProgress(audio.currentTime / audio.duration);
__updateTimeDisplay(audio.currentTime, audio.duration);
}
// Position alone is not worth persisting on every tick (several
// times a second) - throttled here rather than through
// __renderQueue(), which only runs on actual playlist/track changes,
// not on ordinary mid-song progress.
var now = Date.now();
if (now - __lastPersistTime > 5000) {
__lastPersistTime = now;
__persistPlayerState();
}
});
// Stereo FFT-style bar graph in the band itself. Web Audio requires a
// real user gesture before an AudioContext will actually run, which a
// play event always is - built lazily here, once, on the first real
// play rather than up front at page load. A ChannelSplitter feeds one
// AnalyserNode per channel so left and right are genuinely independent
// readings, not the same mono data mirrored twice.
var audioCtx = null, leftAnalyser = null, rightAnalyser = null;
function setupAudioAnalysis() {
if (audioCtx) return;
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var source = audioCtx.createMediaElementSource(audio);
var splitter = audioCtx.createChannelSplitter(2);
leftAnalyser = audioCtx.createAnalyser();
rightAnalyser = audioCtx.createAnalyser();
leftAnalyser.fftSize = 128;
rightAnalyser.fftSize = 128;
leftAnalyser.smoothingTimeConstant = 0.7;
rightAnalyser.smoothingTimeConstant = 0.7;
// createMediaElementSource() reroutes the audio element's own output
// through the Web Audio graph exclusively - it no longer reaches
// speakers on its own past this point, so this connection to
// destination is what keeps playback audible, not optional wiring.
source.connect(audioCtx.destination);
source.connect(splitter);
splitter.connect(leftAnalyser, 0);
splitter.connect(rightAnalyser, 1);
requestAnimationFrame(drawEQ);
}
// Picks bars on a log scale rather than evenly across the raw bin
// range - real music concentrates nearly all of its energy in the
// first few linearly-indexed bins, so evenly-spaced bins beyond those
// read as flat/empty and the whole graph reads as one solid block
// instead of a varied spectrum. Spacing bar selection logarithmically
// (the same way a real hardware equalizer's bands are laid out) picks
// bins that are far enough apart in the actual data to show real
// variation bar to bar.
function logBin(i, count, bufferLength) {
var t = (i + 1) / count;
return Math.max(0, Math.min(bufferLength - 1, Math.floor(Math.pow(bufferLength, t)) - 1));
}
function drawEQ() {
requestAnimationFrame(drawEQ);
var w = eqCanvas.width, h = eqCanvas.height;
eqCtx.clearRect(0, 0, w, h);
if (!leftAnalyser || !rightAnalyser || audio.paused) return;
var bufferLength = leftAnalyser.frequencyBinCount;
var leftData = new Uint8Array(bufferLength);
var rightData = new Uint8Array(bufferLength);
leftAnalyser.getByteFrequencyData(leftData);
rightAnalyser.getByteFrequencyData(rightData);
// Two separate bar groups, left channel and right channel, each
// rising from the bottom with a visible gap between bars and between
// the two groups - reads as two independent stereo meters rather
// than one shape mirrored around a center line.
var barsPerChannel = 5;
var gap = 2;
var channelWidth = (w - gap) / 2;
var barWidth = (channelWidth - gap * (barsPerChannel - 1)) / barsPerChannel;
eqCtx.fillStyle = '#1a8fc4';
for (var i = 0; i < barsPerChannel; i++) {
var bin = logBin(i, barsPerChannel, bufferLength);
var barH = Math.max(2, (leftData[bin] / 255) * h);
eqCtx.fillRect(i * (barWidth + gap), h - barH, barWidth, barH);
}
for (var i = 0; i < barsPerChannel; i++) {
var bin = logBin(i, barsPerChannel, bufferLength);
var barH = Math.max(2, (rightData[bin] / 255) * h);
eqCtx.fillRect(channelWidth + gap * 2 + i * (barWidth + gap), h - barH, barWidth, barH);
}
}
audio.addEventListener('play', function() {
playIcon.style.display = 'none';
pauseIcon.style.display = '';
if (!audioCtx) setupAudioAnalysis();
else if (audioCtx.state === 'suspended') audioCtx.resume();
__persistPlayerState();
});
audio.addEventListener('pause', function() {
// Deliberately does NOT close the band - that is tied to __isIdle
// (see __playerLoad/__goIdle) rather than the raw play/pause events,
// so pausing just shows the paused icon with the band, LCD, and
// scrubber all staying visible. It used to close here, which made a
// plain pause look like the whole player had reset.
playIcon.style.display = '';
pauseIcon.style.display = 'none';
__persistPlayerState();
});
// A regular fetch() made this late in a page's life is not reliably
// delivered by the browser - sendBeacon exists specifically to still
// get a small POST out as the page is actually going away, so a
// reload/tab-close/navigation right after a timeupdate tick does not
// lose up to 5 seconds of position progress.
window.addEventListener('pagehide', function() {
var body = 'PROCESS=setplayerstate&state=' + encodeURIComponent(btoa(JSON.stringify(__buildPlayerState())));
navigator.sendBeacon(window.location.pathname, new Blob([body], {type: 'application/x-www-form-urlencoded'}));
});
__restoreSavedPlayerState();
__renderQueue();
})();
</script>
<div class="menubar" id="menubar"> <div class="menubar" id="menubar">
<include file="menu.bar"> <include file="menu.bar">
</div> </div>
@@ -115,6 +855,7 @@ $[_BODY]
<div style="clear: both;"></div> <div style="clear: both;"></div>
</div> </div>
</div> </div>
<div id="spa-loading-indicator" class="spa-loading-indicator">Retrieving content...</div>
<div class="footer" style="clear: both;">&copy; 1999-2026 BARANT Systems, All Rights Reserved</div> <div class="footer" style="clear: both;">&copy; 1999-2026 BARANT Systems, All Rights Reserved</div>
</div> </div>
</form> </form>
@@ -131,7 +872,7 @@ $[_BODY]
<div id="filemgr-list"><div id="filemgr-empty">No transfers yet.</div></div> <div id="filemgr-list"><div id="filemgr-empty">No transfers yet.</div></div>
</div> </div>
</div> </div>
<script src="/assets/spa.js?v=20260913a"></script> <script src="/assets/spa.js?v=20261006"></script>
<script src="/assets/documents.js?v=20260906a"></script> <script src="/assets/documents.js?v=20260906a"></script>
</body> </body>
</html> </html>
+2 -3
View File
@@ -9,10 +9,7 @@
<td style="border-bottom: 1pt solid #bbb; width: 20px;">&nbsp;</td> <td style="border-bottom: 1pt solid #bbb; width: 20px;">&nbsp;</td>
<tab page="main"><a href="/main">HOME</a></tab> <tab page="main"><a href="/main">HOME</a></tab>
<tab page="services"><a href="/services">SERVICES</a></tab> <tab page="services"><a href="/services">SERVICES</a></tab>
<tab page="hosting"><a href="/hosting">HOSTING</a></tab>
<tab page="store"><a href="/store/createstore">CREATE STORE</a></tab> <tab page="store"><a href="/store/createstore">CREATE STORE</a></tab>
<tab page="documents"><a href="/documents">DOCUMENT MGMT</a></tab>
<tab page="siptrunk"><a href="/siptrunk">SIP TRUNKING</a></tab>
<tab page="vst"><a href="/vst">VST</a></tab> <tab page="vst"><a href="/vst">VST</a></tab>
<tab page="wordpress"><a href="/wordpress">WORDPRESS</a></tab> <tab page="wordpress"><a href="/wordpress">WORDPRESS</a></tab>
<tab page="opensource"><a href="/opensource">OPEN SOURCE</a></tab> <tab page="opensource"><a href="/opensource">OPEN SOURCE</a></tab>
@@ -27,7 +24,9 @@
</if> </if>
<if value1="$[_login_id]" value2="" type="ne"> <if value1="$[_login_id]" value2="" type="ne">
<tab page="account"><a href="/account">ACCOUNT</a></tab> <tab page="account"><a href="/account">ACCOUNT</a></tab>
<if value1="$[_login_type]" value2="admin" type="eq">
<tab page="admin"><a href="/admin">ADMIN</a></tab> <tab page="admin"><a href="/admin">ADMIN</a></tab>
</if>
<else> <else>
<tab page="login"><a href="/login">LOGIN</a></tab> <tab page="login"><a href="/login">LOGIN</a></tab>
</if> </if>
+2 -2
View File
@@ -3,8 +3,8 @@
<contents> <contents>
<script> <script>
var index = 0; var index = 0;
const paths = []; var paths = [];
const songs = []; var songs = [];
function onselection(id) { function onselection(id) {
var name = '/get_modular_sample.cgi?id=' + id; var name = '/get_modular_sample.cgi?id=' + id;
var player = document.getElementById('player'); var player = document.getElementById('player');
-47
View File
@@ -1,47 +0,0 @@
<page secure="yes" loggedin="no">
<title>BAE MUSIC</title>
<contents>
<script>
var index = 0;
const paths = [];
const songs = [];
function onselection(path,selection) {
var name = path + '/' + selection;
var player = document.getElementById('player');
var audio = document.getElementById('audio');
var title = document.getElementById('title');
player.src = name;
title.textContent = selection;
audio.load();
audio.play();
}
function selectNext() {
var index = Math.floor(Math.random()*songs.length) + 1;
onselection(paths[index],songs[index]);
}
</script>
<retain name="download_file">
<div style="display: inline-block;">
<audio id="audio" controls onended="selectNext();">
<source id="player" type="audio/mp3">
</audio>
</div>
<div style="font-size: 20px; display: inline-block;" id="title">Click on a title below</div>
<sectionframe title="BARANT Audio Experiments">
<div>
<whiledir name="file" dir="musiclink/bae">
<if expr="left('$[file]',1) != '.' ">
<div style="cursor: pointer;" onclick="onselection('musiclink/bae','$[file]');">$[file]</div>
<script>
paths[index]='musiclink/bae';
songs[index++]='$[file]';
</script>
</if>
</whiledir>
</div>
<script>
</script>
</sectionframe>
</contents>
</page>
+10 -5
View File
@@ -1,7 +1,7 @@
<page secure="yes" loggedin="yes"> <page secure="yes" loggedin="yes">
<title>PAY INVOICE</title> <title>PAY INVOICE</title>
<script src="https://sandbox.web.squarecdn.com/v1/square.js></script>
<contents> <contents>
<script src="https://sandbox.web.squarecdn.com/v1/square.js"></script>
<sectionframe title="Pay Invoice"> <sectionframe title="Pay Invoice">
<entryform> <entryform>
<sql>select * from invoices where id=$[_invoice_id]</sql> <sql>select * from invoices where id=$[_invoice_id]</sql>
@@ -10,8 +10,8 @@
<formdata prompt="Date:" data="$[created]"> <formdata prompt="Date:" data="$[created]">
<formdata prompt="Amount Due:" data="$[amount]"> <formdata prompt="Amount Due:" data="$[amount]">
<script> <script>
const appId = 'sandbox-sq0idb-GGY04gvAQJAmneJHgn_p8Q'; var appId = 'sandbox-sq0idb-GGY04gvAQJAmneJHgn_p8Q';
const locationId = 'LEMFWBZPEE9ST'; var locationId = 'LEMFWBZPEE9ST';
async function initializeCard(payments) { async function initializeCard(payments) {
const card = await payments.card(); const card = await payments.card();
@@ -74,7 +74,7 @@
statusContainer.style.visibility = 'visible'; statusContainer.style.visibility = 'visible';
} }
document.addEventListener('DOMContentLoaded', async function () { async function initPayInvoice() {
if (!window.Square) { if (!window.Square) {
throw new Error('Square.js failed to load properly'); throw new Error('Square.js failed to load properly');
} }
@@ -122,7 +122,12 @@
cardButton.addEventListener('click', async function (event) { cardButton.addEventListener('click', async function (event) {
await handlePaymentMethodSubmission(event, card); await handlePaymentMethodSubmission(event, card);
}); });
}); }
if (document.readyState === 'loading')
document.addEventListener('DOMContentLoaded', initPayInvoice);
else
initPayInvoice();
</script> </script>
<div id="card-container"></div> <div id="card-container"></div>
+30 -10
View File
@@ -8,8 +8,12 @@
console.log(">" + this.responseText + "<"); console.log(">" + this.responseText + "<");
if(this.responseText == "OK\n") { if(this.responseText == "OK\n") {
document.forms[0].PAGE.value = 'thankyou'; document.forms[0].PAGE.value = 'thankyou';
document.forms[0].submit(); document.forms[0].requestSubmit();
} else { } else {
var payBtn = document.getElementById('pay');
payBtn.disabled = false;
var processbanner = document.getElementById('process');
processbanner.style.visibility = 'hidden';
message.innerText = this.responseText; message.innerText = this.responseText;
} }
}; };
@@ -18,30 +22,46 @@
} }
var card; var card;
async function buildForm() { async function buildForm() {
// let payments = Square.payments('sandbox-sq0idb-GGY04gvAQJAmneJHgn_p8Q','LEMFWBZPEE9ST');
let payments = Square.payments('sq0idp-V4R4vEferpF9kr7d5x5abQ','LV0MRENX5ED3Z'); let payments = Square.payments('sq0idp-V4R4vEferpF9kr7d5x5abQ','LV0MRENX5ED3Z');
const card = await payments.card({ const card = await payments.card({
style: { style: {
'.input-container.is-focus': { borderColor: '#006AFF' }, input: {
'.message-text.is-error': { color: '#BF0020' } backgroundColor: '#1c1c24',
color: '#e7e4dc',
fontSize: '14px'
},
'input::placeholder': { color: '#8d8c92' },
'.input-container': { borderColor: 'rgba(197, 164, 90, 0.28)' },
'.input-container.is-focus': { borderColor: '#c5a45a' },
'.input-container.is-error': { borderColor: '#a13a3a' },
'.message-text': { color: '#8d8c92' },
'.message-text.is-error': { color: '#a13a3a' }
} }
}); });
await card.attach('#card'); await card.attach('#card');
let button = document.getElementById('pay'); let button = document.getElementById('pay');
button.addEventListener('click', async () => { button.addEventListener('click', async () => {
message.innerText = '';
let result = await card.tokenize(); let result = await card.tokenize();
if (result.status === 'OK') { if (result.status === 'OK') {
button.disabled = true;
let processbanner = document.getElementById('process'); let processbanner = document.getElementById('process');
processbanner.style.visibility = 'visible'; processbanner.style.visibility = 'visible';
processCardForm(result.token); processCardForm(result.token);
} else {
let errorMessage = 'Please check your card details and try again.';
if (result.errors && result.errors.length && result.errors[0].message)
errorMessage = result.errors[0].message;
message.innerText = errorMessage;
} }
}); });
} }
buildForm(); buildForm();
</script> </script>
<div>Please enter your payment information:</div> <div class="checkout-pay-wrap">
<div id="card" style="background-color: #ddd;width: 300px; padding: 5px;"></div> <div class="checkout-pay-label">Card Details</div>
<div style="padding: 5px;"><button id= "pay" type="button">Pay</button></div> <div id="card" class="checkout-card-input"></div>
<div id="process" style="background-color: #0f0; border: 2px solid #000; padding: <button id="pay" type="button" class="button checkout-pay-btn">Pay $$[amount]</button>
5px; display: block-inline; margin: 10px; visibility: hidden;"> Processing Payment - Please wait... </div> <div id="process" class="checkout-processing">Processing Payment &mdash; Please wait&hellip;</div>
<div id="message" style="color: #f00; margin-top: 20px;"></div> <div id="message" class="checkout-error"></div>
</div>
+4 -1
View File
@@ -1,3 +1,5 @@
<sql>select extensions.id as 'X', extensions.exten as 'Phone Number' from phones.extensions where extensions.user_id=$[@_login_id]</sql>
<ifrow>
<sectionframe title="Phones"> <sectionframe title="Phones">
<button> <button>
@@ -7,7 +9,8 @@
<showtable page="request" process="selectrequest" name="request_id" value="X"> <showtable page="request" process="selectrequest" name="request_id" value="X">
select extensions.id as 'X', select extensions.id as 'X',
extensions.exten as 'Phone Number' extensions.exten as 'Phone Number'
from phones.extensions from phones.extensions where extensions.user_id=$[@_login_id]
</showtable> </showtable>
</sectionframe> </sectionframe>
</ifrow>
+1 -1
View File
@@ -1,3 +1,3 @@
<process> <process>
<setenv name="_invoice_id">$[invoice_id]</setenv> <set name="@_invoice_id" value="$[invoice_id]">
</process> </process>
@@ -0,0 +1,27 @@
<set name="_send_invoice_id" value="$[invoice_id]">
<if value1="$[_send_invoice_id]" value2="" type="eq">
<set name="_send_invoice_id" value="$[@_invoice_id]">
</if>
<sql>select u.email as email, u.name as name from invoices i join users u on i.user_id=u.id where i.id=$[_send_invoice_id]</sql>
<ifrow>
<set name="_invoice_email_to" value="$[.email]">
<if value1="$[_invoice_email_override]" value2="" type="ne">
<set name="_invoice_email_to" value="$[_invoice_email_override]">
</if>
<set name="_invoice_id" value="$[_send_invoice_id]">
<eval name="_invoice_html">
<include file="invoice.method">
</eval>
<eval name="_invoice_email_body">
<html>
<head></head>
<body style="margin: 0; padding: 30px 10px; background: #0a0a0d; font-family: Arial, Helvetica, sans-serif;">
$[_invoice_html]
<p style="text-align: center; color: #8d8c92; font-size: 11px; margin-top: 20px;">BARANT Technology Group</p>
</body>
</html>
</eval>
<eval name="_invoice_smtpsend_discard">
<smtpsend config="./email.cfg" user="noreply@barant.com" password="NgCe0RolitzgBKVHz2HKfnTd" to="$[_invoice_email_to]" subject="Your BARANT Technology Group Invoice #$[_send_invoice_id]" html="$[_invoice_email_body]">
</eval>
</ifrow>
@@ -1,5 +1,3 @@
<page>
<title>Document Management</title>
<style> <style>
.price {display: table-cell; .price {display: table-cell;
background-color: #fff; background-color: #fff;
@@ -32,7 +30,6 @@
#documents-list td a:hover, #documents-list td .documents-action:hover { text-decoration: underline; } #documents-list td a:hover, #documents-list td .documents-action:hover { text-decoration: underline; }
#documents-empty { color: var(--bond-text-dim); padding: 10px 0; } #documents-empty { color: var(--bond-text-dim); padding: 10px 0; }
</style> </style>
<contents>
<sectionframe title="Document Management"> <sectionframe title="Document Management">
<h1>Online Document Management</h1> <h1>Online Document Management</h1>
<p>BARANT Technology Group now offers document management storage and <p>BARANT Technology Group now offers document management storage and
@@ -52,5 +49,3 @@ documents for any activity with that account.</p>
</sectionframe> </sectionframe>
<script src="/assets/documents-page.js?v=20260906a"></script> <script src="/assets/documents-page.js?v=20260906a"></script>
</if> </if>
</contents>
</page>
@@ -1,6 +1,3 @@
<page>
<title>HOSTING</title>
<contents>
<retain name="sku"> <retain name="sku">
<sectionframe title="Virtual Machine Hosting"> <sectionframe title="Virtual Machine Hosting">
@@ -56,10 +53,8 @@ bandwidth and 50GB storage for voice-mail and recordings. Full root
access. Full service support contacts available to maintain your access. Full service support contacts available to maintain your
phones and other VoIP devices. </p> phones and other VoIP devices. </p>
<p>$49.95/month</p> <p>$49.95/month</p>
<p>See our SIP trunking pricing and DID line options as well for a complete <p>See our <linkbutton page="services" subpage="siptrunking">SIP trunking pricing</linkbutton> and DID line options as well for a complete
telephony solution.</p> telephony solution.</p>
<hr> <hr>
</sectionframe> </sectionframe>
<set name="pagemenu" value="davidarant"> <set name="pagemenu" value="davidarant">
</contents>
</page>
@@ -0,0 +1,45 @@
<sectionframe title="Welcome to BARANT Systems">
<div style="width: 48%;">
<p>We are BARANT Technology Group. Contact us for information on how we can
help you with your technical objectives.</p>
<h1>Our Services</h1>
<ul>
<li>Software architecture and development on many platforms.
<ul>
<li>40+ years on IBM System/3x, AS/400, i Series and IBM i platform.</li>
<li>20+ years .NET Web and Winform application development.</li>
<li>10+ Android mobile development.</li>
</ul>
</li><br>
<li>Database architecture and development on many platforms.
<ul>
<li>DB2/400</li>
<li>Oracle</li>
<li>MySQL</li>
<li>PostgreSQL</li>
<li>MSSQL</li>
<li>Amazon Aurora</li>
<li>Amazon DynamoDB</li>
<li>MongoDB</li>
</ul>
</li><br>
<li>Telephony and Call Center Solutions
<ul>
<li>25+ years in call center development and application integration.</li>
<li>15+ years on open source FreePBX development and maintenance.</li>
<li>10+ as <linkbutton page="services" subpage="siptrunking">SIP trunk provider</linkbutton> offering very competitive rates.</li>
</ul>
</li><br>
<li>Audio Engineering products and projects
<ul>
<li>Product offering for VST synthesizers for modular analog simulation.</li>
<li>Module development for super clean digitally pure wave harmonics.</li>
</ul>
</li>
</ul>
</div>
</sectionframe>
@@ -1,5 +1,3 @@
<page>
<title>SIP Trunking</title>
<style> <style>
.price {display: table-cell; .price {display: table-cell;
background-color: #fff; background-color: #fff;
@@ -12,7 +10,6 @@
} }
.number {font-size: 30px;} .number {font-size: 30px;}
</style> </style>
<contents>
<sectionframe title="SIP Trunking"> <sectionframe title="SIP Trunking">
<h1>For PBX Systems</h1> <h1>For PBX Systems</h1>
<p>Some of the best prices around for adding trunks to your PBX. We <p>Some of the best prices around for adding trunks to your PBX. We
@@ -46,5 +43,3 @@ We can also host a PBX for you as well. Complete functionality
utilizing FreePBX can be provided on the internet so you do not need utilizing FreePBX can be provided on the internet so you do not need
to worry about the hardware. We manage and maintain everything for you. to worry about the hardware. We manage and maintain everything for you.
</sectionframe> </sectionframe>
</contents>
</page>
+22
View File
@@ -0,0 +1,22 @@
<sectionframe title="SERVICES">
<if value1="$[SUBPAGE]" value2="" type="eq">
<linkbutton page="services" class="submenuitem-active">OVERVIEW</linkbutton><br>
<else>
<linkbutton page="services">OVERVIEW</linkbutton><br>
</if>
<if value1="$[SUBPAGE]" value2="hosting" type="eq">
<linkbutton page="services" subpage="hosting" class="submenuitem-active">HOSTING</linkbutton><br>
<else>
<linkbutton page="services" subpage="hosting">HOSTING</linkbutton><br>
</if>
<if value1="$[SUBPAGE]" value2="siptrunking" type="eq">
<linkbutton page="services" subpage="siptrunking" class="submenuitem-active">SIP TRUNKING</linkbutton><br>
<else>
<linkbutton page="services" subpage="siptrunking">SIP TRUNKING</linkbutton><br>
</if>
<if value1="$[SUBPAGE]" value2="documents" type="eq">
<linkbutton page="services" subpage="documents" class="submenuitem-active">DOCUMENTS</linkbutton><br>
<else>
<linkbutton page="services" subpage="documents">DOCUMENTS</linkbutton><br>
</if>
</sectionframe>
+10 -44
View File
@@ -2,50 +2,16 @@
<title>BARANT Technology Group</title> <title>BARANT Technology Group</title>
<contents> <contents>
<setenv name="_menubar"></setenv> <setenv name="_menubar"></setenv>
<sectionframe title="Welcome to BARANT Systems"> <div id="services-subpage">
<if value1="$[SUBPAGE]" value2="" type="eq">
<div style="width: 48%;"> <include file="services-overview.subpage">
<p>We are BARANT Technology Group. Contact us for information on how we can <else>
help you with your technical objectives.</p> <try>
<include file="services-$[SUBPAGE].subpage">
<h1>Our Services</h1> <catch>
<ul> <p>That services category doesn't exist.</p>
<li>Software architecture and development on many platforms. </try>
<ul> </if>
<li>40+ years on IBM System/3x, AS/400, i Series and IBM i platform.</li>
<li>20+ years .NET Web and Winform application development.</li>
<li>10+ Android mobile development.</li>
</ul>
</li><br>
<li>Database architecture and development on many platforms.
<ul>
<li>DB2/400</li>
<li>Oracle</li>
<li>MySQL</li>
<li>PostgreSQL</li>
<li>MSSQL</li>
<li>Amazon Aurora</li>
<li>Amazon DynamoDB</li>
<li>MongoDB</li>
</ul>
</li><br>
<li>Telephony and Call Center Solutions
<ul>
<li>25+ years in call center development and application integration.</li>
<li>15+ years on open source FreePBX development and maintenance.</li>
<li>10+ as SIP trunk provider offering very competitive rates.</li>
</ul>
</li><br>
<li>Audio Engineering products and projects
<ul>
<li>Product offering for VST synthesizers for modular analog simulation.</li>
<li>Module development for super clean digitally pure wave harmonics.</li>
</ul>
</li>
</ul>
</div> </div>
</sectionframe>
</contents> </contents>
</page> </page>
+1
View File
@@ -0,0 +1 @@
<setenv name="_player_state">$[state]</setenv>
+1
View File
@@ -0,0 +1 @@
<setenv name="_player_volume">$[volume]</setenv>
+5 -4
View File
@@ -1,10 +1,11 @@
<process> <process>
<sql>delete from invoices_detail where invoice_id=$[_invoice_id]</sql> <sql>delete from invoices_detail where invoice_id=$[@_invoice_id]</sql>
<for start="0" end="$[linecount]" step="1" name="ix"> <for start="0" end="$[linecount]" step="1" name="ix">
<sql>insert into invoices_detail (invoice_id,sku,sku_suffix,quantity,description,text,price,total,tax_amount,type) <sql>insert into invoices_detail (invoice_id,sku,sku_suffix,quantity,description,text,price,total,tax_amount,type)
values($[_invoice_id],'$[sku$[ix]]','',$[quantity$[ix]],'$[description$[ix]]','$[textarea$[ix]]',$[price$[ix]],$[total$[ix]],$[tax_amount$[ix]],'$[type$[ix]]')</sql>$[sqlerror] values($[@_invoice_id],'$[sku$[ix]]','',$[quantity$[ix]],'$[description$[ix]]','$[textarea$[ix]]',$[price$[ix]],$[total$[ix]],$[tax_amount$[ix]],'$[type$[ix]]')</sql>$[sqlerror]
</for> </for>
<sql>update invoices set amount=$[invoice_total] where id=$[_invoice_id]</sql> <sql>update invoices set amount=$[invoice_total], user_id=$[user_id] where id=$[@_invoice_id]</sql>
<setpage name="admin_invoice"> <setpage name="admin">
<set name="SUBPAGE" value="invoice">
</process> </process>
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,39 @@
CKEditor 4
==========
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
http://ckeditor.com - See LICENSE.md for license information.
CKEditor is a text editor to be used inside web pages. It's not a replacement
for desktop text editors like Word or OpenOffice, but a component to be used as
part of web applications and websites.
## Documentation
The full editor documentation is available online at the following address:
http://docs.ckeditor.com
## Installation
Installing CKEditor is an easy task. Just follow these simple steps:
1. **Download** the latest version from the CKEditor website:
http://ckeditor.com. You should have already completed this step, but be
sure you have the very latest version.
2. **Extract** (decompress) the downloaded file into the root of your website.
**Note:** CKEditor is by default installed in the `ckeditor` folder. You can
place the files in whichever you want though.
## Checking Your Installation
The editor comes with a few sample pages that can be used to verify that
installation proceeded properly. Take a look at the `samples` directory.
To test your installation, just call the following page at your website:
http://<your site>/<CKEditor installation path>/samples/index.html
For example:
http://www.example.com/ckeditor/samples/index.html
@@ -0,0 +1,166 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/license
*/
/**
* This file was added automatically by CKEditor builder.
* You may re-use it at any time to build CKEditor again.
*
* If you would like to build CKEditor online again
* (for example to upgrade), visit one the following links:
*
* (1) https://ckeditor.com/cke4/builder
* Visit online builder to build CKEditor from scratch.
*
* (2) https://ckeditor.com/cke4/builder/8ff7b71bcccc296bcc3a4a5b82942d17
* Visit online builder to build CKEditor, starting with the same setup as before.
*
* (3) https://ckeditor.com/cke4/builder/download/8ff7b71bcccc296bcc3a4a5b82942d17
* Straight download link to the latest version of CKEditor (Optimized) with the same setup as before.
*
* NOTE:
* This file is not used by CKEditor, you may remove it.
* Changing this file will not change your CKEditor configuration.
*/
var CKBUILDER_CONFIG = {
skin: 'moono-lisa',
preset: 'standard',
ignore: [
'.DS_Store',
'.bender',
'.editorconfig',
'.gitattributes',
'.gitignore',
'.idea',
'.jscsrc',
'.jshintignore',
'.jshintrc',
'.mailmap',
'.npm',
'.travis.yml',
'bender-err.log',
'bender-out.log',
'bender.ci.js',
'bender.js',
'dev',
'gruntfile.js',
'less',
'node_modules',
'package.json',
'tests'
],
plugins : {
'a11yhelp' : 1,
'about' : 1,
'basicstyles' : 1,
'blockquote' : 1,
'clipboard' : 1,
'contextmenu' : 1,
'elementspath' : 1,
'enterkey' : 1,
'entities' : 1,
'filebrowser' : 1,
'floatingspace' : 1,
'format' : 1,
'horizontalrule' : 1,
'htmlwriter' : 1,
'image' : 1,
'indentlist' : 1,
'link' : 1,
'list' : 1,
'magicline' : 1,
'maximize' : 1,
'pastefromword' : 1,
'pastetext' : 1,
'removeformat' : 1,
'resize' : 1,
'scayt' : 1,
'showborders' : 1,
'sourcearea' : 1,
'specialchar' : 1,
'stylescombo' : 1,
'tab' : 1,
'table' : 1,
'tableselection' : 1,
'tabletools' : 1,
'toolbar' : 1,
'undo' : 1,
'uploadimage' : 1,
'wsc' : 1,
'wysiwygarea' : 1
},
languages : {
'af' : 1,
'ar' : 1,
'az' : 1,
'bg' : 1,
'bn' : 1,
'bs' : 1,
'ca' : 1,
'cs' : 1,
'cy' : 1,
'da' : 1,
'de' : 1,
'de-ch' : 1,
'el' : 1,
'en' : 1,
'en-au' : 1,
'en-ca' : 1,
'en-gb' : 1,
'eo' : 1,
'es' : 1,
'es-mx' : 1,
'et' : 1,
'eu' : 1,
'fa' : 1,
'fi' : 1,
'fo' : 1,
'fr' : 1,
'fr-ca' : 1,
'gl' : 1,
'gu' : 1,
'he' : 1,
'hi' : 1,
'hr' : 1,
'hu' : 1,
'id' : 1,
'is' : 1,
'it' : 1,
'ja' : 1,
'ka' : 1,
'km' : 1,
'ko' : 1,
'ku' : 1,
'lt' : 1,
'lv' : 1,
'mk' : 1,
'mn' : 1,
'ms' : 1,
'nb' : 1,
'nl' : 1,
'no' : 1,
'oc' : 1,
'pl' : 1,
'pt' : 1,
'pt-br' : 1,
'ro' : 1,
'ru' : 1,
'si' : 1,
'sk' : 1,
'sl' : 1,
'sq' : 1,
'sr' : 1,
'sr-latn' : 1,
'sv' : 1,
'th' : 1,
'tr' : 1,
'tt' : 1,
'ug' : 1,
'uk' : 1,
'vi' : 1,
'zh' : 1,
'zh-cn' : 1
}
};
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,38 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see https://ckeditor.com/legal/ckeditor-oss-license
*/
CKEDITOR.editorConfig = function( config ) {
// Define changes to default configuration here.
// For complete reference see:
// https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_config.html
// The toolbar groups arrangement, optimized for two toolbar rows.
config.toolbarGroups = [
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
{ name: 'links' },
{ name: 'insert' },
{ name: 'forms' },
{ name: 'tools' },
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
{ name: 'others' },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
{ name: 'styles' },
{ name: 'colors' },
{ name: 'about' }
];
// Remove some buttons provided by the standard plugins, which are
// not needed in the Standard(s) toolbar.
config.removeButtons = 'Underline,Subscript,Superscript';
// Set the most common block elements.
config.format_tags = 'p;h1;h2;h3;pre';
// Simplify the dialog windows.
config.removeDialogTabs = 'image:advanced;link:advanced';
};
@@ -0,0 +1,208 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
body
{
/* Font */
/* Emoji fonts are added to visualise them nicely in Internet Explorer. */
font-family: sans-serif, Arial, Verdana, "Trebuchet MS", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 12px;
/* Text color */
color: #333;
/* Remove the background color to make it transparent. */
background-color: #fff;
margin: 20px;
}
.cke_editable
{
font-size: 13px;
line-height: 1.6;
/* Fix for missing scrollbars with RTL texts. (#10488) */
word-wrap: break-word;
}
blockquote
{
font-style: italic;
font-family: Georgia, Times, "Times New Roman", serif;
padding: 2px 0;
border-style: solid;
border-color: #ccc;
border-width: 0;
}
.cke_contents_ltr blockquote
{
padding-left: 20px;
padding-right: 8px;
border-left-width: 5px;
}
.cke_contents_rtl blockquote
{
padding-left: 8px;
padding-right: 20px;
border-right-width: 5px;
}
a
{
color: #0782C1;
}
ol,ul,dl
{
/* IE7: reset rtl list margin. (#7334) */
*margin-right: 0px;
/* Preserved spaces for list items with text direction different than the list. (#6249,#8049)*/
padding: 0 40px;
}
h1,h2,h3,h4,h5,h6
{
font-weight: normal;
line-height: 1.2;
}
hr
{
border: 0px;
border-top: 1px solid #ccc;
}
img.right
{
border: 1px solid #ccc;
float: right;
margin-left: 15px;
padding: 5px;
}
img.left
{
border: 1px solid #ccc;
float: left;
margin-right: 15px;
padding: 5px;
}
pre
{
white-space: pre-wrap; /* CSS 2.1 */
word-wrap: break-word; /* IE7 */
-moz-tab-size: 4;
tab-size: 4;
}
.marker
{
background-color: Yellow;
}
span[lang]
{
font-style: italic;
}
figure
{
text-align: center;
outline: solid 1px #ccc;
background: rgba(0,0,0,0.05);
padding: 10px;
margin: 10px 20px;
display: inline-block;
}
figure > figcaption
{
text-align: center;
display: block; /* For IE8 */
}
a > img {
padding: 1px;
margin: 1px;
border: none;
outline: 1px solid #0782C1;
}
/* Widget Styles */
.code-featured
{
border: 5px solid red;
}
.math-featured
{
padding: 20px;
box-shadow: 0 0 2px rgba(200, 0, 0, 1);
background-color: rgba(255, 0, 0, 0.05);
margin: 10px;
}
.image-clean
{
border: 0;
background: none;
padding: 0;
}
.image-clean > figcaption
{
font-size: .9em;
text-align: right;
}
.image-grayscale
{
background-color: white;
color: #666;
}
.image-grayscale img, img.image-grayscale
{
filter: grayscale(100%);
}
.embed-240p
{
max-width: 426px;
max-height: 240px;
margin:0 auto;
}
.embed-360p
{
max-width: 640px;
max-height: 360px;
margin:0 auto;
}
.embed-480p
{
max-width: 854px;
max-height: 480px;
margin:0 auto;
}
.embed-720p
{
max-width: 1280px;
max-height: 720px;
margin:0 auto;
}
.embed-1080p
{
max-width: 1920px;
max-height: 1080px;
margin:0 auto;
}
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['af']={"editor":"Woordverwerker","editorPanel":"Woordverwerkerpaneel","common":{"editorHelp":"Druk op ALT 0 vir hulp","browseServer":"Blaai op bediener","url":"URL","protocol":"Protokol","upload":"Oplaai","uploadSubmit":"Stuur aan die bediener","image":"Beeld","flash":"Flash","form":"Vorm","checkbox":"Merkhokkie","radio":"Radioknoppie","textField":"Teksveld","textarea":"Teksarea","hiddenField":"Versteekteveld","button":"Knop","select":"Keuseveld","imageButton":"Beeldknop","notSet":"<geen instelling>","id":"Id","name":"Naam","langDir":"Skryfrigting","langDirLtr":"Links na regs (LTR)","langDirRtl":"Regs na links (RTL)","langCode":"Taalkode","longDescr":"Lang beskrywing URL","cssClass":"CSS klasse","advisoryTitle":"Aanbevole titel","cssStyle":"Styl","ok":"OK","cancel":"Kanselleer","close":"Sluit","preview":"Voorbeeld","resize":"Skalierung","generalTab":"Algemeen","advancedTab":"Gevorderd","validateNumberFailed":"Hierdie waarde is nie 'n nommer nie.","confirmNewPage":"Alle wysiginge sal verlore gaan. Is jy seker dat jy 'n nuwe bladsy wil laai?","confirmCancel":"Sommige opsies is gewysig. Is jy seker dat jy hierdie dialoogvenster wil sluit?","options":"Opsies","target":"Teiken","targetNew":"Nuwe venster (_blank)","targetTop":"Boonste venster (_top)","targetSelf":"Selfde venster (_self)","targetParent":"Oorspronklike venster (_parent)","langDirLTR":"Links na Regs (LTR)","langDirRTL":"Regs na Links (RTL)","styles":"Styl","cssClasses":"CSS klasse","width":"Breedte","height":"Hoogte","align":"Orienteerung","left":"Links","right":"Regs","center":"Middel","justify":"Eweredig","alignLeft":"Links oplyn","alignRight":"Regs oplyn","alignCenter":"Middel oplyn","alignTop":"Bo","alignMiddle":"Middel","alignBottom":"Onder","alignNone":"Geen","invalidValue":"Ongeldige waarde","invalidHeight":"Hoogte moet 'n getal wees","invalidWidth":"Breedte moet 'n getal wees.","invalidLength":"Die waarde vir die veld \"%1\" moet 'n posetiewe nommer wees met of sonder die meeteenheid (%2).","invalidCssLength":"Die waarde vir die \"%1\" veld moet 'n posetiewe getal wees met of sonder 'n geldige CSS eenheid (px, %, in, cm, mm, em, ex, pt, of pc).","invalidHtmlLength":"Die waarde vir die \"%1\" veld moet 'n posetiewe getal wees met of sonder 'n geldige HTML eenheid (px of %).","invalidInlineStyle":"Ongeldige CSS. Formaat is een of meer sleutel-wert paare, \"naam : wert\" met kommapunte gesky.","cssLengthTooltip":"Voeg 'n getal wert in pixel in, of 'n waarde met geldige CSS eenheid (px, %, in, cm, mm, em, ex, pt, of pc).","unavailable":"%1<span class=\"cke_accessibility\">, nie beskikbaar nie</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Skuif","17":"Ctrl","18":"Alt","32":"Spasie","35":"Einde","36":"Tuis","46":"Verwyder","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Bevel"},"keyboardShortcut":"Sleutel kombenasie","optionDefault":"Verstek"},"about":{"copy":"Kopiereg &copy; $1. Alle regte voorbehou.","dlgTitle":"Meer oor CKEditor 4","moreInfo":"Vir lisensie-informasie, besoek asb. ons webwerf:"},"basicstyles":{"bold":"Vet","italic":"Skuins","strike":"Deurgestreep","subscript":"Onderskrif","superscript":"Bo-skrif","underline":"Onderstreep"},"blockquote":{"toolbar":"Sitaatblok"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Verklein werkbalk","toolbarExpand":"Vergroot werkbalk","toolbarGroups":{"document":"Dokument","clipboard":"Knipbord/Undo","editing":"Verander","forms":"Vorms","basicstyles":"Eenvoudige Styl","paragraph":"Paragraaf","links":"Skakels","insert":"Toevoeg","styles":"Style","colors":"Kleure","tools":"Gereedskap"},"toolbars":"Werkbalke"},"clipboard":{"copy":"Kopiëer","copyError":"U leser se sekuriteitsinstelling belet die kopiëringsaksie. Gebruik die sleutelbordkombinasie (Ctrl/Cmd+C).","cut":"Uitsnei","cutError":"U leser se sekuriteitsinstelling belet die outomatiese uitsnei-aksie. Gebruik die sleutelbordkombinasie (Ctrl/Cmd+X).","paste":"Byvoeg","pasteNotification":"Druk %1 om by te voeg. You leser ondersteun nie die toolbar knoppie of inoud kieslysie opsie nie. ","pasteArea":"Area byvoeg","pasteMsg":"Voeg jou inhoud in die gebied onder by en druk OK"},"contextmenu":{"options":"Konteks Spyskaart-opsies"},"elementspath":{"eleLabel":"Elemente-pad","eleTitle":"%1 element"},"filetools":{"loadError":"Error occurred during file read.","networkError":"Network error occurred during file upload.","httpError404":"HTTP error occurred during file upload (404: File not found).","httpError403":"HTTP error occurred during file upload (403: Forbidden).","httpError":"HTTP error occurred during file upload (error status: %1).","noUrlError":"Upload URL is not defined.","responseError":"Incorrect server response."},"format":{"label":"Opmaak","panelTitle":"OpmLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['ar']={"editor":"محرر النص الغني","editorPanel":"لائحة محرر النص المنسق","common":{"editorHelp":"إضغط على ALT + 0 للحصول على المساعدة.","browseServer":"تصفح","url":"الرابط","protocol":"البروتوكول","upload":"رفع","uploadSubmit":"أرسل","image":"صورة","flash":"فلاش","form":"نموذج","checkbox":"خانة إختيار","radio":"زر اختيار","textField":"مربع نص","textarea":"مساحة نصية","hiddenField":"إدراج حقل خفي","button":"زر ضغط","select":"اختار","imageButton":"زر صورة","notSet":"<بدون تحديد>","id":"الرقم","name":"إسم","langDir":"إتجاه النص","langDirLtr":"اليسار لليمين (LTR)","langDirRtl":"اليمين لليسار (RTL)","langCode":"رمز اللغة","longDescr":"الوصف التفصيلى","cssClass":"فئات التنسيق","advisoryTitle":"عنوان التقرير","cssStyle":"نمط","ok":"موافق","cancel":"إلغاء الأمر","close":"أغلق","preview":"استعراض","resize":"تغيير الحجم","generalTab":"عام","advancedTab":"متقدم","validateNumberFailed":"لايوجد نتيجة","confirmNewPage":"ستفقد أي متغييرات اذا لم تقم بحفظها اولا. هل أنت متأكد أنك تريد صفحة جديدة؟","confirmCancel":"بعض الخيارات قد تغيرت. هل أنت متأكد من إغلاق مربع النص؟","options":"خيارات","target":"هدف الرابط","targetNew":"نافذة جديدة","targetTop":"النافذة الأعلى","targetSelf":"داخل النافذة","targetParent":"النافذة الأم","langDirLTR":"اليسار لليمين (LTR)","langDirRTL":"اليمين لليسار (RTL)","styles":"نمط","cssClasses":"فئات التنسيق","width":"العرض","height":"الإرتفاع","align":"محاذاة","left":"يسار","right":"يمين","center":"وسط","justify":"ضبط","alignLeft":"محاذاة إلى اليسار","alignRight":"محاذاة إلى اليمين","alignCenter":"Align Center","alignTop":"أعلى","alignMiddle":"وسط","alignBottom":"أسفل","alignNone":"None","invalidValue":"قيمة غير مفبولة.","invalidHeight":"الارتفاع يجب أن يكون عدداً.","invalidWidth":"العرض يجب أن يكون عدداً.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"قيمة الخانة المخصصة لـ \"%1\" يجب أن تكون رقما موجبا، باستخدام أو من غير استخدام وحدة CSS قياس مقبولة (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"قيمة الخانة المخصصة لـ \"%1\" يجب أن تكون رقما موجبا، باستخدام أو من غير استخدام وحدة HTML قياس مقبولة (px or %).","invalidInlineStyle":"قيمة الخانة المخصصة لـ Inline Style يجب أن تختوي على مجموع واحد أو أكثر بالشكل التالي: \"name : value\", مفصولة بفاصلة منقزطة.","cssLengthTooltip":"أدخل رقما للقيمة بالبكسل أو رقما بوحدة CSS مقبولة (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, غير متاح</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"حقوق النشر &copy; $1. جميع الحقوق محفوظة.","dlgTitle":"عن CKEditor","moreInfo":"للحصول على معلومات الترخيص ، يرجى زيارة موقعنا:"},"basicstyles":{"bold":"عريض","italic":"مائل","strike":"يتوسطه خط","subscript":"منخفض","superscript":"مرتفع","underline":"تسطير"},"blockquote":{"toolbar":"اقتباس"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"تقليص شريط الأدوت","toolbarExpand":"تمديد شريط الأدوات","toolbarGroups":{"document":"مستند","clipboard":"الحافظة/الرجوع","editing":"تحرير","forms":"نماذج","basicstyles":"نمط بسيط","paragraph":"فقرة","links":"روابط","insert":"إدراج","styles":"أنماط","colors":"ألوان","tools":"أدوات"},"toolbars":"أشرطة أدوات المحرر"},"clipboard":{"copy":"نسخ","copyError":"الإعدادات الأمنية للمتصفح الذي تستخدمه تمنع عمليات النسخ التلقائي.Line truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['az']={"editor":"Mətn Redaktoru","editorPanel":"Mətn Redaktorun Paneli","common":{"editorHelp":"Yardım üçün ALT 0 düymələrini basın","browseServer":"Fayların siyahı","url":"URL","protocol":"Protokol","upload":"Serverə yüklə","uploadSubmit":"Göndər","image":"Şəkil","flash":"Flash","form":"Forma","checkbox":"Çekboks","radio":"Radio düyməsi","textField":"Mətn xanası","textarea":"Mətn","hiddenField":"Gizli xana","button":"Düymə","select":"Opsiyaların seçilməsi","imageButton":"Şəkil tipli düymə","notSet":"<seçilməmiş>","id":"Id","name":"Ad","langDir":"Yaziların istiqaməti","langDirLtr":"Soldan sağa (LTR)","langDirRtl":"Sağdan sola (RTL)","langCode":"Dilin kodu","longDescr":"URL-ın ətraflı izahı","cssClass":"CSS klassları","advisoryTitle":"Başlıq","cssStyle":"CSS","ok":"Tədbiq et","cancel":"İmtina et","close":"Bağla","preview":"Baxış","resize":"Eni dəyiş","generalTab":"Əsas","advancedTab":"Əlavə","validateNumberFailed":"Rəqəm deyil.","confirmNewPage":"Yadda saxlanılmamış dəyişikliklər itiriləcək. Davam etmək istədiyinizə əminsinizmi?","confirmCancel":"Dəyişikliklər edilib. Pəncərəni bağlamaq istəyirsizə əminsinizmi?","options":"Seçimlər","target":"Hədəf çərçivə","targetNew":"Yeni pəncərə (_blank)","targetTop":"Əsas pəncərə (_top)","targetSelf":"Carı pəncərə (_self)","targetParent":"Ana pəncərə (_parent)","langDirLTR":"Soldan sağa (LTR)","langDirRTL":"Sağdan sola (RTL)","styles":"Üslub","cssClasses":"Üslub klası","width":"En","height":"Uzunluq","align":"Yerləşmə","left":"Sol","right":"Sağ","center":"Mərkəz","justify":"Eninə görə","alignLeft":"Soldan düzləndir","alignRight":"Sağdan düzləndir","alignCenter":"Align Center","alignTop":"Yuxarı","alignMiddle":"Orta","alignBottom":"Aşağı","alignNone":"Yoxdur","invalidValue":"Yanlışdır.","invalidHeight":"Hündürlük rəqəm olmalıdır.","invalidWidth":"En rəqəm olmalıdır.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"\"%1\" xanasında göstərilən məzmun tam və müsbət olmalıdır, CSS-də olan ölçü vahidlərin (px, %, in, cm, mm, em, ex, pt, or pc) istifadısinə icazə verilir.","invalidHtmlLength":"\"%1\" xanasında göstərilən məzmun tam və müsbət olmalıdır HTML-də olan ölçü vahidlərin (px və ya %) istifadısinə icazə verilir.","invalidInlineStyle":"Teq içində olan üslub \"ad : məzmun\" şəklidə, nöqtə-verqül işarəsi ilə bitməlidir","cssLengthTooltip":"Piksel sayı və ya digər CSS ölçü vahidləri (px, %, in, cm, mm, em, ex, pt, or pc) daxil edin.","unavailable":"%1<span class=\"cke_accessibility\">, mövcud deyil</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Boşluq","35":"Son","36":"Evə","46":"Sil","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Əmr"},"keyboardShortcut":"Qısayol düymələri","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. Bütün hüquqlar qorunur.","dlgTitle":"CKEditor haqqında","moreInfo":"Lisenziya informasiyası üçün zəhmət olmasa saytımızı ziyarət edin:"},"basicstyles":{"bold":"Qalın","italic":"Kursiv","strike":"Üstüxətli","subscript":"Aşağı indeks","superscript":"Yuxarı indeks","underline":"Altdan xətt"},"blockquote":{"toolbar":"Sitat bloku"},"notification":{"closed":"Xəbərdarlıq pəncərəsi bağlanıb"},"toolbar":{"toolbarCollapse":"Paneli gizlət","toolbarExpand":"Paneli göstər","toolbarGroups":{"document":"Mətn","clipboard":"Mübadilə buferi/İmtina et","editing":"Redaktə edilməsi","forms":"Formalar","basicstyles":"Əsas üslublar","paragraph":"Abzas","links":"Link","insert":"Əlavə et","styles":"Üslublar","colors":"Rənqlər","tools":"Alətləri"},"toolbars":"Redaktorun panelləri"},"clipboard":{"copy":"Köçür","copyError":"Avtomatik köçürülməsi mümkün deyil. Ctrl+C basın.","cut":"Kəs","cutError":"Avtomatik kəsmə mümkün deyil. Ctrl+X basın.","paste":"Əlavə et","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Paste Area","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Əlavə əməliyyatlar"},"elementspath":{"eleLabel":"Elementin izləri","eleTitle":"%1 element"},"filetools":{"loadError":"Faylını oxumaq mümkün deyil","networkError":"Xəta baş verdi.","httpError404":"Serverə göndərilməsinin zamanı xəta baş verdi (404 - fayl tapılmayıb)","httpError403":"Serverə göndərilməsinin zamanı xəta baş verdi (403 - gadağandır)","httpError":"Serverə göndərLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['bg']={"editor":"Редактор за форматиран текст","editorPanel":"Панел на текстовия редактор","common":{"editorHelp":"натиснете ALT+0 за помощ","browseServer":"Избор от сървъра","url":"URL адрес","protocol":"Протокол","upload":"Качване","uploadSubmit":"Изпращане към сървъра","image":"Изображение","flash":"Флаш","form":"Форма","checkbox":"Поле за избор","radio":"Радио бутон","textField":"Текстово поле","textarea":"Текстова зона","hiddenField":"Скрито поле","button":"Бутон","select":"Поле за избор","imageButton":"Бутон за изображение","notSet":"<не е избрано>","id":"ID","name":"Име","langDir":"Посока на езика","langDirLtr":"От ляво надясно (LTR)","langDirRtl":"От дясно наляво (RTL)","langCode":"Код на езика","longDescr":"Уеб адрес за дълго описание","cssClass":"Класове за CSS","advisoryTitle":"Заглавие","cssStyle":"Стил","ok":"ОК","cancel":"Отказ","close":"Затвори","preview":"Преглед","resize":"Влачете за да оразмерите","generalTab":"Общи","advancedTab":"Разширено","validateNumberFailed":"Тази стойност не е число","confirmNewPage":"Всички незапазени промени ще бъдат изгубени. Сигурни ли сте, че желаете да заредите нова страница?","confirmCancel":"Някои от опциите са променени. Сигурни ли сте, че желаете да затворите прозореца?","options":"Опции","target":"Цел","targetNew":"Нов прозорец (_blank)","targetTop":"Най-горният прозорец (_top)","targetSelf":"Текущият прозорец (_self)","targetParent":"Горният прозорец (_parent)","langDirLTR":"От ляво надясно (LTR)","langDirRTL":"От дясно наляво (RTL)","styles":"Стил","cssClasses":"Класове за CSS","width":"Ширина","height":"Височина","align":"Подравняване","left":"Ляво","right":"Дясно","center":"Център","justify":"Двустранно","alignLeft":"Подравни ляво","alignRight":"Подравни дясно","alignCenter":"Подравни център","alignTop":"Горе","alignMiddle":"По средата","alignBottom":"Долу","alignNone":"Без подравняване","invalidValue":"Невалидна стойност.","invalidHeight":"Височината трябва да е число.","invalidWidth":"Ширина трябва да е число.","invalidLength":"Стойността на полето \"%1\" трябва да е положително число с или без валидна мерна единица (%2).","invalidCssLength":"Стойността на полето \"%1\" трябва да е положително число с или без валидна CSS мерна единица (px, %, in, cm, mm, em, ex, pt, или pc).","invalidHtmlLength":"Стойността на полето \"%1\" трябва да е положително число с или без валидна HTML мерна единица (px или %).","invalidInlineStyle":"Стойността на стилa трябва да съдържат една или повече двойки във формат \"name : value\", разделени с двоеточие.","cssLengthTooltip":"Въведете числена стойност в пиксели или друга валидна CSS единица (px, %, in, cm, mm, em, ex, pt, или pc).","unavailable":"%1<span class=\"cke_accessibility\">, недостъпно</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Клавишна комбинация","optionDefault":"По подразбиране"},"about":{"copy":"Авторско право &copy; $1. Всички права запазени.","dlgTitle":"Относно CKEditor 4","moreInfo":"За лицензионна информация моля посетете сайта ни:"},"basicstyles":{"bold":"Удебелен","italic":"Наклонен","strike":"Зачертан текст","subscript":"Долен индекс","superscript":"Горен индекс","underline":"Подчертан"},"blockquote":{"toolbar":"Блок за цитLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['bn']={"editor":"Rich Text Editor","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"Press ALT 0 for help","browseServer":"ব্রাউজ সার্ভার","url":"URL","protocol":"প্রোটোকল","upload":"আপলোড","uploadSubmit":"ইহাকে সার্ভারে প্রেরন কর","image":"ছবির লেবেল যুক্ত কর","flash":"ফ্লাশ লেবেল যুক্ত কর","form":"ফর্ম","checkbox":"চেক বাক্স","radio":"রেডিও বাটন","textField":"টেক্সট ফীল্ড","textarea":"টেক্সট এরিয়া","hiddenField":"গুপ্ত ফীল্ড","button":"বাটন","select":"বাছাই ফীল্ড","imageButton":"ছবির বাটন","notSet":"<সেট নেই>","id":"আইডি","name":"নাম","langDir":"ভাষা লেখার দিক","langDirLtr":"বাম থেকে ডান (LTR)","langDirRtl":"ডান থেকে বাম (RTL)","langCode":"ভাষা কোড","longDescr":"URL এর লম্বা বর্ণনা","cssClass":"স্টাইল-শীট ক্লাস","advisoryTitle":"পরামর্শ শীর্ষক","cssStyle":"স্টাইল","ok":"ওকে","cancel":"বাতিল","close":"Close","preview":"প্রিভিউ","resize":"Resize","generalTab":"General","advancedTab":"এডভান্সড","validateNumberFailed":"This value is not a number.","confirmNewPage":"Any unsaved changes to this content will be lost. Are you sure you want to load new page?","confirmCancel":"You have changed some options. Are you sure you want to close the dialog window?","options":"Options","target":"টার্গেট","targetNew":"New Window (_blank)","targetTop":"Topmost Window (_top)","targetSelf":"Same Window (_self)","targetParent":"Parent Window (_parent)","langDirLTR":"বাম থেকে ডান (LTR)","langDirRTL":"ডান থেকে বাম (RTL)","styles":"স্টাইল","cssClasses":"স্টাইল-শীট ক্লাস","width":"প্রস্থ","height":"দৈর্ঘ্য","align":"এলাইন","left":"বামে","right":"ডানে","center":"মাঝখানে","justify":"ব্লক জাস্টিফাই","alignLeft":"বা দিকে ঘেঁষা","alignRight":"ডান দিকে ঘেঁষা","alignCenter":"Align Center","alignTop":"উপর","alignMiddle":"মধ্য","alignBottom":"নীচে","alignNone":"None","invalidValue":"Invalid value.","invalidHeight":"Height must be a number.","invalidWidth":"Width must be a number.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Value specified for the \"%1\" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"Value specified for the \"%1\" field must be a positive number with or without a valid HTML measurement unit (px or %).","invalidInlineStyle":"Value specified for the inline style must consist of one or more tuples with the format of \"name : value\", separated by semi-colons.","cssLengthTooltip":"Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, unavailable</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. All rights reserved.","dlgTitle":"About CKEditor 4","moreInfo":"For licensing information please visit our web site:"},"basicstyles":{"bold":"বোল্ড","italic":"বাঁকা","strike":"স্ট্রাইক থ্রু","subscript":"অধোলেখ","superscript":"অভিলেখ","underline":"আন্ডারলাইন"},"blockquote":{"toolbar":"Block Quote"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Collapse Toolbar","toolbarExpand":"Expand Toolbar","toolbarGroups":{"document":"Document","clipboard":"Clipboard/Undo","editing":"Editing","forms":"Forms","basicstyles":"Basic Styles","paragraph":"Paragraph","links":"Links","insert":"Insert","styles":"Styles","colors":"Colors","tools":"Tools"},"toolbars":"Editor toolbars"},"clipboard":{"copy":"কপি","copyError":"আপনার ব্রাউজারের নিরাপত্তা সেটিংসমূহ এডিটরকLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['bs']={"editor":"Rich Text Editor","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"Press ALT 0 for help","browseServer":"Browse Server","url":"URL","protocol":"Protokol","upload":"Šalji","uploadSubmit":"Šalji na server","image":"Slika","flash":"Flash","form":"Form","checkbox":"Checkbox","radio":"Radio Button","textField":"Text Field","textarea":"Textarea","hiddenField":"Hidden Field","button":"Button","select":"Selection Field","imageButton":"Image Button","notSet":"<nije podešeno>","id":"Id","name":"Naziv","langDir":"Smjer pisanja","langDirLtr":"S lijeva na desno (LTR)","langDirRtl":"S desna na lijevo (RTL)","langCode":"Jezièni kôd","longDescr":"Dugaèki opis URL-a","cssClass":"Klase CSS stilova","advisoryTitle":"Advisory title","cssStyle":"Stil","ok":"OK","cancel":"Odustani","close":"Close","preview":"Prikaži","resize":"Resize","generalTab":"General","advancedTab":"Naprednije","validateNumberFailed":"This value is not a number.","confirmNewPage":"Any unsaved changes to this content will be lost. Are you sure you want to load new page?","confirmCancel":"You have changed some options. Are you sure you want to close the dialog window?","options":"Options","target":"Prozor","targetNew":"New Window (_blank)","targetTop":"Topmost Window (_top)","targetSelf":"Same Window (_self)","targetParent":"Parent Window (_parent)","langDirLTR":"S lijeva na desno (LTR)","langDirRTL":"S desna na lijevo (RTL)","styles":"Stil","cssClasses":"Klase CSS stilova","width":"Širina","height":"Visina","align":"Poravnanje","left":"Lijevo","right":"Desno","center":"Centar","justify":"Puno poravnanje","alignLeft":"Lijevo poravnanje","alignRight":"Desno poravnanje","alignCenter":"Align Center","alignTop":"Vrh","alignMiddle":"Sredina","alignBottom":"Dno","alignNone":"None","invalidValue":"Invalid value.","invalidHeight":"Height must be a number.","invalidWidth":"Width must be a number.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Value specified for the \"%1\" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"Value specified for the \"%1\" field must be a positive number with or without a valid HTML measurement unit (px or %).","invalidInlineStyle":"Value specified for the inline style must consist of one or more tuples with the format of \"name : value\", separated by semi-colons.","cssLengthTooltip":"Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, unavailable</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. All rights reserved.","dlgTitle":"About CKEditor 4","moreInfo":"For licensing information please visit our web site:"},"basicstyles":{"bold":"Boldiraj","italic":"Ukosi","strike":"Precrtaj","subscript":"Subscript","superscript":"Superscript","underline":"Podvuci"},"blockquote":{"toolbar":"Block Quote"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Collapse Toolbar","toolbarExpand":"Expand Toolbar","toolbarGroups":{"document":"Document","clipboard":"Clipboard/Undo","editing":"Editing","forms":"Forms","basicstyles":"Basic Styles","paragraph":"Paragraph","links":"Links","insert":"Insert","styles":"Styles","colors":"Colors","tools":"Tools"},"toolbars":"Editor toolbars"},"clipboard":{"copy":"Kopiraj","copyError":"Sigurnosne postavke Vašeg pretraživaèa ne dozvoljavaju operacije automatskog kopiranja. Molimo koristite kraticu na tastaturi (Ctrl/Cmd+C).","cut":"Izreži","cutError":"Sigurnosne postavke vašeg pretraživaèa ne dozvoljavaju operacije automatskog rezanja. Molimo koristite kraticu na tastaturi (Ctrl/Cmd+X).","paste":"Zalijepi","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Paste Area","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Context Menu Options"},"elementspath":{"eleLabel":"Elements path","eleTitle":"%1 element"},"filetools":{"loadError":"Error occurred during file read.","networkError":"Network error occurred during file upload.","httpError404":"HTTP error occurred during file upload (404: File not found).","httpError403":"HTTP error occurred during file upload (403: Forbidden).","httpError":"HTTP error occurred during file upload Line truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['ca']={"editor":"Editor de text enriquit","editorPanel":"Panell de l'editor de text enriquit","common":{"editorHelp":"Premeu ALT 0 per ajuda","browseServer":"Veure servidor","url":"URL","protocol":"Protocol","upload":"Puja","uploadSubmit":"Envia-la al servidor","image":"Imatge","flash":"Flash","form":"Formulari","checkbox":"Casella de verificació","radio":"Botó d'opció","textField":"Camp de text","textarea":"Àrea de text","hiddenField":"Camp ocult","button":"Botó","select":"Camp de selecció","imageButton":"Botó d'imatge","notSet":"<no definit>","id":"Id","name":"Nom","langDir":"Direcció de l'idioma","langDirLtr":"D'esquerra a dreta (LTR)","langDirRtl":"De dreta a esquerra (RTL)","langCode":"Codi d'idioma","longDescr":"Descripció llarga de la URL","cssClass":"Classes del full d'estil","advisoryTitle":"Títol consultiu","cssStyle":"Estil","ok":"D'acord","cancel":"Cancel·la","close":"Tanca","preview":"Previsualitza","resize":"Arrossegueu per redimensionar","generalTab":"General","advancedTab":"Avançat","validateNumberFailed":"Aquest valor no és un número.","confirmNewPage":"Els canvis en aquest contingut que no es desin es perdran. Esteu segur que voleu carregar una pàgina nova?","confirmCancel":"Algunes opcions s'han canviat. Esteu segur que voleu tancar el quadre de diàleg?","options":"Opcions","target":"Destí","targetNew":"Nova finestra (_blank)","targetTop":"Finestra superior (_top)","targetSelf":"Mateixa finestra (_self)","targetParent":"Finestra pare (_parent)","langDirLTR":"D'esquerra a dreta (LTR)","langDirRTL":"De dreta a esquerra (RTL)","styles":"Estil","cssClasses":"Classes del full d'estil","width":"Amplada","height":"Alçada","align":"Alineació","left":"Ajusta a l'esquerra","right":"Ajusta a la dreta","center":"Centre","justify":"Justificat","alignLeft":"Alinea a l'esquerra","alignRight":"Alinea a la dreta","alignCenter":"Align Center","alignTop":"Superior","alignMiddle":"Centre","alignBottom":"Inferior","alignNone":"Cap","invalidValue":"Valor no vàlid.","invalidHeight":"L'alçada ha de ser un número.","invalidWidth":"L'amplada ha de ser un número.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"El valor especificat per als \"%1\" camps ha de ser un número positiu amb o sense unitat de mesura vàlida de CSS (px, %, in, cm, mm, em, ex, pt o pc).","invalidHtmlLength":"El valor especificat per als \"%1\" camps ha de ser un número positiu amb o sense unitat de mesura vàlida d'HTML (px o %).","invalidInlineStyle":"El valor especificat per l'estil en línia ha de constar d'una o més tuples amb el format \"name: value\", separats per punt i coma.","cssLengthTooltip":"Introduïu un número per un valor en píxels o un número amb una unitat vàlida de CSS (px, %, in, cm, mm, em, ex, pt o pc).","unavailable":"%1<span class=\"cke_accessibility\">, no disponible</span>","keyboard":{"8":"Retrocés","13":"Intro","16":"Majúscules","17":"Ctrl","18":"Alt","32":"Space","35":"Fi","36":"Inici","46":"Eliminar","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. Tots els drets reservats.","dlgTitle":"Quant al CKEditor 4","moreInfo":"Per informació sobre llicències visiteu el nostre lloc web:"},"basicstyles":{"bold":"Negreta","italic":"Cursiva","strike":"Ratllat","subscript":"Subíndex","superscript":"Superíndex","underline":"Subratllat"},"blockquote":{"toolbar":"Bloc de cita"},"notification":{"closed":"Notificació tancada."},"toolbar":{"toolbarCollapse":"Redueix la barra d'eines","toolbarExpand":"Amplia la barra d'eines","toolbarGroups":{"document":"Document","clipboard":"Clipboard/Undo","editing":"Editing","forms":"Forms","basicstyles":"Basic Styles","paragraph":"Paragraph","links":"Links","insert":"Insert","styles":"Styles","colors":"Colors","tools":"Tools"},"toolbars":"Editor de barra d'eines"},"clipboard":{"copy":"Copiar","copyError":"La configuració de seguretat del vostre navegador no permet executar automàticament les operacions de copiar. Si us plau, utilitzeu el teclat (Ctrl/Cmd+C).","cut":"Retallar","cutError":"La configuració de seguretat del vostre navegador no permet executar automàticament les operacions de retallar. Si us plau, utilitzeu el teclat (Ctrl/Cmd+X).","paste":"Enganxar","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Àrea d'enganxat","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Opcions del menú contextual"},"elementspath":{"eleLabel":"Ruta dels elements","eleTitlLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['cs']={"editor":"Textový editor","editorPanel":"Panel textového editoru","common":{"editorHelp":"Stiskněte ALT 0 pro nápovědu","browseServer":"Vybrat na serveru","url":"URL","protocol":"Protokol","upload":"Odeslat","uploadSubmit":"Odeslat na server","image":"Obrázek","flash":"Flash","form":"Formulář","checkbox":"Zaškrtávací políčko","radio":"Přepínač","textField":"Textové pole","textarea":"Textová oblast","hiddenField":"Skryté pole","button":"Tlačítko","select":"Seznam","imageButton":"Obrázkové tlačítko","notSet":"<nenastaveno>","id":"Id","name":"Jméno","langDir":"Směr jazyka","langDirLtr":"Zleva doprava (LTR)","langDirRtl":"Zprava doleva (RTL)","langCode":"Kód jazyka","longDescr":"Dlouhý popis URL","cssClass":"Třída stylu","advisoryTitle":"Pomocný titulek","cssStyle":"Styl","ok":"OK","cancel":"Zrušit","close":"Zavřít","preview":"Náhled","resize":"Uchopit pro změnu velikosti","generalTab":"Obecné","advancedTab":"Rozšířené","validateNumberFailed":"Zadaná hodnota není číselná.","confirmNewPage":"Jakékoliv neuložené změny obsahu budou ztraceny. Skutečně chcete otevřít novou stránku?","confirmCancel":"Některá z nastavení byla změněna. Skutečně chcete zavřít dialogové okno?","options":"Nastavení","target":"Cíl","targetNew":"Nové okno (_blank)","targetTop":"Okno nejvyšší úrovně (_top)","targetSelf":"Stejné okno (_self)","targetParent":"Rodičovské okno (_parent)","langDirLTR":"Zleva doprava (LTR)","langDirRTL":"Zprava doleva (RTL)","styles":"Styly","cssClasses":"Třídy stylů","width":"Šířka","height":"Výška","align":"Zarovnání","left":"Vlevo","right":"Vpravo","center":"Na střed","justify":"Zarovnat do bloku","alignLeft":"Zarovnat vlevo","alignRight":"Zarovnat vpravo","alignCenter":"Zarovnat na střed","alignTop":"Nahoru","alignMiddle":"Na střed","alignBottom":"Dolů","alignNone":"Žádné","invalidValue":"Neplatná hodnota.","invalidHeight":"Zadaná výška musí být číslo.","invalidWidth":"Šířka musí být číslo.","invalidLength":"Hodnota určená pro pole \"%1\" musí být kladné číslo bez nebo s platnou jednotkou míry (%2).","invalidCssLength":"Hodnota určená pro pole \"%1\" musí být kladné číslo bez nebo s platnou jednotkou míry CSS (px, %, in, cm, mm, em, ex, pt, nebo pc).","invalidHtmlLength":"Hodnota určená pro pole \"%1\" musí být kladné číslo bez nebo s platnou jednotkou míry HTML (px nebo %).","invalidInlineStyle":"Hodnota určená pro řádkový styl se musí skládat z jedné nebo více n-tic ve formátu \"název : hodnota\", oddělené středníky","cssLengthTooltip":"Zadejte číslo jako hodnotu v pixelech nebo číslo s platnou jednotkou CSS (px, %, v cm, mm, em, ex, pt, nebo pc).","unavailable":"%1<span class=\"cke_accessibility\">, nedostupné</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Mezerník","35":"Konec","36":"Domů","46":"Smazat","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Klávesová zkratka","optionDefault":"Výchozí"},"about":{"copy":"Copyright &copy; $1. All rights reserved.","dlgTitle":"O aplikaci CKEditor 4","moreInfo":"Pro informace o lincenci navštivte naši webovou stránku:"},"basicstyles":{"bold":"Tučné","italic":"Kurzíva","strike":"Přeškrtnuté","subscript":"Dolní index","superscript":"Horní index","underline":"Podtržené"},"blockquote":{"toolbar":"Citace"},"notification":{"closed":"Oznámení zavřeno."},"toolbar":{"toolbarCollapse":"Skrýt panel nástrojů","toolbarExpand":"Zobrazit panel nástrojů","toolbarGroups":{"document":"Dokument","clipboard":"Schránka/Zpět","editing":"Úpravy","forms":"Formuláře","basicstyles":"Základní styly","paragraph":"Odstavec","links":"Odkazy","insert":"Vložit","styles":"Styly","colors":"Barvy","tools":"Nástroje"},"toolbars":"Panely nástrojů editoru"},"clipboard":{"copy":"Kopírovat","copyError":"Bezpečnostní nastavení vašeho prohlížeče nedovolují editoru spustit funkci pro kopírování zvoleného textu do schránky. Prosím zkopírujte zvolený text do schránky pomocí klávesnice (Ctrl/Cmd+C).","cut":"Vyjmout","cutError":"Bezpečnostní nastavení vašeho prohlížeče nedovolují editoru spustit funkci pro vyjmutí zvoleného textu do schránky. Prosím vyjměte zvolený text do schránky pomocí klávesnice (Ctrl/Cmd+X).","paste":"Vložit","pasteNotification":"Stiskněte %1 pro vložení. Váš prohlížeč nepodporuje vkládání pomocí tlačítka na panelu nástrojů nebo volby kontextového menu.","pasteArea":"Oblast vkládání","pasteMsg":"Vložte svůj obsah do oblasti níže a stiskněte OK."},"contextmenu":{"options":"Nastavení kontextové nabídky"},"elementspLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['cy']={"editor":"Golygydd Testun Cyfoethog","editorPanel":"Panel Golygydd Testun Cyfoethog","common":{"editorHelp":"Gwasgwch ALT 0 am gymorth","browseServer":"Pori'r Gweinydd","url":"URL","protocol":"Protocol","upload":"Lanlwytho","uploadSubmit":"Anfon i'r Gweinydd","image":"Delwedd","flash":"Flash","form":"Ffurflen","checkbox":"Blwch ticio","radio":"Botwm Radio","textField":"Maes Testun","textarea":"Ardal Testun","hiddenField":"Maes Cudd","button":"Botwm","select":"Maes Dewis","imageButton":"Botwm Delwedd","notSet":"<heb osod>","id":"Id","name":"Name","langDir":"Cyfeiriad Iaith","langDirLtr":"Chwith i'r Dde (LTR)","langDirRtl":"Dde i'r Chwith (RTL)","langCode":"Cod Iaith","longDescr":"URL Disgrifiad Hir","cssClass":"Dosbarthiadau Dalen Arddull","advisoryTitle":"Teitl Cynghorol","cssStyle":"Arddull","ok":"Iawn","cancel":"Diddymu","close":"Cau","preview":"Rhagolwg","resize":"Ailfeintio","generalTab":"Cyffredinol","advancedTab":"Uwch","validateNumberFailed":"'Dyw'r gwerth hwn ddim yn rhif.","confirmNewPage":"Byddwch chi'n colli unrhyw newidiadau i'r cynnwys sydd heb eu cadw. Ydych am barhau i lwytho tudalen newydd?","confirmCancel":"Cafodd rhai o'r opsiynau eu newid. Ydych chi wir am gau'r deialog?","options":"Opsiynau","target":"Targed","targetNew":"Ffenest Newydd (_blank)","targetTop":"Ffenest ar y Brig (_top)","targetSelf":"Yr un Ffenest (_self)","targetParent":"Ffenest y Rhiant (_parent)","langDirLTR":"Chwith i'r Dde (LTR)","langDirRTL":"Dde i'r Chwith (RTL)","styles":"Arddull","cssClasses":"Dosbarthiadau Dalen Arddull","width":"Lled","height":"Uchder","align":"Alinio","left":"Chwith","right":"Dde","center":"Canol","justify":"Unioni","alignLeft":"Alinio i'r Chwith","alignRight":"Alinio i'r Dde","alignCenter":"Align Center","alignTop":"Brig","alignMiddle":"Canol","alignBottom":"Gwaelod","alignNone":"None","invalidValue":"Gwerth annilys.","invalidHeight":"Mae'n rhaid i'r uchder fod yn rhif.","invalidWidth":"Mae'n rhaid i'r lled fod yn rhif.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Mae'n rhaid i'r gwerth ar gyfer maes \"%1\" fod yn rhif positif gyda neu heb uned fesuriad CSS dilys (px, %, in, cm, mm, em, ex, pt, neu pc).","invalidHtmlLength":"Mae'n rhaid i'r gwerth ar gyfer maes \"%1\" fod yn rhif positif gyda neu heb uned fesuriad HTML dilys (px neu %).","invalidInlineStyle":"Mae'n rhaid i'r gwerth ar gyfer arddull mewn-llinell gynnwys un set neu fwy ar y fformat \"enw : gwerth\", wedi'u gwahanu gyda hanner colon.","cssLengthTooltip":"Rhowch rif am werth mewn picsel neu rhif gydag uned CSS dilys (px, %, in, cm, mm, em, pt neu pc).","unavailable":"%1<span class=\"cke_accessibility\">, ddim ar gael</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Hawlfraint &copy; $1. Cedwir pob hawl.","dlgTitle":"About CKEditor 4","moreInfo":"Am wybodaeth ynghylch trwyddedau, ewch i'n gwefan:"},"basicstyles":{"bold":"Bras","italic":"Italig","strike":"Llinell Trwyddo","subscript":"Is-sgript","superscript":"Uwchsgript","underline":"Tanlinellu"},"blockquote":{"toolbar":"Dyfyniad bloc"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Cyfangu'r Bar Offer","toolbarExpand":"Ehangu'r Bar Offer","toolbarGroups":{"document":"Dogfen","clipboard":"Clipfwrdd/Dadwneud","editing":"Golygu","forms":"Ffurflenni","basicstyles":"Arddulliau Sylfaenol","paragraph":"Paragraff","links":"Dolenni","insert":"Mewnosod","styles":"Arddulliau","colors":"Lliwiau","tools":"Offer"},"toolbars":"Bariau offer y golygydd"},"clipboard":{"copy":"Copïo","copyError":"'Dyw gosodiadau diogelwch eich porwr ddim yn caniatàu'r golygydd i gynnal 'gweithredoedd copïo' yn awtomatig. Defnyddiwch y bysellfwrdd (Ctrl/Cmd+C).","cut":"Torri","cutError":"Nid yw gosodiadau diogelwch eich porwr yn caniatàu'r golygydd i gynnal 'gweithredoedd torri' yn awtomatig. Defnyddiwch y bysellfwrdd (Ctrl/Cmd+X).","paste":"Gludo","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Ardal Gludo","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Opsiynau Dewislen Cyd-destun"},"elementspath":{"eleLabel":"Llwybr elfennau","eleTitle":"Elfen %1"},"filetools":{"loadError":"Error occurred during file read.","networkError":"Network error occurred during file upload.","httpError404":"HTTP error occurred during file upload (404: File not found).","httpError403":"HLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['da']={"editor":"Rich Text Editor","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"Tryk ALT 0 for hjælp","browseServer":"Gennemse...","url":"URL","protocol":"Protokol","upload":"Upload","uploadSubmit":"Upload","image":"Indsæt billede","flash":"Indsæt Flash","form":"Indsæt formular","checkbox":"Indsæt afkrydsningsfelt","radio":"Indsæt alternativknap","textField":"Indsæt tekstfelt","textarea":"Indsæt tekstboks","hiddenField":"Indsæt skjult felt","button":"Indsæt knap","select":"Indsæt liste","imageButton":"Indsæt billedknap","notSet":"<intet valgt>","id":"Id","name":"Navn","langDir":"Tekstretning","langDirLtr":"Fra venstre mod højre (LTR)","langDirRtl":"Fra højre mod venstre (RTL)","langCode":"Sprogkode","longDescr":"Udvidet beskrivelse","cssClass":"Typografiark (CSS)","advisoryTitle":"Titel","cssStyle":"Typografi (CSS)","ok":"OK","cancel":"Annullér","close":"Luk","preview":"Forhåndsvisning","resize":"Træk for at skalere","generalTab":"Generelt","advancedTab":"Avanceret","validateNumberFailed":"Værdien er ikke et tal.","confirmNewPage":"Alt indhold, der ikke er blevet gemt, vil gå tabt. Er du sikker på, at du vil indlæse en ny side?","confirmCancel":"Nogle af indstillingerne er blevet ændret. Er du sikker på, at du vil lukke vinduet?","options":"Vis muligheder","target":"Mål","targetNew":"Nyt vindue (_blank)","targetTop":"Øverste vindue (_top)","targetSelf":"Samme vindue (_self)","targetParent":"Samme vindue (_parent)","langDirLTR":"Venstre til højre (LTR)","langDirRTL":"Højre til venstre (RTL)","styles":"Style","cssClasses":"Stylesheetklasser","width":"Bredde","height":"Højde","align":"Justering","left":"Venstre","right":"Højre","center":"Center","justify":"Lige margener","alignLeft":"Venstrestillet","alignRight":"Højrestillet","alignCenter":"Centreret","alignTop":"Øverst","alignMiddle":"Centreret","alignBottom":"Nederst","alignNone":"Ingen","invalidValue":"Ugyldig værdi.","invalidHeight":"Højde skal være et tal.","invalidWidth":"Bredde skal være et tal.","invalidLength":"Værdien angivet for feltet \"%1\" skal være et positivt heltal med eller uden en gyldig måleenhed (%2).","invalidCssLength":"Værdien specificeret for \"%1\" feltet skal være et positivt nummer med eller uden en CSS måleenhed (px, %, in, cm, mm, em, ex, pt, eller pc).","invalidHtmlLength":"Værdien specificeret for \"%1\" feltet skal være et positivt nummer med eller uden en CSS måleenhed (px eller %).","invalidInlineStyle":"Værdien specificeret for inline style skal indeholde en eller flere elementer med et format som \"name:value\", separeret af semikoloner","cssLengthTooltip":"Indsæt en numerisk værdi i pixel eller nummer med en gyldig CSS værdi (px, %, in, cm, mm, em, ex, pt, eller pc).","unavailable":"%1<span class=\"cke_accessibility\">, ikke tilgængelig</span>","keyboard":{"8":"Backspace","13":"Retur","16":"Shift","17":"Ctrl","18":"Alt","32":"Mellemrum","35":"End","36":"Home","46":"Slet","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Kommando"},"keyboardShortcut":"Tastatur genvej","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. Alle rettigheder forbeholdes.","dlgTitle":"Om CKEditor 4","moreInfo":"For informationer omkring licens, se venligst vores hjemmeside (på engelsk):"},"basicstyles":{"bold":"Fed","italic":"Kursiv","strike":"Gennemstreget","subscript":"Sænket skrift","superscript":"Hævet skrift","underline":"Understreget"},"blockquote":{"toolbar":"Blokcitat"},"notification":{"closed":"Notefikation lukket."},"toolbar":{"toolbarCollapse":"Sammenklap værktøjslinje","toolbarExpand":"Udvid værktøjslinje","toolbarGroups":{"document":"Dokument","clipboard":"Udklipsholder/Fortryd","editing":"Redigering","forms":"Formularer","basicstyles":"Basis styles","paragraph":"Paragraf","links":"Links","insert":"Indsæt","styles":"Typografier","colors":"Farver","tools":"Værktøjer"},"toolbars":"Editors værktøjslinjer"},"clipboard":{"copy":"Kopiér","copyError":"Din browsers sikkerhedsindstillinger tillader ikke editoren at få automatisk adgang til udklipsholderen.<br><br>Brug i stedet tastaturet til at kopiere teksten (Ctrl/Cmd+C).","cut":"Klip","cutError":"Din browsers sikkerhedsindstillinger tillader ikke editoren at få automatisk adgang til udklipsholderen.<br><br>Brug i stedet tastaturet til at klippe teksten (Ctrl/Cmd+X).","paste":"Indsæt","pasteNotification":"Tryk %1 for at sætte ind. Din browser understøtter ikke indsættelse med værktøjslinje knappen eller kontekst menuen.","pasteArea":"Indsættelses område","pasteMsg":"Indsæt dit indhold i området nedenfor og tryk OK."},"contextmenu":{"options":"Muligheder for hjælpemenu"},"elementspath":{"eleLabel":"Sti på element","eleTitle":"%1 element"}Line truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['de-ch']={"editor":"WYSIWYG-Editor","editorPanel":"WYSIWYG-Editor-Leiste","common":{"editorHelp":"Drücken Sie ALT 0 für Hilfe","browseServer":"Server durchsuchen","url":"URL","protocol":"Protokoll","upload":"Hochladen","uploadSubmit":"Zum Server senden","image":"Bild","flash":"Flash","form":"Formular","checkbox":"Kontrollbox","radio":"Optionsfeld","textField":"Textfeld","textarea":"Textfeld","hiddenField":"Verstecktes Feld","button":"Schaltfläche","select":"Auswahlfeld","imageButton":"Bildschaltfläche","notSet":"<nicht festgelegt>","id":"Kennung","name":"Name","langDir":"Schreibrichtung","langDirLtr":"Links nach Rechts (LTR)","langDirRtl":"Rechts nach Links (RTL)","langCode":"Sprachcode","longDescr":"Langbeschreibungs-URL","cssClass":"Formatvorlagenklassen","advisoryTitle":"Titel Beschreibung","cssStyle":"Stil","ok":"OK","cancel":"Abbrechen","close":"Schliessen","preview":"Vorschau","resize":"Grösse ändern","generalTab":"Allgemein","advancedTab":"Erweitert","validateNumberFailed":"Dieser Wert ist keine Nummer.","confirmNewPage":"Alle nicht gespeicherten Änderungen gehen verlohren. Sind Sie sicher die neue Seite zu laden?","confirmCancel":"Einige Optionen wurden geändert. Wollen Sie den Dialog dennoch schliessen?","options":"Optionen","target":"Zielseite","targetNew":"Neues Fenster (_blank)","targetTop":"Oberstes Fenster (_top)","targetSelf":"Gleiches Fenster (_self)","targetParent":"Oberes Fenster (_parent)","langDirLTR":"Links nach Rechts (LNR)","langDirRTL":"Rechts nach Links (RNL)","styles":"Style","cssClasses":"Stylesheet Klasse","width":"Breite","height":"Höhe","align":"Ausrichtung","left":"Links","right":"Rechts","center":"Zentriert","justify":"Blocksatz","alignLeft":"Linksbündig","alignRight":"Rechtsbündig","alignCenter":"Align Center","alignTop":"Oben","alignMiddle":"Mitte","alignBottom":"Unten","alignNone":"Keine","invalidValue":"Ungültiger Wert.","invalidHeight":"Höhe muss eine Zahl sein.","invalidWidth":"Breite muss eine Zahl sein.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Wert spezifiziert für \"%1\" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).","invalidHtmlLength":"Wert spezifiziert für \"%1\" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte HTML Messeinheit (px oder %).","invalidInlineStyle":"Wert spezifiziert für inline Stilart muss enthalten ein oder mehr Tupels mit dem Format \"Name : Wert\" getrennt mit Semikolons.","cssLengthTooltip":"Gebe eine Zahl ein für ein Wert in pixels oder eine Zahl mit einer korrekten CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).","unavailable":"%1<span class=\"cke_accessibility\">, nicht verfügbar</span>","keyboard":{"8":"Rücktaste","13":"Eingabe","16":"Umschalt","17":"Strg","18":"Alt","32":"Space","35":"Ende","36":"Pos1","46":"Entfernen","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. Alle Rechte vorbehalten.","dlgTitle":"Über CKEditor 4","moreInfo":"Für Informationen über unsere Lizenzbestimmungen besuchen sie bitte unsere Webseite:"},"basicstyles":{"bold":"Fett","italic":"Kursiv","strike":"Durchgestrichen","subscript":"Tiefgestellt","superscript":"Hochgestellt","underline":"Unterstrichen"},"blockquote":{"toolbar":"Zitatblock"},"notification":{"closed":"Benachrichtigung geschlossen."},"toolbar":{"toolbarCollapse":"Werkzeugleiste einklappen","toolbarExpand":"Werkzeugleiste ausklappen","toolbarGroups":{"document":"Dokument","clipboard":"Zwischenablage/Rückgängig","editing":"Editieren","forms":"Formulare","basicstyles":"Grundstile","paragraph":"Absatz","links":"Links","insert":"Einfügen","styles":"Stile","colors":"Farben","tools":"Werkzeuge"},"toolbars":"Editor Werkzeugleisten"},"clipboard":{"copy":"Kopieren","copyError":"Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch kopieren. Bitte benutzen Sie die System-Zwischenablage über STRG-C (kopieren).","cut":"Ausschneiden","cutError":"Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch auszuschneiden. Bitte benutzen Sie die System-Zwischenablage über STRG-X (ausschneiden) und STRG-V (einfügen).","paste":"Einfügen","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Einfügebereich","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Kontextmenüoptionen"},"elementspath":{"eleLabel":"Elementepfad","eleTitle":"%1 ElemeLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['de']={"editor":"WYSIWYG-Editor","editorPanel":"WYSIWYG-Editor-Leiste","common":{"editorHelp":"Drücken Sie ALT 0 für Hilfe","browseServer":"Server durchsuchen","url":"URL","protocol":"Protokoll","upload":"Hochladen","uploadSubmit":"Zum Server senden","image":"Bild","flash":"Flash","form":"Formular","checkbox":"Kontrollbox","radio":"Optionsfeld","textField":"Textfeld","textarea":"Textfeld","hiddenField":"Verstecktes Feld","button":"Schaltfläche","select":"Auswahlfeld","imageButton":"Bildschaltfläche","notSet":"<nicht festgelegt>","id":"Kennung","name":"Name","langDir":"Schreibrichtung","langDirLtr":"Links nach Rechts (LTR)","langDirRtl":"Rechts nach Links (RTL)","langCode":"Sprachcode","longDescr":"Langbeschreibungs-URL","cssClass":"Formatvorlagenklassen","advisoryTitle":"Titel Beschreibung","cssStyle":"Stil","ok":"OK","cancel":"Abbrechen","close":"Schließen","preview":"Vorschau","resize":"Größe ändern","generalTab":"Allgemein","advancedTab":"Erweitert","validateNumberFailed":"Dieser Wert ist keine Nummer.","confirmNewPage":"Alle nicht gespeicherten Änderungen gehen verloren. Sind Sie sicher die neue Seite zu laden?","confirmCancel":"Einige Optionen wurden geändert. Wollen Sie den Dialog dennoch schließen?","options":"Optionen","target":"Zielseite","targetNew":"Neues Fenster (_blank)","targetTop":"Oberstes Fenster (_top)","targetSelf":"Gleiches Fenster (_self)","targetParent":"Oberes Fenster (_parent)","langDirLTR":"Links nach Rechts (LNR)","langDirRTL":"Rechts nach Links (RNL)","styles":"Style","cssClasses":"Stylesheet Klasse","width":"Breite","height":"Höhe","align":"Ausrichtung","left":"Links","right":"Rechts","center":"Zentriert","justify":"Blocksatz","alignLeft":"Linksbündig","alignRight":"Rechtsbündig","alignCenter":"Zentriert","alignTop":"Oben","alignMiddle":"Mitte","alignBottom":"Unten","alignNone":"Keine","invalidValue":"Ungültiger Wert.","invalidHeight":"Höhe muss eine Zahl sein.","invalidWidth":"Breite muss eine Zahl sein.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Wert spezifiziert für \"%1\" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).","invalidHtmlLength":"Wert spezifiziert für \"%1\" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte HTML Messeinheit (px oder %).","invalidInlineStyle":"Wert spezifiziert für inline Stilart muss enthalten ein oder mehr Tupels mit dem Format \"Name : Wert\" getrennt mit Semikolons.","cssLengthTooltip":"Gebe eine Zahl ein für ein Wert in pixels oder eine Zahl mit einer korrekten CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).","unavailable":"%1<span class=\"cke_accessibility\">, nicht verfügbar</span>","keyboard":{"8":"Rücktaste","13":"Eingabe","16":"Umschalt","17":"Strg","18":"Alt","32":"Leer","35":"Ende","36":"Pos1","46":"Entfernen","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Befehl"},"keyboardShortcut":"Tastaturkürzel","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. Alle Rechte vorbehalten.","dlgTitle":"Über CKEditor 4","moreInfo":"Für Informationen über unsere Lizenzbestimmungen besuchen sie bitte unsere Webseite:"},"basicstyles":{"bold":"Fett","italic":"Kursiv","strike":"Durchgestrichen","subscript":"Tiefgestellt","superscript":"Hochgestellt","underline":"Unterstrichen"},"blockquote":{"toolbar":"Zitatblock"},"notification":{"closed":"Benachrichtigung geschlossen."},"toolbar":{"toolbarCollapse":"Werkzeugleiste einklappen","toolbarExpand":"Werkzeugleiste ausklappen","toolbarGroups":{"document":"Dokument","clipboard":"Zwischenablage/Rückgängig","editing":"Editieren","forms":"Formulare","basicstyles":"Grundstile","paragraph":"Absatz","links":"Links","insert":"Einfügen","styles":"Stile","colors":"Farben","tools":"Werkzeuge"},"toolbars":"Editor Werkzeugleisten"},"clipboard":{"copy":"Kopieren","copyError":"Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch kopieren. Bitte benutzen Sie die System-Zwischenablage über STRG-C (kopieren).","cut":"Ausschneiden","cutError":"Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch auszuschneiden. Bitte benutzen Sie die System-Zwischenablage über STRG-X (ausschneiden) und STRG-V (einfügen).","paste":"Einfügen","pasteNotification":"Drücken Sie %1 zum Einfügen. Ihr Browser unterstützt nicht das Einfügen über dem Knopf in der Toolbar oder dem Kontextmenü.","pasteArea":"Einfügebereich","pasteMsg":"Fügen Sie den Inhalt in den unteren Bereich ein und drücken Sie OK."},"contextmenu":{"options":"Kontextmenüoptionen"},"elementspath":{"eleLabel":"ElemenLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['el']={"editor":"Επεξεργαστής Πλούσιου Κειμένου","editorPanel":"Πίνακας Επεξεργαστή Πλούσιου Κειμένου","common":{"editorHelp":"Πατήστε το ALT 0 για βοήθεια","browseServer":"Εξερεύνηση Διακομιστή","url":"URL","protocol":"Πρωτόκολλο","upload":"Αποστολή","uploadSubmit":"Αποστολή στον Διακομιστή","image":"Εικόνα","flash":"Flash","form":"Φόρμα","checkbox":"Κουτί Επιλογής","radio":"Κουμπί Επιλογής","textField":"Πεδίο Κειμένου","textarea":"Περιοχή Κειμένου","hiddenField":"Κρυφό Πεδίο","button":"Κουμπί","select":"Πεδίο Επιλογής","imageButton":"Κουμπί Εικόνας","notSet":"<δεν έχει ρυθμιστεί>","id":"Id","name":"Όνομα","langDir":"Κατεύθυνση Κειμένου","langDirLtr":"Αριστερά προς Δεξιά (LTR)","langDirRtl":"Δεξιά προς Αριστερά (RTL)","langCode":"Κωδικός Γλώσσας","longDescr":"Αναλυτική Περιγραφή URL","cssClass":"Κλάσεις Φύλλων Στυλ","advisoryTitle":"Ενδεικτικός Τίτλος","cssStyle":"Μορφή Κειμένου","ok":"OK","cancel":"Ακύρωση","close":"Κλείσιμο","preview":"Προεπισκόπηση","resize":"Αλλαγή Μεγέθους","generalTab":"Γενικά","advancedTab":"Για Προχωρημένους","validateNumberFailed":"Αυτή η τιμή δεν είναι αριθμός.","confirmNewPage":"Οι όποιες αλλαγές στο περιεχόμενο θα χαθούν. Είσαστε σίγουροι ότι θέλετε να φορτώσετε μια νέα σελίδα;","confirmCancel":"Μερικές επιλογές έχουν αλλάξει. Είσαστε σίγουροι ότι θέλετε να κλείσετε το παράθυρο διαλόγου;","options":"Επιλογές","target":"Προορισμός","targetNew":"Νέο Παράθυρο (_blank)","targetTop":"Αρχική Περιοχή (_top)","targetSelf":"Ίδιο Παράθυρο (_self)","targetParent":"Γονεϊκό Παράθυρο (_parent)","langDirLTR":"Αριστερά προς Δεξιά (LTR)","langDirRTL":"Δεξιά προς Αριστερά (RTL)","styles":"Μορφή","cssClasses":"Κλάσεις Φύλλων Στυλ","width":"Πλάτος","height":"Ύψος","align":"Στοίχιση","left":"Αριστερά","right":"Δεξιά","center":"Κέντρο","justify":"Πλήρης Στοίχιση","alignLeft":"Στοίχιση Αριστερά","alignRight":"Στοίχιση Δεξιά","alignCenter":"Align Center","alignTop":"Πάνω","alignMiddle":"Μέση","alignBottom":"Κάτω","alignNone":"Χωρίς","invalidValue":"Μη έγκυρη τιμή.","invalidHeight":"Το ύψος πρέπει να είναι ένας αριθμός.","invalidWidth":"Το πλάτος πρέπει να είναι ένας αριθμός.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Η τιμή που ορίζεται για το πεδίο \"%1\" πρέπει να είναι ένας θετικός αριθμός με ή χωρίς μια έγκυρη μονάδα μέτρησης CSS (px, %, in, cm, mm, em, ex, pt, ή pc).","invalidHtmlLength":"Η τιμή που ορίζεται για το πεδίο \"%1\" πρέπει να είναι ένας θετικός αριθμός με ή χωρίς μια έγκυρη μονάδα μέτρησης HTML (px ή %).","invalidInlineStyle":"Η τιμή για το εν σειρά στυλ πρέπει να περιέχει ένα ή περισσότερα ζεύγη με την μορφή \"όνομα: τιμή\" διαχωρισμένα με Ελληνικό ερωτηματικό.","cssLengthTooltip":"Εισάγεται μια τιμή σε pixel ή έναν αριθμό μαζί με μια έγκυρη μονάδα μέτρησης CSS (px, %, in, cm, mm, em, ex, pt, ή pc).","unavailable":"%1<span class=\"cke_accessibility\">, δεν είναι διαθέσιμο</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Κενό","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Εντολή"},"keyboardShortcut":"Συντόμευση πληκτρολογίου","optionDefault":"Default"},"about":{"copy":"Πνευματικά δικαιώματα &copy; $1 Με επιφύλαξη παντός δικαιώματος.","dlgTitle":"Περί του CKEditor 4","moreInfo":"ΓLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['en-au']={"editor":"Rich Text Editor","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"Press ALT 0 for help","browseServer":"Browse Server","url":"URL","protocol":"Protocol","upload":"Upload","uploadSubmit":"Send it to the Server","image":"Image","flash":"Flash","form":"Form","checkbox":"Checkbox","radio":"Radio Button","textField":"Text Field","textarea":"Textarea","hiddenField":"Hidden Field","button":"Button","select":"Selection Field","imageButton":"Image Button","notSet":"<not set>","id":"Id","name":"Name","langDir":"Language Direction","langDirLtr":"Left to Right (LTR)","langDirRtl":"Right to Left (RTL)","langCode":"Language Code","longDescr":"Long Description URL","cssClass":"Stylesheet Classes","advisoryTitle":"Advisory Title","cssStyle":"Style","ok":"OK","cancel":"Cancel","close":"Close","preview":"Preview","resize":"Resize","generalTab":"General","advancedTab":"Advanced","validateNumberFailed":"This value is not a number.","confirmNewPage":"Any unsaved changes to this content will be lost. Are you sure you want to load new page?","confirmCancel":"You have changed some options. Are you sure you want to close the dialog window?","options":"Options","target":"Target","targetNew":"New Window (_blank)","targetTop":"Topmost Window (_top)","targetSelf":"Same Window (_self)","targetParent":"Parent Window (_parent)","langDirLTR":"Left to Right (LTR)","langDirRTL":"Right to Left (RTL)","styles":"Style","cssClasses":"Stylesheet Classes","width":"Width","height":"Height","align":"Align","left":"Left","right":"Right","center":"Centre","justify":"Justify","alignLeft":"Align Left","alignRight":"Align Right","alignCenter":"Align Centre","alignTop":"Top","alignMiddle":"Middle","alignBottom":"Bottom","alignNone":"None","invalidValue":"Invalid value.","invalidHeight":"Height must be a number.","invalidWidth":"Width must be a number.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Value specified for the \"%1\" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"Value specified for the \"%1\" field must be a positive number with or without a valid HTML measurement unit (px or %).","invalidInlineStyle":"Value specified for the inline style must consist of one or more tuples with the format of \"name : value\", separated by semi-colons.","cssLengthTooltip":"Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, unavailable</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. All rights reserved.","dlgTitle":"About CKEditor 4","moreInfo":"For licensing information please visit our web site:"},"basicstyles":{"bold":"Bold","italic":"Italic","strike":"Strike Through","subscript":"Subscript","superscript":"Superscript","underline":"Underline"},"blockquote":{"toolbar":"Block Quote"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Collapse Toolbar","toolbarExpand":"Expand Toolbar","toolbarGroups":{"document":"Document","clipboard":"Clipboard/Undo","editing":"Editing","forms":"Forms","basicstyles":"Basic Styles","paragraph":"Paragraph","links":"Links","insert":"Insert","styles":"Styles","colors":"Colors","tools":"Tools"},"toolbars":"Editor toolbars"},"clipboard":{"copy":"Copy","copyError":"Your browser security settings don't permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).","cut":"Cut","cutError":"Your browser security settings don't permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).","paste":"Paste","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Paste Area","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Context Menu Options"},"elementspath":{"eleLabel":"Elements path","eleTitle":"%1 element"},"filetools":{"loadError":"Error occurred during file read.","networkError":"Network error occurred during file upload.","httpError404":"HTTP error occurred during file upload (404: File not found).","httpError403":"HTTP error occurred during file upload (403: Forbidden).","httpError":"HTTP error occurred during file upload (error status: %1).","noUrlError"Line truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['en-ca']={"editor":"Rich Text Editor","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"Press ALT 0 for help","browseServer":"Browse Server","url":"URL","protocol":"Protocol","upload":"Upload","uploadSubmit":"Send it to the Server","image":"Image","flash":"Flash","form":"Form","checkbox":"Checkbox","radio":"Radio Button","textField":"Text Field","textarea":"Textarea","hiddenField":"Hidden Field","button":"Button","select":"Selection Field","imageButton":"Image Button","notSet":"<not set>","id":"Id","name":"Name","langDir":"Language Direction","langDirLtr":"Left to Right (LTR)","langDirRtl":"Right to Left (RTL)","langCode":"Language Code","longDescr":"Long Description URL","cssClass":"Stylesheet Classes","advisoryTitle":"Advisory Title","cssStyle":"Style","ok":"OK","cancel":"Cancel","close":"Close","preview":"Preview","resize":"Resize","generalTab":"General","advancedTab":"Advanced","validateNumberFailed":"This value is not a number.","confirmNewPage":"Any unsaved changes to this content will be lost. Are you sure you want to load new page?","confirmCancel":"You have changed some options. Are you sure you want to close the dialog window?","options":"Options","target":"Target","targetNew":"New Window (_blank)","targetTop":"Topmost Window (_top)","targetSelf":"Same Window (_self)","targetParent":"Parent Window (_parent)","langDirLTR":"Left to Right (LTR)","langDirRTL":"Right to Left (RTL)","styles":"Style","cssClasses":"Stylesheet Classes","width":"Width","height":"Height","align":"Align","left":"Left","right":"Right","center":"Centre","justify":"Justify","alignLeft":"Align Left","alignRight":"Align Right","alignCenter":"Align Center","alignTop":"Top","alignMiddle":"Middle","alignBottom":"Bottom","alignNone":"None","invalidValue":"Invalid value.","invalidHeight":"Height must be a number.","invalidWidth":"Width must be a number.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Value specified for the \"%1\" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"Value specified for the \"%1\" field must be a positive number with or without a valid HTML measurement unit (px or %).","invalidInlineStyle":"Value specified for the inline style must consist of one or more tuples with the format of \"name : value\", separated by semi-colons.","cssLengthTooltip":"Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, unavailable</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. All rights reserved.","dlgTitle":"About CKEditor 4","moreInfo":"For licensing information please visit our web site:"},"basicstyles":{"bold":"Bold","italic":"Italic","strike":"Strike Through","subscript":"Subscript","superscript":"Superscript","underline":"Underline"},"blockquote":{"toolbar":"Block Quote"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Collapse Toolbar","toolbarExpand":"Expand Toolbar","toolbarGroups":{"document":"Document","clipboard":"Clipboard/Undo","editing":"Editing","forms":"Forms","basicstyles":"Basic Styles","paragraph":"Paragraph","links":"Links","insert":"Insert","styles":"Styles","colors":"Colors","tools":"Tools"},"toolbars":"Editor toolbars"},"clipboard":{"copy":"Copy","copyError":"Your browser security settings don't permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).","cut":"Cut","cutError":"Your browser security settings don't permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).","paste":"Paste","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Paste Area","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Context Menu Options"},"elementspath":{"eleLabel":"Elements path","eleTitle":"%1 element"},"filetools":{"loadError":"Error occurred during file read.","networkError":"Network error occurred during file upload.","httpError404":"HTTP error occurred during file upload (404: File not found).","httpError403":"HTTP error occurred during file upload (403: Forbidden).","httpError":"HTTP error occurred during file upload (error status: %1).","noUrlError"Line truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['en-gb']={"editor":"Rich Text Editor","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"Press ALT 0 for help","browseServer":"Browse Server","url":"URL","protocol":"Protocol","upload":"Upload","uploadSubmit":"Send it to the Server","image":"Image","flash":"Flash","form":"Form","checkbox":"Checkbox","radio":"Radio Button","textField":"Text Field","textarea":"Textarea","hiddenField":"Hidden Field","button":"Button","select":"Selection Field","imageButton":"Image Button","notSet":"<not set>","id":"Id","name":"Name","langDir":"Language Direction","langDirLtr":"Left to Right (LTR)","langDirRtl":"Right to Left (RTL)","langCode":"Language Code","longDescr":"Long Description URL","cssClass":"Stylesheet Classes","advisoryTitle":"Advisory Title","cssStyle":"Style","ok":"OK","cancel":"Cancel","close":"Close","preview":"Preview","resize":"Drag to resize","generalTab":"General","advancedTab":"Advanced","validateNumberFailed":"This value is not a number.","confirmNewPage":"Any unsaved changes to this content will be lost. Are you sure you want to load new page?","confirmCancel":"You have changed some options. Are you sure you want to close the dialogue window?","options":"Options","target":"Target","targetNew":"New Window (_blank)","targetTop":"Topmost Window (_top)","targetSelf":"Same Window (_self)","targetParent":"Parent Window (_parent)","langDirLTR":"Left to Right (LTR)","langDirRTL":"Right to Left (RTL)","styles":"Style","cssClasses":"Stylesheet Classes","width":"Width","height":"Height","align":"Align","left":"Left","right":"Right","center":"Center","justify":"Justify","alignLeft":"Align Left","alignRight":"Align Right","alignCenter":"Align Center","alignTop":"Top","alignMiddle":"Middle","alignBottom":"Bottom","alignNone":"None","invalidValue":"Invalid value.","invalidHeight":"Height must be a number.","invalidWidth":"Width must be a number.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Value specified for the \"%1\" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"Value specified for the \"%1\" field must be a positive number with or without a valid HTML measurement unit (px or %).","invalidInlineStyle":"Value specified for the inline style must consist of one or more tuples with the format of \"name : value\", separated by semi-colons.","cssLengthTooltip":"Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, unavailable</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. All rights reserved.","dlgTitle":"About CKEditor 4","moreInfo":"For licensing information please visit our web site:"},"basicstyles":{"bold":"Bold","italic":"Italic","strike":"Strike Through","subscript":"Subscript","superscript":"Superscript","underline":"Underline"},"blockquote":{"toolbar":"Block Quote"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Collapse Toolbar","toolbarExpand":"Expand Toolbar","toolbarGroups":{"document":"Document","clipboard":"Clipboard/Undo","editing":"Editing","forms":"Forms","basicstyles":"Basic Styles","paragraph":"Paragraph","links":"Links","insert":"Insert","styles":"Styles","colors":"Colors","tools":"Tools"},"toolbars":"Editor toolbars"},"clipboard":{"copy":"Copy","copyError":"Your browser security settings don't permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).","cut":"Cut","cutError":"Your browser security settings don't permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).","paste":"Paste","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Paste Area","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Context Menu Options"},"elementspath":{"eleLabel":"Elements path","eleTitle":"%1 element"},"filetools":{"loadError":"Error occurred during file read.","networkError":"Network error occurred during file upload.","httpError404":"HTTP error occurred during file upload (404: File not found).","httpError403":"HTTP error occurred during file upload (403: Forbidden).","httpError":"HTTP error occurred during file upload (error status: %1).","nLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['en']={"editor":"Rich Text Editor","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"Press ALT 0 for help","browseServer":"Browse Server","url":"URL","protocol":"Protocol","upload":"Upload","uploadSubmit":"Send it to the Server","image":"Image","flash":"Flash","form":"Form","checkbox":"Checkbox","radio":"Radio Button","textField":"Text Field","textarea":"Textarea","hiddenField":"Hidden Field","button":"Button","select":"Selection Field","imageButton":"Image Button","notSet":"<not set>","id":"Id","name":"Name","langDir":"Language Direction","langDirLtr":"Left to Right (LTR)","langDirRtl":"Right to Left (RTL)","langCode":"Language Code","longDescr":"Long Description URL","cssClass":"Stylesheet Classes","advisoryTitle":"Advisory Title","cssStyle":"Style","ok":"OK","cancel":"Cancel","close":"Close","preview":"Preview","resize":"Resize","generalTab":"General","advancedTab":"Advanced","validateNumberFailed":"This value is not a number.","confirmNewPage":"Any unsaved changes to this content will be lost. Are you sure you want to load new page?","confirmCancel":"You have changed some options. Are you sure you want to close the dialog window?","options":"Options","target":"Target","targetNew":"New Window (_blank)","targetTop":"Topmost Window (_top)","targetSelf":"Same Window (_self)","targetParent":"Parent Window (_parent)","langDirLTR":"Left to Right (LTR)","langDirRTL":"Right to Left (RTL)","styles":"Style","cssClasses":"Stylesheet Classes","width":"Width","height":"Height","align":"Alignment","left":"Left","right":"Right","center":"Center","justify":"Justify","alignLeft":"Align Left","alignRight":"Align Right","alignCenter":"Align Center","alignTop":"Top","alignMiddle":"Middle","alignBottom":"Bottom","alignNone":"None","invalidValue":"Invalid value.","invalidHeight":"Height must be a number.","invalidWidth":"Width must be a number.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Value specified for the \"%1\" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"Value specified for the \"%1\" field must be a positive number with or without a valid HTML measurement unit (px or %).","invalidInlineStyle":"Value specified for the inline style must consist of one or more tuples with the format of \"name : value\", separated by semi-colons.","cssLengthTooltip":"Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, unavailable</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. All rights reserved.","dlgTitle":"About CKEditor 4","moreInfo":"For licensing information please visit our web site:"},"basicstyles":{"bold":"Bold","italic":"Italic","strike":"Strikethrough","subscript":"Subscript","superscript":"Superscript","underline":"Underline"},"blockquote":{"toolbar":"Block Quote"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Collapse Toolbar","toolbarExpand":"Expand Toolbar","toolbarGroups":{"document":"Document","clipboard":"Clipboard/Undo","editing":"Editing","forms":"Forms","basicstyles":"Basic Styles","paragraph":"Paragraph","links":"Links","insert":"Insert","styles":"Styles","colors":"Colors","tools":"Tools"},"toolbars":"Editor toolbars"},"clipboard":{"copy":"Copy","copyError":"Your browser security settings don't permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).","cut":"Cut","cutError":"Your browser security settings don't permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).","paste":"Paste","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Paste Area","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Context Menu Options"},"elementspath":{"eleLabel":"Elements path","eleTitle":"%1 element"},"filetools":{"loadError":"Error occurred during file read.","networkError":"Network error occurred during file upload.","httpError404":"HTTP error occurred during file upload (404: File not found).","httpError403":"HTTP error occurred during file upload (403: Forbidden).","httpError":"HTTP error occurred during file upload (error status: %1).","noUrlError"Line truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['eo']={"editor":"RiĉTeksta Redaktilo","editorPanel":"Panelo de la RiĉTeksta Redaktilo","common":{"editorHelp":"Premu ALT 0 por helpilo","browseServer":"Foliumi en la Servilo","url":"URL","protocol":"Protokolo","upload":"Alŝuti","uploadSubmit":"Sendu al Servilo","image":"Bildo","flash":"Flaŝo","form":"Formularo","checkbox":"Markobutono","radio":"Radiobutono","textField":"Teksta kampo","textarea":"Teksta Areo","hiddenField":"Kaŝita Kampo","button":"Butono","select":"Elekta Kampo","imageButton":"Bildbutono","notSet":"<Defaŭlta>","id":"Id","name":"Nomo","langDir":"Skribdirekto","langDirLtr":"De maldekstro dekstren (LTR)","langDirRtl":"De dekstro maldekstren (RTL)","langCode":"Lingva Kodo","longDescr":"URL de Longa Priskribo","cssClass":"Klasoj de Stilfolioj","advisoryTitle":"Priskriba Titolo","cssStyle":"Stilo","ok":"Akcepti","cancel":"Rezigni","close":"Fermi","preview":"Vidigi Aspekton","resize":"Movigi por ŝanĝi la grandon","generalTab":"Ĝenerala","advancedTab":"Speciala","validateNumberFailed":"Tiu valoro ne estas nombro.","confirmNewPage":"La neregistritaj ŝanĝoj estas perdotaj. Ĉu vi certas, ke vi volas ŝargi novan paĝon?","confirmCancel":"Iuj opcioj esta ŝanĝitaj. Ĉu vi certas, ke vi volas fermi la dialogon?","options":"Opcioj","target":"Celo","targetNew":"Nova Fenestro (_blank)","targetTop":"Supra Fenestro (_top)","targetSelf":"Sama Fenestro (_self)","targetParent":"Patra Fenestro (_parent)","langDirLTR":"De maldekstro dekstren (LTR)","langDirRTL":"De dekstro maldekstren (RTL)","styles":"Stilo","cssClasses":"Stilfoliaj Klasoj","width":"Larĝo","height":"Alto","align":"Ĝisrandigo","left":"Maldekstre","right":"Dekstre","center":"Centre","justify":"Ĝisrandigi Ambaŭflanke","alignLeft":"Ĝisrandigi maldekstren","alignRight":"Ĝisrandigi dekstren","alignCenter":"Align Center","alignTop":"Supre","alignMiddle":"Centre","alignBottom":"Malsupre","alignNone":"Neniu","invalidValue":"Nevalida Valoro","invalidHeight":"Alto devas esti nombro.","invalidWidth":"Larĝo devas esti nombro.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"La valoro indikita por la \"%1\" kampo devas esti pozitiva nombro kun aŭ sen valida CSSmezurunuo (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"La valoro indikita por la \"%1\" kampo devas esti pozitiva nombro kun aŭ sen valida HTMLmezurunuo (px or %).","invalidInlineStyle":"La valoro indikita por la enlinia stilo devas konsisti el unu aŭ pluraj elementoj kun la formato de \"nomo : valoro\", apartigitaj per punktokomoj.","cssLengthTooltip":"Entajpu nombron por rastrumera valoro aŭ nombron kun valida CSSunuo (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, nehavebla</span>","keyboard":{"8":"Retropaŝo","13":"Enigi","16":"Registrumo","17":"Stirklavo","18":"Alt-klavo","32":"Spaco","35":"Fino","36":"Hejmo","46":"Forigi","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Komando"},"keyboardShortcut":"Fulmoklavo","optionDefault":"Defaŭlta"},"about":{"copy":"Copyright &copy; $1. Ĉiuj rajtoj rezervitaj.","dlgTitle":"Pri CKEditor 4","moreInfo":"Por informoj pri licenco, bonvolu viziti nian retpaĝaron:"},"basicstyles":{"bold":"Grasa","italic":"Kursiva","strike":"Trastreko","subscript":"Suba indico","superscript":"Supra indico","underline":"Substreko"},"blockquote":{"toolbar":"Citaĵo"},"notification":{"closed":"Sciigo fermita"},"toolbar":{"toolbarCollapse":"Faldi la ilbreton","toolbarExpand":"Malfaldi la ilbreton","toolbarGroups":{"document":"Dokumento","clipboard":"Poŝo/Malfari","editing":"Redaktado","forms":"Formularoj","basicstyles":"Bazaj stiloj","paragraph":"Paragrafo","links":"Ligiloj","insert":"Enmeti","styles":"Stiloj","colors":"Koloroj","tools":"Iloj"},"toolbars":"Ilobretoj de la redaktilo"},"clipboard":{"copy":"Kopii","copyError":"La sekurecagordo de via TTT-legilo ne permesas, ke la redaktilo faras kopiajn operaciojn. Bonvolu uzi la klavaron por tio (Ctrl/Cmd-C).","cut":"Eltondi","cutError":"La sekurecagordo de via TTT-legilo ne permesas, ke la redaktilo faras eltondajn operaciojn. Bonvolu uzi la klavaron por tio (Ctrl/Cmd-X).","paste":"Interglui","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Intergluoareo","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Opcioj de Kunteksta Menuo"},"elementspath":{"eleLabel":"Vojo al Elementoj","eleTitle":"%1 elementoj"},"filetools":{"loadError":"Eraro okazis dum la dosiera legado.","networkError":"Reta eraro okazis dum la dosiera alŝuto.","httpError404":"HTTP eraro okazis dum la dosierLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['es-mx']={"editor":"Editor de texto enriquecido","editorPanel":"Panel del editor de texto","common":{"editorHelp":"Presiona ALT + 0 para ayuda","browseServer":"Examinar servidor","url":"URL","protocol":"Protocolo","upload":"Subir","uploadSubmit":"Enviar al servidor","image":"Imagen","flash":"Flash","form":"Formulario","checkbox":"Casilla de verificación","radio":"Botón de opción","textField":"Campo de texto","textarea":"Área de texto","hiddenField":"Campo oculto","button":"Botón","select":"Campo de selección","imageButton":"Botón de imagen","notSet":"<not set>","id":"Id","name":"Nombre","langDir":"Dirección de idiomas","langDirLtr":"Izquierda a derecha (LTR)","langDirRtl":"Derecha a izquierda (RTL)","langCode":"Código de lenguaje","longDescr":"URL descripción larga","cssClass":"Clases de hoja de estilo","advisoryTitle":"Título del anuncio","cssStyle":"Estilo","ok":"OK","cancel":"Cancelar","close":"Cerrar","preview":"Vista previa","resize":"Redimensionar","generalTab":"General","advancedTab":"Avanzada","validateNumberFailed":"Este valor no es un número.","confirmNewPage":"Se perderán todos los cambios no guardados en este contenido. ¿Seguro que quieres cargar nueva página?","confirmCancel":"Ha cambiado algunas opciones. ¿Está seguro de que desea cerrar la ventana de diálogo?","options":"Opciones","target":"Objetivo","targetNew":"Nueva ventana (_blank)","targetTop":"Ventana superior (_top)","targetSelf":"Misma ventana (_self)","targetParent":"Ventana principal (_parent)","langDirLTR":"Izquierda a Derecha (LTR)","langDirRTL":"Derecha a Izquierda (RTL)","styles":"Estilo","cssClasses":"Clases de hojas de estilo","width":"Ancho","height":"Alto","align":"Alineación","left":"Izquierda","right":"Derecha","center":"Centrado","justify":"Justificado","alignLeft":"Alinear a la izquierda","alignRight":"Alinear a la derecha","alignCenter":"Align Center","alignTop":"Arriba","alignMiddle":"En medio","alignBottom":"Abajo","alignNone":"Ninguno","invalidValue":"Valor inválido","invalidHeight":"La altura debe ser un número.","invalidWidth":"La anchura debe ser un número.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"El valor especificado para el campo \"% 1\" debe ser un número positivo con o sin una unidad de medida CSS válida (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"El valor especificado para el campo \"% 1\" debe ser un número positivo con o sin una unidad de medición HTML válida (px or %).","invalidInlineStyle":"El valor especificado para el estilo en línea debe constar de una o más tuplas con el formato de \"nombre: valor\", separados por punto y coma","cssLengthTooltip":"Introduzca un número para un valor en píxeles o un número con una unidad CSS válida (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, no disponible</span>","keyboard":{"8":"Retroceso","13":"Intro","16":"Shift","17":"Ctrl","18":"Alt","32":"Espacio","35":"Fin","36":"Inicio","46":"Borrar","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Comando"},"keyboardShortcut":"Atajo de teclado","optionDefault":"Default"},"about":{"copy":"Derechos reservados &copy; $1. Todos los derechos reservados","dlgTitle":"Acerca de CKEditor 4","moreInfo":"Para información sobre la licencia por favor visita nuestro sitio web:"},"basicstyles":{"bold":"Negrita","italic":"Cursiva","strike":"Tachado","subscript":"subíndice","superscript":"Sobrescrito","underline":"Subrayada"},"blockquote":{"toolbar":"Entrecomillado"},"notification":{"closed":"Notificación cerrada."},"toolbar":{"toolbarCollapse":"Colapsar barra de herramientas","toolbarExpand":"Expandir barra de herramientas","toolbarGroups":{"document":"Documento","clipboard":"Portapapeles/deshacer","editing":"Editando","forms":"Formularios","basicstyles":"Estilo básico","paragraph":"Párrafo","links":"Enlaces","insert":"Insertar","styles":"Estilos","colors":"Colores","tools":"Herramientas"},"toolbars":"Editor de barra de herramientas"},"clipboard":{"copy":"Copiar","copyError":"La configuración de seguridad de su navegador no permite al editor ejecutar automáticamente operaciones de copiado. Por favor, utilice el teclado para (Ctrl/Cmd+C).","cut":"Cortar","cutError":"La configuración de seguridad de su navegador no permite al editor ejecutar automáticamente operaciones de corte. Por favor, utilice el teclado para (Ctrl/Cmd+X).","paste":"Pegar","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Paste Area","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"optioLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['es']={"editor":"Editor de texto enriquecido","editorPanel":"Panel del Editor de Texto Enriquecido","common":{"editorHelp":"Pulse ALT 0 para ayuda","browseServer":"Ver Servidor","url":"URL","protocol":"Protocolo","upload":"Cargar","uploadSubmit":"Enviar al Servidor","image":"Imagen","flash":"Flash","form":"Formulario","checkbox":"Casilla de Verificación","radio":"Botones de Radio","textField":"Campo de Texto","textarea":"Area de Texto","hiddenField":"Campo Oculto","button":"Botón","select":"Campo de Selección","imageButton":"Botón Imagen","notSet":"<No definido>","id":"Id","name":"Nombre","langDir":"Orientación","langDirLtr":"Izquierda a Derecha (LTR)","langDirRtl":"Derecha a Izquierda (RTL)","langCode":"Cód. de idioma","longDescr":"Descripción larga URL","cssClass":"Clases de hojas de estilo","advisoryTitle":"Título","cssStyle":"Estilo","ok":"Aceptar","cancel":"Cancelar","close":"Cerrar","preview":"Previsualización","resize":"Arrastre para redimensionar","generalTab":"General","advancedTab":"Avanzado","validateNumberFailed":"El valor no es un número.","confirmNewPage":"Cualquier cambio que no se haya guardado se perderá.\r\n¿Está seguro de querer crear una nueva página?","confirmCancel":"Algunas de las opciones se han cambiado.\r\n¿Está seguro de querer cerrar el diálogo?","options":"Opciones","target":"Destino","targetNew":"Nueva ventana (_blank)","targetTop":"Ventana principal (_top)","targetSelf":"Misma ventana (_self)","targetParent":"Ventana padre (_parent)","langDirLTR":"Izquierda a derecha (LTR)","langDirRTL":"Derecha a izquierda (RTL)","styles":"Estilos","cssClasses":"Clase de la hoja de estilos","width":"Anchura","height":"Altura","align":"Alineación","left":"Izquierda","right":"Derecha","center":"Centrado","justify":"Justificado","alignLeft":"Alinear a Izquierda","alignRight":"Alinear a Derecha","alignCenter":"Align Center","alignTop":"Tope","alignMiddle":"Centro","alignBottom":"Pie","alignNone":"Ninguno","invalidValue":"Valor no válido","invalidHeight":"Altura debe ser un número.","invalidWidth":"Anchura debe ser un número.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"El valor especificado para el campo \"%1\" debe ser un número positivo, incluyendo optionalmente una unidad de medida CSS válida (px, %, in, cm, mm, em, ex, pt, o pc).","invalidHtmlLength":"El valor especificado para el campo \"%1\" debe ser un número positivo, incluyendo optionalmente una unidad de medida HTML válida (px o %).","invalidInlineStyle":"El valor especificado para el estilo debe consistir en uno o más pares con el formato \"nombre: valor\", separados por punto y coma.","cssLengthTooltip":"Introduca un número para el valor en pixels o un número con una unidad de medida CSS válida (px, %, in, cm, mm, em, ex, pt, o pc).","unavailable":"%1<span class=\"cke_accessibility\">, no disponible</span>","keyboard":{"8":"Retroceso","13":"Ingresar","16":"Mayús.","17":"Ctrl","18":"Alt","32":"Space","35":"Fin","36":"Inicio","46":"Suprimir","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. Todos los derechos reservados.","dlgTitle":"Acerca de CKEditor 4","moreInfo":"Para información de licencia, por favor visite nuestro sitio web:"},"basicstyles":{"bold":"Negrita","italic":"Cursiva","strike":"Tachado","subscript":"Subíndice","superscript":"Superíndice","underline":"Subrayado"},"blockquote":{"toolbar":"Cita"},"notification":{"closed":"Notificación cerrada."},"toolbar":{"toolbarCollapse":"Contraer barra de herramientas","toolbarExpand":"Expandir barra de herramientas","toolbarGroups":{"document":"Documento","clipboard":"Portapapeles/Deshacer","editing":"Edición","forms":"Formularios","basicstyles":"Estilos básicos","paragraph":"Párrafo","links":"Enlaces","insert":"Insertar","styles":"Estilos","colors":"Colores","tools":"Herramientas"},"toolbars":"Barras de herramientas del editor"},"clipboard":{"copy":"Copiar","copyError":"La configuración de seguridad de este navegador no permite la ejecución automática de operaciones de copiado.\r\nPor favor use el teclado (Ctrl/Cmd+C).","cut":"Cortar","cutError":"La configuración de seguridad de este navegador no permite la ejecución automática de operaciones de cortado.\r\nPor favor use el teclado (Ctrl/Cmd+X).","paste":"Pegar","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Zona de pegado","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Opciones del menú contLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['et']={"editor":"Rikkalik tekstiredaktor","editorPanel":"Rikkaliku tekstiredaktori paneel","common":{"editorHelp":"Abi saamiseks vajuta ALT 0","browseServer":"Serveri sirvimine","url":"URL","protocol":"Protokoll","upload":"Laadi üles","uploadSubmit":"Saada serverisse","image":"Pilt","flash":"Flash","form":"Vorm","checkbox":"Märkeruut","radio":"Raadionupp","textField":"Tekstilahter","textarea":"Tekstiala","hiddenField":"Varjatud lahter","button":"Nupp","select":"Valiklahter","imageButton":"Piltnupp","notSet":"<määramata>","id":"ID","name":"Nimi","langDir":"Keele suund","langDirLtr":"Vasakult paremale (LTR)","langDirRtl":"Paremalt vasakule (RTL)","langCode":"Keele kood","longDescr":"Pikk kirjeldus URL","cssClass":"Stiilistiku klassid","advisoryTitle":"Soovituslik pealkiri","cssStyle":"Laad","ok":"Olgu","cancel":"Loobu","close":"Sulge","preview":"Eelvaade","resize":"Suuruse muutmiseks lohista","generalTab":"Üldine","advancedTab":"Täpsemalt","validateNumberFailed":"See väärtus pole number.","confirmNewPage":"Kõik salvestamata muudatused lähevad kaotsi. Kas oled kindel, et tahad laadida uue lehe?","confirmCancel":"Mõned valikud on muudetud. Kas oled kindel, et tahad dialoogi sulgeda?","options":"Valikud","target":"Sihtkoht","targetNew":"Uus aken (_blank)","targetTop":"Kõige ülemine aken (_top)","targetSelf":"Sama aken (_self)","targetParent":"Vanemaken (_parent)","langDirLTR":"Vasakult paremale (LTR)","langDirRTL":"Paremalt vasakule (RTL)","styles":"Stiili","cssClasses":"Stiililehe klassid","width":"Laius","height":"Kõrgus","align":"Joondus","left":"Vasak","right":"Paremale","center":"Kesk","justify":"Rööpjoondus","alignLeft":"Vasakjoondus","alignRight":"Paremjoondus","alignCenter":"Align Center","alignTop":"Üles","alignMiddle":"Keskele","alignBottom":"Alla","alignNone":"Pole","invalidValue":"Vigane väärtus.","invalidHeight":"Kõrgus peab olema number.","invalidWidth":"Laius peab olema number.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"\"%1\" välja jaoks määratud väärtus peab olema positiivne täisarv CSS ühikuga (px, %, in, cm, mm, em, ex, pt või pc) või ilma.","invalidHtmlLength":"\"%1\" välja jaoks määratud väärtus peab olema positiivne täisarv HTML ühikuga (px või %) või ilma.","invalidInlineStyle":"Reasisese stiili määrangud peavad koosnema paarisväärtustest (tuples), mis on semikoolonitega eraldatult järgnevas vormingus: \"nimi : väärtus\".","cssLengthTooltip":"Sisesta väärtus pikslites või number koos sobiva CSS-i ühikuga (px, %, in, cm, mm, em, ex, pt või pc).","unavailable":"%1<span class=\"cke_accessibility\">, pole saadaval</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Tühik","35":"End","36":"Home","46":"Kustuta","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Vaikeväärtus"},"about":{"copy":"Copyright &copy; $1. Kõik õigused kaitstud.","dlgTitle":"About CKEditor 4","moreInfo":"Litsentsi andmed leiab meie veebilehelt:"},"basicstyles":{"bold":"Paks","italic":"Kursiiv","strike":"Läbijoonitud","subscript":"Allindeks","superscript":"Ülaindeks","underline":"Allajoonitud"},"blockquote":{"toolbar":"Blokktsitaat"},"notification":{"closed":"Teavitused on suletud."},"toolbar":{"toolbarCollapse":"Tööriistariba peitmine","toolbarExpand":"Tööriistariba näitamine","toolbarGroups":{"document":"Dokument","clipboard":"Lõikelaud/tagasivõtmine","editing":"Muutmine","forms":"Vormid","basicstyles":"Põhistiilid","paragraph":"Lõik","links":"Lingid","insert":"Sisesta","styles":"Stiilid","colors":"Värvid","tools":"Tööriistad"},"toolbars":"Redaktori tööriistaribad"},"clipboard":{"copy":"Kopeeri","copyError":"Sinu veebisirvija turvaseaded ei luba redaktoril automaatselt kopeerida. Palun kasutage selleks klaviatuuri klahvikombinatsiooni (Ctrl/Cmd+C).","cut":"Lõika","cutError":"Sinu veebisirvija turvaseaded ei luba redaktoril automaatselt lõigata. Palun kasutage selleks klaviatuuri klahvikombinatsiooni (Ctrl/Cmd+X).","paste":"Aseta","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Asetamise ala","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Kontekstimenüü valikud"},"elementspath":{"eleLabel":"Elementide asukoht","eleTitle":"%1 element"},"filetools":{"loadError":"Error occurred during file read.","networkError":"Network error occurred during file upload.","httpError404":"HTTP error occurred during file upload (404: File not found).","httpError403":"HTTP error oLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['eu']={"editor":"Testu aberastuaren editorea","editorPanel":"Testu aberastuaren editorearen panela","common":{"editorHelp":"Sakatu ALT 0 laguntza jasotzeko","browseServer":"Arakatu zerbitzaria","url":"URLa","protocol":"Protokoloa","upload":"Kargatu","uploadSubmit":"Bidali zerbitzarira","image":"Irudia","flash":"Flash","form":"Formularioa","checkbox":"Kontrol-laukia","radio":"Aukera-botoia","textField":"Testu-eremua","textarea":"Testu-area","hiddenField":"Ezkutuko eremua","button":"Botoia","select":"Hautespen-eremua","imageButton":"Irudi-botoia","notSet":"<ezarri gabe>","id":"Id","name":"Izena","langDir":"Hizkuntzaren norabidea","langDirLtr":"Ezkerretik eskuinera (LTR)","langDirRtl":"Eskuinetik ezkerrera (RTL)","langCode":"Hizkuntzaren kodea","longDescr":"URLaren deskribapen luzea","cssClass":"Estilo-orriko klaseak","advisoryTitle":"Aholkatutako izenburua","cssStyle":"Estiloa","ok":"Ados","cancel":"Utzi","close":"Itxi","preview":"Aurrebista","resize":"Aldatu tamainaz","generalTab":"Orokorra","advancedTab":"Aurreratua","validateNumberFailed":"Balio hau ez da zenbaki bat.","confirmNewPage":"Eduki honetan gorde gabe dauden aldaketak galduko dira. Ziur zaude orri berri bat kargatu nahi duzula?","confirmCancel":"Aukera batzuk aldatu dituzu. Ziur zaude elkarrizketa-koadroa itxi nahi duzula?","options":"Aukerak","target":"Helburua","targetNew":"Leiho berria (_blank)","targetTop":"Goieneko leihoan (_top)","targetSelf":"Leiho berean (_self)","targetParent":"Leiho gurasoan (_parent)","langDirLTR":"Ezkerretik eskuinera (LTR)","langDirRTL":"Eskuinetik ezkerrera (RTL)","styles":"Estiloa","cssClasses":"Estilo-orriko klaseak","width":"Zabalera","height":"Altuera","align":"Lerrokatzea","left":"Ezkerrean","right":"Eskuinean","center":"Erdian","justify":"Justifikatu","alignLeft":"Lerrokatu ezkerrean","alignRight":"Lerrokatu eskuinean","alignCenter":"Align Center","alignTop":"Goian","alignMiddle":"Erdian","alignBottom":"Behean","alignNone":"Bat ere ez","invalidValue":"Balio desegokia.","invalidHeight":"Altuera zenbaki bat izan behar da.","invalidWidth":"Zabalera zenbaki bat izan behar da.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"\"%1\" eremurako zehaztutako balioak zenbaki positibo bat izan behar du, CSS neurri unitate batekin edo gabe (px, %, in, cm, mm, em, ex, pt edo pc).","invalidHtmlLength":"\"%1\" eremurako zehaztutako balioak zenbaki positibo bat izan behar du, HTML neurri unitate batekin edo gabe (px edo %).","invalidInlineStyle":"Lineako estiloan zehaztutako balioak \"izen : balio\" formatuko tupla bat edo gehiago izan behar dira, komaz bereiztuak.","cssLengthTooltip":"Sartu zenbaki bat edo zenbaki bat baliozko CSS unitate batekin (px, %, in, cm, mm, em, ex, pt, edo pc).","unavailable":"%1<span class=\"cke_accessibility\">, erabilezina</span>","keyboard":{"8":"Atzera tekla","13":"Sartu","16":"Maius","17":"Ktrl","18":"Alt","32":"Zuriunea","35":"Buka","36":"Etxea","46":"Ezabatu","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Komandoa"},"keyboardShortcut":"Laster-tekla","optionDefault":"Lehenetsia"},"about":{"copy":"Copyright &copy; $1. Eskubide guztiak erreserbaturik.","dlgTitle":"CKEditor 4ri buruz","moreInfo":"Lizentziari buruzko informazioa gure webgunean:"},"basicstyles":{"bold":"Lodia","italic":"Etzana","strike":"Marratua","subscript":"Azpi-indizea","superscript":"Goi-indizea","underline":"Azpimarratu"},"blockquote":{"toolbar":"Aipamen blokea"},"notification":{"closed":"Jakinarazpena itxita."},"toolbar":{"toolbarCollapse":"Tolestu tresna-barra","toolbarExpand":"Zabaldu tresna-barra","toolbarGroups":{"document":"Dokumentua","clipboard":"Arbela/Desegin","editing":"Editatu","forms":"Formularioak","basicstyles":"Oinarrizko estiloak","paragraph":"Paragrafoa","links":"Estekak","insert":"Txertatu","styles":"Estiloak","colors":"Koloreak","tools":"Tresnak"},"toolbars":"Editorearen tresna-barrak"},"clipboard":{"copy":"Kopiatu","copyError":"Zure web nabigatzailearen segurtasun ezarpenek ez dute baimentzen testuak automatikoki kopiatzea. Mesedez teklatua erabil ezazu (Ctrl/Cmd+C).","cut":"Ebaki","cutError":"Zure web nabigatzailearen segurtasun ezarpenek ez dute baimentzen testuak automatikoki moztea. Mesedez teklatua erabil ezazu (Ctrl/Cmd+X).","paste":"Itsatsi","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Itsasteko area","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Testuinguru-menuaren aukerak"},"elementspath":{"eleLabel":"Elementuen bidea","eleTitle":"%1 elementua"},"filetools":{"loadError":"Errorea gertatu da fitxategia irakuLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['fa']={"editor":"ویرایش‌گر متن غنی","editorPanel":"پنل ویرایشگر متن غنی","common":{"editorHelp":"کلید Alt+0 را برای راهنمایی بفشارید","browseServer":"فهرست​نمایی سرور","url":"URL","protocol":"قرارداد","upload":"بالاگذاری","uploadSubmit":"به سرور بفرست","image":"تصویر","flash":"فلش","form":"فرم","checkbox":"چک‌باکس","radio":"دکمه‌ی رادیویی","textField":"فیلد متنی","textarea":"ناحیهٴ متنی","hiddenField":"فیلد پنهان","button":"دکمه","select":"فیلد انتخاب چند گزینه​ای","imageButton":"دکمه‌ی تصویری","notSet":"<تعیین‌نشده>","id":"شناسه","name":"نام","langDir":"جهت زبان","langDirLtr":"چپ به راست","langDirRtl":"راست به چپ","langCode":"کد زبان","longDescr":"URL توصیف طولانی","cssClass":"کلاس​های شیوه​نامه (Stylesheet)","advisoryTitle":"عنوان کمکی","cssStyle":"سبک","ok":"پذیرش","cancel":"انصراف","close":"بستن","preview":"پیش‌نمایش","resize":"تغییر اندازه","generalTab":"عمومی","advancedTab":"پیش‌رفته","validateNumberFailed":"این مقدار یک عدد نیست.","confirmNewPage":"هر تغییر ایجاد شده​ی ذخیره نشده از بین خواهد رفت. آیا اطمینان دارید که قصد بارگیری صفحه جدیدی را دارید؟","confirmCancel":"برخی از گزینه‌ها تغییر کرده‌اند. آیا واقعا قصد بستن این پنجره را دارید؟","options":"گزینه​ها","target":"مقصد","targetNew":"پنجره جدید","targetTop":"بالاترین پنجره","targetSelf":"همان پنجره","targetParent":"پنجره والد","langDirLTR":"چپ به راست","langDirRTL":"راست به چپ","styles":"سبک","cssClasses":"کلاس‌های سبک‌نامه","width":"عرض","height":"طول","align":"چینش","left":"چپ","right":"راست","center":"وسط","justify":"بلوک چین","alignLeft":"چپ چین","alignRight":"راست چین","alignCenter":"مرکز قرار بده","alignTop":"بالا","alignMiddle":"میانه","alignBottom":"پائین","alignNone":"هیچ","invalidValue":"مقدار نامعتبر.","invalidHeight":"ارتفاع باید یک عدد باشد.","invalidWidth":"عرض باید یک عدد باشد.","invalidLength":"عدد تعیین شده برای فیلد \"%1\" باید یک عدد مثبت با یا بدون یک واحد اندازه گیری معتبر (\"%2\") باشد.","invalidCssLength":"عدد تعیین شده برای فیلد \"%1\" باید یک عدد مثبت با یا بدون یک واحد اندازه گیری CSS معتبر باشد (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"عدد تعیین شده برای فیلد \"%1\" باید یک عدد مثبت با یا بدون یک واحد اندازه گیری HTML معتبر باشد (px or %).","invalidInlineStyle":"عدد تعیین شده برای سبک درون​خطی -Inline Style- باید دارای یک یا چند چندتایی با شکلی شبیه \"name : value\" که باید با یک \";\" از هم جدا شوند.","cssLengthTooltip":"یک عدد برای یک مقدار بر حسب پیکسل و یا یک عدد با یک واحد CSS معتبر وارد کنید (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">، غیر قابل دسترس</span>","keyboard":{"8":"عقبگرد","13":"ورود","16":"تعویض","17":"کنترل","18":"دگرساز","32":"فاصله","35":"پایان","36":"خانه","46":"حذف","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"فرمان"},"keyboardShortcut":"میانبر صفحه کلید","optionDefault":"پیش فرض"},"about":{"copy":"حق نشر &copy; $1. کلیه حقوق محفوظ است.","dlgTitle":"درباره CKEditor","moreInfo":"برای کسب اطلاعات مجوز لطفا به وب سایت ما مراجعه کنید:"},"basicstyles":{"bold":"درشت","italic":"خمیده","strike":"خط‌خورده","subscript":"زیرنویس","superscript":"بالانویس","underline":"زیرخط‌دار"},"blockquote":{"toolbar":"بلوک نقل قول"},"notification":{"closed":"آگاه‌سازی بسته شد"},"toolbar":{"toolbarCollapse":"بستن نوار ابزار","toolbarExpand":"بازکردن نوار ابزار","toolbarGroups":{"document":"سند","clipboard":"حافظه موقت/برگشت","editing":"در حال ویرایش","forms":"فرم​ها","basicstyles":"سبک‌های پایه","paraLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['fi']={"editor":"Rikastekstieditori","editorPanel":"Rikastekstieditoripaneeli","common":{"editorHelp":"Paina ALT 0 nähdäksesi ohjeen","browseServer":"Selaa palvelinta","url":"Osoite","protocol":"Protokolla","upload":"Lisää tiedosto","uploadSubmit":"Lähetä palvelimelle","image":"Kuva","flash":"Flash-animaatio","form":"Lomake","checkbox":"Valintaruutu","radio":"Radiopainike","textField":"Tekstikenttä","textarea":"Tekstilaatikko","hiddenField":"Piilokenttä","button":"Painike","select":"Valintakenttä","imageButton":"Kuvapainike","notSet":"<ei asetettu>","id":"Tunniste","name":"Nimi","langDir":"Kielen suunta","langDirLtr":"Vasemmalta oikealle (LTR)","langDirRtl":"Oikealta vasemmalle (RTL)","langCode":"Kielikoodi","longDescr":"Pitkän kuvauksen URL","cssClass":"Tyyliluokat","advisoryTitle":"Avustava otsikko","cssStyle":"Tyyli","ok":"OK","cancel":"Peruuta","close":"Sulje","preview":"Esikatselu","resize":"Raahaa muuttaaksesi kokoa","generalTab":"Yleinen","advancedTab":"Lisäominaisuudet","validateNumberFailed":"Arvon pitää olla numero.","confirmNewPage":"Kaikki tallentamattomat muutokset tähän sisältöön menetetään. Oletko varma, että haluat ladata uuden sivun?","confirmCancel":"Jotkut asetuksista on muuttuneet. Oletko varma, että haluat sulkea valintaikkunan?","options":"Asetukset","target":"Kohde","targetNew":"Uusi ikkuna (_blank)","targetTop":"Päällimmäinen ikkuna (_top)","targetSelf":"Sama ikkuna (_self)","targetParent":"Ylemmän tason ikkuna (_parent)","langDirLTR":"Vasemmalta oikealle (LTR)","langDirRTL":"Oikealta vasemmalle (RTL)","styles":"Tyyli","cssClasses":"Tyylitiedoston luokat","width":"Leveys","height":"Korkeus","align":"Kohdistus","left":"Vasemmalle","right":"Oikealle","center":"Keskelle","justify":"Tasaa molemmat reunat","alignLeft":"Tasaa vasemmat reunat","alignRight":"Tasaa oikeat reunat","alignCenter":"Align Center","alignTop":"Ylös","alignMiddle":"Keskelle","alignBottom":"Alas","alignNone":"Ei asetettu","invalidValue":"Virheellinen arvo.","invalidHeight":"Korkeuden täytyy olla numero.","invalidWidth":"Leveyden täytyy olla numero.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Kentän \"%1\" arvon täytyy olla positiivinen luku CSS mittayksikön (px, %, in, cm, mm, em, ex, pt tai pc) kanssa tai ilman.","invalidHtmlLength":"Kentän \"%1\" arvon täytyy olla positiivinen luku HTML mittayksikön (px tai %) kanssa tai ilman.","invalidInlineStyle":"Tyylille annetun arvon täytyy koostua yhdestä tai useammasta \"nimi : arvo\" parista, jotka ovat eroteltuna toisistaan puolipisteillä.","cssLengthTooltip":"Anna numeroarvo pikseleinä tai numeroarvo CSS mittayksikön kanssa (px, %, in, cm, mm, em, ex, pt, tai pc).","unavailable":"%1<span class=\"cke_accessibility\">, ei saatavissa</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. Kaikki oikeuden pidätetään.","dlgTitle":"Tietoa CKEditorista","moreInfo":"Lisenssitiedot löytyvät kotisivuiltamme:"},"basicstyles":{"bold":"Lihavoitu","italic":"Kursivoitu","strike":"Yliviivattu","subscript":"Alaindeksi","superscript":"Yläindeksi","underline":"Alleviivattu"},"blockquote":{"toolbar":"Lainaus"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Kutista työkalupalkki","toolbarExpand":"Laajenna työkalupalkki","toolbarGroups":{"document":"Dokumentti","clipboard":"Leikepöytä/Kumoa","editing":"Muokkaus","forms":"Lomakkeet","basicstyles":"Perustyylit","paragraph":"Kappale","links":"Linkit","insert":"Lisää","styles":"Tyylit","colors":"Värit","tools":"Työkalut"},"toolbars":"Editorin työkalupalkit"},"clipboard":{"copy":"Kopioi","copyError":"Selaimesi turva-asetukset eivät salli editorin toteuttaa kopioimista. Käytä näppäimistöä kopioimiseen (Ctrl+C).","cut":"Leikkaa","cutError":"Selaimesi turva-asetukset eivät salli editorin toteuttaa leikkaamista. Käytä näppäimistöä leikkaamiseen (Ctrl+X).","paste":"Liitä","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Leikealue","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Pikavalikon ominaisuudet"},"elementspath":{"eleLabel":"Elementin polku","eleTitle":"%1 elementti"},"filetools":{"loadError":"Error occurred during file read.","networkError":"Network error occurred during file upload.","httpError404":"HTTP error occurred dLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['fo']={"editor":"Rich Text Editor","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"Trýst ALT og 0 fyri vegleiðing","browseServer":"Ambætarakagi","url":"URL","protocol":"Protokoll","upload":"Send til ambætaran","uploadSubmit":"Send til ambætaran","image":"Myndir","flash":"Flash","form":"Formur","checkbox":"Flugubein","radio":"Radioknøttur","textField":"Tekstteigur","textarea":"Tekstumráði","hiddenField":"Fjaldur teigur","button":"Knøttur","select":"Valskrá","imageButton":"Myndaknøttur","notSet":"<ikki sett>","id":"Id","name":"Navn","langDir":"Tekstkós","langDirLtr":"Frá vinstru til høgru (LTR)","langDirRtl":"Frá høgru til vinstru (RTL)","langCode":"Málkoda","longDescr":"Víðkað URL frágreiðing","cssClass":"Typografi klassar","advisoryTitle":"Vegleiðandi heiti","cssStyle":"Typografi","ok":"Góðkent","cancel":"Avlýs","close":"Lat aftur","preview":"Frumsýn","resize":"Drag fyri at broyta stødd","generalTab":"Generelt","advancedTab":"Fjølbroytt","validateNumberFailed":"Hetta er ikki eitt tal.","confirmNewPage":"Allar ikki goymdar broytingar í hesum innihaldið hvørva. Skal nýggj síða lesast kortini?","confirmCancel":"Nakrir valmøguleikar eru broyttir. Ert tú vísur í, at dialogurin skal latast aftur?","options":"Options","target":"Target","targetNew":"Nýtt vindeyga (_blank)","targetTop":"Vindeyga ovast (_top)","targetSelf":"Sama vindeyga (_self)","targetParent":"Upphavligt vindeyga (_parent)","langDirLTR":"Frá vinstru til høgru (LTR)","langDirRTL":"Frá høgru til vinstru (RTL)","styles":"Style","cssClasses":"Stylesheet Classes","width":"Breidd","height":"Hædd","align":"Justering","left":"Vinstra","right":"Høgra","center":"Miðsett","justify":"Javnir tekstkantar","alignLeft":"Vinstrasett","alignRight":"Høgrasett","alignCenter":"Align Center","alignTop":"Ovast","alignMiddle":"Miðja","alignBottom":"Botnur","alignNone":"Eingin","invalidValue":"Invalid value.","invalidHeight":"Hædd má vera eitt tal.","invalidWidth":"Breidd má vera eitt tal.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Virðið sett í \"%1\" feltið má vera eitt positivt tal, við ella uttan gyldugum CSS mátieind (px, %, in, cm, mm, em, ex, pt, ella pc).","invalidHtmlLength":"Virðið sett í \"%1\" feltiðield má vera eitt positivt tal, við ella uttan gyldugum CSS mátieind (px ella %).","invalidInlineStyle":"Virði specifiserað fyri inline style má hava eitt ella fleiri pør (tuples) skrivað sum \"name : value\", hvørt parið sundurskilt við semi-colon.","cssLengthTooltip":"Skriva eitt tal fyri eitt virði í pixels ella eitt tal við gyldigum CSS eind (px, %, in, cm, mm, em, ex, pt, ella pc).","unavailable":"%1<span class=\"cke_accessibility\">, ikki tøkt</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. All rights reserved.","dlgTitle":"Um CKEditor 4","moreInfo":"Licens upplýsingar finnast á heimasíðu okkara:"},"basicstyles":{"bold":"Feit skrift","italic":"Skráskrift","strike":"Yvirstrikað","subscript":"Lækkað skrift","superscript":"Hækkað skrift","underline":"Undirstrikað"},"blockquote":{"toolbar":"Blockquote"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Lat Toolbar aftur","toolbarExpand":"Vís Toolbar","toolbarGroups":{"document":"Dokument","clipboard":"Clipboard/Undo","editing":"Editering","forms":"Formar","basicstyles":"Grundleggjandi Styles","paragraph":"Reglubrot","links":"Leinkjur","insert":"Set inn","styles":"Styles","colors":"Litir","tools":"Tól"},"toolbars":"Editor toolbars"},"clipboard":{"copy":"Avrita","copyError":"Trygdaruppseting alnótskagans forðar tekstviðgeranum í at avrita tekstin. Vinarliga nýt knappaborðið til at avrita tekstin (Ctrl/Cmd+C).","cut":"Kvett","cutError":"Trygdaruppseting alnótskagans forðar tekstviðgeranum í at kvetta tekstin. Vinarliga nýt knappaborðið til at kvetta tekstin (Ctrl/Cmd+X).","paste":"Innrita","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Avritingarumráði","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Context Menu Options"},"elementspath":{"eleLabel":"Slóð til elementir","eleTitle":"%1 element"},"filetools":{"loadError":"Error occurred during file read.","networkError":"Network error occurred during file upload.","httpError404":"HTTPLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['fr-ca']={"editor":"Éditeur de texte enrichi","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"Appuyez sur 0 pour de l'aide","browseServer":"Parcourir le serveur","url":"URL","protocol":"Protocole","upload":"Envoyer","uploadSubmit":"Envoyer au serveur","image":"Image","flash":"Animation Flash","form":"Formulaire","checkbox":"Case à cocher","radio":"Bouton radio","textField":"Champ texte","textarea":"Zone de texte","hiddenField":"Champ caché","button":"Bouton","select":"Liste déroulante","imageButton":"Bouton image","notSet":"<Par défaut>","id":"Id","name":"Nom","langDir":"Sens d'écriture","langDirLtr":"De gauche à droite (LTR)","langDirRtl":"De droite à gauche (RTL)","langCode":"Code langue","longDescr":"URL de description longue","cssClass":"Classes CSS","advisoryTitle":"Titre","cssStyle":"Style","ok":"OK","cancel":"Annuler","close":"Fermer","preview":"Aperçu","resize":"Redimensionner","generalTab":"Général","advancedTab":"Avancé","validateNumberFailed":"Cette valeur n'est pas un nombre.","confirmNewPage":"Les changements non sauvegardés seront perdus. Êtes-vous certain de vouloir charger une nouvelle page?","confirmCancel":"Certaines options ont été modifiées. Êtes-vous certain de vouloir fermer?","options":"Options","target":"Cible","targetNew":"Nouvelle fenêtre (_blank)","targetTop":"Fenêtre supérieur (_top)","targetSelf":"Cette fenêtre (_self)","targetParent":"Fenêtre parent (_parent)","langDirLTR":"De gauche à droite (LTR)","langDirRTL":"De droite à gauche (RTL)","styles":"Style","cssClasses":"Classe CSS","width":"Largeur","height":"Hauteur","align":"Alignement","left":"Gauche","right":"Droite","center":"Centré","justify":"Justifié","alignLeft":"Aligner à gauche","alignRight":"Aligner à Droite","alignCenter":"Align Center","alignTop":"Haut","alignMiddle":"Milieu","alignBottom":"Bas","alignNone":"None","invalidValue":"Valeur invalide.","invalidHeight":"La hauteur doit être un nombre.","invalidWidth":"La largeur doit être un nombre.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"La valeur spécifiée pour le champ \"%1\" doit être un nombre positif avec ou sans unité de mesure CSS valide (px, %, in, cm, mm, em, ex, pt, ou pc).","invalidHtmlLength":"La valeur spécifiée pour le champ \"%1\" doit être un nombre positif avec ou sans unité de mesure HTML valide (px ou %).","invalidInlineStyle":"La valeur spécifiée pour le style intégré doit être composée d'un ou plusieurs couples de valeur au format \"nom : valeur\", separés par des points-virgules.","cssLengthTooltip":"Entrer un nombre pour la valeur en pixel ou un nombre avec une unité CSS valide (px, %, in, cm, mm, em, ex, pt, ou pc).","unavailable":"%1<span class=\"cke_accessibility\">, indisponible</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. Tous droits réservés.","dlgTitle":"À propos de CKEditor 4","moreInfo":"Pour les informations de licence, consulter notre site internet:"},"basicstyles":{"bold":"Gras","italic":"Italique","strike":"Barré","subscript":"Indice","superscript":"Exposant","underline":"Souligné"},"blockquote":{"toolbar":"Citation"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Enrouler la barre d'outils","toolbarExpand":"Dérouler la barre d'outils","toolbarGroups":{"document":"Document","clipboard":"Presse papier/Annuler","editing":"Édition","forms":"Formulaires","basicstyles":"Styles de base","paragraph":"Paragraphe","links":"Liens","insert":"Insérer","styles":"Styles","colors":"Couleurs","tools":"Outils"},"toolbars":"Barre d'outils de l'éditeur"},"clipboard":{"copy":"Copier","copyError":"Les paramètres de sécurité de votre navigateur empêchent l'éditeur de copier automatiquement vos données. Veuillez utiliser les équivalents claviers (Ctrl/Cmd+C).","cut":"Couper","cutError":"Les paramètres de sécurité de votre navigateur empêchent l'éditeur de couper automatiquement vos données. Veuillez utiliser les équivalents claviers (Ctrl/Cmd+X).","paste":"Coller","pasteNotification":"Press %1 to paste. Your browser doesn‘t support pasting with the toolbar button or context menu option.","pasteArea":"Coller la zone","pasteMsg":"Paste your content inside the area below and press OK."},"contextmenu":{"options":"Options du menu contextuel"},"elementspath":{"eleLabel":"Chemin d'éléments","eleTitle":"element %1"},"filetools":{"loadError":"ELine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['fr']={"editor":"Éditeur de texte enrichi","editorPanel":"Tableau de bord de l'éditeur de texte enrichi","common":{"editorHelp":"Utilisez le raccourci Alt-0 pour obtenir de l'aide","browseServer":"Parcourir le serveur","url":"URL","protocol":"Protocole","upload":"Télécharger","uploadSubmit":"Envoyer sur le serveur","image":"Image","flash":"Flash","form":"Formulaire","checkbox":"Case à cocher","radio":"Bouton radio","textField":"Champ texte","textarea":"Zone de texte","hiddenField":"Champ invisible","button":"Bouton","select":"Liste déroulante","imageButton":"Bouton avec image","notSet":"<indéfini>","id":"ID","name":"Nom","langDir":"Sens d'écriture","langDirLtr":"Gauche à droite (LTR)","langDirRtl":"Droite à gauche (RTL)","langCode":"Code de langue","longDescr":"URL de description longue","cssClass":"Classes de style","advisoryTitle":"Infobulle","cssStyle":"Style","ok":"OK","cancel":"Annuler","close":"Fermer","preview":"Aperçu","resize":"Redimensionner","generalTab":"Général","advancedTab":"Avancé","validateNumberFailed":"Cette valeur n'est pas un nombre.","confirmNewPage":"Les changements non sauvegardés seront perdus. Êtes-vous sûr de vouloir charger une nouvelle page ?","confirmCancel":"Certaines options ont été modifiées. Êtes-vous sûr de vouloir fermer ?","options":"Options","target":"Cible","targetNew":"Nouvelle fenêtre (_blank)","targetTop":"Fenêtre supérieure (_top)","targetSelf":"Même fenêtre (_self)","targetParent":"Fenêtre parent (_parent)","langDirLTR":"Gauche à droite (LTR)","langDirRTL":"Droite à gauche (RTL)","styles":"Style","cssClasses":"Classes de style","width":"Largeur","height":"Hauteur","align":"Alignement","left":"Gauche","right":"Droite","center":"Centrer","justify":"Justifier","alignLeft":"Aligner à gauche","alignRight":"Aligner à droite","alignCenter":"Aligner au centre","alignTop":"Haut","alignMiddle":"Milieu","alignBottom":"Bas","alignNone":"Aucun","invalidValue":"Valeur invalide.","invalidHeight":"La hauteur doit être un nombre.","invalidWidth":"La largeur doit être un nombre.","invalidLength":"La valeur de \"%1\" doit être un nombre positif avec ou sans unité de mesure (%2).","invalidCssLength":"La valeur spécifiée pour le champ « %1 » doit être un nombre positif avec ou sans unité de mesure CSS valide (px, %, in, cm, mm, em, ex, pt, ou pc).","invalidHtmlLength":"La valeur spécifiée pour le champ « %1 » doit être un nombre positif avec ou sans unité de mesure HTML valide (px ou %).","invalidInlineStyle":"La valeur spécifiée pour le style en ligne doit être composée d'un ou plusieurs couples au format « nom : valeur », séparés par des points-virgules.","cssLengthTooltip":"Entrer un nombre pour une valeur en pixels ou un nombre avec une unité de mesure CSS valide (px, %, in, cm, mm, em, ex, pt, ou pc).","unavailable":"%1<span class=\"cke_accessibility\">, indisponible</span>","keyboard":{"8":"Retour arrière","13":"Entrée","16":"Majuscule","17":"Ctrl","18":"Alt","32":"Espace","35":"Fin","36":"Origine","46":"Supprimer","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Commande"},"keyboardShortcut":"Raccourci clavier","optionDefault":"Par défaut"},"about":{"copy":"Copyright &copy; $1. Tous droits réservés.","dlgTitle":"À propos de CKEditor 4","moreInfo":"Pour les informations de licence, veuillez visiter notre site web :"},"basicstyles":{"bold":"Gras","italic":"Italique","strike":"Barré","subscript":"Indice","superscript":"Exposant","underline":"Souligné"},"blockquote":{"toolbar":"Citation"},"notification":{"closed":"Notification fermée."},"toolbar":{"toolbarCollapse":"Enrouler la barre d'outils","toolbarExpand":"Dérouler la barre d'outils","toolbarGroups":{"document":"Document","clipboard":"Presse-papier/Défaire","editing":"Édition","forms":"Formulaires","basicstyles":"Styles de base","paragraph":"Paragraphe","links":"Liens","insert":"Insérer","styles":"Styles","colors":"Couleurs","tools":"Outils"},"toolbars":"Barres d'outils de l'éditeur"},"clipboard":{"copy":"Copier","copyError":"Les paramètres de sécurité de votre navigateur n'autorisent pas l'éditeur à exécuter automatiquement l'opération « Copier ». Veuillez utiliser le raccourci clavier à cet effet (Ctrl/Cmd+C).","cut":"Couper","cutError":"Les paramètres de sécurité de votre navigateur n'autorisent pas l'éditeur à exécuter automatiquement l'opération « Couper ». Veuillez utiliser le raccourci clavier à cet effet (Ctrl/Cmd+X).","paste":"Coller","pasteNotification":"Utilisez le raccourci %1 pour coller. Votre navigateur n'accepte pas de coller à l'aide du bouton ou du menu contextuel.","pasteArea":"Coller la zone","pasteMsg":"Collez votre contenu dans la zone de saisie ci-dessouLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['gl']={"editor":"Editor de texto mellorado","editorPanel":"Panel do editor de texto mellorado","common":{"editorHelp":"Prema ALT 0 para obter axuda","browseServer":"Examinar o servidor","url":"URL","protocol":"Protocolo","upload":"Enviar","uploadSubmit":"Enviar ao servidor","image":"Imaxe","flash":"Flash","form":"Formulario","checkbox":"Caixa de selección","radio":"Botón de opción","textField":"Campo de texto","textarea":"Área de texto","hiddenField":"Campo agochado","button":"Botón","select":"Campo de selección","imageButton":"Botón de imaxe","notSet":"<sen estabelecer>","id":"ID","name":"Nome","langDir":"Dirección de escritura do idioma","langDirLtr":"Esquerda a dereita (LTR)","langDirRtl":"Dereita a esquerda (RTL)","langCode":"Código do idioma","longDescr":"Descrición completa do URL","cssClass":"Clases da folla de estilos","advisoryTitle":"Título","cssStyle":"Estilo","ok":"Aceptar","cancel":"Cancelar","close":"Pechar","preview":"Vista previa","resize":"Redimensionar","generalTab":"Xeral","advancedTab":"Avanzado","validateNumberFailed":"Este valor non é un número.","confirmNewPage":"Calquera cambio que non gardara neste contido perderase.\r\nConfirma que quere cargar unha páxina nova?","confirmCancel":"Algunhas das opcións foron cambiadas.\r\nConfirma que quere pechar o diálogo?","options":"Opcións","target":"Destino","targetNew":"Nova xanela (_blank)","targetTop":"Xanela principal (_top)","targetSelf":"Mesma xanela (_self)","targetParent":"Xanela superior (_parent)","langDirLTR":"Esquerda a dereita (LTR)","langDirRTL":"Dereita a esquerda (RTL)","styles":"Estilo","cssClasses":"Clases da folla de estilos","width":"Largo","height":"Alto","align":"Aliñamento","left":"Esquerda","right":"Dereita","center":"Centro","justify":"Xustificado","alignLeft":"Aliñar á esquerda","alignRight":"Aliñar á dereita","alignCenter":"Aliñar ao centro","alignTop":"Arriba","alignMiddle":"Centro","alignBottom":"Abaixo","alignNone":"Ningún","invalidValue":"Valor incorrecto.","invalidHeight":"O alto debe ser un número.","invalidWidth":"O largo debe ser un número.","invalidLength":"O valor especificado para o campo «%1» debe ser un número positivo con ou sen unha unidade de medida correcta (%2).","invalidCssLength":"O valor especificado para o campo «%1» debe ser un número positivo con ou sen unha unidade de medida CSS correcta (px, %, in, cm, mm, em, ex, pt, ou pc).","invalidHtmlLength":"O valor especificado para o campo «%1» debe ser un número positivo con ou sen unha unidade de medida HTML correcta (px ou %).","invalidInlineStyle":"O valor especificado no estilo en liña debe consistir nunha ou máis tuplas co formato «nome : valor», separadas por punto e coma.","cssLengthTooltip":"Escriba un número para o valor en píxeles ou un número cunha unidade CSS correcta (px, %, in, cm, mm, em, ex, pt, ou pc).","unavailable":"%1<span class=\"cke_accessibility\">, non dispoñíbel</span>","keyboard":{"8":"Ir atrás","13":"Intro","16":"Maiús","17":"Ctrl","18":"Alt","32":"Espazo","35":"Fin","36":"Inicio","46":"Supr","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Orde"},"keyboardShortcut":"Atallo de teclado","optionDefault":"Predeterminado"},"about":{"copy":"Copyright &copy; $1. Todos os dereitos reservados.","dlgTitle":"Sobre o CKEditor 4","moreInfo":"Para obter información sobre a licenza, visite o noso sitio web:"},"basicstyles":{"bold":"Negra","italic":"Cursiva","strike":"Riscado","subscript":"Subíndice","superscript":"Superíndice","underline":"Subliñado"},"blockquote":{"toolbar":"Cita"},"notification":{"closed":"Notificación pechada."},"toolbar":{"toolbarCollapse":"Contraer a barra de ferramentas","toolbarExpand":"Expandir a barra de ferramentas","toolbarGroups":{"document":"Documento","clipboard":"Portapapeis/desfacer","editing":"Edición","forms":"Formularios","basicstyles":"Estilos básicos","paragraph":"Paragrafo","links":"Ligazóns","insert":"Inserir","styles":"Estilos","colors":"Cores","tools":"Ferramentas"},"toolbars":"Barras de ferramentas do editor"},"clipboard":{"copy":"Copiar","copyError":"Os axustes de seguranza do seu navegador non permiten que o editor realice automaticamente as tarefas de copia. Use o teclado para iso (Ctrl/Cmd+C).","cut":"Cortar","cutError":"Os axustes de seguranza do seu navegador non permiten que o editor realice automaticamente as tarefas de corte. Use o teclado para iso (Ctrl/Cmd+X).","paste":"Pegar","pasteNotification":"Prema %1 para pegar. O seu navegador non admite pegar co botón da barra de ferramentas ou coa opción do menú contextual.","pasteArea":"Zona de pegado","pasteMsg":"Pegue o contido dentro da área de abaixo e prema Aceptar."},"contextmenu":{"options":"Opcións do menú contextual"},"elemenLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['gu']={"editor":"રીચ ટેક્ષ્ત્ એડીટર","editorPanel":"વધુ વિકલ્પ વાળુ એડિટર","common":{"editorHelp":"મદદ માટ ALT 0 દબાવો","browseServer":"સર્વર બ્રાઉઝ કરો","url":"URL","protocol":"પ્રોટોકૉલ","upload":"અપલોડ","uploadSubmit":"આ સર્વરને મોકલવું","image":"ચિત્ર","flash":"ફ્લૅશ","form":"ફૉર્મ/પત્રક","checkbox":"ચેક બોક્સ","radio":"રેડિઓ બટન","textField":"ટેક્સ્ટ ફીલ્ડ, શબ્દ ક્ષેત્ર","textarea":"ટેક્સ્ટ એરિઆ, શબ્દ વિસ્તાર","hiddenField":"ગુપ્ત ક્ષેત્ર","button":"બટન","select":"પસંદગી ક્ષેત્ર","imageButton":"ચિત્ર બટન","notSet":"<સેટ નથી>","id":"Id","name":"નામ","langDir":"ભાષા લેખવાની પદ્ધતિ","langDirLtr":"ડાબે થી જમણે (LTR)","langDirRtl":"જમણે થી ડાબે (RTL)","langCode":"ભાષા કોડ","longDescr":"વધારે માહિતી માટે URL","cssClass":"સ્ટાઇલ-શીટ ક્લાસ","advisoryTitle":"મુખ્ય મથાળું","cssStyle":"સ્ટાઇલ","ok":"ઠીક છે","cancel":"રદ કરવું","close":"બંધ કરવું","preview":"જોવું","resize":"ખેંચી ને યોગ્ય કરવું","generalTab":"જનરલ","advancedTab":"અડ્વાન્સડ","validateNumberFailed":"આ રકમ આકડો નથી.","confirmNewPage":"સવે કાર્ય વગરનું ફકરો ખોવાઈ જશે. તમને ખાતરી છે કે તમને નવું પાનું ખોલવું છે?","confirmCancel":"ઘણા વિકલ્પો બદલાયા છે. તમારે આ બોક્ષ્ બંધ કરવું છે?","options":"વિકલ્પો","target":"લક્ષ્ય","targetNew":"નવી વિન્ડો (_blank)","targetTop":"ઉપરની વિન્ડો (_top)","targetSelf":"એજ વિન્ડો (_self)","targetParent":"પેરનટ વિન્ડો (_parent)","langDirLTR":"ડાબે થી જમણે (LTR)","langDirRTL":"જમણે થી ડાબે (RTL)","styles":"શૈલી","cssClasses":"શૈલી કલાસીસ","width":"પહોળાઈ","height":"ઊંચાઈ","align":"લાઇનદોરીમાં ગોઠવવું","left":"ડાબી બાજુ ગોઠવવું","right":"જમણી","center":"મધ્ય સેન્ટર","justify":"બ્લૉક, અંતરાય જસ્ટિફાઇ","alignLeft":"ડાબી બાજુએ/બાજુ તરફ","alignRight":"જમણી બાજુએ/બાજુ તરફ","alignCenter":"Align Center","alignTop":"ઉપર","alignMiddle":"વચ્ચે","alignBottom":"નીચે","alignNone":"કઇ નહી","invalidValue":"અનુચિત મૂલ્ય","invalidHeight":"ઉંચાઈ એક આંકડો હોવો જોઈએ.","invalidWidth":"પોહળ ઈ એક આંકડો હોવો જોઈએ.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"\"%1\" ની વેલ્યુ એક પોસીટીવ આંકડો હોવો જોઈએ અથવા CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc) વગર.","invalidHtmlLength":"\"%1\" ની વેલ્યુ એક પોસીટીવ આંકડો હોવો જોઈએ અથવા HTML measurement unit (px or %) વગર.","invalidInlineStyle":"ઈનલાઈન સ્ટાઈલ ની વેલ્યુ \"name : value\" ના ફોર્મેટ માં હોવી જોઈએ, વચ્ચે સેમી-કોલોન જોઈએ.","cssLengthTooltip":"પિક્ષ્લ્ નો આંકડો CSS unit (px, %, in, cm, mm, em, ex, pt, or pc) માં નાખો.","unavailable":"%1<span class=\"cke_accessibility\">, નથી મળતું</span>","keyboard":{"8":"Backspace કી","13":"Enter કી","16":"Shift કી","17":"Ctrl કી","18":"Alt કી","32":"Space કી","35":"End કી","36":"Home કી","46":"Delete કી","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command કી"},"keyboardShortcut":"કીબોર્ડ શૉર્ટકટ","optionDefault":"Default"},"about":{"copy":"કોપીરાઈટ &copy;Line truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['he']={"editor":"עורך טקסט עשיר","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"לחץ אלט ALT + 0 לעזרה","browseServer":"סייר השרת","url":"כתובת (URL)","protocol":"פרוטוקול","upload":"העלאה","uploadSubmit":"שליחה לשרת","image":"תמונה","flash":"פלאש","form":"טופס","checkbox":"תיבת סימון","radio":"לחצן אפשרויות","textField":"שדה טקסט","textarea":"איזור טקסט","hiddenField":"שדה חבוי","button":"כפתור","select":"שדה בחירה","imageButton":"כפתור תמונה","notSet":"<לא נקבע>","id":"זיהוי (ID)","name":"שם","langDir":"כיוון שפה","langDirLtr":"שמאל לימין (LTR)","langDirRtl":"ימין לשמאל (RTL)","langCode":"קוד שפה","longDescr":"קישור לתיאור מפורט","cssClass":"מחלקת עיצוב (CSS Class)","advisoryTitle":"כותרת מוצעת","cssStyle":"סגנון","ok":"אישור","cancel":"ביטול","close":"סגירה","preview":"תצוגה מקדימה","resize":"יש לגרור בכדי לשנות את הגודל","generalTab":"כללי","advancedTab":"אפשרויות מתקדמות","validateNumberFailed":"הערך חייב להיות מספרי.","confirmNewPage":"כל השינויים שלא נשמרו יאבדו. האם להעלות דף חדש?","confirmCancel":"חלק מהאפשרויות שונו, האם לסגור את הדיאלוג?","options":"אפשרויות","target":"מטרה","targetNew":"חלון חדש (_blank)","targetTop":"החלון העליון ביותר (_top)","targetSelf":"אותו חלון (_self)","targetParent":"חלון האב (_parent)","langDirLTR":"שמאל לימין (LTR)","langDirRTL":"ימין לשמאל (RTL)","styles":"סגנון","cssClasses":"מחלקות גליונות סגנון","width":"רוחב","height":"גובה","align":"יישור","left":"לשמאל","right":"לימין","center":"מרכז","justify":"יישור לשוליים","alignLeft":"יישור לשמאל","alignRight":"יישור לימין","alignCenter":"Align Center","alignTop":"למעלה","alignMiddle":"לאמצע","alignBottom":"לתחתית","alignNone":"None","invalidValue":"ערך לא חוקי.","invalidHeight":"הגובה חייב להיות מספר.","invalidWidth":"הרוחב חייב להיות מספר.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"הערך שצוין לשדה \"%1\" חייב להיות מספר חיובי עם או ללא יחידת מידה חוקית של CSS (px, %, in, cm, mm, em, ex, pt, או pc).","invalidHtmlLength":"הערך שצוין לשדה \"%1\" חייב להיות מספר חיובי עם או ללא יחידת מידה חוקית של HTML (px או %).","invalidInlineStyle":"הערך שצויין לשדה הסגנון חייב להכיל זוג ערכים אחד או יותר בפורמט \"שם : ערך\", מופרדים על ידי נקודה-פסיק.","cssLengthTooltip":"יש להכניס מספר המייצג פיקסלים או מספר עם יחידת גליונות סגנון תקינה (px, %, in, cm, mm, em, ex, pt, או pc).","unavailable":"%1<span class=\"cke_accessibility\">, לא זמין</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"מחק","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. כל הזכויות שמורות.","dlgTitle":"אודות CKEditor","moreInfo":"למידע נוסף בקרו באתרנו:"},"basicstyles":{"bold":"מודגש","italic":"נטוי","strike":"כתיב מחוק","subscript":"כתיב תחתון","superscript":"כתיב עליון","underline":"קו תחתון"},"blockquote":{"toolbar":"בלוק ציטוט"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"מזעור סרגל כלים","toolbarExpand":"הרחבת סרגל כלים","toolbarGroups":{"document":"מסמך","clipboard":"לוח הגזירים (Clipboard)/צעד אחרון","editing":"עריכה","forms":"טפסים","basicstyles":"עיצוב בסיסי","paragraph":"פסקה","links":"קישורים","insert":"הכנסה","styles":"עיצוב","colors":"צבעים","tools":"כלים"},"toolbars":"סרגלי כלים של העורך"},"clipboard":{"copy":"העתקה","copyError":"הגדרות האבטחה בדפדפן שלך לא מאפשרות לעורך לבצע פעולות העתקה אוטומטיות. יש להשתמש במקלדת לשם כך (Ctrl/Cmd+C).","cut":"גזירהLine truncated
@@ -0,0 +1,5 @@
/*
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/license
*/
CKEDITOR.lang['hi']={"editor":"रिच टेक्स्ट एडिटर","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"मदद के लिये ALT 0 दबाए","browseServer":"सर्वर ब्राउज़ करें","url":"URL","protocol":"प्रोटोकॉल","upload":"अपलोड","uploadSubmit":"इसे सर्वर को भेजें","image":"तस्वीर","flash":"फ़्लैश","form":"फ़ॉर्म","checkbox":"चॅक बॉक्स","radio":"रेडिओ बटन","textField":"टेक्स्ट फ़ील्ड","textarea":"टेक्स्ट एरिया","hiddenField":"गुप्त फ़ील्ड","button":"बटन","select":"चुनाव फ़ील्ड","imageButton":"तस्वीर बटन","notSet":"<सॅट नहीं>","id":"Id","name":"नाम","langDir":"भाषा लिखने की दिशा","langDirLtr":"बायें से दायें (LTR)","langDirRtl":"दायें से बायें (RTL)","langCode":"भाषा कोड","longDescr":"अधिक विवरण के लिए URL","cssClass":"स्टाइल-शीट क्लास","advisoryTitle":"परामर्श शीर्शक","cssStyle":"स्टाइल","ok":"ठीक है","cancel":"रद्द करें","close":"Close","preview":"प्रीव्यू","resize":"Resize","generalTab":"सामान्य","advancedTab":"ऍड्वान्स्ड","validateNumberFailed":"This value is not a number.","confirmNewPage":"Any unsaved changes to this content will be lost. Are you sure you want to load new page?","confirmCancel":"You have changed some options. Are you sure you want to close the dialog window?","options":"Options","target":"टार्गेट","targetNew":"New Window (_blank)","targetTop":"Topmost Window (_top)","targetSelf":"Same Window (_self)","targetParent":"Parent Window (_parent)","langDirLTR":"बायें से दायें (LTR)","langDirRTL":"दायें से बायें (RTL)","styles":"स्टाइल","cssClasses":"स्टाइल-शीट क्लास","width":"चौड़ाई","height":"ऊँचाई","align":"ऍलाइन","left":"दायें","right":"दायें","center":"बीच में","justify":"ब्लॉक जस्टीफ़ाई","alignLeft":"बायीं तरफ","alignRight":"दायीं तरफ","alignCenter":"Align Center","alignTop":"ऊपर","alignMiddle":"मध्य","alignBottom":"नीचे","alignNone":"None","invalidValue":"Invalid value.","invalidHeight":"Height must be a number.","invalidWidth":"Width must be a number.","invalidLength":"Value specified for the \"%1\" field must be a positive number with or without a valid measurement unit (%2).","invalidCssLength":"Value specified for the \"%1\" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"Value specified for the \"%1\" field must be a positive number with or without a valid HTML measurement unit (px or %).","invalidInlineStyle":"Value specified for the inline style must consist of one or more tuples with the format of \"name : value\", separated by semi-colons.","cssLengthTooltip":"Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, unavailable</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","112":"F1","113":"F2","114":"F3","115":"F4","116":"F5","117":"F6","118":"F7","119":"F8","120":"F9","121":"F10","122":"F11","123":"F12","124":"F13","125":"F14","126":"F15","127":"F16","128":"F17","129":"F18","130":"F19","131":"F20","132":"F21","133":"F22","134":"F23","135":"F24","224":"Command"},"keyboardShortcut":"Keyboard shortcut","optionDefault":"Default"},"about":{"copy":"Copyright &copy; $1. All rights reserved.","dlgTitle":"About CKEditor 4","moreInfo":"For licensing information please visit our web site:"},"basicstyles":{"bold":"बोल्ड","italic":"इटैलिक","strike":"स्ट्राइक थ्रू","subscript":"अधोलेख","superscript":"अभिलेख","underline":"रेखांकण"},"blockquote":{"toolbar":"ब्लॉक-कोट"},"notification":{"closed":"Notification closed."},"toolbar":{"toolbarCollapse":"Collapse Toolbar","toolbarExpand":"Expand Toolbar","toolbarGroups":{"document":"Document","clipboard":"Clipboard/Undo","editing":"Editing","forms":"Forms","basicstyles":"Basic Styles","paragraph":"Paragraph","links":"Links","insert":"Insert","styles":"Styles","colors":"Colors","tools":"Tools"},"toolbars":"एडिटर टूलबार"},"clipboard":{"copy":"कॉपी","copyError":"आपके ब्राआउज़र की सुरक्षLine truncated
Loaded 100 of 406 files, more files were not shown because too many files have changed in this diff. Show more