#wip(go|ecma|sass|wmd): Starter run with loading and publish files.

This commit is contained in:
KyMAN 2025-04-21 20:23:39 +02:00
parent 62704d53c8
commit 237c280553
95 changed files with 6457 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/Data
/Public/data
*[Ss]ecrets*
/Go/Modules

BIN
Bin/AnP.golang.debug Executable file

Binary file not shown.

BIN
Bin/AnP.test.golang.debug Executable file

Binary file not shown.

28
Go/Application/AnP.go Normal file
View File

@ -0,0 +1,28 @@
package Application
import (
"AnP/Drivers"
"AnP/Managers"
"AnP/Models"
"AnP/Modules"
"sync"
)
func NewAnP(inputs any, wait_group *sync.WaitGroup) Models.AnPModel {
var anp Models.AnPModel = Models.AnPModel{
WaitGroup: wait_group,
}
var wmarkdown Modules.WMarkDown = Modules.NewWMarkDown()
anp.Request = Drivers.NewURLPathDriver(anp)
anp.Settings = Managers.NewSettingsManager(anp, inputs)
anp.I18N = Managers.NewI18NManager(anp, inputs)
anp.Attributes = NewAttributes(anp)
anp.Components = NewComponents(anp)
anp.WMarkDown = &wmarkdown
anp.Applications = Managers.NewApplicationsManager(anp)
anp.HTTPServers = Managers.NewHTTPServersManager(anp, inputs)
return anp
}

View File

@ -0,0 +1,128 @@
package Application
import (
"AnP/Models"
"AnP/Utils"
"slices"
"strings"
)
type Attributes struct {
anp Models.AnPModel
without_values []string
normals []string
}
func NewAttributes(anp Models.AnPModel) Attributes {
var attributes Attributes = Attributes{
anp: anp,
without_values: []string{
"disabled", "readonly",
},
normals: []string{
"src", "class", "title", "id", "alt", "target", "href", "style", "lang",
"type", "name", "placeholder", "min", "max", "value", "step", "disabled",
"readonly",
},
}
return attributes
}
func (_self Attributes) process_fixed(
attributes any,
included []string,
excluded []string,
callback func(name string, value string, has_value bool),
) {
switch group := attributes.(type) {
case map[string]any:
for name, value := range group {
var pascal string = strings.ToLower(Utils.Patterns.Replace(name, Utils.Patterns.RE_ATTRIBUTE_BAD_SET_CHARACTERS, "-"))
if (len(included) == 0 || slices.Contains(included, pascal)) && (len(excluded) == 0 || !slices.Contains(excluded, pascal)) {
var processed_name string = pascal
var processed_value string = ""
var has_value bool = value != nil || slices.Contains(_self.without_values, pascal)
if !slices.Contains(_self.normals, pascal) && !slices.Contains([]string{"data-", "aria-"}, pascal[:5]) {
processed_name = "data-" + processed_name
}
if has_value {
processed_value = Utils.ToString(value)
}
callback(processed_name, processed_value, has_value)
}
}
case []any:
for _, subgroup := range group {
_self.process_fixed(subgroup, included, excluded, callback)
}
}
}
func (_self Attributes) process(
attributes any,
included any,
excluded any,
callback func(name string, value string, has_value bool),
) {
_self.process_fixed(attributes, Utils.GetPascalKeys(included), Utils.GetPascalKeys(excluded), callback)
}
func (_self Attributes) Create(attributes any, included any, excluded any) string {
var html string = ``
_self.process(attributes, included, excluded, func(name string, value string, has_value bool) {
html += ` ` + name
if has_value {
if strings.Contains(value, "\"") {
value = Utils.Base64Encode(value)
}
html += `="` + value + `"`
}
})
return html
}
func GetClasses(classes any) []string {
switch group := classes.(type) {
case string:
return Utils.Patterns.RE_SPACES.Split(group, -1)
case []string:
return group
}
return []string{}
}
func JoinClasses(sets ...any) string {
var attributes []string = []string{}
for _, set := range sets {
attributes = append(attributes, GetClasses(set)...)
}
return strings.Join(Utils.GetPascalKeys(attributes), " ")
}
func AttributesRemove(attributes map[string]any, keys []string) map[string]any {
for _, key := range keys {
_, exists := attributes[key]
if exists {
delete(attributes, key)
}
}
return attributes
}

View File

@ -0,0 +1,184 @@
package Application
import (
"AnP/ComponentsBox"
"AnP/Models"
"AnP/Utils"
"slices"
)
type Components struct {
anp Models.AnPModel
autoclosed []string
items map[string]func(parameters ...any) any
Licenses ComponentsBox.LicensesComponent
}
func NewComponents(anp Models.AnPModel) Components {
var components Components = Components{
anp: anp,
autoclosed: []string{"img", "hr", "br"},
items: map[string]func(parameters ...any) any{},
Licenses: ComponentsBox.NewLicensesComponent(anp),
}
components.items["image"] = func(inputs ...any) any {
return components.Image(inputs[0])
}
components.items["licenses"] = func(inputs ...any) any {
return components.Licenses.Build(Utils.Get(inputs, Utils.GetPointer([][]any{}))...)
}
components.items["main_menu"] = func(inputs ...any) any {
return components.CreateMainMenu(Utils.Get(inputs, Utils.GetPointer([]any{}))...)
}
return components
}
func GetItem(item []any) (string, any, any) {
var l int = len(item)
var name string
var attributes any
var childs any = nil
if l > 0 {
name = Utils.Get[string](item[0], nil)
}
if l > 1 {
attributes = item[1]
}
if l >= 3 {
childs = item[2]
}
return name, attributes, childs
}
func (_self Components) Set(items ...[]any) string {
var html string = ``
for _, subitem := range items {
tag, attributes, childs := GetItem(subitem)
method, is_method := _self.items[tag]
if is_method && attributes != nil {
var attributes_processed map[string]any = Utils.GetDictionary(attributes, false)
if _, is := attributes_processed["built"]; is {
is_method = false
}
}
if is_method {
switch results := method(Utils.GetArray(attributes)...).(type) {
case string:
html += results
case []any:
html += _self.Set(results)
}
} else {
html += `<` + tag + _self.anp.Attributes.Create(attributes, nil, "build")
if slices.Contains(_self.autoclosed, tag) {
html += ` />`
} else {
html += `>`
if childs != nil {
switch values := any(childs).(type) {
case [][]any:
html += _self.Set(values...)
case []any:
html += _self.Set(values)
default:
html += Utils.ToString(values)
}
}
html += `</` + tag + `>`
}
}
}
return html
}
func (_self Components) Image(inputs any) []any {
switch value := inputs.(type) {
case []string:
inputs = map[string]any{"sources": value}
}
var attributes map[string]any = Utils.GetDictionary(inputs, false)
var source_keys []string = []string{"images", "sources", "image", "source", "src"}
var images []string = Utils.GetStrings(Utils.GetValue[any](source_keys, attributes, nil))
attributes = AttributesRemove(attributes, append([]string{
"class", "classes", "status", "data_status", "data_i", "data_sources",
}, source_keys...))
return []any{"span", Utils.GetDictionary([]any{attributes, map[string]any{
"class": JoinClasses("image", Utils.GetValue[any]([]string{"class", "classes"}, attributes, nil)),
"data_status": "unloaded",
"data_sources": images,
"data_i": 0,
}}, true), [][]any{
{"img"},
{"span"},
}}
}
func (_self Components) LicensesBuild(licenses ...[]any) []any {
return _self.Licenses.Build(licenses...)
}
func (_self Components) CreateMainMenu(items ...any) []any {
var blocks [][]any = [][]any{}
for _, item := range items {
var attributes map[string]any = map[string]any{}
var text string = ""
var name string = ""
switch set := item.(type) {
case []any:
var link string = *Utils.GetArgument[string](set, 0, nil)
var target string = *Utils.GetArgument(set, 1, Utils.GetPointer("_self"))
name = *Utils.GetArgument(set, 2, Utils.GetPointer(""))
text = _self.anp.I18N.Get([]string{*Utils.GetArgument(set, 3, Utils.GetPointer("")), name}, nil, name)
attributes["href"] = link
attributes["target"] = target
if name != "" {
attributes["data_i18n"] = name
attributes["data_i18n_without"] = true
}
if text != "" || name != "" {
attributes["title"] = text
}
case string, any:
attributes["href"] = item
}
blocks = append(blocks, []any{"li", nil, [][]any{
{"a", attributes, [][]any{
{"span", map[string]any{"data_icon": name}, ""},
{"span", map[string]any{"data_i18n": name}, text},
}},
}})
}
return []any{"nav", map[string]any{"class": "main-menu"}, [][]any{
{"ul", nil, blocks},
}}
}

View File

@ -0,0 +1,199 @@
package ComponentsBox
import (
"AnP/Models"
"AnP/Utils"
"strconv"
)
type LicensesComponent struct {
anp Models.AnPModel
items map[string]func(inputs ...any) []any
}
func NewLicensesComponent(anp Models.AnPModel) LicensesComponent {
var component LicensesComponent = LicensesComponent{
anp: anp,
items: map[string]func(inputs ...any) []any{},
}
component.items["gplv3"] = func(inputs ...any) []any {
return component.GPLv3()
}
component.items["cc_by_nc_sa_4"] = func(inputs ...any) []any {
return component.CC_BY_NC_SA_4()
}
component.items["copyright"] = func(inputs ...any) []any {
return component.Copyright(
*Utils.GetArgument[any](inputs, 0, nil),
*Utils.GetArgument[any](inputs, 1, nil),
*Utils.GetArgument(inputs, 2, Utils.GetPointer(false)),
)
}
return component
}
func (_self LicensesComponent) Build(licenses ...[]any) []any {
var blocks [][]any = [][]any{}
for _, data := range licenses {
var l int = len(data)
var name string
var inputs []any = []any{}
if l > 0 {
name = Utils.Get[string](data[0], nil)
}
if l > 1 {
inputs = data[1:]
}
if method, exists := _self.items[name]; exists {
blocks = append(blocks, method(inputs...))
}
}
return []any{"span", map[string]any{
"class": "licenses",
}, blocks}
}
func (_self LicensesComponent) GPLv3() []any {
return []any{"a", map[string]any{
"class": "license gpl-v3",
"href": "https://www.gnu.org/licenses/gpl-3.0.txt",
"target": "_blank",
"title": "GPLv3",
}, [][]any{
{"span", map[string]any{"class": "text"}, "GPLv3"},
{"image", map[string]any{
"sources": []any{"https://www.gnu.org/graphics/gplv3-88x31.png"},
"alt": "GPLv3",
}},
}}
}
func (_self LicensesComponent) CC_BY_NC_SA_4() []any {
var text string = _self.anp.I18N.Get([]string{
"Creative Commons Attribution-NonCommertial-ShareAlike 4.0 International (CC-SA-NC-BY 4.0)",
"cc_by_nc_sa_4",
}, nil, "")
return []any{"a", map[string]any{
"class": "license cc-by-nc-sa-4",
"href": "https://creativecommons.org/licenses/by-nc-sa/4.0/",
"target": "_blank",
"data_i18n": "cc_by_nc_sa_4",
"data_i18n_without": true,
"title": text,
}, [][]any{
{"span", map[string]any{"class": "text"}, text},
{"image", map[string]any{
"sources": []any{"https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png"},
"data_i18n": "cc_by_nc_sa_4",
"data_i18n_without": true,
"alt": text,
}},
}}
}
func get_year(value any) string {
_float, _ := value.(float64)
return strconv.FormatInt(int64(_float), 10)
}
func (_self LicensesComponent) Copyright(year any, authors any, all_rights_reserved bool) []any {
var year_string string = ""
var authors_string string = ""
switch value := year.(type) {
case []any:
var l int = len(value)
switch l {
case 0:
break
case 1:
year_string = get_year(value)
case 2:
year_string = get_year(value[0]) + "-" + get_year(value[1])
default:
for i, subvalue := range value[0 : l-1] {
if i != 0 {
year_string += ", "
}
year_string += get_year(subvalue)
}
year_string += " & " + get_year(value[l-1])
}
case any:
year_string = strconv.FormatInt(Utils.Get[int64](value, nil), 10)
}
switch value := authors.(type) {
case string:
authors_string = value
case []string:
var l int = len(value)
switch l {
case 0:
break
case 1:
authors_string = value[0]
case 2:
authors_string = value[0] + " &" + value[1]
default:
for i, subvalue := range value[0 : l-1] {
if i != 0 {
authors_string += ", "
}
authors_string += subvalue
}
authors_string += " & " + value[l-1]
}
}
if year_string != "" {
year_string = " " + year_string + "."
}
if authors_string != "" {
authors_string = " " + authors_string + "."
}
var variables = map[string]any{
"year": year_string,
"authors": authors_string,
"all_rights_reserved": "",
}
if all_rights_reserved {
variables["all_rights_reserved"] = " " + _self.anp.I18N.Get([]string{
"All rights reserved.",
"all_rights_reserved",
}, nil, "")
}
var text string = _self.anp.I18N.Get([]string{
"© Copyright{year}{authors}{all_rights_reserved}",
"copyright",
}, variables, "")
return []any{"span", map[string]any{
"class": "license copyright",
"data_i18n": "copyriht",
"data_i18n_variables": variables,
"title": text,
}, text}
}

101
Go/Drivers/HTTPDriver.go Normal file
View File

@ -0,0 +1,101 @@
package Drivers
import (
"AnP/Models"
"AnP/Utils"
"context"
"fmt"
"mime"
"net/http"
"strconv"
"strings"
)
type HTTPDriver struct {
anp Models.AnPModel
host string
port int16
server *http.Server
listener func(writer http.ResponseWriter, request *http.Request)
autorun bool
}
func NewHTTPDriver(anp Models.AnPModel, inputs any) *HTTPDriver {
mime.AddExtensionType(".js", "application/javascript")
var server HTTPDriver = HTTPDriver{
anp: anp,
host: Utils.Get(anp.Settings.Get([]string{
"http_driver_host", "http_host", "host",
}, inputs, Utils.GetPointer[any]("")), Utils.GetPointer("")),
port: Utils.Get(anp.Settings.Get([]string{
"http_driver_port", "http_port", "port",
}, inputs, Utils.GetPointer[any](8080)), Utils.GetPointer[int16](8080)),
listener: Utils.Get[func(writer http.ResponseWriter, request *http.Request)](anp.Settings.Get([]string{
"http_driver_listener", "http_listener", "listener",
}, inputs, nil), nil),
autorun: Utils.Get(anp.Settings.Get([]string{
"http_driver_autorun", "http_autorun", "autorun",
}, inputs, Utils.GetPointer[any](true)), Utils.GetPointer(true)),
}
if server.listener == nil {
server.listener = server.listen
}
if server.autorun {
server.Run()
}
return &server
}
func (_self HTTPDriver) listen(writer http.ResponseWriter, request *http.Request) {
var response map[string]any = _self.anp.Applications.Go(request.Host, strings.ToLower(request.Method), request.RequestURI)
var response_bytes []byte = []byte{}
if response["response"] != nil {
switch value := response["response"].(type) {
case string:
response_bytes = []byte(value)
case []byte:
response_bytes = value
}
}
writer.Header().Set("Content-Type", Utils.Get[string](response["mime"], nil))
writer.WriteHeader(Utils.Get[int](response["code"], nil))
writer.Write(response_bytes)
}
func (_self HTTPDriver) Run() {
_self.server = &http.Server{
Addr: _self.host + ":" + strconv.FormatInt(int64(_self.port), 10),
Handler: http.HandlerFunc(_self.listener),
}
_self.anp.WaitGroup.Add(1)
go func() {
if error := _self.server.ListenAndServe(); error != nil {
fmt.Printf("Error: %v\n", error)
}
_self.anp.WaitGroup.Done()
}()
}
func (_self HTTPDriver) Stop() {
context_timeout, cancel := context.WithTimeout(context.Background(), 2000)
defer cancel()
if _self.server.Shutdown(context_timeout) != nil {
Models.DebugPrint("PASA SHUTDOWN")
}
}

191
Go/Drivers/URLPathDriver.go Normal file
View File

@ -0,0 +1,191 @@
package Drivers
import (
"AnP/Models"
"AnP/Utils"
"encoding/json"
"mime"
"os"
"strings"
"time"
)
type URLPathDriver struct {
anp Models.AnPModel
root_paths []string
is_dos bool
slash string
}
func NewURLPathDriver(anp Models.AnPModel) URLPathDriver {
var driver URLPathDriver = URLPathDriver{
anp: anp,
root_paths: []string{""},
is_dos: false,
slash: "/",
}
var path string = GetCurrentDirectory()
if path != "" {
driver.is_dos = strings.Contains(path, "\\")
driver.root_paths = append(driver.root_paths, path)
if driver.is_dos {
driver.slash = "\\"
}
for range 3 {
path = Utils.Patterns.RE_PARENT_PATH.ReplaceAllString(path, "$1")
if path == "" {
break
}
driver.root_paths = append(driver.root_paths, path)
}
}
return driver
}
func GetCurrentDirectory() string {
var path string = ""
executable_path, exception := os.Executable()
if exception != nil {
command_path, exception := os.Getwd()
if exception == nil {
path = command_path
}
} else {
path = executable_path
}
return path
}
func (_self URLPathDriver) FixPath(path string) string {
return Utils.Patterns.RE_SLASH.ReplaceAllString(path, _self.slash)
}
func (_self URLPathDriver) GetAbsolutePath(path string) string {
for _, root := range _self.root_paths {
var full_path string = root
if full_path != "" {
full_path += _self.slash
}
full_path = _self.FixPath(full_path + path)
if _, error := os.Stat(full_path); error == nil {
path = full_path
break
}
}
return path
}
func (_self URLPathDriver) LoadFile(path string) string {
data, _ := os.ReadFile(_self.GetAbsolutePath(path))
return string(data)
}
func (_self URLPathDriver) LoadBinaryFile(path string) []byte {
data, _ := os.ReadFile(_self.GetAbsolutePath(path))
return data
}
func (_self URLPathDriver) LoadJSON(inputs any, callback func(any), only_dictionaries bool) {
switch group := inputs.(type) {
case map[string]any:
callback(group)
case []any:
if only_dictionaries {
for _, subgroup := range group {
_self.LoadJSON(subgroup, callback, only_dictionaries)
}
} else {
callback(group)
}
case string:
var data any
if json.Unmarshal([]byte(group), &data) != nil {
json.Unmarshal([]byte(_self.LoadFile(group)), &data)
}
_self.LoadJSON(data, callback, only_dictionaries)
}
}
func (_self URLPathDriver) GetSlash() string {
return _self.slash
}
func GetExtension(path string) string {
var matches Utils.PatternMatch = Utils.Patterns.Match(path, Utils.Patterns.RE_EXTENSION)
if matches.Ok {
return matches.Groups[1]
}
return ""
}
func GetMime(path string) string {
var mime_type string = mime.TypeByExtension("." + GetExtension(path))
if mime_type != "" {
return mime_type
}
return "application/octet-stream"
}
func PathExists(path string) bool {
_, error := os.Stat(path)
return error == nil
}
func FileExists(path string) bool {
stat, error := os.Stat(path)
return error == nil && !stat.IsDir()
}
func DirectoryExists(path string) bool {
stat, error := os.Stat(path)
return error == nil && stat.IsDir()
}
func LastDateModified(path string) *time.Time {
stat, error := os.Stat(path)
if error == nil {
var date time.Time = stat.ModTime()
return &date
}
return nil
}

View File

@ -0,0 +1,5 @@
package Interfaces
type ApplicationsInterface interface {
Go(domain string, method string, url string) map[string]any
}

View File

@ -0,0 +1,5 @@
package Interfaces
type AttributesInterface interface {
Create(attributes any, included any, excluded any) string
}

View File

@ -0,0 +1,8 @@
package Interfaces
type ComponentsInterface interface {
Set(items ...[]any) string
Image(inputs any) []any
LicensesBuild(licenses ...[]any) []any
CreateMainMenu(items ...any) []any
}

View File

@ -0,0 +1,5 @@
package Interfaces
type HTTPServersInterfaces interface {
// Add(inputs any, overwrite bool)
}

View File

@ -0,0 +1,7 @@
package Interfaces
type I18NInterface interface {
GetRaw(texts any, _default string) string
Get(keys any, inputs any, _default string) string
// Add(inputs any, overwrite bool, header string)
}

View File

@ -0,0 +1,6 @@
package Interfaces
type RoutesInterface interface {
// Add(inputs any, overwrite bool)
Go(domain string, method string, url string, settings map[string]any) (map[string]any, bool)
}

View File

@ -0,0 +1,7 @@
package Interfaces
type SettingsInterface interface {
Get(keys any, inputs any, _default *any) any
// Add(inputs any, overwrite bool, header string)
// AddSecrets(inputs any, overwrite bool, header string)
}

View File

@ -0,0 +1,10 @@
package Interfaces
type URLPathInterface interface {
FixPath(path string) string
GetAbsolutePath(path string) string
LoadFile(path string) string
LoadBinaryFile(path string) []byte
LoadJSON(inputs any, callback func(any), only_dictionaries bool)
GetSlash() string
}

16
Go/Main/Server/Main.go Normal file
View File

@ -0,0 +1,16 @@
package main
import (
"AnP/Application"
"sync"
)
func main() {
var wait_group sync.WaitGroup
Application.NewAnP(nil, &wait_group)
wait_group.Wait()
}

10
Go/Main/Test/Main.go Normal file
View File

@ -0,0 +1,10 @@
package main
import "AnP/Tests"
func main() {
// var http Tests.HTTPServerTest = Tests.NewHTTPServerTest()
Tests.NewHTTPServerTest()
}

View File

@ -0,0 +1,53 @@
package Managers
import (
"AnP/Models"
"AnP/Utils"
)
type ApplicationsManager struct {
anp Models.AnPModel
applications map[string]Models.ApplicationModel
}
func NewApplicationsManager(anp Models.AnPModel) ApplicationsManager {
var module ApplicationsManager = ApplicationsManager{
anp: anp,
applications: map[string]Models.ApplicationModel{},
}
for _, key := range []string{
"default_applications_files", "applications_files",
"default_applications", "applications",
} {
module.Add(anp.Settings.Get(key, nil, nil), true)
}
return module
}
func (_self *ApplicationsManager) Add(inputs any, overwrite bool) {
_self.anp.Request.LoadJSON(inputs, func(response any) {
for key, data := range Utils.Get[map[string]any](inputs, nil) {
_, exists := _self.applications[key]
if overwrite || !exists {
_self.applications[key] = Models.NewApplicationModel(_self.anp, NewRoutesManager(_self.anp, data), data)
}
}
}, true)
}
func (_self ApplicationsManager) Go(domain string, method string, url string) map[string]any {
var response map[string]any = GetDefaultHTTPResponse()
var done bool
for _, application := range _self.applications {
if response, done = application.Routes.Go(domain, method, url, application.GetAttributes()); done {
break
}
}
return response
}

View File

@ -0,0 +1,44 @@
package Managers
import (
"AnP/Drivers"
"AnP/Models"
)
type HTTPServersManager struct {
anp Models.AnPModel
servers map[string]*Drivers.HTTPDriver
}
func NewHTTPServersManager(anp Models.AnPModel, inputs any) HTTPServersManager {
var manager HTTPServersManager = HTTPServersManager{
anp: anp,
servers: map[string]*Drivers.HTTPDriver{},
}
for _, key := range []string{
"default_http_servers_files", "default_http_servers", "http_servers_files", "http_servers",
} {
manager.Add(anp.Settings.Get(key, nil, nil), false)
}
return manager
}
func (_self *HTTPServersManager) Add(inputs any, overwrite bool) {
_self.anp.Request.LoadJSON(inputs, func(response any) {
switch group := response.(type) {
case map[string]any:
for key, data := range group {
_, exists := _self.servers[key]
if overwrite || !exists {
switch subinputs := data.(type) {
case map[string]any:
_self.servers[key] = Drivers.NewHTTPDriver(_self.anp, subinputs)
}
}
}
}
}, true)
}

View File

@ -0,0 +1,98 @@
package Managers
import (
"AnP/Models"
"AnP/Utils"
"slices"
"strings"
)
type I18NManager struct {
anp Models.AnPModel
default_language string
language_selected string
sentences map[string]map[string]any
}
func NewI18NManager(anp Models.AnPModel, inputs any) I18NManager {
var i18n I18NManager = I18NManager{
anp: anp,
default_language: "english",
language_selected: "english",
sentences: map[string]map[string]any{},
}
for _, key := range []string{"default_i18n_files", "default_i18n", "i18n_files", "i18n"} {
i18n.Add(anp.Settings.Get(key, nil, nil), true, "AnP")
}
return i18n
}
func (_self *I18NManager) Add(inputs any, overwrite bool, header string) {
_self.anp.Request.LoadJSON(inputs, func(data any) {
for language, sentences := range Utils.Get[map[string]map[string]any](data, nil) {
if _, exists := _self.sentences[language]; !exists {
_self.sentences[language] = map[string]any{}
}
for key, sentence := range sentences {
if Utils.IsAnPKey(key, header) {
_, exists := _self.sentences[language][key]
if overwrite || !exists {
_self.sentences[language][key] = sentence
}
}
}
}
}, true)
}
func (_self I18NManager) GetRaw(texts any, _default string) string {
var keys []string = Utils.GetKeys(texts)
if len(keys) != 0 {
var done []string = []string{}
for _, language := range append(
[]string{_self.language_selected, _self.default_language},
Utils.GetMapKeys(_self.sentences)...,
) {
if !slices.Contains(done, language) {
if _, exists := _self.sentences[language]; !exists {
for _, key := range keys {
if _, exists := _self.sentences[language][key]; exists {
switch text := _self.sentences[language][key].(type) {
case string:
return text
case []string:
return strings.Join(text, "")
}
return _default
}
}
}
done = append(done, language)
}
}
}
var text_options []string = Utils.GetStrings(texts)
if len(text_options) != 0 {
return text_options[0]
}
return _default
}
func (_self I18NManager) Get(texts any, inputs any, _default string) string {
var text string = _self.GetRaw(texts, _default)
if inputs == nil {
return text
}
return Utils.StringVariables(text, inputs, nil)
}

View File

@ -0,0 +1,207 @@
package Managers
import (
"AnP/Drivers"
"AnP/Models"
"AnP/Modules"
"AnP/Utils"
"maps"
"slices"
"time"
)
type RoutesManager struct {
anp Models.AnPModel
domains []string
routes []Models.RoutesModel
indexes []string
wmarkdown_html_file string
}
var default_indexes []string = []string{"index.w.md", "index.md", "index.html", "index.htm"}
var default_wmarkdown_html string = "/HTML/AnP.wmarkdown.html"
func GetDefaultHTTPResponse() map[string]any {
return map[string]any{
"ok": false,
"code": 502,
}
}
func NewRoutesManager(anp Models.AnPModel, inputs any) RoutesManager {
var manager RoutesManager = RoutesManager{
anp: anp,
domains: Utils.GetStrings(anp.Settings.Get([]string{
"default_routes_domains", "default_routes_domain",
"default_domains", "default_domain",
"domains", "domain",
}, inputs, nil)),
routes: []Models.RoutesModel{},
indexes: Utils.GetStrings(anp.Settings.Get([]string{}, inputs, Utils.GetPointer[any](default_indexes))),
wmarkdown_html_file: Utils.Get(anp.Settings.Get("wmarkdown_html", inputs, Utils.GetPointer[any](default_wmarkdown_html)), &default_wmarkdown_html),
}
for _, key := range []string{"default_routes_files", "default_routes", "routes_files", "routes"} {
manager.Add(anp.Settings.Get(key, inputs, nil), true)
}
return manager
}
func (_self *RoutesManager) Add(inputs any, overwrite bool) {
switch group := inputs.(type) {
case string:
var route Models.RoutesModel = Models.NewRoutesModel(group)
if route.Ok {
var i int = -1
var exists bool = false
for _, current := range _self.routes {
if current.IsSame(route) {
i = current.I
exists = true
break
}
}
if overwrite || !exists {
if exists {
_self.routes[i] = route
route.I = i
} else {
route.I = len(_self.routes)
_self.routes = append(_self.routes, route)
}
}
} else {
_self.anp.Request.LoadJSON(group, func(data any) {
_self.Add(data, overwrite)
}, false)
}
case []any:
for _, subinputs := range group {
_self.Add(subinputs, overwrite)
}
}
}
func (_self RoutesManager) StringVariables(_string string, inputs any) string {
var dictionary map[string]any = Utils.GetDictionary(inputs, false)
return Utils.Patterns.Replace(_string, Utils.Patterns.RE_VIEWS_STRING_VARIABLES, func(matches Utils.PatternMatch) string {
if matches.Groups[1] != "" {
if value, exists := dictionary[matches.Groups[1]]; exists {
return Utils.ToString(value)
}
} else if matches.Groups[2] != "" {
return _self.anp.I18N.Get(Utils.StringVariables(matches.Groups[2], inputs, nil), inputs, matches.Groups[0])
}
return matches.Groups[0]
})
}
func (_self RoutesManager) Go(domain string, method string, url string, settings map[string]any) (map[string]any, bool) {
var response map[string]any = GetDefaultHTTPResponse()
var done bool = false
if slices.Contains(_self.domains, domain) || slices.Contains(_self.domains, "") {
response["code"] = 404
done = true
for _, route := range _self.routes {
var matches Utils.PatternMatch = Utils.Patterns.Match(url, route.URL)
if matches.Ok {
var variables map[string]any = route.GetVariables(matches)
if route.Type == Models.RouteTypePath {
switch subpath := variables["path"].(type) {
case string:
var slash string = _self.anp.Request.GetSlash()
subpath = route.Path + slash + subpath
var full_path string = _self.anp.Request.GetAbsolutePath(subpath)
var ok bool = Drivers.FileExists(full_path)
if !ok {
for _, index := range _self.indexes {
var temporary_path string = _self.anp.Request.GetAbsolutePath(subpath + slash + index)
ok = Drivers.FileExists(temporary_path)
if ok {
full_path = temporary_path
break
}
}
}
if ok {
if full_path[len(full_path)-3:] == ".md" {
html, subvariables := _self.anp.WMarkDown.Process(_self.anp.Request.LoadFile(full_path), Modules.WMD.HTML, full_path)
var last_date_modified time.Time = *Drivers.LastDateModified(full_path)
variables["contents"] = html
variables["version"] = last_date_modified.Format("20060102")
maps.Copy(variables, settings)
for key, value := range subvariables {
variables[key] = value
}
response["ok"] = true
response["code"] = 200
response["mime"] = "text/html;charset=" + variables["charset"].(string)
response["response"] = _self.StringVariables(_self.anp.Request.LoadFile(_self.wmarkdown_html_file), variables)
} else {
var mime_type string = Drivers.GetMime(full_path)
var data []byte = _self.anp.Request.LoadBinaryFile(full_path)
response["ok"] = true
response["code"] = 200
response["mime"] = mime_type
if mime_type[:5] == "text/" {
response["response"] = string(data)
} else {
response["response"] = data
}
}
}
default:
response["code"] = 501
}
} else if route.Type == Models.RouteTypeView {
response["code"] = 503
} else if route.Type == Models.RouteTypeController {
response["code"] = 503
} else {
response["code"] = 500
}
}
}
}
return response, done
}

View File

@ -0,0 +1,80 @@
package Managers
import (
"AnP/Models"
"AnP/Utils"
)
var default_settings map[string]any = map[string]any{
"default_settings_files": []any{
"/Public/json/AnP.go.settings.json",
"/JSON/AnP.go.settings.json",
"AnP.go.settings.json",
},
"default_secrets_files": []any{
"/Public/json/AnP.go.secrets.json",
"/JSON/AnP.go.secrets.json",
"AnP.go.secrets.json",
},
}
type SettingsManager struct {
anp Models.AnPModel
inputs map[string]any
settings map[string]any
secrets map[string]any
}
func NewSettingsManager(anp Models.AnPModel, inputs any) SettingsManager {
var settings SettingsManager = SettingsManager{
anp: anp,
inputs: Utils.GetDictionary(inputs, true),
settings: map[string]any{},
secrets: map[string]any{},
}
for _, key := range []string{"default_settings_files", "default_settings", "settings_files", "settings"} {
settings.Add(settings.Get(key, nil, nil), true, "AnP")
}
for _, key := range []string{"default_secrets_files", "default_secrets", "secrets_files", "secrets"} {
settings.AddSecrets(settings.Get(key, nil, nil), true, "AnP")
}
return settings
}
func GetSettings[T any](_self SettingsManager, keys any, inputs any, _default *T) T {
return Utils.GetValue(keys, []any{inputs, _self.secrets, _self.inputs, _self.settings, default_settings}, _default)
}
func (_self SettingsManager) Get(keys any, inputs any, _default *any) any {
return GetSettings(_self, keys, inputs, _default)
}
func (_self *SettingsManager) Add(inputs any, overwrite bool, header string) {
_self.anp.Request.LoadJSON(inputs, func(data any) {
for key, value := range Utils.Get[map[string]any](data, nil) {
if !Utils.IsAnPKey(key, header) {
_, exists := _self.settings[key]
if overwrite || !exists {
_self.settings[key] = value
}
}
}
}, true)
}
func (_self *SettingsManager) AddSecrets(inputs any, overwrite bool, header string) {
_self.anp.Request.LoadJSON(inputs, func(data any) {
for key, value := range Utils.Get[map[string]any](data, nil) {
if !Utils.IsAnPKey(key, header) {
_, exists := _self.secrets[key]
if overwrite || !exists {
_self.secrets[key] = value
}
}
}
}, true)
}

19
Go/Models/AnPModel.go Normal file
View File

@ -0,0 +1,19 @@
package Models
import (
"AnP/Interfaces"
"AnP/Modules"
"sync"
)
type AnPModel struct {
WaitGroup *sync.WaitGroup
Request Interfaces.URLPathInterface
Settings Interfaces.SettingsInterface
I18N Interfaces.I18NInterface
Attributes Interfaces.AttributesInterface
Components Interfaces.ComponentsInterface
Applications Interfaces.ApplicationsInterface
WMarkDown *Modules.WMarkDown
HTTPServers Interfaces.HTTPServersInterfaces
}

View File

@ -0,0 +1,115 @@
package Models
import (
"AnP/Interfaces"
"AnP/Utils"
"maps"
"slices"
"strings"
)
type ApplicationModel struct {
anp AnPModel
Attributes map[string]any
Routes Interfaces.RoutesInterface
}
func SetClasses(classes []string) string {
if !slices.Contains(classes, "anp") {
classes = append(classes, "anp")
}
return strings.Join(classes, " ")
}
func NewApplicationModel(anp AnPModel, routes Interfaces.RoutesInterface, inputs any) ApplicationModel {
var attributes map[string]any = map[string]any{}
var strings_sets map[string][]string = map[string][]string{}
var l int
var licenses [][]any = [][]any{}
var menu []any = []any{}
for _, license := range Utils.GetValue[[]any]([]string{
"application_licenses", "application_license", "licenses", "license",
}, inputs, nil) {
licenses = append(licenses, Utils.Get[[]any](license, nil))
}
for _, item := range Utils.GetValue[[]any]([]string{
"application_menu", "menu",
}, inputs, nil) {
menu = append(menu, Utils.Get[any](item, nil))
}
for key, keys := range map[string][]string{
"git": {"application_git", "git"},
"project": {"application_name", "name", "project"},
"web": {"application_link", "application_url", "application_web", "link", "url", "web"},
"logo": {"application_logo", "logo"},
"snake": {"application_snake", "snake"},
} {
attributes[key] = Utils.GetValue[string](keys, inputs, nil)
}
switch logo := attributes["logo"].(type) {
case []string, []any:
attributes["logo_sources"] = logo
case string, any:
attributes["logo_sources"] = []any{logo}
default:
attributes["logo_sources"] = []any{}
}
attributes["logo_sources"] = Utils.VariablesEncode(attributes["logo_sources"])
for key, keys := range map[string][][]string{
"charset": {{"charset"}, {"utf-8"}},
} {
attributes[key] = Utils.GetValue(keys[0], inputs, &keys[1][0])
}
for key, keys := range map[string][]string{
"class": {"application_class", "class"},
"authors": {"application_authors", "application_author", "authors", "author"},
"scripts": {"application_scripts", "application_script", "scripts", "script"},
"styles": {"application_styles", "application_style", "styles", "style"},
"dictionaries": {"application_dictionaries", "application_dictionary", "dictionaries", "dictionary"},
"menu": {"application_menu", "menu"},
} {
strings_sets[key] = Utils.GetStringsFilled(Utils.GetValue[any](keys, inputs, nil))
}
attributes["class"] = SetClasses(strings_sets["class"])
for _, key := range []string{"scripts", "styles", "dictionaries"} {
attributes[key] = Utils.JSONEncode(strings_sets[key])
}
l = len(strings_sets["authors"])
switch l {
case 0:
attributes["authors"] = ""
case 1:
attributes["authors"] = strings_sets["authors"][0]
case 2:
attributes["authors"] = strings.Join(strings_sets["authors"], " & ")
default:
attributes["authors"] = strings.Join(strings_sets["authors"][:l-1], ", ") + " & " + strings_sets["authors"][l-1]
}
attributes["licenses"] = licenses
attributes["licenses_html"] = anp.Components.Set(anp.Components.LicensesBuild(licenses...))
attributes["menu"] = menu
attributes["menu_html"] = anp.Components.Set(anp.Components.CreateMainMenu(menu...))
return ApplicationModel{
anp: anp,
Attributes: attributes,
Routes: routes,
}
}
func (_self ApplicationModel) GetAttributes() map[string]any {
return maps.Clone(_self.Attributes)
}

153
Go/Models/DebugModel.go Normal file
View File

@ -0,0 +1,153 @@
package Models
import (
"AnP/Utils"
"encoding/json"
"runtime/debug"
"strconv"
)
type DebugStackLineModel struct {
Line int
Method string
File string
}
func NewDebugStackLineModel(line int, file string, method string) DebugStackLineModel {
return DebugStackLineModel{
Line: line,
File: file,
Method: method,
}
}
func NewDebugStackLineFromMatch(match Utils.PatternMatch) DebugStackLineModel {
line, _ := strconv.ParseInt(match.Groups[4], 10, 32)
return NewDebugStackLineModel(int(line), match.Groups[3], match.Groups[1])
}
func (_self *DebugStackLineModel) ToDictionary() map[string]any {
return map[string]any{
"line": _self.Line,
"file": _self.File,
"method": _self.Method,
}
}
func DebugStackToDictionaries(lines []DebugStackLineModel) []map[string]any {
var stack []map[string]any = []map[string]any{}
for _, line := range lines {
stack = append(stack, line.ToDictionary())
}
return stack
}
func GetTraceStack(i int) []DebugStackLineModel {
var stack_map []DebugStackLineModel = []DebugStackLineModel{}
Utils.Patterns.Replace(string(debug.Stack()), Utils.Patterns.RE_TRACE_STACK, func(match Utils.PatternMatch) string {
stack_map = append(stack_map, NewDebugStackLineFromMatch(match))
return ""
})
return stack_map[i+2:]
}
func DebugPrintPointer[T any](item *T) {
print("*")
if item == nil {
print("nil")
return
}
print(*item)
}
func DebugPrintJSON(item any) {
data, error := json.Marshal(item)
if error == nil {
print(string(data))
} else {
print(item)
}
}
func DebugPrint(items ...any) {
var stack DebugStackLineModel = GetTraceStack(1)[0]
print(">[DEV]>[", stack.Line, "]", stack.File, "(", stack.Method, "): ")
for _, item := range items {
if item == nil {
print("nil")
continue
}
switch value := item.(type) {
case string:
print(value)
case *string:
DebugPrintPointer(value)
case int:
print(value)
case int8:
print(value)
case int16:
print(value)
case int32:
print(value)
case int64:
print(value)
case *int:
DebugPrintPointer(value)
case *int8:
DebugPrintPointer(value)
case *int16:
DebugPrintPointer(value)
case *int32:
DebugPrintPointer(value)
case *int64:
DebugPrintPointer(value)
case uint:
print(value)
case uint8:
print(value)
case uint16:
print(value)
case uint32:
print(value)
case uint64:
print(value)
case *uint:
DebugPrintPointer(value)
case *uint8:
DebugPrintPointer(value)
case *uint16:
DebugPrintPointer(value)
case *uint32:
DebugPrintPointer(value)
case *uint64:
DebugPrintPointer(value)
case float32, float64:
print(value)
case *float32:
DebugPrintPointer(value)
case *float64:
DebugPrintPointer(value)
case bool:
print(value)
default:
DebugPrintJSON(value)
}
}
print("\n")
}

91
Go/Models/RoutesModel.go Normal file
View File

@ -0,0 +1,91 @@
package Models
import (
"AnP/Utils"
"regexp"
"strings"
)
const (
RouteTypeUnknown = iota
RouteTypePath
RouteTypeView
RouteTypeController
)
type RoutesModel struct {
Method string
URL *regexp.Regexp
View string
Path string
Ok bool
I int
Variables []string
Permissions []string
Type int
}
func NewRoutesModel(pattern string) RoutesModel {
var matches Utils.PatternMatch = Utils.Patterns.Match(pattern, Utils.Patterns.RE_ROUTE)
var route RoutesModel = RoutesModel{
Ok: matches.Ok,
}
if matches.Ok {
var pattern string
route.Variables = []string{}
pattern = `(?i)^` + Utils.Patterns.Replace(matches.Groups[3], Utils.Patterns.RE_ROUTES_FORMAT, func(matches Utils.PatternMatch) string {
if matches.Groups[1] != "" {
route.Variables = append(route.Variables, matches.Groups[1])
return `([^\/]+)`
}
return `\` + matches.Groups[2]
})
if matches.Groups[8] != "" {
route.Variables = append(route.Variables, "path")
pattern += `(.*)$`
} else {
pattern += `$`
}
route.Method = strings.ToLower(matches.Groups[2])
route.URL = regexp.MustCompile(pattern)
// 5 - 6 == Controller - Method
route.View = matches.Groups[7]
route.Path = matches.Groups[8]
if matches.Groups[10] != "" {
route.Permissions = strings.Split(matches.Groups[10], ",")
}
if route.Path != "" {
route.Type = RouteTypePath
} else if route.View != "" {
route.Type = RouteTypeView
}
}
return route
}
func (_self RoutesModel) IsSame(route RoutesModel) bool {
return route.Method == _self.Method && route.URL == _self.URL
}
func (_self RoutesModel) GetVariables(matches Utils.PatternMatch) map[string]any {
var url_variables map[string]any = map[string]any{}
for i, key := range _self.Variables {
url_variables[key] = matches.Groups[i+1]
}
return url_variables
}

View File

@ -0,0 +1,21 @@
package Tests
import (
"io"
"net/http"
)
type HTTPServerTest struct{}
func NewHTTPServerTest() HTTPServerTest {
var server HTTPServerTest = HTTPServerTest{}
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
io.WriteString(writer, "¿PASA? "+request.URL.Path)
})
http.ListenAndServe(":8080", nil)
return server
}

28
Go/Utils/Check.go Normal file
View File

@ -0,0 +1,28 @@
package Utils
func IsAnPKey(item any, header string) bool {
switch value := item.(type) {
case string:
var l int = len(value)
return value[:len(header)+1] == header+"_" && value[l-6:] == "_start" || value[l-4:] == "_end"
}
return false
}
func IsKey(item any) bool {
switch value := item.(type) {
case string:
return len(value) != 0 && Patterns.RE_KEY.MatchString(value)
}
return false
}
func IsPascalKey(item any) bool {
switch value := item.(type) {
case string:
return len(value) != 0 && Patterns.RE_PASCAL_KEY.MatchString(value)
}
return false
}

95
Go/Utils/Patterns.go Normal file
View File

@ -0,0 +1,95 @@
package Utils
import (
"bytes"
"regexp"
)
type PatternMatch struct {
String string
Groups []string
Span []int
Ok bool
}
type PatternsModel struct {
RE_PARENT_PATH *regexp.Regexp
RE_SLASH *regexp.Regexp
RE_KEY *regexp.Regexp
RE_PASCAL_KEY *regexp.Regexp
RE_STRING_VARIABLES *regexp.Regexp
RE_ROUTE *regexp.Regexp
RE_ROUTES_FORMAT *regexp.Regexp
RE_TRACE_STACK *regexp.Regexp
RE_EXTENSION *regexp.Regexp
RE_VIEWS_STRING_VARIABLES *regexp.Regexp
RE_ATTRIBUTE_BAD_SET_CHARACTERS *regexp.Regexp
RE_SPACES *regexp.Regexp
}
var Patterns PatternsModel = PatternsModel{
RE_PARENT_PATH: regexp.MustCompile(`^(.+)[\/\\][^\/\\]+$`),
RE_SLASH: regexp.MustCompile(`[\/\\]+`),
RE_KEY: regexp.MustCompile(`(?i)^[a-z0-9_]+$`),
RE_PASCAL_KEY: regexp.MustCompile(`(?i)^[a-z0-9_\-]+$`),
RE_STRING_VARIABLES: regexp.MustCompile(`(?i)\{([a-z0-9_]+)\}`),
RE_ROUTE: regexp.MustCompile(`(?i)^(([^\:]+)\:)?([^ ]+) +(([^ \:]+)\:([^ ]+)|([a-z0-9_]+)|([^ ]+))( +([^\s]+))?$`),
RE_ROUTES_FORMAT: regexp.MustCompile(`(?i)\{([a-z0-9_]+)\}|([\\\/\-\{\[\]\}\\(\)\*\^\|\!\?\+\.\:\$])`),
RE_TRACE_STACK: regexp.MustCompile(`[\n\r](([^\.\(\s]+|\..)+)\([^\n\r]+[\r\n]+\s+([^\:\s]+)\:([0-9]+)`),
RE_EXTENSION: regexp.MustCompile(`\.([^\.\/\\]+)$`),
RE_VIEWS_STRING_VARIABLES: regexp.MustCompile(`(?i)\{([a-z0-9_]+)\}|\{2}((?:[a-z0-9_]+|\{[a-z0-9_]+\})+)\}{2}`),
RE_ATTRIBUTE_BAD_SET_CHARACTERS: regexp.MustCompile(`(?i)[^a-z0-9]+`),
RE_SPACES: regexp.MustCompile(` +`),
}
func (_self *PatternsModel) GetMatches(_string string, groups [][]byte) PatternMatch {
var binary []byte = []byte(_string)
var matches PatternMatch
if groups != nil {
matches.String = _string
matches.Groups = []string{}
matches.Span = []int{bytes.Index(binary, groups[0]), len(groups[0])}
matches.Ok = true
for _, group := range groups {
matches.Groups = append(matches.Groups, string(group))
}
}
return matches
}
func (_self *PatternsModel) Match(_string string, pattern *regexp.Regexp) PatternMatch {
return _self.GetMatches(_string, pattern.FindSubmatch([]byte(_string)))
}
func (_self *PatternsModel) Replace(_string string, pattern *regexp.Regexp, to any) string {
var processed string = ""
var binary []byte = []byte(_string)
for {
var matches PatternMatch = _self.Match(string(binary), pattern)
if !matches.Ok {
break
}
processed += string(binary[:matches.Span[0]])
switch value := to.(type) {
case func(PatternMatch) string:
processed += value(matches)
case string:
processed += value
}
binary = binary[matches.Span[0]+matches.Span[1]:]
}
return processed + string(binary)
}

345
Go/Utils/Utils.go Normal file
View File

@ -0,0 +1,345 @@
package Utils
import (
"encoding/base64"
"encoding/json"
"iter"
"maps"
"slices"
"strconv"
"strings"
)
func Get[T any](inputs any, _default *T) T {
var value T
if _default != nil {
value = *_default
}
switch input_value := inputs.(type) {
case T:
value = input_value
case *T:
value = *input_value
case []byte:
value = any(input_value).(T)
}
return value
}
func GetPointer[T any](value T) *T {
return &value
}
func Trim(_string string) string {
return strings.Trim(_string, " \r\t\n")
}
func GetStrings(inputs any) []string {
var _strings []string = []string{}
switch value := inputs.(type) {
case string:
_strings = append(_strings, value)
case []string:
_strings = append(_strings, value...)
case []any:
for _, subvalue := range value {
_strings = append(_strings, GetStrings(subvalue)...)
}
}
return _strings
}
func GetStringsFilled(inputs any) []string {
var _strings []string = []string{}
switch value := inputs.(type) {
case string:
value = Trim(value)
if value != "" {
_strings = append(_strings, value)
}
case []string:
for _, subvalue := range value {
_strings = append(_strings, GetStringsFilled(subvalue)...)
}
case []any:
for _, subvalue := range value {
_strings = append(_strings, GetStringsFilled(subvalue)...)
}
}
return _strings
}
func GetKeys(inputs any) []string {
var keys []string = []string{}
switch value := inputs.(type) {
case string:
if IsKey(value) {
keys = append(keys, value)
}
case []string:
for _, subvalue := range value {
if IsKey(subvalue) && !slices.Contains(keys, subvalue) {
keys = append(keys, subvalue)
}
}
case []any:
for _, value := range value {
for _, subvalue := range GetKeys(value) {
if !slices.Contains(keys, subvalue) {
keys = append(keys, GetKeys(subvalue)...)
}
}
}
}
return keys
}
func GetPascalKeys(inputs any) []string {
var keys []string
switch value := inputs.(type) {
case string:
if IsPascalKey(value) {
keys = append(keys, value)
}
case []string:
for _, subvalue := range value {
if IsPascalKey(subvalue) && !slices.Contains(keys, subvalue) {
keys = append(keys, subvalue)
}
}
case []any:
for _, value := range value {
for _, subvalue := range GetPascalKeys(value) {
if !slices.Contains(keys, subvalue) {
keys = append(keys, GetPascalKeys(subvalue)...)
}
}
}
}
return keys
}
func get_value[T any](keys []string, inputs any, _default *T) (T, bool) {
var response T
var ok bool = false
if _default != nil {
response = *_default
}
switch block := inputs.(type) {
case map[string]any:
for _, key := range keys {
value, subok := block[key]
if subok {
response = Get[T](value, nil)
ok = true
break
}
}
case []any:
for _, subinputs := range block {
value, subok := get_value[T](keys, subinputs, nil)
if subok {
response = value
ok = true
break
}
}
}
return response, ok
}
func GetValue[T any](keys any, inputs any, _default *T) T {
response, _ := get_value(GetKeys(keys), inputs, _default)
return response
}
func AppendInDictionary(dictionary *map[string]any, new_dictionary map[string]any, overwrite bool) {
for key, value := range new_dictionary {
_, exists := (*dictionary)[key]
if overwrite || !exists {
(*dictionary)[key] = value
}
}
}
func GetDictionary(inputs any, overwrite bool) map[string]any {
var dictionary map[string]any = map[string]any{}
switch block := inputs.(type) {
case map[string]any:
AppendInDictionary(&dictionary, block, overwrite)
case []any:
for _, subinputs := range block {
AppendInDictionary(&dictionary, GetDictionary(subinputs, overwrite), overwrite)
}
}
return dictionary
}
func IterSeqToSlice[T any](iterator iter.Seq[T]) []T {
var slice []T
for item := range iterator {
slice = append(slice, item)
}
return slice
}
func GetMapKeys(value any) []string {
switch dictionary := value.(type) {
case map[string]any:
return IterSeqToSlice(maps.Keys(dictionary))
}
return []string{}
}
func ToString(data any) string {
if data == nil {
return "null"
}
switch value := data.(type) {
case string:
return value
case int:
return strconv.Itoa(value)
case int8:
return strconv.FormatInt(int64(value), 10)
case int16:
return strconv.FormatInt(int64(value), 10)
case int32:
return strconv.FormatInt(int64(value), 10)
case int64:
return strconv.FormatInt(value, 10)
case uint:
return strconv.FormatUint(uint64(value), 10)
case uint8:
return strconv.FormatUint(uint64(value), 10)
case uint16:
return strconv.FormatUint(uint64(value), 10)
case uint32:
return strconv.FormatUint(uint64(value), 10)
case uint64:
return strconv.FormatUint(value, 10)
case float32:
return strconv.FormatFloat(float64(value), 'f', -1, 32)
case float64:
return strconv.FormatFloat(value, 'f', -1, 64)
case bool:
return strconv.FormatBool(value)
}
json, error := json.Marshal(data)
if error != nil {
return "[object]"
}
return string(json)
}
func StringVariables(_string string, variables any, _default *any) string {
var dictionary map[string]any = GetDictionary(variables, false)
var has_default bool = _default != nil
var default_processed string = Get[string](_default, nil)
return Patterns.Replace(_string, Patterns.RE_STRING_VARIABLES, func(match PatternMatch) string {
if value, exists := dictionary[match.Groups[1]]; exists {
return ToString(value)
}
if has_default {
return default_processed
}
return match.Groups[0]
})
}
func ToSliceAny[T any](data []T) []any {
var slice_any []any = []any{}
for _, value := range data {
slice_any = append(slice_any, value)
}
return slice_any
}
func ToMapAny[T any](data map[string]T) map[string]any {
var map_any map[string]any = map[string]any{}
for key, value := range data {
map_any[key] = value
}
return map_any
}
func JSONEncode(data any) string {
json, _ := json.Marshal(data)
return string(json)
}
func GetArray(data any) []any {
switch value := data.(type) {
case []any:
return value
}
return []any{data}
}
func GetArgument[T any](arguments []any, i int, _default *T) *T {
if arguments != nil && i >= 0 && i < len(arguments) {
switch value := arguments[i].(type) {
case *T:
return value
case T:
return &value
}
}
return _default
}
func Base64Encode(_string string) string {
return base64.StdEncoding.EncodeToString([]byte(_string))
}
func Base64Decode(_string string) string {
data, error := base64.StdEncoding.DecodeString(_string)
if error != nil {
return ""
}
return string(data)
}
func VariablesEncode(value any) string {
return Base64Encode(JSONEncode(value))
}

3
Go/go.mod Normal file
View File

@ -0,0 +1,3 @@
module AnP
go 1.24.0

74
HTML/AnP.wmarkdown.html Normal file
View File

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="{language}">
<head>
<title data-i18n="{title_i18n}">{title_text}</title>
<meta http-equiv="content-type" content="text/html;charset={charset}" />
<meta charset="{charset}" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="xdoc:project" content="{project}" />
<meta name="xdoc:link" content="{web}" />
<meta name="xdoc:git" content="{git}" />
<meta name="xdoc:author" content="{authors}" />
<meta name="xdoc:since" content="{since}" />
<meta name="xdoc:version" content="{version}" />
<meta name="xdoc:access" content="public" /><!-- [[metas]] -->
<style data-type="text/css;charset=utf-8" data-language="CSS1.2" data-rel="stylesheet" charset="utf-8">
html,body{
height : 100%;
margin : 0em;
}
</style>
<link type="text/css;charset=utf-8" data-language="CSS3" rel="stylesheet" href="/css/FontAwesome-6.7.2.css" data-crossorigin="anonymous" charset="utf-8" />
<link type="text/css;charset=utf-8" data-language="CSS3" rel="stylesheet" href="https://wmarkdown.k3y.pw/css/WMarkDown.icons.FontAwesome.css" data-crossorigin="anonymous" charset="utf-8" />
<link type="text/css;charset=utf-8" data-language="SASS/CSS3" rel="stylesheet" href="https://wmarkdown.k3y.pw/scss/WMarkDown.css" data-scss="https://wmarkdown.k3y.pw/scss/WMarkDown.scss" data-css-map="https://wmarkdown.k3y.pw/scss/WMarkDown.css.map" data-crossorigin="anonymous" charset="utf-8" />
<link type="text/css;charset=utf-8" data-language="SASS/CSS3" rel="stylesheet" href="/scss/AnP.css" data-scss="/scss/AnP.scss" data-css-map="/scss/AnP.css.map" data-crossorigin="anonymous" charset="utf-8" />
<script data-type="text/javascript;charset=utf-8" data-language="ECMAScript 2015" src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/11.5.0/mermaid.min.js" data-crossorigin="anonymous" charset="utf-8"></script>
<script data-type="text/javascript;charset=utf-8" data-language="ECMAScript 2015" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.min.js" data-crossorigin="anonymous" charset="utf-8"></script>
<script type="module" data-type="text/javascript;charset=utf-8" data-language="ECMAScript 2015" charset="utf-8">
"use strict";
import {AnP} from "/ecma/Application/AnP.ecma.js";
import {Utils} from "/ecma/Utils/Utils.ecma.js";
import {WMarkDown} from "https://wmarkdown.k3y.pw/ecma/WMarkDown.ecma.js";
/** @type {string} */
const domain = /^[^\:]+\:\/{2}[^\/]+\.([lg]ocal|anprm(\.[lg]ocal)?)\/?/i.test(window.location.href) ? "local" : "k3y.pw";
/** @type {WMarkDown} */
const wmarkdown = new WMarkDown({dictionary : {dictionaries}.map(link => Utils.string_variables(link, {
domain : domain
}))}),
/** @type {AnP} */
anp = new AnP({
debug_mode : true,
position : ".anp"
});
</script>
</head>
<body class="{class}">
<header>
<h1 title="{project}">
<a href="{web}" target="_blank">
<span class="image" data-status="unloaded" data-sources="{logo_sources}" data-i="0">
<img />
<span></span>
</span>
<span class="text">{project}</span>
</a>
</h1>
{menu_html}
</header>
<main>{contents}</main>
<footer data-zoom-maximum="1">
{licenses_html}
</footer>
</body>
</html>

View File

@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="{language}">
<head>
<title data-i18n="{title_i18n}">{title_text}</title>
<meta http-equiv="content-type" content="text/html;charset={charset}" />
<meta charset="{charset}" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="xdoc:project" content="{project}" />
<meta name="xdoc:link" content="{web}" />
<meta name="xdoc:git" content="{git}" />
<meta name="xdoc:author" content="{authors}" />
<meta name="xdoc:since" content="{since}" />
<meta name="xdoc:version" content="{version}" />
<meta name="xdoc:access" content="public" /><!-- [[metas]] -->
<style data-type="text/css;charset=utf-8" data-language="CSS1.2" data-rel="stylesheet" charset="utf-8">
html,body{
height : 100%;
margin : 0em;
}
</style>
<script type="module" data-type="text/javascript;charset=utf-8" data-language="ECMAScript 2015" charset="utf-8">
"use strict";
import {AnPScriptsLoader} from "https://anp.k3y.pw/ecma/AnPScriptsLoader.ecma.js";
import {WMarkDown} from "https://wmarkdown.k3y.pw/ecma/WMarkDown.ecma.js";
import {AnP} from "https://anp.k3y.pw/ecma/Application/AnP.ecma.js";
import {Utils} from "https://anp.k3y.pw/ecma/Utils/Utils.ecma.js";
/** @type {string} */
const domain = /^[^\:]+\:\/{2}[^\/]+\.([lg]ocal|anprm(\.[lg]ocal)?)\/?/i.test(window.location.href) ? "local" : "k3y.pw";
new AnPScriptsLoader({
domain : domain,
mode : "wmarkdown",
// styles : [[], [
// "https://anp.{domain}/scss/AnPWeb.scss"
// ]]
styles : {styles},
scripts : {scripts}
}, () => {
/** @type {WMarkDown} */
const wmarkdown = new WMarkDown({dictionary : {dictionaries}.map(link => Utils.string_variables(link, {
domain : domain
}))}),
/** @type {AnP} */
anp = new AnP({
globals : {anp_root : "https://anp." + domain},
callback : () => {
anp.base.set(".{class}");
}
});
});
</script>
</head>
<body class="{class}">
<header>
<h1 data-i18n="{snake}" data-i18n-without="true" title="{{{snake}}}">
<a href="{web}" target="_blank">
<span class="image">
<img src="{logo}" />
<span style="background-image:url('{logo}');"></span>
</span>
<span data-i18n="{snake}">{{{snake}}}</span>
</a>
</h1>
<nav class="main-menu">
<ul>{menu_html}</ul>
</nav>
</header>
<main>{contents}</main>
<footer data-zoom-maximum="1">
<span class="licenses">{licenses_html}</span>
</footer>
</body>
</html>

View File

@ -0,0 +1,70 @@
@font-face {
font-family : "FA6FB";
font-style : normal;
font-weight : 400;
font-display : block;
src : url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-brands-400.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-brands-400.ttf") format("truetype");
}
@font-face {
font-family : "FA6FR";
font-style : normal;
font-weight : 400;
font-display : block;
src : url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-regular-400.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-regular-400.ttf") format("truetype");
}
@font-face {
font-family : "FA6FS";
font-style : normal;
font-weight : 900;
font-display : block;
src : url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-solid-900.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-solid-900.ttf") format("truetype");
}
@font-face {
font-family : "FA5FB";
font-display : block;
font-weight : 400;
src : url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-brands-400.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-brands-400.ttf") format("truetype");
}
@font-face {
font-family : "FA5FS";
font-display : block;
font-weight : 900;
src : url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-solid-900.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-solid-900.ttf") format("truetype");
}
@font-face {
font-family : "FA5FR";
font-display : block;
font-weight : 400;
src : url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-regular-400.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-regular-400.ttf") format("truetype");
}
@font-face {
font-family : "FAS";
font-display : block;
src : url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-solid-900.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-solid-900.ttf") format("truetype");
}
@font-face {
font-family : "FAB";
font-display : block;
src : url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-brands-400.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-brands-400.ttf") format("truetype");
}
@font-face {
font-family : "FAR";
font-display : block;
src : url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-regular-400.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-regular-400.ttf") format("truetype");
unicode-range : U+F003,U+F006,U+F014,U+F016-F017,U+F01A-F01B,U+F01D,U+F022,U+F03E,U+F044,U+F046,U+F05C-F05D,U+F06E,U+F070,U+F087-F088,U+F08A,U+F094,U+F096-F097,U+F09D,U+F0A0,U+F0A2,U+F0A4-F0A7,U+F0C5,U+F0C7,U+F0E5-F0E6,U+F0EB,U+F0F6-F0F8,U+F10C,U+F114-F115,U+F118-F11A,U+F11C-F11D,U+F133,U+F147,U+F14E,U+F150-F152,U+F185-F186,U+F18E,U+F190-F192,U+F196,U+F1C1-F1C9,U+F1D9,U+F1DB,U+F1E3,U+F1EA,U+F1F7,U+F1F9,U+F20A,U+F247-F248,U+F24A,U+F24D,U+F255-F25B,U+F25D,U+F271-F274,U+F278,U+F27B,U+F28C,U+F28E,U+F29C,U+F2B5,U+F2B7,U+F2BA,U+F2BC,U+F2BE,U+F2C0-F2C1,U+F2C3,U+F2D0,U+F2D2,U+F2D4,U+F2DC;
}
@font-face {
font-family : "FAC";
font-display : block;
src : url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-v4compatibility.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-v4compatibility.ttf") format("truetype");
unicode-range : U+F041,U+F047,U+F065-F066,U+F07D-F07E,U+F080,U+F08B,U+F08E,U+F090,U+F09A,U+F0AC,U+F0AE,U+F0B2,U+F0D0,U+F0D6,U+F0E4,U+F0EC,U+F10A-F10B,U+F123,U+F13E,U+F148-F149,U+F14C,U+F156,U+F15E,U+F160-F161,U+F163,U+F175-F178,U+F195,U+F1F8,U+F219,U+F27A;
}

View File

@ -0,0 +1,39 @@
```wmd-options
language = es
title_i18n = anp_title_description
title_text = Descripción - AnP
since = 20250417
```
<!-- [[WMD]] -->
AnP es un proyecto desarrollado por KyMAN para facilitar el desarrollo de Páginas Web y Aplicaciones Web. En este caso nos encontramos con su versión Lite, es decir, una versión ultraligera en la cual se centró. No es más que un pequeño Framework con las herramientas básicas necesarias que KyMAN vio necesarias para una producción óptima, sencilla y básica. El objetivo de este proyecto es facilitar en lo máximo posible la capacidad de crear servicios web, independientemente de ser Páginas Web con su SEO y otros mecanismos importantes en la difusión de información; así como de Aplicaciones Web y su gestión de los datos e información.
> [[!! IMPORTANTE]] Es de vital importancia que este proyecto, pese a tener un servicio de servidor Web, éste no consta de las herramientas de seguridad pues está pensado para ser implementado detrás de un Proxy, independientemente de que éste sea un Nginx, Apache, IIS, Tomcat, etc. Por lo que el uso directo del servicio de servidor Web de este proyecto sólo sea usado en entorno local específicamente, independientemente de la finalidad o uso del mismo.
La lógica de funcionamiento de este proyecto es muy básico y sencillo. Se basa en un flujo de información cara lo que es cada interactuación con el usuario, independizando lo que viene siendo el lado cliente, del servidor de los datos, siendo ésto último posible cuando hablamos de un motor de datos como los SQL. Su flujo es el siguiente:
```mermaid
flowchart TD
C[Cliente]
P([Proxy])
S[Servidor]
DB["Bases de datos"]
C -.-> P
P -.-> S
C -->|"hace petición a"| S
S -->|"Consulta a"| DB
DB -->|"devuelve datos a"| S
S -->|"procesa y responde a"| C
S -.-> P
P -.-> C
```
> [!#] En el esquema vemos el paso intermedio del Proxy con el cual no se enteraría el usuario final pues hace una función intermedia en la petición entre el cliente y el servidor para garantizar en la medida de lo posible una conectividad flexible, múltiple, dinámica y segura.
Esto no quita que el servidor pueda estar conformado en distintas capas tales como pueden ser un Servidor Web y servicios como APIs, WebServices, etc. Incluso puede estar conformado de servicios HTTP y WS (Web Sockets).
<!-- [[WMD]] -->

12
Public/doc/es/index.w.md Normal file
View File

@ -0,0 +1,12 @@
```wmd-options
language = es
title_i18n = anp_title
title_text = AnP
since = 20250417
```
<!-- [[WMD]] -->
[[include description.w.md]]
<!-- [[WMD]] -->

View File

@ -0,0 +1,39 @@
```wmd-options
language = es
title_i18n = anp_title_targets
title_text = Objectivos - AnP
since = 20250417
```
<!-- [[WMD]] -->
AnP es un proyecto desarrollado por KyMAN para facilitar el desarrollo de Páginas Web y Aplicaciones Web. En este caso nos encontramos con su versión Lite, es decir, una versión ultraligera en la cual se centró. No es más que un pequeño Framework con las herramientas básicas necesarias que KyMAN vio necesarias para una producción óptima, sencilla y básica. El objetivo de este proyecto es facilitar en lo máximo posible la capacidad de crear servicios web, independientemente de ser Páginas Web con su SEO y otros mecanismos importantes en la difusión de información; así como de Aplicaciones Web y su gestión de los datos e información.
> [[!! IMPORTANTE]] Es de vital importancia que este proyecto, pese a tener un servicio de servidor Web, éste no consta de las herramientas de seguridad pues está pensado para ser implementado detrás de un Proxy, independientemente de que éste sea un Nginx, Apache, IIS, Tomcat, etc. Por lo que el uso directo del servicio de servidor Web de este proyecto sólo sea usado en entorno local específicamente, independientemente de la finalidad o uso del mismo.
La lógica de funcionamiento de este proyecto es muy básico y sencillo. Se basa en un flujo de información cara lo que es cada interactuación con el usuario, independizando lo que viene siendo el lado cliente, del servidor de los datos, siendo ésto último posible cuando hablamos de un motor de datos como los SQL. Su flujo es el siguiente:
```mermaid
flowchart TD
C[Cliente]
P([Proxy])
S[Servidor]
DB["Bases de datos"]
C -.-> P
P -.-> S
C -->|"hace petición a"| S
S -->|"Consulta a"| DB
DB -->|"devuelve datos a"| S
S -->|"procesa y responde a"| C
S -.-> P
P -.-> C
```
> [!#] En el esquema vemos el paso intermedio del Proxy con el cual no se enteraría el usuario final pues hace una función intermedia en la petición entre el cliente y el servidor para garantizar en la medida de lo posible una conectividad flexible, múltiple, dinámica y segura.
Esto no quita que el servidor pueda estar conformado en distintas capas tales como pueden ser un Servidor Web y servicios como APIs, WebServices, etc. Incluso puede estar conformado de servicios HTTP y WS (Web Sockets).
<!-- [[WMD]] -->

View File

@ -0,0 +1,135 @@
"use strict";
/**
* @class
* @constructor
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
* @returns {void}
* @access public
*/
export const AnPLoader = (function(){
/**
* @constructs AnPLoader
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
* @returns {void}
* @access private
*/
const AnPLoader = function(inputs){
/** @type {AnPLoader} */
const self = this;
/**
* @returns {void}
* @access private
*/
const constructor = () => {
/** @type {Array.<any>} */
const scripts = AnPLoader.get_list_strings(AnPLoader.get_value(["script", "scripts"], inputs)),
/** @type {Array.<any>} */
styles = AnPLoader.get_list_strings.apply(AnPLoader.get_value(["style", "styles"], inputs));
};
constructor();
};
/** @type {string} */
AnPLoader.domain = /^[^\:]+\:\/{2}[^\/]+\.([lg]ocal|anprm(\.[lg]ocal)?)\/?/i.test(window.location.href) ? "local" : "k3y.pw";
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
AnPLoader.is_string = item => typeof item == "string";
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
AnPLoader.is_key = item => item && AnPLoader.is_string(item) && /^[a-z0-9_]+$/i.test(item);
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
AnPLoader.is_array = item => item instanceof Array;
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
AnPLoader.is_dictionary = item => item && item.constructor == Object;
/**
* @param {?any} item
* @returns {Array.<any|null>}
* @access public
* @static
*/
AnPLoader.get_array = item => AnPLoader.is_array(item) ? item : [item];
/**
* @param {!(string|Array.<string>)} keys
* @returns {Array.<string>}
* @access public
* @static
*/
AnPLoader.get_keys = keys => AnPLoader.get_array(keys).filter((key, i, array) => AnPLoader.is_key(key) && array.indexOf(key) == i);
/**
* @param {!(string|Array.<string>)} keys
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
* @param {?any} [_default = null]
* @returns {any|null|undefined}
* @access public
* @static
*/
AnPLoader.get_value = (keys, inputs, _default = null) => {
if(AnPLoader.is_array(inputs)){
for(let i = 0, l = inputs.length; i < l; i ++){
/** @type {any|null|undefined} */
const value = AnPLoader.get_value(keys, inputs[i], undefined)
if(value !== undefined)
return value;
};
}else if(Check.is_dictionary(inputs)){
for(let i = 0, l = (keys = AnPLoader.get_keys(keys)).length; i < l; i ++)
if(inputs[keys[i]] !== undefined)
return inputs[keys[i]];
};
return _default;
};
/**
* @param {!(string|Array.<any|null>)} items
* @returns {Array.<any>}
* @access public
* @static
*/
AnPLoader.get_list_strings = items => {
if(items){
if(Check.is_string(items))
return [items];
if(Check.is_array(items))
return items.filter(item => Check.is_string(item) || Check.is_array(item)).map(item => Check.is_array(item) ? AnPLoader.get_list_strings(item) : item);
};
return [];
};
return AnPLoader;
})();

View File

@ -0,0 +1,291 @@
"use strict";
import {SettingsManager} from "../Managers/SettingsManager.ecma.js";
import {I18NManager} from "../Managers/I18NManager.ecma.js";
import {URLPathDriver} from "../Drivers/URLPathDriver.ecma.js";
import {ThreadsManager} from "../Managers/ThreadsManager.ecma.js";
import {Attributes} from "./Attributes.ecma.js";
import {Components} from "./Components.ecma.js";
import {Check} from "../Utils/Check.ecma.js";
import {Utils} from "../Utils/Utils.ecma.js";
import {Patterns} from "../Utils/Patterns.ecma.js";
/**
* @callback anp_preload_callback
* @param {?HTMLElement} item
* @param {!boolean} asynchronous
* @param {!boolean} ok
* @returns {void}
*/
/**
* @callback anp_settings_get_callback
* @param {!(string|Array.<string>)} keys
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {?any} [_default = null]
* @returns {any|null}
*/
/**
* @callback anp_start_callback
* @param {!boolean} ok
* @returns {boolean}
*/
/**
* @callback anp_autostart_callback
* @param {!AnP} anp
* @returns {void}
*/
/**
* @class
* @constructor
* @param {?(Object.<string, any|null>|Array.<any|null>)} inputs
* @param {?anp_autostart_callback} [autostart_callback = null]
* @returns {void}
* @access public
*/
export const AnP = (function(){
/**
* @constructs AnP
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {?anp_autostart_callback} [autostart_callback = null]
* @returns {void}
* @access private
*/
const AnP = function(inputs = null, autostart_callback = null){
/** @type {AnP} */
const self = this,
/** @type {Array.<string>} */
random_chains = [],
// http://detectmobilebrowsers.com/
/** @type {boolean} */
is_mobile = ((a) => (
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) ||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))
))(navigator.userAgent || navigator.vendor || window.opera),
// https://stackoverflow.com/questions/56393880/how-do-i-detect-dark-mode-using-javascript#answer-57795495
/** @type {boolean} */
is_dark_mode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
/** @type {boolean} */
let started = false,
/** @type {number} */
preload_timeout = 2000,
/** @type {string} */
chain_alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
/** @type {number} */
chain_length = 11;
/** @type {SettingsManager} */
this.settings = null;
/** @type {I18NManager} */
this.i18n = null;
/** @type {URLPathDriver} */
this.request = null;
/** @type {ThreadsManager} */
this.threads = null;
/** @type {Attributes} */
this.attributes = this.attr = null;
/** @type {Components} */
this.components = this.comp = null;
/** @type {string|null} */
this.object_name = null;
/** @type {HTMLElement|Document} */
this.item_self = document;
/** @type {string|null} */
this.hash_self = null;
/**
* @returns {void}
* @access private
*/
const set_basics = () => {
/** @type {anp_settings_get_callback} */
const get = self.settings ? self.settings.get : Utils.get_value;
preload_timeout = get(["preload_timeout", "timeout"], inputs, preload_timeout);
chain_alphabet = get(["random_chain_alphabet", "chain_alphabet", "alphabet"], inputs, chain_alphabet);
chain_length = get(["random_chain_length", "chain_length", "length"], inputs, chain_length);
};
/**
* @returns {void}
* @access private
*/
const execute_constructor = () => {
set_basics();
self.settings = new SettingsManager(self, inputs);
self.object_name = self.settings.get("object_name");
set_basics();
self.i18n = new I18NManager(self);
self.request = new URLPathDriver(self);
self.threads = new ThreadsManager(self);
self.attributes = self.attr = new Attributes(self);
self.components = self.comp = new Components(self);
set_basics();
self.settings.get("autostart") && self.start();
}
/**
* @returns {void}
* @access private
*/
const constructor = () => {
if(Utils.get_value("debug_mode")){
try{
execute_constructor();
}catch(exception){
console.error(exception);
};
}else
execute_constructor();
};
/**
* @param {?anp_start_callback} callback
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
/** @type {!anp_start_callback} */
const end = ok => {
Utils.execute(callback, ok);
ok && Utils.execute(autostart_callback, self);
return ok;
};
if(started)
return end(false);
started = true;
Utils.execute_items([
"settings", "i18n", "request", "threads", "attributes", "components"
], (key, next) => {
self[key].start(ok => {
next();
});
}, () => {
end(true);
});
return true;
};
/**
* @param {!(string|HTMLElement)} selector
* @param {!anp_preload_callback} callback
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @returns {void}
* @access public
*/
this.preload = (selector, callback, inputs = null) => {
if(!Check.is_function(callback))
return;
if(Check.is_html_item(selector)){
callback(selector, false, true);
return;
};
if(Check.is_string(selector)){
/** @type {HTMLElement|null} */
let item;
try{
if(item = self.item_self.querySelector(selector)){
callback(item, false, true);
return;
};
}catch(exception){
callback(null, false, false);
return;
};
/** @type {number} */
const date = Date.now(),
/** @type {number} */
timeout = Utils.get_value(["preload_timeout", "timeout"], inputs, preload_timeout);
self.threads.add(thread => {
if(item = self.item_self.querySelector(selector)){
self.threads.remove(thread);
callback(item, true, true);
}else if(Date.now() - date > timeout){
self.threads.remove(thread);
callback(null, true, false);
};
}, {
/** @type {boolean} */
bucle : true
});
}else
callback(null, false, false);
};
/**
* @returns {string}
* @access public
*/
this.random_chain = () => {
/** @type {string} */
let chain;
/** @type {number} */
const l = chain_alphabet.length;
do{
chain = "";
while((chain += chain_alphabet[Math.random() * l >> 0]).length < chain_length);
}while(
random_chains.includes(chain) ||
!Patterns.RE_RIGHT_RANDOM_CHAIN.test(chain) ||
document.querySelector("." + chain + ",#" + chain + ",[name=" + chain + "]")
);
random_chains.push(chain);
return chain;
};
/**
* @param {!string} chain
* @returns {void}
* @access public
*/
this.remove_random_chain = chain => {
random_chains.includes(chain) &&
random_chains.splice(random_chains.indexOf(chain), 1);
};
/**
* @returns {boolean}
* @access public
*/
this.is_mobile = () => is_mobile;
/**
* @returns {boolean}
* @access public
*/
this.is_dark_mode = () => is_dark_mode;
constructor();
};
return AnP
})();

View File

@ -0,0 +1,260 @@
"use strict";
import {Check} from "../Utils/Check.ecma.js";
import {Utils} from "../Utils/Utils.ecma.js";
import {Patterns} from "../Utils/Patterns.ecma.js";
import {EventsManager} from "../Managers/EventsManager.ecma.js";
/**
* @typedef {import("./AnP.ecma.js").AnP} AnP
*/
/**
* @callback anp_attributes_name_callback
* @param {!string} name
* @param {?string} value
* @returns {void}
*/
/**
* @callback anp_attributes_remove_callback
* @param {!string} name
* @returns {void}
*/
/**
* @callback anp_attributes_load_callback
* @param {!HTMLElement} item
* @returns {void}
*/
/**
* @class
* @constructor
* @param {!AnP} anp
* @returns {void}
* @access public
*/
export const Attributes = (function(){
/**
* @constructs Attributes
* @param {!AnP} anp
* @returns {void}
* @access private
*/
const Attributes = function(anp){
/** @type {Attributes} */
const self = this,
/** @type {Array.<string>} */
without_values = [
"disabled", "readonly"
],
/** @type {Array.<string>} */
normals = [
"src", "class", "title", "id", "alt", "target", "href", "style", "lang",
"type", "name", "placeholder", "min", "max", "value", "step", "disabled",
"readonly"
];
/** @type {boolean} */
let started = false;
/**
* @returns {void}
* @access private
*/
const constructor = () => {};
/**
* @param {?anp_start_callback} callback
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
/** @type {!anp_start_callback} */
const end = ok => {
Utils.execute(callback, ok);
return ok;
};
return end(started ? false : started = true);
};
/**
* @param {!(Object.<string, any|null>|Array.<any|null>)} attributes
* @param {!Array.<string>} included
* @param {!Array.<string>} excluded
* @param {!anp_attributes_name_callback} callback
* @param {!Object.<string, any|null>} parameters
* @returns {void}
* @access private
*/
const process_fixed = (attributes, included, excluded, callback, parameters) => {
if(Check.is_dictionary(attributes)){
/** @type {boolean} */
const has_events_loader = !!parameters.on_load_for_events;
for(let name in attributes){
/** @type {any|null} */
const value = attributes[name],
/** @type {string} */
pascal = name.replace(Patterns.RE_ATTRIBUTE_BAD_SET_CHARACTERS, "-").toLowerCase();
if(
(!included.length || included.includes(pascal)) &&
(!excluded.length || !excluded.includes(pascal))
){
if(pascal.slice(0, 2) == "on" && Check.is_function(value)){
parameters.on_load_for_events || (parameters.on_load_for_events = new EventsManager());
if(name == "on_load_execute")
parameters.on_load_execute = value;
else
parameters.on_load_for_events.add(item => {
item.addEventListener(pascal.replace(Patterns.RE_CLEAN_EVENT_NAME, ""), event => value(item, event));
});
continue;
};
callback(
((
normals.includes(pascal) ||
["data-", "aria-"].includes(pascal.slice(0, 5))
) ? "" : "data-") + pascal,
(
without_values.includes(pascal) ? null :
Check.is_bool(value) ? value ? "true" : "false" :
Check.is_json_object(value) ? Utils.variables_encode(value) :
"" + value)
);
};
};
if(!has_events_loader && parameters.on_load_for_events){
/** @type {string} */
const chain = anp.random_chain();
callback("data-anp-events-loader", chain);
anp.preload("[data-anp-events-loader=" + chain + "]", (item, asynchronous, ok) => {
anp.remove_random_chain(chain);
if(ok){
item.removeAttribute("data-anp-events-loader");
parameters.on_load_for_events.execute(item);
parameters.on_load_execute && parameters.on_load_execute(item);
};
});
};
}else if(Check.is_array(attributes))
attributes.forEach(group => {
process_fixed(group, included, excluded, callback, parameters);
});
};
/**
* @param {!(Object.<string, any|null>|Array.<any|null>)} attributes
* @param {?(string|Array.<string>)} included
* @param {?(string|Array.<string>)} excluded
* @param {!anp_attributes_name_callback} callback
* @returns {void}
* @access private
*/
const process = (attributes, included, excluded, callback) => {
process_fixed(attributes, Utils.get_pascal_keys(included), Utils.get_pascal_keys(excluded), callback, {});
};
/**
* @param {!(Object.<string, any|null>|Array.<any|null>)} attributes
* @param {?(string|Array.<string>)} [included = null]
* @param {?(string|Array.<string>)} [excluded = null]
* @returns {string}
* @access public
*/
this.create = (attributes, included = null, excluded = null) => {
/** @type {string} */
let html = ``;
process(attributes, included, excluded, (name, value) => {
html += ` ` + name + (value === null ? `` : `="` + value + `"`)
});
return html;
};
/**
* @param {!(string|HTMLElement)} item
* @param {!(Object.<string, any|null>|Array.<any|null>)} attributes
* @param {?(string|Array.<string>)} [included = null]
* @param {?(string|Array.<string>)} [excluded = null]
* @returns {void}
* @access public
*/
this.set = (item, attributes, included, excluded) => {
anp.preload(item, (item, asynchronous, ok) => {
ok && process(attributes, included, excluded, (name, value) => {
item.setAttribute(name, value);
});
});
};
constructor();
};
/**
* @param {!(string|Array.<string>)} classes
* @returns {Array.<string>}
* @access public
* @static
*/
Attributes.get_classes = classes => Utils.get_pascal_keys(
Check.is_array(classes) ? classes :
Check.is_string(classes) ? classes.split(Patterns.RE_SPACES) :
[]);
/**
* @param {!(string|Array.<string>)} classes
* @param {?(Object.<string, any|null>|Array.<any|null>)} attributes
* @returns {Array.<string>}
* @access public
* @static
*/
Attributes.join_classes = (...sets) => Utils.get_pascal_keys(
sets.reduce((set, new_classes) => set.concat(Attributes.get_classes(new_classes)), [])
).join(" ");
/**
* @param {!(Object.<string, any|null>|HTMLElement)} item
* @param {!(string|Array.<string>)} names
* @returns {Object.<string, any|null>|void}
* @access public
* @static
*/
Attributes.remove = (item, names) => {
/** @type {anp_attributes_remove_callback|null} */
var action = (
Check.is_dictionary(item) ? name => {
if(item[name] !== undefined)
delete item[name];
} :
Check.is_html_item(item) ? name => {
item.hasAttribute(name) &&
item.removeAttribute(name)
} :
null);
action && Utils.get_pascal_keys(names).forEach(action);
if(Check.is_dictionary(item))
return item;
};
return Attributes;
})();

View File

@ -0,0 +1,392 @@
"use strict";
import {Utils} from "../Utils/Utils.ecma.js";
import {Check} from "../Utils/Check.ecma.js";
import {Attributes} from "./Attributes.ecma.js";
import {LicensesComponent} from "../Components/LicensesComponent.ecma.js";
import {BaseComponent} from "../Components/BaseComponent.ecma.js";
/**
* @typedef {import("./AnP.ecma.js").AnP} AnP
* @typedef {import("../Models/ThreadModel.ecma.js").ThreadModel} ThreadModel
*/
/**
* @callback anp_event_callback
* @param {!Event} event
* @returns {any|null|void}
*/
/**
* @class
* @constructor
* @param {!AnP} anp
* @returns {void}
* @access public
*/
export const Components = (function(){
/**
* @constructs Components
* @param {!AnP} anp
* @returns {void}
* @access private
*/
const Components = function(anp){
/** @type {Components} */
const self = this;
/** @type {boolean} */
let started = false,
/** @type {ThreadModel|null} */
thread = null;
/**
* @returns {void}
* @access private
*/
const constructor = () => {
[
["licenses", LicensesComponent],
["base", BaseComponent]
].forEach(([name, Class]) => {
if(Class){
self[name + "_component"] = new Class(anp);
Check.is_function(self[name + "_component"].build) &&
(self[name] = self[name + "_component"].build);
};
});
};
/**
* @param {!ThreadModel} thread
* @returns {void}
* @access private
*/
const analyzer = thread => {
if(anp.item_self == document)
return;
anp.item_self.querySelectorAll(".image[data-status=unloaded]").forEach(image => {
image.setAttribute("data-status", "loading");
image.querySelector("img").setAttribute("src", Utils.variables_decode(image.getAttribute("data-sources"))[0]);
});
};
/**
* @param {?anp_start_callback} callback
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
/** @type {!anp_start_callback} */
const end = ok => {
Utils.execute(callback, ok);
return ok;
};
if(started)
return end(false);
started = true;
thread = anp.threads.add(analyzer, {
bucle : true,
timer : 100
});
Utils.execute_items([
"licenses", "base"
], (key, next) => {
self[key + "_component"].start(ok => {
next();
});
}, () => {
end(true);
});
return true;
};
/**
* @param {!(Array.<any|null>)} childs
* @returns {Array.<Array.<string, Object.<string, any|null>|Array.<any|null>|null>, Array.<Array.<any|null>>|null>>}
* @access private
*/
const set_childs = childs => Check.is_string(childs[0]) ? [childs] : childs;
/**
* @param {...Array.<string, Object.<string, any|null>|Array.<any|null>|null>, Array.<Array.<any|null>>|null} items
* @returns {string}
* @access public
*/
this.set = (...items) => items.reduce((html, [tag, attributes, childs]) => {
const subitem = (
self[tag] && (!attributes || !attributes.built) ? self[tag](...Utils.get_array(attributes)) :
`<` + tag + anp.attributes.create(attributes, null, "built") + `>` + (
Check.is_array(childs) && childs.length ? self.set(...set_childs(childs)) :
Check.is_null_or_undefined(childs) ? "" :
"" + childs) + `</` + tag + `>`);
return html + (Check.is_array(subitem) ? self.set(...[subitem]) : subitem);
}, ``);
/**
* @param {!(string|HTMLElement)} item
* @param {...Array.<string, Object.<string, any|null>|Array.<any|null>|null>, Array.<Array.<any|null>>|null>} items
* @returns {string}
* @access public
*/
this.set_to = (item, ...items) => {
anp.preload(item, (item, asynchronous, ok) => {
ok && items.forEach(([tag, attributes, childs]) => {
if(self[tag] && (!attributes || !attributes.built)){
/** @type {string|Array.<any|null>|HTMLElement|NodeList} */
const subitem = self[tag](...Utils.get_array(attributes));
if(Check.is_string(subitem))
item.innerHTML += subitem;
else if(Check.is_array(subitem))
self.set_to(item, subitem);
else if(Check.is_html_items(subitem))
subitem.forEach(subnode => item.appendChild(subnode));
else if(Check.is_html_item(subitem))
item.appendChild(subitem);
}else{
/** @type {HTMLElement} */
const subitem = item.appendChild(document.createElement(tag));
anp.attributes.set(subitem, attributes, null, ["built"]);
Check.is_array(childs) && childs.length && self.set_to(subitem, ...set_childs(childs));
};
});
});
};
/**
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
* @returns {Array.<any|null>}
* @access public
*/
this.image = inputs => {
/** @type {Object.<string, any|null>} */
const attributes = Utils.get_dictionary(Check.is_array_string(inputs) ? {sources : inputs} : inputs),
/** @type {Array.<string>} */
source_keys = ["images", "sources", "image", "source", "src"],
/** @type {Array.<string>} */
images = Utils.get_strings(Utils.get_value(source_keys, attributes));
Attributes.remove(attributes, source_keys.concat([
"class", "classes", "status", "data_status", "data_i", "data_sources"
]));
return ["span", {
...attributes,
class : Attributes.join_classes("image", Utils.get_value(["class", "classes"], attributes)),
data_status : "unloaded",
data_sources : images,
data_i : 0
}, [
["img", {
// on_load_execute : item => {
// item.setAttribute("src", images[0]);
// },
onload : (item, event) => {
item.parentNode.setAttribute("data-status", "loaded");
item.parentNode.querySelector("span").style.backgroundImage = "url('" + item.src + "')";
},
onerror : (item, event) => {
/** @type {Array.<string>} */
const images = Utils.variables_decode(item.parentNode.getAttribute("data-sources")),
/** @type {number} */
i = Number(item.parentNode.getAttribute("data-i")) + 1;
if(i < images.length){
item.parentNode.setAttribute("data-i", i);
item.setAttribute("src", images[i]);
}else
item.parentNode.setAttribute("data-status", "error");
},
...(attributes.title ? {alt : attributes.title} : {})
}],
["span"]
]];
};
/**
* @param {!string} name
* @param {!string} [tag = "span"]
* @param {?(Object.<string, any|null>|Array.<any|null>)} [attributes = null]
* @returns {Array.<any|null>}
* @access public
*/
this.icon = (name, tag = "span", attributes = null) => {
/** @type {Array.<any|null>|string|null} */
const childs = Utils.get_value(["content", "child", "childs"], attributes, null);
Attributes.remove(attributes = Utils.get_dictionary(attributes), [
["content", "child", "childs"]
]);
attributes.data_icon = name;
return [tag, attributes, childs];
};
/**
* @param {?string} base
* @param {?(Object.<string, any|null>|Array.<any|null>)} attributes
* @returns {Array.<any|null>}
* @access private
*/
const process_title = (base, attributes) => [
anp.i18n.get([base].concat(Utils.get_strings(Utils.get_value([
"title", "text", "texts", "default_text", "default_texts"
], attributes, []))), attributes),
(
!Check.is_null_or_undefined(Utils.get_dictionary(attributes).title) ||
Utils.get_value(["with_title", "has_title"], attributes, false)
)
];
/**
* @param {!string} name
* @param {!string} [tag = "span"]
* @param {?(Object.<string, any|null>|Array.<any|null>)} [attributes = null]
* @returns {Array.<any|null>}
* @access public
*/
this.i18n = (name, tag = "span", attributes = null) => {
/** @type {[string, boolean]} */
const [text, has_title] = process_title(name, attributes);
Attributes.remove(attributes = Utils.get_dictionary(attributes), [
"text", "texts", "default_text", "default_texts", "with_title", "has_title"
]);
attributes.data_i18n = name;
has_title && (attributes.title = text);
return [tag, attributes, text];
};
/**
* @param {!string} name
* @param {?(anp_event_callback|Object.<string, any|null>|Array.<any|null>)} [attributes = null]
* @returns {Array.<any|null>}
*/
this.button = (name, attributes = null) => {
/** @type {[string, boolean]} */
const [text, has_title] = process_title(name, {with_title : true, ...(
Check.is_function(attributes) ? attributes = {onclick : attributes} :
attributes)}),
/** @type {Array.<Array.<any|null>|string>} */
childs = [
self.icon(Utils.get_value(["icon", "data_icon"], attributes, name)),
self.i18n(name)
],
/** @type {Array.<any|null>|string|null} */
content = Utils.get_value(["child", "childs", "content"], attributes, null);
content && childs.push(content);
Attributes.remove(attributes = Utils.get_dictionary(attributes), [
"text", "texts", "default_text", "default_texts", "with_title", "has_title",
"icon", "data_icon", "child", "childs", "content"
]);
attributes.built = true;
attributes.type || (attributes.type = "button");
if(has_title){
attributes.title = text;
attributes.data_i18n = name;
attributes.data_i18n_without = true;
};
return ["button", {
...attributes,
}, childs];
};
/**
* @param {!Array.<Array.<any|null>|string>} items
* @param {?(Object.<string, any|null>|Array.<any|null>)} [attributes = null]
* @param {!string} [tag = "div"]
* @returns {Array.<any|null>}
* @access public
*/
this.group = (items, attributes = null, tag = "div") => {
/** @type {string} */
const classes = Attributes.join_classes("group", Utils.get_value(["class", "classes"], attributes));
Attributes.remove(attributes = Utils.get_dictionary(attributes), [
"class", "classes"
]);
attributes.class = classes;
return [tag, attributes, items];
};
/**
* @param {!Array.<Array.<any|null>|string>} buttons
* @param {?(Object.<string, any|null>|Array.<any|null>)} [attributes = null]
* @param {!string} [tag = "div"]
* @returns {Array.<any|null>}
* @access public
*/
this.buttons = (buttons, attributes = null, tag = "div") => self.group(buttons, Utils.get_dictionary([attributes, {
class : Attributes.join_classes("buttons", Utils.get_value(["class", "classes"], attributes))
}]), tag);
/**
* @param {?(Object.<string, any|null|Array.<any|null>)} [attributes = null]
* @param {?(Object.<string, any|null|Array.<any|null>)} [own_attributes = null]
* @returns {Array.<any|null>}
* @access public
*/
this.input = (attributes = null, own_attributes = null) => ["input", {
...Utils.get_dictionary(attributes),
...Utils.get_dictionary(own_attributes),
built : true
}];
/**
* @param {?(Object.<string, any|null|Array.<any|null>)} [attributes = null]
* @returns {Array.<any|null>}
* @access public
* @returns
*/
this.number = (attributes = null) => {
/** @type {string} */
const classes = Attributes.join_classes("input-field input-number", Utils.get_value(["class", "classes"], attributes));
Attributes.remove(attributes = Utils.get_dictionary(attributes), ["class", "classes"]);
return ["span", {class : classes}, [
["input", {
...attributes,
type : "number"
}]
]];
};
constructor();
};
return Components;
})();

View File

@ -0,0 +1,452 @@
"use strict";
import {Attributes} from "../Application/Attributes.ecma.js";
import {Utils} from "../Utils/Utils.ecma.js";
import {Check} from "../Utils/Check.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
* @typedef {import("../Models/ThreadModel.ecma.js").ThreadModel} ThreadModel
*/
/**
* @class
* @constructor
* @param {!AnP} anp
* @returns {void}
* @access public
*/
export const BaseComponent = (function(){
/**
* @constructs BaseComponent
* @param {!AnP} anp
* @returns {void}
* @access private
*/
const BaseComponent = function(anp){
/** @type {BaseComponent} */
const self = this,
/** @type {Array.<Array.<Object.<string, any|null>>>} */
identifiers = [];
/** @type {boolean} */
let started = false,
/** @type {ThreadModel|null} */
thread = null;
/**
* @returns {void}
* @access private
*/
const constructor = () => {};
/**
* @param {!ThreadModel} thread
* @returns {void}
* @access private
*/
const analyzer = thread => {
/** @type {Array.<number>} */
const for_delete = [];
identifiers.forEach((cache, i) => {
if(!cache.item && !(cache.item = document.querySelector("#" + cache.id))){
for_delete.push(i);
return;
};
/** @type {number} */
const zoom = Number(cache.item.getAttribute("data-zoom")) / 100;
if(
cache.x != cache.item.offsetWidth ||
cache.y != cache.item.offsetHeight ||
cache.zoom != zoom
){
cache.x = cache.item.offsetWidth;
cache.y = cache.item.offsetHeight;
cache.zoom = zoom;
/** @type {number} */
const cells = Number(cache.item.getAttribute("data-cells")),
/** @type {number} */
minimum_size = Number(cache.item.getAttribute("data-minimum-size")),
/** @type {number} */
size = zoom * (cache.x < cache.y ? cache.x : cache.y) / cells;
cache.item.style.fontSize = (size > minimum_size ? size : minimum_size) + "px";
cache.item.querySelectorAll("[data-maximum-zoom]").forEach(item => {
/** @type {number} */
const maximum_zoom = Number(item.getAttribute("data-maximum-zoom")) / 100,
/** @type {number} */
maximum_size = maximum_zoom * (cache.x < cache.y ? cache.x : cache.y) / cells;
item.style.fontSize = size > maximum_size ? maximum_size + "px" : "inherit";
});
};
});
if(for_delete.length){
for_delete.reverse();
for_delete.forEach(i => {
identifiers.splice(i, 1);
});
};
};
/**
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @returns {Object.<string, any|null>}
* @access private
*/
const get_attributes = (inputs = null) => {
/** @type {string} */
const id = anp.random_chain(),
/** @type {Object.<string, any|null>} */
attributes = Utils.get_dictionary(inputs),
/** @type {anp_attributes_load_callback|null} */
on_load_execute = attributes.on_load_execute;
Attributes.remove(attributes, [
"class", "classes", "id", "data_hash", "hash", "cells", "minimum_size",
"zoom", "data_cells", "data_minimum_size", "data_zoom", "on_load_execute",
"data_dark_mode", "data_mobile", "dark_mode", "mobile"
]);
return {
...attributes,
on_load_execute : item => {
identifiers.push({id : id});
Utils.execute(on_load_execute, item);
},
class : Attributes.join_classes(Utils.get_value(["class", "classes"], inputs, []), ["anp", id]),
id : id,
data_hash : id,
data_cells : anp.settings.get(["base_cells", "data_cells", "cells"], inputs, 40),
data_minimum_size : anp.settings.get(["base_minimum_size", "data_minimum_size", "minimum_size"], inputs, 12),
data_zoom : anp.settings.get(["base_zoom", "data_zoom", "zoom"], inputs, 100),
data_gui_mode : anp.settings.get(["base_gui_mode", "data_gui_mode", "gui_mode"], inputs, "default"),
data_dark_mode : anp.is_dark_mode(),
data_mobile : anp.is_mobile()
};
};
/**
* @param {?anp_start_callback} callback
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
/** @type {!anp_start_callback} */
const end = ok => {
Utils.execute(callback, ok);
return ok;
};
if(started)
return end(false);
started = true;
/** @type {string|HTMLElement|null} */
const position = anp.settings.get("position");
thread = anp.threads.add(analyzer, {
timer : 100,
bucle : true
});
if(position)
anp.preload(position, (position, asyncrhonous, ok) => {
if(ok){
/** @type {Object.<string, any|null>} */
const attributes = {
on_load_execute : item => {
anp.item_self = item;
anp.hash_self = item.getAttribute("id");
end(true);
}
};
["name", "git", "link", "since", "version"].forEach(key => {
const value = anp.settings.get("application_" + key);
Check.is_null_or_undefined(value) ||
(attributes["data_" + key] = value);
});
if(position.classList.contains("anp")){
/** @type {HTMLElement} */
const footer = position.querySelector("footer"),
/** @type {HTMLFieldSetElement} */
gui_controls = footer.insertBefore(document.createElement("fieldset"), footer.childNodes[0]);
anp.components.set_to(gui_controls, ...self.build_view_menu());
gui_controls.setAttribute("class", "gui-controls");
anp.attributes.set(position, get_attributes(attributes));
}else{
try{
position.innerHTML = self.build(attributes);
}catch(exception){
console.error(exception);
};
};
}else
end(false);
});
else
end(true);
return true;
};
/**
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
* @returns {string}
* @access public
*/
this.build = inputs => {
/** @type {Array.<any|null>} */
const licenses = anp.settings.get(["application_licenses", "application_license", "licenses", "license"], inputs, []),
/** @type {Object.<string, any|null>} */
attributes = get_attributes(inputs);
return anp.components.set(["div", attributes, [
["header", null, [
["h1", {class : "logo", title : "AnP"}, [
["a", {href : "https://anp.k3y.pw/", target : "_blank"}, [
["image", {sources : "/images/AnP.png", title : "AnP"}],
["span", {class : "text"}, "AnP"]
]]
]]
]],
["main"],
["footer", {
"data_maximum_zoom" : anp.settings.get(["base_footer_maximum_zoom", "footer_maximum_zoom"], inputs, 100)
}, [].concat(
[["fieldset", {class : "gui-controls"}, self.build_view_menu()]],
(licenses ? [["licenses", licenses]] : [])
)]
]]);
};
/**
* @returns {Array.<any|null>}
* @access public
*/
this.build_view_menu = (inputs = null) => [
["legend", {data_i18n : "gui_controls"}, anp.i18n.get("gui_controls")],
["button", ["less_zoom", set_less_zoom]],
["number", {
name : "zoom",
min : anp.settings.get("zoom_minimum", inputs, 1),
max : anp.settings.get("zoom_maximum", inputs, 200),
value : anp.settings.get(["default_zoom", "base_zoom", "zoom"], inputs, 100),
step : anp.settings.get("zoom_step", inputs, 1),
onchange : change_zoom
}],
["button", ["reset_zoom", reset_zoom]],
["button", ["zoom_mode", {
onclick : change_zoom_mode,
data_modes : anp.settings.get("zoom_modes", inputs, [50, 75, 100, 125, 150])
}]],
["button", ["more_zoom", set_more_zoom]],
["button", ["gui_mode", change_gui_mode]],
["button", ["more_options", {
onclick : show_more_options,
disabled : true
}]]
];
/**
* @param {!HTMLElement} item
* @param {!number} value
* @returns {void}
* @access public
*/
this.change_zoom = (item, value) => {
/** @type {HTMLInputElement} */
const number_field = (item = BaseComponent.get(item)).querySelector("footer .gui-controls [type=number]");
item.setAttribute("data-zoom", value);
Number(number_field.value) != value && (number_field.value = value);
};
/**
* @param {!HTMLElement} button
* @param {!number} value
* @returns {void}
* @access private
*/
const set_zoom = (button, value) => {
if(Check.is_number(value)){
/** @type {HTMLInputElement} */
const number_field = button.parentNode.querySelector("[type=number]");
if(value){
value += Number(number_field.value) || 0;
if(value < 0){
/** @type {number} */
const minimum = Number(number_field.getAttribute("min"));
!isNaN(minimum) && minimum > value && (value = minimum);
}else{
/** @type {number} */
const maximum = Number(number_field.getAttribute("max"));
!isNaN(maximum) && maximum < value && (value = maximum);
};
number_field.value = value;
}else
number_field.value = value = 100;
self.change_zoom(button, value);
};
};
/**
* @param {!HTMLElement} item
* @param {?Event} [event = null]
* @returns {void}
* @access private
*/
const set_less_zoom = (item, event = null) => {
set_zoom(item, -BaseComponent.get_input_gui_step(item));
};
/**
* @param {!HTMLElement} item
* @param {?Event} [event = null]
* @returns {void}
* @access private
*/
const change_zoom_mode = (item, event = null) => {
/** @type {number} */
const current_zoom = Number(item.parentNode.querySelector("[type=number]").value),
/** @type {Array.<number>} */
modes = Utils.variables_decode(item.getAttribute("data-modes"));
modes.some((value, i) => {
if(current_zoom < value){
self.change_zoom(item, value);
return true;
};
}) || self.change_zoom(item, modes[0]);
};
/**
* @param {!HTMLElement} item
* @param {?Event} [event = null]
* @returns {void}
* @access private
*/
const reset_zoom = (item, event = null) => {
set_zoom(item, 0);
};
/**
* @param {!HTMLElement} item
* @param {?Event} [event = null]
* @returns {void}
* @access private
*/
const set_more_zoom = (item, event = null) => {
set_zoom(item, BaseComponent.get_input_gui_step(item));
};
/**
* @param {!HTMLElement} item
* @param {?Event} [event = null]
* @returns {void}
* @access private
*/
const change_gui_mode = (item, event = null) => {
(item = BaseComponent.get(item)).setAttribute("data-gui-mode", {
"default" : "dark",
"dark" : "light",
"light" : "default"
}[item.getAttribute("data-gui-mode")] || "default");
};
/**
* @param {!HTMLElement} item
* @param {?Event} [event = null]
* @returns {void}
* @access private
*/
const show_more_options = (item, event = null) => {
console.log("PASA");
};
/**
* @param {!HTMLElement} item
* @param {?Event} [event = null]
* @returns {void}
* @access private
*/
const change_zoom = (item, event = null) => {
self.change_zoom(item, Number(item.value));
};
constructor();
};
/**
* @param {!HTMLElement} item
* @returns {HTMLElement}
* @access public
* @static
*/
BaseComponent.get = item => {
if(item)
while(true){
if(!item.classList)
return null;
if(item.classList.contains("anp") || !(item = item.parentNode))
break;
};
return item || null;
};
/**
* @param {!HTMLElement} item
* @returns {number}
* @access public
* @static
*/
BaseComponent.get_input_gui_step = item => Number(item.parentNode.querySelector("[type=number]").getAttribute("step"));
return BaseComponent;
})();

View File

@ -0,0 +1,161 @@
"use strict";
import {Utils} from "../Utils/Utils.ecma.js";
import {Check} from "../Utils/Check.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @class
* @constructor
* @param {!AnP} anp
* @returns {void}
* @access private
*/
export const LicensesComponent = (function(){
/**
* @constructs LicensesComponent
* @param {!AnP} anp
* @returns {void}
* @access private
*/
const LicensesComponent = function(anp){
/** @type {LicensesComponent} */
const self = this;
/** @type {boolean} */
let started = false;
/**
* @returns {void}
* @access private
*/
const constructor = () => {};
/**
* @param {?anp_start_callback} callback
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
/** @type {!anp_start_callback} */
const end = ok => {
Utils.execute(callback, ok);
return ok;
};
return end(started ? false : started = true);
};
/**
* @param {!...Array.<any|null>} [licenses]
* @returns {Array.<any|null>}
* @access public
*/
this.build = (...licenses) => ["span", {
class : "licenses"
}, licenses.map(([name, ...inputs]) => (
Check.is_function(self[name]) ? self[name](...inputs) :
[]))];
/**
* @returns {Array.<any|null>}
* @access public
*/
this.gplv3 = () => ["a", {
class : "license gpl-v3",
href : "https://www.gnu.org/licenses/gpl-3.0.txt",
target : "_blank",
title : "GPLv3"
}, [
["span", {class : "text"}, "GPLv3"],
["image", {
sources : "https://www.gnu.org/graphics/gplv3-88x31.png",
alt : "GPLv3"
}]
]];
/**
* @returns {Array.<any|null>}
* @access public
*/
this.cc_by_nc_sa_4 = () => {
/** @type {string} */
const text = anp.i18n.get([
"Creative Commons Attribution-NonCommertial-ShareAlike 4.0 International (CC-SA-NC-BY 4.0)",
"cc_by_nc_sa_4"
]);
return ["a", {
class : "license cc-by-nc-sa-4",
href : "https://creativecommons.org/licenses/by-nc-sa/4.0/",
target : "_blank",
data_i18n : "cc_by_nc_sa_4",
data_i18n_without : true,
title : text
}, [
["span", {class : "text"}, text],
["image", {
sources : "https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png",
data_i18n : "cc_by_nc_sa_4",
data_i18n_without : true,
alt : text
}]
]];
};
/**
* @param {?(number|string|Array.<number|string>)} [year = null]
* @param {?(string|Array.<string>)} [authors = null]
* @param {!boolean} [all_rights_reserved = false]
* @returns {Array.<any|null>}
* @access public
*/
this.copyright = (year = null, authors = null, all_rights_reserved = false) => {
/** @type {Object.<string, string>} */
const variables = {
year : Check.is_array(year) ? (
year.length == 1 ? year[0] :
year.length == 2 ? year.join("-") :
year.length ? year.slice(0, year.length - 1).join(", ") + " & " + year.slice(-1)[0] :
"") : year || "",
authors : Check.is_array(authors) ? (
authors.length == 1 ? authors[0] :
authors.length == 2 ? authors.join(" & ") :
authors.length ? authors.slice(0, authors.length - 1).join(", ") + " & " + authors.slice(-1)[0] :
"") : authors || "",
all_rights_reserved : all_rights_reserved ? anp.i18n.get([
"All rights reserved.",
"all_rights_reserved"
]) : ""
},
/** @type {string} */
text = anp.i18n.get([
"© Copyright{year}{authors}{all_rights_reserved}",
"copyright"
], {
year : variables.year = variables.year ? " " + variables.year + "." : "",
authors : variables.authors = variables.authors ? " " + variables.authors + "." : "",
all_rights_reserved : variables.all_rights_reserved = variables.all_rights_reserved ? (variables.year || variables.authors ? "" : ". ") + variables.all_rights_reserved : ""
});
return ["span", {
class : "license copyright",
data_i18n : "copyriht",
data_i18n_variables : variables,
title : text
}, text];
};
constructor();
};
return LicensesComponent;
})();

View File

@ -0,0 +1,199 @@
"use strict";
import {Utils} from "../Utils/Utils.ecma.js";
import {Check} from "../Utils/Check.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @callback anp_url_path_driver_default_callback
* @returns {void}
*/
/**
* @callback anp_url_path_driver_callback
* @param {?string} response
* @param {!number} status
* @param {!number} state
* @param {!boolean} ok
* @param {!string} message
* @returns {void}
*/
/**
* @callback anp_url_path_driver_ajax_end_callback
* @param {!string} message
* @returns {void}
*/
/**
* @callback anp_url_path_driver_load_json_each_callback
* @param {?any} item
* @param {!anp_url_path_driver_default_callback} calback
* @returns {void}
*/
/**
* @class
* @constructor
* @param {!AnP} anp
* @returns {void}
* @access public
*/
export const URLPathDriver = (function(){
/**
* @constructs URLPathDriver
* @param {!AnP} anp
* @returns {void}
* @access private
*/
const URLPathDriver = function(anp){
/** @type {URLPathDriver} */
const self = this;
/** @type {boolean} */
let started = false,
/** @type {boolean} */
default_timeout = false;
/**
* @returns {void}
* @access public
*/
this.set_basics = () => {
default_timeout = anp.settings.get(["ajax_timeout", "timeout"], null, default_timeout);
};
/**
* @returns {void}
* @access private
*/
const constructor = () => {
self.set_basics();
};
/**
* @param {?anp_start_callback} callback
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
/** @type {!anp_start_callback} */
const end = ok => {
Utils.execute(callback, ok);
return ok;
};
return end(started ? false : started = true);
};
/**
* @param {!XMLHttpRequest} ajax
* @param {!anp_url_path_driver_callback} callback
* @param {?(Object.<string, any|null>|Array.<any|null>)} inputs
* @param {?(string|Object.<string, any|null>|Array.<any|null>)} [data = null]
* @returns {XMLHttpRequest}
* @access private
*/
const execute = (ajax, callback, inputs, data = null) => {
let ended = false;
const date = Date.now(),
timeout = Utils.get_value(["ajax_timeout", "timeout"], inputs, default_timeout),
end = message => {
!ended && (ended = true) && Utils.execute(
callback, ajax.responseText, ajax.status, ajax.readyState, message == "OK", message
);
};
ajax.timeout = timeout;
ajax.onreadystatechange = () => {
if(ended)
return;
if(ajax.readyState == 4)
end((ajax.status >= 200 && ajax.status < 300) || [301, 302, 304].includes(ajax.status) ? "OK" : "HTTP_ERROR");
else if(timeout && Date.now() - date > timeout)
end("FORCED_TIMEOUT");
};
ajax.onabort = () => end("ABORTED");
ajax.onerror = () => end("ERROR");
ajax.ontimeout = () => end("TIMEOUT");
ajax.send(data);
return ajax;
};
/**
* @param {!string} url
* @param {!anp_url_path_driver_callback} callback
* @param {?(object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @returns {XMLHttpRequest}
* @access public
*/
this.get = (url, callback = null, inputs = null) => {
/** @type {XMLHttpRequest} */
const ajax = new XMLHttpRequest();
ajax.open("get", url, true);
return execute(ajax, callback, inputs);
};
/**
* @param {!(string|Object.<string, any|null>|Array.<any|null>)} inputs
* @param {!anp_url_path_driver_default_callback} each_callback
* @param {?anp_url_path_driver_default_callback} [end_callback = null]
* @param {!boolean} [only_dictionaries = true]
* @returns {void}
* @access public
*/
this.load_json = (inputs, each_callback, end_callback = null, only_dictionaries = true) => {
if(Check.is_string(inputs)){
/** @type {Object.<string, any|null>|Array.<any|null>|null} */
let json;
try{
json = JSON.parse(inputs);
}catch(exception){};
if(json)
self.load_json(json, each_callback, end_callback, only_dictionaries);
else
self.get(inputs, (response, status, state, ok, message) => {
try{
json = JSON.parse(response);
}catch(exception){};
self.load_json(json, each_callback, end_callback, only_dictionaries);
});
}else if(Check.is_array(inputs)){
if(only_dictionaries)
Utils.execute_items(inputs, (item, callback) => {
self.load_json(item, each_callback, callback, only_dictionaries);
}, end_callback);
else
Utils.execute(each_callback, inputs, end_callback);
}else if(Check.is_dictionary(inputs))
Utils.execute(each_callback, inputs, end_callback);
else
Utils.execute(end_callback);
};
constructor();
};
return URLPathDriver;
})();

View File

@ -0,0 +1,73 @@
"use string";
import {Utils} from "../Utils/Utils.ecma.js";
/**
* @callback anp_events_manager_callback
* @param {...any} [parameters]
* @returns {any|null}
*/
/**
* @class
* @constructor
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @returns {void}
* @access public
*/
export const EventsManager = (function(){
/**
* @constructs EventsManager
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @returns {void}
* @access private
*/
const EventsManager = function(inputs = null){
/** @type {Array.<anp_events_manager_callback|null>} */
const events = [];
/** @type {boolean} */
this.autoexecute = Utils.get_value("autoexecute", inputs, false);
/**
* @param {...any} [parameters]
* @returns {Array.<any|null>}
* @access public
*/
this.execute = (...parameters) => events.map(callback => callback ? callback(...parameters) : null);
/**
* @param {!anp_events_manager_callback} callback
* @returns {number}
* @access public
*/
this.add = callback => {
/** @type {number} */
let i = -1;
/** @type {number} */
const l = events.length;
while(++ i < l)
if(!events[i])
break;
events[i] = callback;
return i;
};
/**
* @param {!number} i
* @returns {void}
* @access public
*/
this.remove = i => {
events[i] && (events[i] = null);
};
};
return EventsManager;
})();

View File

@ -0,0 +1,152 @@
"use strict";
import {Utils} from "../Utils/Utils.ecma.js";
import {Check} from "../Utils/Check.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @callback anp_i18n_settings_default_callback
* @returns {void}
*/
/**
* @class
* @constructor
* @param {!AnP} anp
* @param {?(Object.<string, any|null>|Array.<any|null>)} inputs
* @returns {void}
* @access public
*/
export const I18NManager = (function(){
/**
* @constructs I18NManager
* @param {!AnP} anp
* @returns {void}
* @access private
*/
const I18NManager = function(anp){
/** @type {I18NManager} */
const self = this,
/** @type {Object.<string, any|null>} */
sentences = {};
/** @type {boolean} */
let started = false,
/** @type {string} */
default_language = "english",
/** @type {string} */
selected_language = "english";
/**
* @returns {void}
* @access private
*/
const constructor = () => {};
/**
* @param {?anp_start_callback} callback
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
/** @type {!anp_start_callback} */
const end = ok => {
Utils.execute(callback, ok);
return ok;
};
if(started)
return end(false);
started = true;
Utils.execute_items([
"default_i18n_files", "default_i18n", "i18n_files", "i18n"
], (key, next) => {
self.add(anp.settings.get(key), next, true);
}, () => {
end(true);
});
return true;
};
/**
* @param {!(string|Object.<string, any|null>|Array.<any|null>)} inputs
* @param {?anp_i18n_settings_default_callback} [callback = null]
* @param {!boolean} [overwrite = false]
* @returns {void}
* @access public
*/
this.add = (inputs, callback = null, overwrite = false) => {
anp.request.load_json(inputs, (data, subcallback) => {
for(const language in data)
if(Check.is_dictionary(data[language])){
sentences[language] || (sentences[language] = {});
for(const key in data[language])
!Check.is_key_mark(key) &&
(overwrite || sentences[language][key] === undefined) &&
(sentences[language][key] = data[language][key]);
};
Utils.execute(subcallback);
}, callback);
};
/**
* @param {!(string|Array.<string>)} texts
* @param {?(string|Array.<string>)} languages
* @returns {string|Array.<string>|null}
* @access private
*/
const get_sentence = (texts, languages) => {
/** @type {Array.<string>} */
const keys = Utils.get_keys(texts);
if(keys.length){
/** @type {number} */
const l = (languages = Utils.get_keys(Utils.get_keys(languages).concat(
[selected_language, default_language],
Object.keys(sentences)
))).length;
for(let i = 0; i < l; i ++)
if(sentences[languages[i]])
for(let j = 0, m = keys.length; j < m; j ++)
if(sentences[languages[i]][keys[j]] !== undefined)
return sentences[languages[i]][keys[j]];
};
return Utils.get_strings(texts)[0];
};
/**
* @param {!(string|Array.<string>)} texts
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {?(string|Array.<string>)} [languages = null]
* @returns {string|null}
* @access public
*/
this.get = (texts, inputs = null, languages = null) => {
/** @type {string|Array.<string>|null} */
const fragments = get_sentence(texts, languages),
/** @type {string|null} */
sentence = Check.is_array(fragments) ? fragments.join("") : fragments;
return inputs ? Utils.string_variables(sentence, inputs) : sentence;
};
constructor();
};
/** @type {Object.<string, any|null>} */
I18NManager.DEFAULT_SETTINGS = {};
return I18NManager;
})()

View File

@ -0,0 +1,151 @@
"use strict";
import {Utils} from "../Utils/Utils.ecma.js";
import {Check} from "../Utils/Check.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @callback anp_settings_managers_default_callback
* @returns {void}
*/
/**
* @class
* @constructor
* @param {!AnP} anp
* @param {?(Object.<string, any|null>|Array.<any|null>)} inputs
* @returns {void}
* @access public
*/
export const SettingsManager = (function(){
/**
* @constructs SettingsManager
* @param {!AnP} anp
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @returns {void}
* @access private
*/
const SettingsManager = function(anp, custom = null){
/** @type {SettingsManager} */
const self = this,
/** @type {Object.<string, any|null>} */
settings = {},
/** @type {Object.<string, any|null>} */
secrets = {};
/** @type {boolean} */
let started = false;
/**
* @returns {void}
* @access private
*/
const constructor = () => {
custom = Utils.get_dictionary(custom, true);
};
/**
* @param {?anp_start_callback} callback
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
/** @type {!anp_start_callback} */
const end = ok => {
Utils.execute(callback, ok);
return ok;
};
if(started)
return end(false);
started = true;
Utils.execute_items([
"default_settings_files", "default_settings", "settings_files", "settings"
], (key, next) => {
self.add(self.get(key), next, true);
}, () => {
Utils.execute_items([
"default_secrets_files", "default_secrets", "secrets_files", "secrets"
], (key, next) => {
self.add_secrets(self.get(key), next, true);
}, () => {
end(true);
});
});
return true;
};
/**
* @param {!(string|Array.<string>)} keys
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {?any} [_default = null]
* @returns {any|null}
* @access public
*/
this.get = (keys, inputs = null, _default = null) => Utils.get_value(keys, [
inputs, custom, secrets, settings, SettingsManager.DEFAULT_SETTINGS
], _default);
/**
* @param {!Object.<string, any|null>} set
* @param {!(string|Object.<string, any|null>|Array.<any|null>)} inputs
* @param {?anp_settings_managers_default_callback} callback
* @param {!boolean} overwrite
* @returns {void}
* @access private
*/
const add_to = (set, inputs, callback, overwrite) => {
anp.request.load_json(inputs, (data, subcallback) => {
for(const key in data)
!Check.is_key_mark(key) &&
(overwrite || set[key] === undefined) &&
(set[key] = data[key]);
Utils.execute(subcallback);
}, callback);
}
/**
* @param {!(string|Object.<string, any|null>|Array.<any|null>)} inputs
* @param {?anp_settings_managers_default_callback} [callback = null]
* @param {!boolean} [overwrite = false]
* @returns {void}
* @access public
*/
this.add = (inputs, callback = null, overwrite = false) => {
add_to(settings, inputs, callback, overwrite);
};
/**
* @param {!(string|Object.<string, any|null>|Array.<any|null>)} inputs
* @param {?anp_settings_managers_default_callback} [callback = null]
* @param {!boolean} [overwrite = false]
* @returns {void}
* @access public
*/
this.add_secrets = (inputs, callback = null, overwrite = false) => {
add_to(secrets, inputs, callback, overwrite);
};
constructor();
};
/** @type {Object.<string, any|null>} */
SettingsManager.DEFAULT_SETTINGS = {
"autostart" : true,
"object_name" : "anp",
"default_settings_files" : [
"/json/AnP.settings.json",
"/json/AnP.ecma.settings.json"
]
};
return SettingsManager;
})()

View File

@ -0,0 +1,129 @@
"use strict";
import {Utils} from "../Utils/Utils.ecma.js";
import {ThreadModel} from "../Models/ThreadModel.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @callback anp_threads_manager_callback
* @param {!ThreadModel} thread
* @returns {void}
*/
/**
* @class
* @constructor
* @param {!AnP} anp
* @returns {void}
* @access public
*/
export const ThreadsManager = (function(){
/**
* @constructs ThreadsManager
* @param {!AnP} anp
* @returns {void}
* @access private
*/
const ThreadsManager = function(anp){
/** @type {ThreadsManager} */
const self = this,
/** @type {Array.<ThreadModel>} */
threads = [];
/** @type {boolean} */
let started = false,
/** @type {number|null} */
thread = null;
/**
* @returns {void}
* @access private
*/
const constructor = () => {
thread = setInterval(try_execute_threads, 1000 / 60);
};
/**
* @param {?anp_start_callback} callback
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
/** @type {!anp_start_callback} */
const end = ok => {
Utils.execute(callback, ok);
return ok;
};
return end(started ? false : started = true);
};
/**
* @returns {void}
* @access private
*/
const try_execute_threads = () => {
threads.forEach(thread => {
thread && thread.try_execute();
});
};
/**
* @param {!anp_threads_manager_callback} callback
* @param {?(Object.<string, any|null>|Array.<any|null>)} inputs
* @returns {ThreadModel}
* @access public
*/
this.add = (callback, inputs = null) => {
/** @type {ThreadModel} */
const thread = new ThreadModel(anp, callback, inputs);
while(++ thread.i < threads.length)
if(!threads[thread.i])
break;
threads[thread.i] = thread;
return thread;
};
/**
* @param {!ThreadModel} thread
* @returns {void}
* @access public
*/
this.remove = thread => {
thread instanceof ThreadModel && threads[thread.i] && (threads[thread.i] = null);
};
/**
* @param {!ThreadModel} thread
* @returns {void}
* @access public
*/
this.play = thread => {
thread.working = true;
};
/**
* @param {!ThreadModel} thread
* @returns {void}
* @access public
*/
this.stop = thread => {
thread.working = false;
};
constructor();
};
return ThreadsManager;
})();

View File

@ -0,0 +1,86 @@
"use strict";
import {Utils} from "../Utils/Utils.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @callback anp_thread_model_callback
* @param {ThreadModel} thread
* @returns {void}
*/
/**
* @class
* @constructor
* @param {!AnP} anp
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
* @access public
*/
export const ThreadModel = (function(){
/**
* @constructs ThreadModel
* @param {!AnP} anp
* @param {!anp_thread_model_callback} callback
* @param {!(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @access private
*/
const ThreadModel = function(anp, callback, inputs = null){
/** @type {ThreadModel} */
const self = this;
/** @type {anp_thread_model_callback} */
this.callback = callback;
/** @type {number} */
this.timer = anp.settings.get(["threads_timer", "timer"], inputs, 0);
/** @type {boolean} */
this.bucle = anp.settings.get(["threads_bucle", "bucle"], inputs, true);
/** @type {number} */
this.last_date = anp.settings.get(["threads_start_now", "start_now"], inputs, true) ? 0 : Date.now();
/** @type {number} */
this.i = -1;
/** @type {boolean} */
this.working = anp.settings.get(["threads_working", "working"], inputs, true);
/**
* @returns {void}
* @access public
*/
this.try_execute = () => {
if(!self.working || self.i < 0)
return;
/** @type {number} */
const date = Date.now();
if(date - self.last_date > self.timer){
self.last_date = date;
Utils.execute(self.callback, self);
};
};
/**
* @returns {void}
* @access public
*/
this.play = () => {
working = true;
};
/**
* @returns {void}
* @access public
*/
this.stop = () => {
working = false;
};
};
return ThreadModel;
})();

View File

@ -0,0 +1,137 @@
"use strict";
import {Patterns} from "./Patterns.ecma.js";
/**
* @class
* @constructor
* @returns {void}
* @access public
*/
export const Check = (function(){
/**
* @constructs Check
* @returns {void}
* @access private
*/
const Check = function(){};
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_array = item => item instanceof Array;
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_dictionary = item => item && item.constructor == Object;
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_string = item => typeof item == "string";
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_key = item => Check.is_string(item) && Patterns.RE_KEY.test(item);
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_pascal_key = item => Check.is_string(item) && Patterns.RE_PASCAL_KEY.test(item);
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_function = item => typeof item == "function";
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_null_or_undefined = item => item === null || item === undefined;
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_html_item = item => item && (item.tagName || item.nodeName);
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_html_items = item => item instanceof NodeList;
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_bool = item => typeof item == "boolean";
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_json_object = item => Check.is_array(item) || Check.is_dictionary(item);
/**
* @param {?any} items
* @returns {boolean}
* @access public
* @static
*/
Check.is_array_string = items => Check.is_array(items) && items.every(Check.is_string);
/**
* @param {!string} key
* @param {!string} [mark = "AnP"]
* @returns {boolean}
* @access public
* @static
*/
Check.is_key_mark = (key, mark = "AnP") => key.slice(0, mark.length + 1) == mark + "_" && (
key.slice(-4) == "_end" ||
key.slice(-6) == "_start"
);
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_number = item => typeof item == "number";
return Check;
})();

View File

@ -0,0 +1,27 @@
"use strict";
/**
* @class
* @constructor
* @returns {void}
* @access public
*/
export const Patterns = (function(){
/**
* @constructs Patterns
* @returns {void}
* @access private
*/
const Patterns = function(){};
Patterns.RE_KEY = /^[a-z0-9_]+$/i;
Patterns.RE_PASCAL_KEY = /^[a-z0-9_\-]+$/i;
Patterns.RE_STRING_VARIABLES = /\{([a-z0-9_]+)\}/gi;
Patterns.RE_RIGHT_RANDOM_CHAIN = /^[a-z][a-z0-9]*$/i;
Patterns.RE_ATTRIBUTE_BAD_SET_CHARACTERS = /[^a-z0-9]+/gi;
Patterns.RE_SPACES = / +/gi;
Patterns.RE_CLEAN_EVENT_NAME = /^on[_\-]*/i;
return Patterns;
})();

View File

@ -0,0 +1,241 @@
"use strict";
import {Check} from "./Check.ecma.js";
import {Patterns} from "./Patterns.ecma.js";
/**
* @callback anp_utils_default_callback
* @returns {void}
*/
/**
* @callback anp_utils_execute_callback
* @param {...any} [parameters]
* @returns {any|null}
*/
/**
* @callback anp_utils_execute_items_callback
* @param {?any} item
* @param {!anp_utils_default_callback} callback
* @returns {any|null}
*/
/**
* @class
* @constructor
* @returns {void}
* @access public
*/
export const Utils = (function(){
/**
* @constructs Utils
* @returns {void}
* @access private
*/
const Utils = function(){};
/**
* @param {?any} item
* @returns {Array.<any|null>}
* @access public
* @static
*/
Utils.get_array = item => Check.is_array(item) ? item : [item];
/**
* @param {!(string|Array.<string>)} keys
* @returns {Array.<string>}
* @access public
* @static
*/
Utils.get_keys = keys => Utils.get_array(keys).filter((key, i, array) => (
Check.is_key(key) && array.indexOf(key) == i
));
/**
* @param {!(string|Array.<string>)} keys
* @returns {Array.<string>}
* @access public
* @static
*/
Utils.get_pascal_keys = keys => Utils.get_array(keys).filter((key, i, array) => (
Check.is_pascal_key(key) && array.indexOf(key) == i
));
/**
* @param {!(string|Array.<string>)} strings
* @returns {Array.<string>}
* @access public
* @static
*/
Utils.get_strings = strings => Utils.get_array(strings).filter(string => Check.is_string(string));
/**
* @param {!(string|Array.<string>)} keys
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
* @param {?any} [_default = null]
* @returns {any|null}
* @access public
* @static
*/
Utils.get_value = (keys, inputs, _default = null) => {
if((keys = Utils.get_keys(keys)).length){
for(let i = 0, l = (inputs = Utils.get_array(inputs)).length; i < l; i ++){
if(Check.is_dictionary(inputs[i])){
for(let j = 0, m = keys.length; j < m; j ++)
if(inputs[i][keys[j]] !== undefined)
return inputs[i][keys[j]];
}else if(Check.is_array(inputs[i])){
/** @type {any|null|undefined} */
const response = Utils.get_value(keys, inputs[i], undefined);
if(response !== undefined)
return response;
};
};
};
return _default;
};
/**
* @param {!(Object.<string, any|null>|Array.<any|null>)} item
* @param {!boolean} [overwrite = false]
* @returns {Object.<string, any|null>}
* @access public
* @static
*/
Utils.get_dictionary = (item, overwrite = false) => Utils.get_array(item).reduce((dictionary, subitem) => {
/** @type {Object.<string, any|null>} */
const results = (
Check.is_dictionary(subitem) ? subitem :
Check.is_array(subitem) ? Utils.get_dictionary(subitem, overwrite) :
{});
for(const key in results)
if(overwrite || dictionary[key] === undefined)
dictionary[key] = results[key];
return dictionary;
}, {});
/**
* @param {!anp_utils_execute_callback} callback
* @param {...any} [parameters]
* @returns {any|null}
* @access public
* @static
*/
Utils.execute = (callback, ...parameters) => {
return Check.is_function(callback) ? callback(...parameters) : null;
};
/**
* @param {!Array.<any|null>} items
* @param {!anp_utils_execute_items_callback} each_callback
* @param {?anp_utils_default_callback} [end_callback = null]
* @param {!number} [i = 0]
* @returns {void}
* @access public
* @static
*/
Utils.execute_items = (items, each_callback, end_callback = null, i = 0) => {
// console.log([i, items.length, items]);
Utils.execute(...(
i == items.length ? [end_callback] :
[each_callback, items[i], () => {
Utils.execute_items(items, each_callback, end_callback, i + 1);
}]));
};
/**
* @param {!string} string
* @param {!(Object.<string, any|null>|Array.<any|null>)} variables
* @param {?any} [_default = null]
* @returns {string}
* @access public
* @static
*/
Utils.string_variables = (string, variables, _default = null) => {
variables = Utils.get_dictionary(variables);
return ("" + string).replace(Patterns.RE_STRING_VARIABLES, (all, key) => (
variables[key] !== undefined ? variables[key] :
Check.is_null_or_undefined(_default) ? all :
_default));
};
/**
* @param {!(Object.<string, any|null>|Array.<any|null>)} data
* @returns {string|null}
* @access public
* @static
*/
Utils.json_encode = data => {
try{
return JSON.stringify(data);
}catch(exception){};
return null;
};
/**
* @param {!string} data
* @returns {Object.<string, any|null>|Array.<any|null>|null}
* @access public
* @static
*/
Utils.json_decode = data => {
try{
return JSON.parse(data);
}catch(exception){};
return null;
};
/**
* @param {!string} string
* @returns {string|null}
* @access public
* @static
*/
Utils.base64_encode = string => {
try{
return btoa(string);
}catch(exception){};
return null;
};
/**
* @param {!string} string
* @returns {string|null}
* @access public
* @static
*/
Utils.base64_decode = string => {
try{
return atob(string);
}catch(exception){};
return null;
};
/**
* @param {!(Object.<string, any|null>|Array.<any|null>)} variables
* @returns {string|null}
* @access public
* @static
*/
Utils.variables_encode = variables => Utils.base64_encode(Utils.json_encode(variables));
/**
* @param {!string} variables
* @returns {Object.<string, any|null>|Array.<any|null>|null}
* @access public
* @static
*/
Utils.variables_decode = variables => Utils.json_decode(Utils.base64_decode(variables));
return Utils
})();

BIN
Public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
Public/images/AnP-180.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
Public/images/AnP-192.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
Public/images/AnP-270.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
Public/images/AnP-32.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
Public/images/AnP-512.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
Public/images/AnP.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

19
Public/index.html Normal file
View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="es">
<head>
<title data-i18n="anp_title_test">Test - AnP</title>
<meta name="content-type" content="text/html;charset=utf-8" />
<meta charset="utf-8" />
<script type="module" data-type="text/javascript;charset=utf-8" data-language="ECMAScript 2015" charset="utf-8">
"use strict";
import {AnP} from "./ecma/Application/AnP.ecma.js";
const anp = new AnP({debug_mode : true});
</script>
</head>
<body></body>
</html>

12
Public/index.w.md Normal file
View File

@ -0,0 +1,12 @@
```wmd-options
language = es
title_i18n = anp_title
title_text = AnP
since = 20250417
```
<!-- [[WMD]] -->
[[include /doc/es/index.w.md]]
<!-- [[WMD]] -->

View File

@ -0,0 +1,57 @@
{
"AnP_start" : null,
"autostart" : true,
"object_name" : "anp",
"application_name" : "AnP",
"application_git" : "https://git.k3y.pw/Lite/AnP",
"application_link" : "https://anp.k3y.pw/",
"application_version" : 20250419,
"application_licenses" : [
["copyright", [2019, 2026], "KyMAN"],
["cc_by_nc_sa_4"]
],
"AnP_end" : null,
"AnP_SettingsManager_start" : null,
"default_settings_files" : [
"/json/AnP.settings.json",
"/json/AnP.ecma.settings.json"
],
"default_secrets_files" : [
"/json/AnP.secrets.json",
"/json/AnP.ecma.secrets.json"
],
"AnP_SettingsManager_end" : null,
"AnP_I18NManager_start" : null,
"default_language" : "english",
"language_selected" : "english",
"default_i18n_files" : [
"/json/i18n/common/AnP.i18n.english.json",
"/json/i18n/common/AnP.i18n.espanol.json",
"/json/i18n/common/AnP.i18n.galego.json",
"/json/i18n/common/AnP.i18n.nihongo.json",
"/json/i18n/common/AnP.i18n.russkiy.json",
"/json/i18n/ecma/AnP.ecma.i18n.english.json",
"/json/i18n/ecma/AnP.ecma.i18n.espanol.json",
"/json/i18n/ecma/AnP.ecma.i18n.galego.json",
"/json/i18n/ecma/AnP.ecma.i18n.nihongo.json",
"/json/i18n/ecma/AnP.ecma.i18n.russkiy.json"
],
"AnP_I18NManager_end" : null,
"AnP_BaseComponent_start" : null,
"base_cells" : 40,
"base_minimum_size" : 12,
"base_zoom" : 100,
"base_gui_mode" : "default",
"base_footer_maximum_zoom" : 100,
"zoom_minimum" : 1,
"zoom_maximum" : 200,
"default_zoom" : 100,
"zoom_step" : 1,
"zoom_modes" : [50, 75, 100, 125, 150],
"AnP_BaseComponent_end" : null
}

View File

@ -0,0 +1,4 @@
{
"default_settings_files" : "/Public/json/AnP.go.settings.json",
"test" : "xD"
}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,3 @@
{
"english" : {}
}

View File

@ -0,0 +1,22 @@
{
"espanol" : {
"AnP_LicensesComponent_start" : null,
"cc_by_nc_sa_4" : "Creative Commons Atribución/Reconocimiento-NoComercial-CompartirIgual 4.0 Internacional (CC-BY-NC-SA 4.0)",
"all_rights_reserved" : "Todos los derechos reservados.",
"copyright" : "© Copyright{year}{authors}{all_rights_reserved}",
"AnP_LicensesComponent_end" : null,
"AnP_BaseComponent_start" : null,
"gui_controls" : "Control del GUI",
"less_zoom" : "Menos Zoom",
"zoom" : "Zoom",
"reset_zoom" : "Reestablecer el Zoom",
"zoom_mode" : "Modo de Zoom",
"more_zoom" : "Menos Zoom",
"gui_mode" : "Modo del GUI",
"more_options" : "Más opciones",
"AnP_BaseComponent_end" : null
}
}

View File

@ -0,0 +1,22 @@
{
"galego" : {
"AnP_LicensesComponent_start" : null,
"cc_by_nc_sa_4" : "Creative Commons Atribución/Recoñecemento-NonComercial-CompartirIgual 4.0 Internacional (CC-BY-NC-SA 4.0)",
"all_rights_reserved" : "Tódoslos dereitos reservados.",
"copyright" : "© Copyright{year}{authors}{all_rights_reserved}",
"AnP_LicensesComponent_end" : null,
"AnP_BaseComponent_start" : null,
"gui_controls" : "Control do GUI",
"less_zoom" : "Menos Zoom",
"zoom" : "Zoom",
"reset_zoom" : "Reestablece-lo Zoom",
"zoom_mode" : "Modo de Zoom",
"more_zoom" : "Menos Zoom",
"gui_mode" : "Modo do GUI",
"more_options" : "Máis opcións",
"AnP_BaseComponent_end" : null
}
}

View File

@ -0,0 +1,3 @@
{
"nihongo" : {}
}

View File

@ -0,0 +1,3 @@
{
"russkiy" : {}
}

View File

@ -0,0 +1,3 @@
{
"english" : {}
}

View File

@ -0,0 +1,3 @@
{
"espanol" : {}
}

View File

@ -0,0 +1,3 @@
{
"galego" : {}
}

View File

@ -0,0 +1,3 @@
{
"nihongo" : {}
}

View File

@ -0,0 +1,3 @@
{
"russkiy" : {}
}

View File

@ -0,0 +1,3 @@
.anp{
@include main_web()
}

211
Public/scss/AnP.common.scss Normal file
View File

@ -0,0 +1,211 @@
@use "sass:map";
@use "sass:list";
@use "sass:meta";
@function unicode($code){
@return unquote("\"") + unquote(str-insert($code, "\\", 1)) + unquote("\"");
}
@function map-deep-get($scope, $keys...){
$i : 1;
@while (type-of($scope) == map) and ($i <= length($keys)){
$scope : map-get($scope, nth($keys, $i));
$i : $i + 1;
}
@return $scope;
}
@mixin main_color_web($mode){
background-color : map-deep-get($color, $mode, "back");
color : map-deep-get($color, $mode, fore);
&,button,input,select,textarea{color : map-deep-get($color, $mode, fore);}
button,input,select,textarea{background-color : map-deep-get($color, $mode, input-back);}
a[href]{
&[disabled]{color : map-deep-get($color, common, grey);}
&[readonly]{color : map-deep-get($color, $mode, fore);}
&:not([disabled],[readonly]){
color : map-deep-get($color, $mode, primary);
&:hover{color : map-deep-get($color, $mode, secondary);}
}
}
button,[type=button],[type=submit],[type=reset]{
&[disabled]{
border-color : map-deep-get($color, common, grey);
color : map-deep-get($color, common, grey);
box-shadow : 0em 0em .4em inset map-deep-get($color, common, grey);
}
&[readonly]{
border-color : map-deep-get($color, $mode, fore);
color : map-deep-get($color, $mode, fore);
box-shadow : 0em 0em .4em inset map-deep-get($color, common, grey);
}
&:not([disabled],[readonly]){
border-color : map-deep-get($color, $mode, primary);
color : mix(map-deep-get($color, $mode, primary), map-deep-get($color, $mode, fore), 50%);
box-shadow : 0em 0em .4em inset map-deep-get($color, $mode, primary);
&:hover{
border-color : map-deep-get($color, $mode, secondary);
color : mix(map-deep-get($color, $mode, secondary), map-deep-get($color, $mode, fore), 50%);
box-shadow : 0em 0em .4em inset map-deep-get($color, $mode, secondary);
}
}
}
}
@mixin main_web($reverse:false){
position : relative;
top : 0em;
left : 0em;
width : 100%;
height : 100%;
overflow : hidden;
&,button,input,select{font-family : $font-normal;}
textarea,pre{font-family : $font-mono;}
button,input,select,textarea{font-size : 1em;}
[data-icon]::before{
margin-right : .4em;
font-family : $font-icon;
}
a[href]{text-decoration : none;}
a[href],button,[type=button],[type=submit],[type=reset]{&:not([disabled],[readonly]){
cursor : pointer;
transition-duration : $transition-out;
transition-property : color;
&:hover{transition-duration : $transition-in;}
}}
button,[type=button],[type=submit],[type=reset],[type=text],[type=number],[type=date],[type=password],textarea{
padding : .1em .4em;
border-width : .1em;
border-style : solid;
border-color : map-deep-get($color, common, grey);
border-radius : $border-radius;
box-shadow : 0em 0em .4em inset map-deep-get($color, common, grey);
}
button,[type=button],[type=submit],[type=reset]{&:not([disabled],[readonly]){
transition-property : color,border-color,background-color,box-shadow;
}}
.group{
&>*{&,&>*{border-radius : 0em;}}
&>:first-child{&,&>:first-child{border-radius : $border-radius 0em 0em $border-radius;}}
&>:last-child{&,&>:last-child{border-radius : 0em $border-radius $border-radius 0em;}}
}
header,main,footer{
position : absolute;
left : 0em;
width : 100%;
}
header{
top : 0em;
height : $header-height;
z-index : 20;
overflow : visible;
}
main{
top : $header-height;
bottom : $footer-height;
z-index : 10;
overflow : auto;
}
footer{
display : flex;
flex-direction : row;
justify-items : center;
bottom : 0em;
height : $footer-height;
z-index : 30;
overflow : visible;
}
@each $key, $option in (dark : true, light : false){
&[data-gui-mode=#{$key}],&[data-gui-mode=default][data-dark-mode=#{$option}]{
@include main_color_web($key);
}
}
h1{
margin : .2em .5em;
padding : 0em;
font-size : 1em;
font-weight : 900;
img{
width : auto;
height : 3.6em;
&+span{display : none;}
}
a>span{vertical-align : middle;}
&,.image{display : inline-block;}
.text{
margin-left : .2em;
font-size : 3.6em;
}
}
.main-menu{
padding-bottom : .4em;
vertical-align : bottom;
&,ul,li{display : inline-block;}
ul{
margin : 0em;
padding : 0em;
list-style-type : none;
}
li{margin : 0em 1em;}
}
.licenses{
display : flex;
flex-direction : row;
justify-items : center;
align-items : center;
width : 100%;
font-weight : 100;
text-align : center;
img{
width : auto;
height : 1.8em;
}
&>span{
margin : 0em .3em;
vertical-align : middle;
}
.text{font-size : .7em;}
}
.copyright{font-size : .7em;}
.cc-by-nc-sa-4,.gplv3{
display : flex;
flex-direction : row;
justify-items : center;
align-items : center;
&>span{margin : 0em .3em;}
}
.gui-controls{
margin : .2em .5em;
padding : 0em;
border : none;
white-space : nowrap;
font-size : .85em;
&>*{&,&>*{border-radius : 0em;}}
&{&>[data-i18n=less_zoom],.input-number,&>[data-i18n=more_zoom],&>[data-i18n=reset_zoom]{display : none;}}
button[data-i18n=zoom_mode]{&,&>:first-child{border-radius : $border-radius 0em 0em $border-radius;}}
&>:last-child{&,&>:last-child{border-radius : 0em $border-radius $border-radius 0em;}}
legend{display : none;}
[data-icon]{
&::before{margin : 0em;}
&+[data-i18n]{display : none;}
};
}
}

228
Public/scss/AnP.css Normal file
View File

@ -0,0 +1,228 @@
@use "sass:map";
@use "sass:list";
@use "sass:meta";
.anp {
position: relative;
top: 0em;
left: 0em;
width: 100%;
height: 100%;
overflow: hidden; }
.anp, .anp button, .anp input, .anp select {
font-family: "Roboto", Arial; }
.anp textarea, .anp pre {
font-family: "RobotoMono", monospace; }
.anp button, .anp input, .anp select, .anp textarea {
font-size: 1em; }
.anp [data-icon]::before {
margin-right: .4em;
font-family: "FA6FS"; }
.anp a[href] {
text-decoration: none; }
.anp a[href]:not([disabled], [readonly]), .anp button:not([disabled], [readonly]), .anp [type=button]:not([disabled], [readonly]), .anp [type=submit]:not([disabled], [readonly]), .anp [type=reset]:not([disabled], [readonly]) {
cursor: pointer;
transition-duration: 1s;
transition-property: color; }
.anp a[href]:not([disabled], [readonly]):hover, .anp button:not([disabled], [readonly]):hover, .anp [type=button]:not([disabled], [readonly]):hover, .anp [type=submit]:not([disabled], [readonly]):hover, .anp [type=reset]:not([disabled], [readonly]):hover {
transition-duration: 0.35s; }
.anp button, .anp [type=button], .anp [type=submit], .anp [type=reset], .anp [type=text], .anp [type=number], .anp [type=date], .anp [type=password], .anp textarea {
padding: .1em .4em;
border-width: .1em;
border-style: solid;
border-color: #898989;
border-radius: 0.3em;
box-shadow: 0em 0em 0.4em inset #898989; }
.anp button:not([disabled], [readonly]), .anp [type=button]:not([disabled], [readonly]), .anp [type=submit]:not([disabled], [readonly]), .anp [type=reset]:not([disabled], [readonly]) {
transition-property: color,border-color,background-color,box-shadow; }
.anp .group > *, .anp .group > * > * {
border-radius: 0em; }
.anp .group > :first-child, .anp .group > :first-child > :first-child {
border-radius: 0.3em 0em 0em 0.3em; }
.anp .group > :last-child, .anp .group > :last-child > :last-child {
border-radius: 0em 0.3em 0.3em 0em; }
.anp header, .anp main, .anp footer {
position: absolute;
left: 0em;
width: 100%; }
.anp header {
top: 0em;
height: 4em;
z-index: 20;
overflow: visible; }
.anp main {
top: 4em;
bottom: 2em;
z-index: 10;
overflow: auto; }
.anp footer {
display: flex;
flex-direction: row;
justify-items: center;
bottom: 0em;
height: 2em;
z-index: 30;
overflow: visible; }
.anp[data-gui-mode=dark], .anp[data-gui-mode=default][data-dark-mode=true] {
background-color: #222;
color: #EFEFEF; }
.anp[data-gui-mode=dark], .anp[data-gui-mode=dark] button, .anp[data-gui-mode=dark] input, .anp[data-gui-mode=dark] select, .anp[data-gui-mode=dark] textarea, .anp[data-gui-mode=default][data-dark-mode=true], .anp[data-gui-mode=default][data-dark-mode=true] button, .anp[data-gui-mode=default][data-dark-mode=true] input, .anp[data-gui-mode=default][data-dark-mode=true] select, .anp[data-gui-mode=default][data-dark-mode=true] textarea {
color: #EFEFEF; }
.anp[data-gui-mode=dark] button, .anp[data-gui-mode=dark] input, .anp[data-gui-mode=dark] select, .anp[data-gui-mode=dark] textarea, .anp[data-gui-mode=default][data-dark-mode=true] button, .anp[data-gui-mode=default][data-dark-mode=true] input, .anp[data-gui-mode=default][data-dark-mode=true] select, .anp[data-gui-mode=default][data-dark-mode=true] textarea {
background-color: #1b1b1b; }
.anp[data-gui-mode=dark] a[href][disabled], .anp[data-gui-mode=default][data-dark-mode=true] a[href][disabled] {
color: #898989; }
.anp[data-gui-mode=dark] a[href][readonly], .anp[data-gui-mode=default][data-dark-mode=true] a[href][readonly] {
color: #EFEFEF; }
.anp[data-gui-mode=dark] a[href]:not([disabled], [readonly]), .anp[data-gui-mode=default][data-dark-mode=true] a[href]:not([disabled], [readonly]) {
color: #2262b0; }
.anp[data-gui-mode=dark] a[href]:not([disabled], [readonly]):hover, .anp[data-gui-mode=default][data-dark-mode=true] a[href]:not([disabled], [readonly]):hover {
color: #b06222; }
.anp[data-gui-mode=dark] button[disabled], .anp[data-gui-mode=dark] [type=button][disabled], .anp[data-gui-mode=dark] [type=submit][disabled], .anp[data-gui-mode=dark] [type=reset][disabled], .anp[data-gui-mode=default][data-dark-mode=true] button[disabled], .anp[data-gui-mode=default][data-dark-mode=true] [type=button][disabled], .anp[data-gui-mode=default][data-dark-mode=true] [type=submit][disabled], .anp[data-gui-mode=default][data-dark-mode=true] [type=reset][disabled] {
border-color: #898989;
color: #898989;
box-shadow: 0em 0em 0.4em inset #898989; }
.anp[data-gui-mode=dark] button[readonly], .anp[data-gui-mode=dark] [type=button][readonly], .anp[data-gui-mode=dark] [type=submit][readonly], .anp[data-gui-mode=dark] [type=reset][readonly], .anp[data-gui-mode=default][data-dark-mode=true] button[readonly], .anp[data-gui-mode=default][data-dark-mode=true] [type=button][readonly], .anp[data-gui-mode=default][data-dark-mode=true] [type=submit][readonly], .anp[data-gui-mode=default][data-dark-mode=true] [type=reset][readonly] {
border-color: #EFEFEF;
color: #EFEFEF;
box-shadow: 0em 0em 0.4em inset #898989; }
.anp[data-gui-mode=dark] button:not([disabled], [readonly]), .anp[data-gui-mode=dark] [type=button]:not([disabled], [readonly]), .anp[data-gui-mode=dark] [type=submit]:not([disabled], [readonly]), .anp[data-gui-mode=dark] [type=reset]:not([disabled], [readonly]), .anp[data-gui-mode=default][data-dark-mode=true] button:not([disabled], [readonly]), .anp[data-gui-mode=default][data-dark-mode=true] [type=button]:not([disabled], [readonly]), .anp[data-gui-mode=default][data-dark-mode=true] [type=submit]:not([disabled], [readonly]), .anp[data-gui-mode=default][data-dark-mode=true] [type=reset]:not([disabled], [readonly]) {
border-color: #2262b0;
color: #89a9d0;
box-shadow: 0em 0em 0.4em inset #2262b0; }
.anp[data-gui-mode=dark] button:not([disabled], [readonly]):hover, .anp[data-gui-mode=dark] [type=button]:not([disabled], [readonly]):hover, .anp[data-gui-mode=dark] [type=submit]:not([disabled], [readonly]):hover, .anp[data-gui-mode=dark] [type=reset]:not([disabled], [readonly]):hover, .anp[data-gui-mode=default][data-dark-mode=true] button:not([disabled], [readonly]):hover, .anp[data-gui-mode=default][data-dark-mode=true] [type=button]:not([disabled], [readonly]):hover, .anp[data-gui-mode=default][data-dark-mode=true] [type=submit]:not([disabled], [readonly]):hover, .anp[data-gui-mode=default][data-dark-mode=true] [type=reset]:not([disabled], [readonly]):hover {
border-color: #b06222;
color: #d0a989;
box-shadow: 0em 0em 0.4em inset #b06222; }
.anp[data-gui-mode=light], .anp[data-gui-mode=default][data-dark-mode=false] {
background-color: #EFEFEF;
color: #222; }
.anp[data-gui-mode=light], .anp[data-gui-mode=light] button, .anp[data-gui-mode=light] input, .anp[data-gui-mode=light] select, .anp[data-gui-mode=light] textarea, .anp[data-gui-mode=default][data-dark-mode=false], .anp[data-gui-mode=default][data-dark-mode=false] button, .anp[data-gui-mode=default][data-dark-mode=false] input, .anp[data-gui-mode=default][data-dark-mode=false] select, .anp[data-gui-mode=default][data-dark-mode=false] textarea {
color: #222; }
.anp[data-gui-mode=light] button, .anp[data-gui-mode=light] input, .anp[data-gui-mode=light] select, .anp[data-gui-mode=light] textarea, .anp[data-gui-mode=default][data-dark-mode=false] button, .anp[data-gui-mode=default][data-dark-mode=false] input, .anp[data-gui-mode=default][data-dark-mode=false] select, .anp[data-gui-mode=default][data-dark-mode=false] textarea {
background-color: #f2f2f2; }
.anp[data-gui-mode=light] a[href][disabled], .anp[data-gui-mode=default][data-dark-mode=false] a[href][disabled] {
color: #898989; }
.anp[data-gui-mode=light] a[href][readonly], .anp[data-gui-mode=default][data-dark-mode=false] a[href][readonly] {
color: #222; }
.anp[data-gui-mode=light] a[href]:not([disabled], [readonly]), .anp[data-gui-mode=default][data-dark-mode=false] a[href]:not([disabled], [readonly]) {
color: #2272D4; }
.anp[data-gui-mode=light] a[href]:not([disabled], [readonly]):hover, .anp[data-gui-mode=default][data-dark-mode=false] a[href]:not([disabled], [readonly]):hover {
color: #D47222; }
.anp[data-gui-mode=light] button[disabled], .anp[data-gui-mode=light] [type=button][disabled], .anp[data-gui-mode=light] [type=submit][disabled], .anp[data-gui-mode=light] [type=reset][disabled], .anp[data-gui-mode=default][data-dark-mode=false] button[disabled], .anp[data-gui-mode=default][data-dark-mode=false] [type=button][disabled], .anp[data-gui-mode=default][data-dark-mode=false] [type=submit][disabled], .anp[data-gui-mode=default][data-dark-mode=false] [type=reset][disabled] {
border-color: #898989;
color: #898989;
box-shadow: 0em 0em 0.4em inset #898989; }
.anp[data-gui-mode=light] button[readonly], .anp[data-gui-mode=light] [type=button][readonly], .anp[data-gui-mode=light] [type=submit][readonly], .anp[data-gui-mode=light] [type=reset][readonly], .anp[data-gui-mode=default][data-dark-mode=false] button[readonly], .anp[data-gui-mode=default][data-dark-mode=false] [type=button][readonly], .anp[data-gui-mode=default][data-dark-mode=false] [type=submit][readonly], .anp[data-gui-mode=default][data-dark-mode=false] [type=reset][readonly] {
border-color: #222;
color: #222;
box-shadow: 0em 0em 0.4em inset #898989; }
.anp[data-gui-mode=light] button:not([disabled], [readonly]), .anp[data-gui-mode=light] [type=button]:not([disabled], [readonly]), .anp[data-gui-mode=light] [type=submit]:not([disabled], [readonly]), .anp[data-gui-mode=light] [type=reset]:not([disabled], [readonly]), .anp[data-gui-mode=default][data-dark-mode=false] button:not([disabled], [readonly]), .anp[data-gui-mode=default][data-dark-mode=false] [type=button]:not([disabled], [readonly]), .anp[data-gui-mode=default][data-dark-mode=false] [type=submit]:not([disabled], [readonly]), .anp[data-gui-mode=default][data-dark-mode=false] [type=reset]:not([disabled], [readonly]) {
border-color: #2272D4;
color: #224a7b;
box-shadow: 0em 0em 0.4em inset #2272D4; }
.anp[data-gui-mode=light] button:not([disabled], [readonly]):hover, .anp[data-gui-mode=light] [type=button]:not([disabled], [readonly]):hover, .anp[data-gui-mode=light] [type=submit]:not([disabled], [readonly]):hover, .anp[data-gui-mode=light] [type=reset]:not([disabled], [readonly]):hover, .anp[data-gui-mode=default][data-dark-mode=false] button:not([disabled], [readonly]):hover, .anp[data-gui-mode=default][data-dark-mode=false] [type=button]:not([disabled], [readonly]):hover, .anp[data-gui-mode=default][data-dark-mode=false] [type=submit]:not([disabled], [readonly]):hover, .anp[data-gui-mode=default][data-dark-mode=false] [type=reset]:not([disabled], [readonly]):hover {
border-color: #D47222;
color: #7b4a22;
box-shadow: 0em 0em 0.4em inset #D47222; }
.anp h1 {
margin: .2em .5em;
padding: 0em;
font-size: 1em;
font-weight: 900; }
.anp h1 img {
width: auto;
height: 3.6em; }
.anp h1 img + span {
display: none; }
.anp h1 a > span {
vertical-align: middle; }
.anp h1, .anp h1 .image {
display: inline-block; }
.anp h1 .text {
margin-left: .2em;
font-size: 3.6em; }
.anp .main-menu {
padding-bottom: .4em;
vertical-align: bottom; }
.anp .main-menu, .anp .main-menu ul, .anp .main-menu li {
display: inline-block; }
.anp .main-menu ul {
margin: 0em;
padding: 0em;
list-style-type: none; }
.anp .main-menu li {
margin: 0em 1em; }
.anp .licenses {
display: flex;
flex-direction: row;
justify-items: center;
align-items: center;
width: 100%;
font-weight: 100;
text-align: center; }
.anp .licenses img {
width: auto;
height: 1.8em; }
.anp .licenses > span {
margin: 0em .3em;
vertical-align: middle; }
.anp .licenses .text {
font-size: .7em; }
.anp .copyright {
font-size: .7em; }
.anp .cc-by-nc-sa-4, .anp .gplv3 {
display: flex;
flex-direction: row;
justify-items: center;
align-items: center; }
.anp .cc-by-nc-sa-4 > span, .anp .gplv3 > span {
margin: 0em .3em; }
.anp .gui-controls {
margin: .2em .5em;
padding: 0em;
border: none;
white-space: nowrap;
font-size: .85em; }
.anp .gui-controls > *, .anp .gui-controls > * > * {
border-radius: 0em; }
.anp .gui-controls > [data-i18n=less_zoom], .anp .gui-controls .input-number, .anp .gui-controls > [data-i18n=more_zoom], .anp .gui-controls > [data-i18n=reset_zoom] {
display: none; }
.anp .gui-controls button[data-i18n=zoom_mode], .anp .gui-controls button[data-i18n=zoom_mode] > :first-child {
border-radius: 0.3em 0em 0em 0.3em; }
.anp .gui-controls > :last-child, .anp .gui-controls > :last-child > :last-child {
border-radius: 0em 0.3em 0.3em 0em; }
.anp .gui-controls legend {
display: none; }
.anp .gui-controls [data-icon]::before {
margin: 0em; }
.anp .gui-controls [data-icon] + [data-i18n] {
display: none; }
.anp [data-icon=less_zoom]::before {
content: "\f010"; }
.anp [data-icon=more_zoom]::before {
content: "\f00e"; }
.anp [data-icon=reset_zoom]::before {
content: "\f002"; }
.anp [data-icon=zoom_mode]::before {
content: "\f689"; }
.anp [data-icon=more_options]::before {
content: "\f013"; }
.anp [data-icon=home]::before {
content: "\f015"; }
.anp [data-icon=web]::before {
content: "\f0ac"; }
.anp [data-icon=git]::before {
content: "\f841";
font-family: "FA6FB"; }
.anp [data-icon=documentation]::before {
content: "\f15c";
font-family: "FA6FR"; }
.anp[data-gui-mode=default] [data-icon=gui_mode]::before {
content: "\f850"; }
.anp[data-gui-mode=dark] [data-icon=gui_mode]::before {
content: "\f3fb"; }
.anp[data-gui-mode=light] [data-icon=gui_mode]::before {
content: "\f009"; }
/*# sourceMappingURL=AnP.css.map */

7
Public/scss/AnP.css.map Normal file
View File

@ -0,0 +1,7 @@
{
"version": 3,
"mappings": "AAAA,eAAe;AACf,gBAAgB;AAChB,gBAAgB;ACFhB,IAAI;ED2DA,QAAQ,EAAG,QAAQ;EACnB,GAAG,EAAG,GAAG;EACT,IAAI,EAAG,GAAG;EACV,KAAK,EAAG,IAAI;EACZ,MAAM,EAAG,IAAI;EACb,QAAQ,EAAG,MAAM;EAEjB,0CAAqB;IAAC,WAAW,EEnCtB,eAAe;EFoC1B,uBAAY;IAAC,WAAW,EEnCf,uBAAuB;EFoChC,mDAA4B;IAAC,SAAS,EAAG,GAAG;EAC5C,wBAAmB;IACf,YAAY,EAAG,IAAI;IACnB,WAAW,EEtCN,OAAO;EFyChB,YAAO;IAAC,eAAe,EAAG,IAAI;EAC0B,gOAA4B;IAChF,MAAM,EAAG,OAAO;IAChB,mBAAmB,EExCT,EAAE;IFyCZ,mBAAmB,EAAG,KAAK;IAC3B,8PAAO;MAAC,mBAAmB,EE3ClB,KAAI;EF6CjB,mKAA8G;IAC1G,OAAO,EAAG,SAAS;IACnB,YAAY,EAAG,IAAI;IACnB,YAAY,EAAG,KAAK;IACpB,YAAY,EAxEH,OAA+B;IAyExC,aAAa,EE1DJ,KAAI;IF2Db,UAAU,EAAG,2BAAqD;EAEtB,sLAA4B;IACxE,mBAAmB,EAAG,8CAA8C;EAIhE,oCAAK;IAAC,aAAa,EAAG,GAAG;EACd,qEAAgB;IAAC,aAAa,EAAG,mBAAqC;EACvE,kEAAe;IAAC,aAAa,EAAG,mBAAqC;EAGvF,mCAAkB;IACd,QAAQ,EAAG,QAAQ;IACnB,IAAI,EAAG,GAAG;IACV,KAAK,EAAG,IAAI;EAGhB,WAAM;IACF,GAAG,EAAG,GAAG;IACT,MAAM,EEjFG,GAAG;IFkFZ,OAAO,EAAG,EAAE;IACZ,QAAQ,EAAG,OAAO;EAGtB,SAAI;IACA,GAAG,EEvFM,GAAG;IFwFZ,MAAM,EEvFG,GAAG;IFwFZ,OAAO,EAAG,EAAE;IACZ,QAAQ,EAAG,IAAI;EAGnB,WAAM;IACF,OAAO,EAAG,IAAI;IACd,cAAc,EAAG,GAAG;IACpB,aAAa,EAAG,MAAM;IACtB,MAAM,EAAG,GAAG;IACZ,MAAM,EEjGG,GAAG;IFkGZ,OAAO,EAAG,EAAE;IACZ,QAAQ,EAAG,OAAO;EAIlB,0EAA4E;IA7GhF,gBAAgB,EARH,IAA+B;IAS5C,KAAK,EATQ,OAA+B;IAU5C,obAA8B;MAAC,KAAK,EAVvB,OAA+B;IAW5C,wWAA4B;MAAC,gBAAgB,EAXhC,OAA+B;IAaxC,8GAAW;MAAC,KAAK,EAbR,OAA+B;IAcxC,8GAAW;MAAC,KAAK,EAdR,OAA+B;IAexC,kJAA4B;MACxB,KAAK,EAhBA,OAA+B;MAiBpC,8JAAO;QAAC,KAAK,EAjBR,OAA+B;IAqBxC,8dAAW;MACP,YAAY,EAtBP,OAA+B;MAuBpC,KAAK,EAvBA,OAA+B;MAwBpC,UAAU,EAAG,2BAAqD;IAEtE,8dAAW;MACP,YAAY,EA3BP,OAA+B;MA4BpC,KAAK,EA5BA,OAA+B;MA6BpC,UAAU,EAAG,2BAAqD;IAEtE,8mBAA4B;MACxB,YAAY,EAhCP,OAA+B;MAiCpC,KAAK,EAAG,OAAiF;MACzF,UAAU,EAAG,2BAAuD;MACpE,8pBAAO;QACH,YAAY,EApCX,OAA+B;QAqChC,KAAK,EAAG,OAAmF;QAC3F,UAAU,EAAG,2BAAyD;EA+E9E,4EAA4E;IA7GhF,gBAAgB,EARH,OAA+B;IAS5C,KAAK,EATQ,IAA+B;IAU5C,8bAA8B;MAAC,KAAK,EAVvB,IAA+B;IAW5C,gXAA4B;MAAC,gBAAgB,EAXhC,OAA+B;IAaxC,gHAAW;MAAC,KAAK,EAbR,OAA+B;IAcxC,gHAAW;MAAC,KAAK,EAdR,IAA+B;IAexC,oJAA4B;MACxB,KAAK,EAhBA,OAA+B;MAiBpC,gKAAO;QAAC,KAAK,EAjBR,OAA+B;IAqBxC,seAAW;MACP,YAAY,EAtBP,OAA+B;MAuBpC,KAAK,EAvBA,OAA+B;MAwBpC,UAAU,EAAG,2BAAqD;IAEtE,seAAW;MACP,YAAY,EA3BP,IAA+B;MA4BpC,KAAK,EA5BA,IAA+B;MA6BpC,UAAU,EAAG,2BAAqD;IAEtE,snBAA4B;MACxB,YAAY,EAhCP,OAA+B;MAiCpC,KAAK,EAAG,OAAiF;MACzF,UAAU,EAAG,2BAAuD;MACpE,sqBAAO;QACH,YAAY,EApCX,OAA+B;QAqChC,KAAK,EAAG,OAAmF;QAC3F,UAAU,EAAG,2BAAyD;EAoFlF,OAAE;IACE,MAAM,EAAG,SAAS;IAClB,OAAO,EAAG,GAAG;IACb,SAAS,EAAG,GAAG;IACf,WAAW,EAAG,GAAG;IACjB,WAAG;MACC,KAAK,EAAG,IAAI;MACZ,MAAM,EAAG,KAAK;MACd,kBAAM;QAAC,OAAO,EAAG,IAAI;IAEzB,gBAAM;MAAC,cAAc,EAAG,MAAM;IAC9B,uBAAQ;MAAC,OAAO,EAAG,YAAY;IAC/B,aAAK;MACD,WAAW,EAAG,IAAI;MAClB,SAAS,EAAG,KAAK;EAIzB,eAAU;IACN,cAAc,EAAG,IAAI;IACrB,cAAc,EAAG,MAAM;IACvB,uDAAO;MAAC,OAAO,EAAG,YAAY;IAC9B,kBAAE;MACE,MAAM,EAAG,GAAG;MACZ,OAAO,EAAG,GAAG;MACb,eAAe,EAAG,IAAI;IAE1B,kBAAE;MAAC,MAAM,EAAG,OAAO;EAGvB,cAAS;IACL,OAAO,EAAG,IAAI;IACd,cAAc,EAAG,GAAG;IACpB,aAAa,EAAG,MAAM;IACtB,WAAW,EAAG,MAAM;IACpB,KAAK,EAAG,IAAI;IACZ,WAAW,EAAG,GAAG;IACjB,UAAU,EAAG,MAAM;IACnB,kBAAG;MACC,KAAK,EAAG,IAAI;MACZ,MAAM,EAAG,KAAK;IAElB,qBAAM;MACF,MAAM,EAAG,QAAQ;MACjB,cAAc,EAAG,MAAM;IAE3B,oBAAK;MAAC,SAAS,EAAG,IAAI;EAE1B,eAAU;IAAC,SAAS,EAAG,IAAI;EAE3B,gCAAqB;IACjB,OAAO,EAAG,IAAI;IACd,cAAc,EAAG,GAAG;IACpB,aAAa,EAAG,MAAM;IACtB,WAAW,EAAG,MAAM;IACpB,8CAAM;MAAC,MAAM,EAAG,QAAQ;EAG5B,kBAAa;IACT,MAAM,EAAG,SAAS;IAClB,OAAO,EAAG,GAAG;IACb,MAAM,EAAG,IAAI;IACb,WAAW,EAAG,MAAM;IACpB,SAAS,EAAG,KAAK;IACb,kDAAK;MAAC,aAAa,EAAG,GAAG;IAC3B,qKAAsF;MAAC,OAAO,EAAG,IAAI;IAC3E,6GAAgB;MAAC,aAAa,EAAG,mBAAqC;IACpF,gFAAe;MAAC,aAAa,EAAG,mBAAqC;IACnF,yBAAM;MAAC,OAAO,EAAG,IAAI;IAEjB,sCAAS;MAAC,MAAM,EAAG,GAAG;IACtB,4CAAa;MAAC,OAAO,EAAG,IAAI;;AGnMhC,kCAA4B;EAAC,OAAO,EAAG,OAAc;AAArD,kCAA4B;EAAC,OAAO,EAAG,OAAc;AAArD,mCAA4B;EAAC,OAAO,EAAG,OAAc;AAArD,kCAA4B;EAAC,OAAO,EAAG,OAAc;AAArD,qCAA4B;EAAC,OAAO,EAAG,OAAc;AAArD,6BAA4B;EAAC,OAAO,EAAG,OAAc;AAArD,4BAA4B;EAAC,OAAO,EAAG,OAAc;AAMrD,4BAA4B;EAAC,OAAO,EAAG,OAAc;EAAE,WAAW,EAAG,OAAO;AAM5E,sCAA4B;EAAC,OAAO,EAAG,OAAc;EAAE,WAAW,EAAG,OAAO;AAQ5E,wDAAsD;EAAC,OAAO,EAAG,OAAc;AAA/E,qDAAsD;EAAC,OAAO,EAAG,OAAc;AAA/E,sDAAsD;EAAC,OAAO,EAAG,OAAc",
"sources": ["AnP.common.scss","AnP.base.scss","AnP.settings.scss","AnP.icons.scss"],
"names": [],
"file": "AnP.css"
}

View File

@ -0,0 +1,35 @@
.anp{
@each $name, $code in (
"less_zoom" : "f010",
"more_zoom" : "f00e",
"reset_zoom" : "f002",
"zoom_mode" : "f689",
"more_options" : "f013",
"home" : "f015",
"web" : "f0ac"
){
[data-icon=#{$name}]::before{content : unicode($code);}
}
@each $name, $code in (
"git" : "f841"
){
[data-icon=#{$name}]::before{content : unicode($code); font-family : "FA6FB";}
}
@each $name, $code in (
"documentation" : "f15c"
){
[data-icon=#{$name}]::before{content : unicode($code); font-family : "FA6FR";}
}
@each $mode, $code in (
"default" : "f850",
"dark" : "f3fb",
"light" : "f009",
){
&[data-gui-mode=#{$mode}] [data-icon=gui_mode]::before{content : unicode($code);}
}
}

1
Public/scss/AnP.scss Normal file
View File

@ -0,0 +1 @@
@import "AnP.settings.scss", "AnP.common.scss", "AnP.base.scss", "AnP.icons.scss";

View File

@ -0,0 +1,39 @@
// Colors.
$color-fore : #222;
$color-back : #EFEFEF;
$color-primary : #2272D4;
$color-secondary : #D47222;
$color : (
light : (
fore : $color-fore,
back : $color-back,
primary : $color-primary,
secondary : $color-secondary,
input-back : mix($color-back, #FFF, 80%)
),
dark : (
fore : $color-back,
back : $color-fore,
primary : mix($color-primary, $color-fore, 80%),
secondary : mix($color-secondary, $color-fore, 80%),
input-back : mix($color-fore, #000, 80%)
),
common : (
grey : mix($color-fore, $color-back, 50%)
)
);
// Sizes.
$header-height : 4em;
$footer-height : 2em;
$border-radius : .3em;
// Fonts.
$font-normal : "Roboto", Arial;
$font-mono : "RobotoMono", monospace;
$font-icon : "FA6FS";
// Transitions.
$transition-in : .35s;
$transition-out : 1s;
$transition : .5s;

35
Public/test.anp.html Normal file
View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="es">
<head>
<title data-i18n="anp_title_test">Test - AnP</title>
<meta name="content-type" content="text/html;charset=utf-8" />
<meta charset="utf-8" />
<style data-type="text/css;charset=utf-8" data-language="CSS3" data-rel="stylesheet" charset="utf-8">
html,body{
height : 100%;
margin : 0em;
}
</style>
<link type="text/css;charset=utf-8" data-language="CSS3" rel="stylesheet" href="/css/FontAwesome-6.7.2.css" data-crossorigin="anonymous" charset="utf-8" />
<link type="text/css;charset=utf-8" data-language="SASS/CSS3" rel="stylesheet" href="/scss/AnP.css" data-scss="/scss/AnP.scss" data-css-map="/scss/AnP.css.map" data-crossorigin="anonymous" charset="utf-8" />
<script type="module" data-type="text/javascript;charset=utf-8" data-language="ECMAScript 2015" charset="utf-8">
"use strict";
import {AnP} from "./ecma/Application/AnP.ecma.js";
/** @type {AnP} */
const anp = new AnP({
debug_mode : true,
position : "body"
});
</script>
</head>
<body></body>
</html>

13
Public/test.w.md Normal file
View File

@ -0,0 +1,13 @@
```wmd-options
language = es
title_i18n = anp_test
title_text = Test - AnP
```
<!-- [[wmd]] -->
# AnP
Esto es ***una*** prueba.
<!-- [[wmd]] -->

237
Public/tests.w.md Normal file
View File

@ -0,0 +1,237 @@
```wmd-options
language = es
title_i18n = wmarkdown_title_tests
title_text = Tests - WMarkDown
```
<!-- [[wmd]] -->
## Tests
Tests de Checks:
[| class="wmd-checks-viewer"
|=| Marca |
|= Upper | Lower | Valor
| \[ ] | \[ ] | [ ]
| \[X] | \[x] | [x]
| \[-] | \[-] | [-]
| \( ) | \( ) | ( )
| \(X) | \(x) | (x)
| \(-) | \(-) | (-)
| \{V} | \{v} | {v}
| \{W} | \{w} | {w}
| \{X} | \{x} | {x}
|]
Con esto, esto [X] es un Checkbox.
Esto es una prueba de ***Italic-Bold***. ¿Funca? ¿Y si *ponemos esto **con negrilla**, funcionaría*?
Bloque de Flowcharts de Mermaid JS:
```mermaid
flowchart TD
A --> B
B --> C
```
Bloque de funciones matemáticas:
```maths
f(x) = a + bc + c
```
Este elemento [[#F00]], que es lo mismo que [[color #F00]] y [[color red]], es una prueba de muestra de color rojo.
[[@ [Integer|String|Array<Integer,String>] ErrorsManager.bitwise(!Integer | String | Array<Integer,String> code = "jojo", !Integer bits)]]
Imagen:
((!image https://images.unsplash.com/photo-1597852074816-d933c7d2b988 Esto es una prueba xD))
((!picture https://images.unsplash.com/photo-1597852074816-d933c7d2b988 Esto es una prueba xD))
Y esto sería un icono ((!icon https://images.unsplash.com/photo-1597852074816-d933c7d2b988 Esto es una prueba xD)) xD
* Elemento A
* Elemento B
* Elemento C
- Elemento A
- Elemento B
- JoJo
- Elemento C
+ Elemento A
+ Elemento B
- jojo
+ Elemento C
# Elemento A
# Elemento B
#* Elemento BA
#* Elemento BB
#*# Elemento BBA
# Elemento C
1. Elemento A
2. Elemento B
3. Elemento C
a. Elemento A
b. Elemento B
c. Elemento C
A. Elemento A
B. Elemento B
C. Elemento C
i. Elemento A
i. Elemento B
i. Elemento C
i. Elemento A
ii. Elemento B
iii. Elemento C
I. Elemento A
I. Elemento B
I. Elemento C
4. Elemento 1.
+ Elemento 2.
# Elemento 2-1.
# Elemento 2-2.
# Elemento 2-3.
* Elemento 3.
# Elemento 3-1.
# Elemento 3-2.
# Elemento 3-3.
- Elemento 4.
# Elemento 4-1.
# Elemento 4-2.
# Elemento 4-3.
* Elemento N.
# Elemento N-1.
# Elemento N-2.
# Elemento N-3.
> [!@Srx00] jojo xDDD
Esto es un texto ~~-tachado-~~ xDDD.
Y esto es un texto __subrayado__ xDD.
##### Esto sería un H5.
###### Esto sería un H6.
https://wmarkdown.k3y.pw/
kyman@wmarkdown.k3y.pw
[+94 683 43 12 441]
===== Esto sería un H5. =====
====== Esto sería un H6. ======
También puedes poner direcciones como Cryptomonedas como [bitcoin:tb1qujswuek3mefsm3m84g94ek40drysxe9z09yfnc tb1qujswuek3mefsm3m84g94ek40drysxe9z09yfnc] o [litecoin:tltc1q4xy8sg2hf6nqqrhp69aukn6md3rx8v6jlqc67s tltc1q4xy8sg2hf6nqqrhp69aukn6md3rx8v6jlqc67s] entre otras.
También puedes poner direcciones como Cryptomonedas como [tb1qujswuek3mefsm3m84g94ek40drysxe9z09yfnc](bitcoin:tb1qujswuek3mefsm3m84g94ek40drysxe9z09yfnc Dirección Bitcoin TestNet) o [tltc1q4xy8sg2hf6nqqrhp69aukn6md3rx8v6jlqc67s](litecoin:tltc1q4xy8sg2hf6nqqrhp69aukn6md3rx8v6jlqc67s Dirección Litecoin TestNet) entre otras.
A continuación montaremos una tabla.
[| class="jojo"
|^ Cabecera 1 | Cabecera 2 | Cabecera 3 | Cabecera N
|= Título 1 | Título 2 | Título 3 | Título N
| Elemento 1 | Elemento 2 | Elemento 3 | Elemento N
| Elemento 1 | Elemento 2 | Elemento 3 | Elemento N
| Elemento 1 | Elemento 2 | Elemento 3 | Elemento N
|_ Pie 1 | Pie 2 | Pie 3 | Pie N
|]
[|
|= Columna 1 | Columna 2 | Columna 3 | Columna 4 | Columna 5
| Columna 1 | Columna 2 | Columna 3 | Columna 4 | Columna 5
||| Columna 1-3 | Columna 4 | Columna 5
| Columna 1 | *Columna* 2 ||| Columna 3-5
| Columna 1 || Columna 2-3 | [https://wmarkdown.k3y.pw/#tablas Columna 4] | Columna 5
|]
[|
|= Columna 1 | Columna 2 | Columna 3
| Celda 1-A | Celda 2-A | Celda 3-A
| Celda 1-B | "Celda 2-B
Esto es más contenido de la celda 2-B." | Celda 3-B
| Celda 1-C | 'Celda 2-C
Esto es más contenido de la celda 2-C.' | Celda 3-C
|]
## Code Sample Block Test
<code-sample-block>
```js
console.log("PASA");
```
```py
print("PASA")
```
¿Funciona? xD
```rust
fn main(){
println!(String::from("PASA"));
}
```
```go
fn main(){
println("PASA")
}
```
```c
print("PASA");
```
```c++
#include <iostream>
#include <string>
std::cout << "PASA" << std::endl;
```
```c#
debug.println("a", "PASA");
```
```java
system.out.println("PASA");
```
```php
echo "PASA";
```
```as
trace("PASA");
```
```sql
select "PASA" as x
```
</code-sample-block>
<!-- [[wmd]] -->

6
Tools/run.go.server.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
cd ../Go
go build -o ../Bin/AnP.golang.debug Main/Server/Main.go
../Bin/AnP.golang.debug
# rm ../Bin/AnP.golang.debug
cd ../Tools

6
Tools/run.go.test.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
cd ../Go
go build -o ../Bin/AnP.test.golang.debug Main/Test/Main.go
../Bin/AnP.test.golang.debug
# rm ../Bin/AnP.test.golang.debug
cd ../Tools

4
Tools/sass.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
directory=`dirname $(readlink -f "$0")`
sass $directory/../Public/scss/AnP.scss ../Public/scss/AnP.css;
# sass $directory/../Public/scss/AnPWeb.scss ../Public/scss/AnPWeb.css;

1
version Normal file
View File

@ -0,0 +1 @@
0.0.1