mirror of
https://github.com/Floriansylvain/RenewCMS.git
synced 2026-08-19 11:43:22 +02:00
+1
-1
@@ -9,6 +9,6 @@ RUN go mod download
|
||||
ADD cmd ./cmd/
|
||||
ADD internal ./internal/
|
||||
COPY .env ./
|
||||
RUN go build -o ./GohCMS/ ./cmd ./internal
|
||||
RUN go build -o ./GohCMS/ ./...
|
||||
|
||||
CMD ["./GohCMS/cmd"]
|
||||
@@ -12,7 +12,10 @@ docker-compose up
|
||||
TODO
|
||||
## Environment variables
|
||||
- ./env
|
||||
- APP_HOST_ADDRESS
|
||||
- APP_BASE_API_PATH
|
||||
- APP_BASE_FRONT_PATH
|
||||
- APP_API_ADDRESS
|
||||
- APP_FRONT_ADDRESS
|
||||
- APP_API_PORT
|
||||
- APP_FRONT_PORT
|
||||
- APP_JWT_SECRET
|
||||
|
||||
+45
-22
@@ -4,36 +4,45 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/Floriansylvain/GohCMS/internal/api"
|
||||
"github.com/Floriansylvain/GohCMS/internal/articles"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gotest/internal"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
var ginMode = os.Getenv("APP_GIN_MODE")
|
||||
var apiPort = os.Getenv("APP_API_PORT")
|
||||
var frontPort = os.Getenv("APP_FRONT_PORT")
|
||||
var hostAddress = os.Getenv("APP_HOST_ADDRESS")
|
||||
var (
|
||||
ginMode string
|
||||
apiPort string
|
||||
apiBaseUrl string
|
||||
frontAddress string
|
||||
)
|
||||
|
||||
func initEnvVariables() {
|
||||
if godotenv.Load() != nil {
|
||||
panic("Error loading .env file.")
|
||||
}
|
||||
|
||||
ginMode = os.Getenv("APP_GIN_MODE")
|
||||
apiPort = os.Getenv("APP_API_PORT")
|
||||
apiBaseUrl = os.Getenv("APP_BASE_API_PATH")
|
||||
frontAddress = os.Getenv("APP_FRONT_ADDRESS")
|
||||
}
|
||||
|
||||
func initJWT() {
|
||||
errInit := internal.AuthMiddleware.MiddlewareInit()
|
||||
errInit := api.AuthMiddleware.MiddlewareInit()
|
||||
if errInit != nil {
|
||||
fmt.Printf(errInit.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func initBasicRoutes(r *gin.Engine) {
|
||||
r.POST("/login/", internal.AuthMiddleware.LoginHandler)
|
||||
r.GET("/ping/", internal.Ping)
|
||||
func initBasicRoutes(r *gin.RouterGroup) {
|
||||
r.POST("/login/", api.AuthMiddleware.LoginHandler)
|
||||
r.POST("/logout/", api.AuthMiddleware.LogoutHandler)
|
||||
r.GET("/ping/", api.Ping)
|
||||
}
|
||||
|
||||
func corsMiddleware(c *gin.Context) {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", fmt.Sprintf("http://%v:%v", hostAddress, frontPort))
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", frontAddress)
|
||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
|
||||
@@ -44,33 +53,47 @@ func corsMiddleware(c *gin.Context) {
|
||||
c.Next()
|
||||
}
|
||||
|
||||
func initArticlesRoutes(r *gin.Engine) {
|
||||
articlesRouter := r.Group("/articles")
|
||||
articlesRouter.Use(corsMiddleware, internal.AuthMiddleware.MiddlewareFunc())
|
||||
func jwtProxyMiddleware(c *gin.Context) {
|
||||
jwtToken, _ := c.Cookie("jwt")
|
||||
c.Request.Header.Set("Authorization", fmt.Sprintf("Bearer %v", jwtToken))
|
||||
c.Next()
|
||||
}
|
||||
|
||||
articlesRouter.GET("/", internal.GetAllArticlesHandler)
|
||||
articlesRouter.GET("/:id", internal.GetArticleHandler)
|
||||
articlesRouter.POST("/:id", internal.AddArticleHandler)
|
||||
articlesRouter.PATCH("/:id", internal.EditArticleHandler)
|
||||
articlesRouter.DELETE("/:id", internal.DeleteArticleHandler)
|
||||
func initArticlesRoutes(r *gin.RouterGroup) {
|
||||
articlesRouter := r.Group("/articles")
|
||||
articlesRouter.Use(corsMiddleware, api.AuthMiddleware.MiddlewareFunc())
|
||||
|
||||
articlesRouter.GET("/", articles.GetArticleHandler)
|
||||
articlesRouter.GET("/:id", articles.GetArticleHandler)
|
||||
articlesRouter.POST("/:id", articles.AddArticleHandler)
|
||||
articlesRouter.PATCH("/:id", articles.EditArticleHandler)
|
||||
articlesRouter.DELETE("/:id", articles.DeleteArticleHandler)
|
||||
}
|
||||
|
||||
func initGin() {
|
||||
r := gin.Default()
|
||||
r.Use(corsMiddleware)
|
||||
r.Use(jwtProxyMiddleware, corsMiddleware)
|
||||
|
||||
var router *gin.RouterGroup
|
||||
if apiBaseUrl != "" {
|
||||
router = r.Group(apiBaseUrl)
|
||||
} else {
|
||||
router = &r.RouterGroup
|
||||
}
|
||||
|
||||
if ginMode == "release" {
|
||||
gin.SetMode(ginMode)
|
||||
api.AuthMiddleware.SecureCookie = true
|
||||
}
|
||||
|
||||
initBasicRoutes(r)
|
||||
initArticlesRoutes(r)
|
||||
initBasicRoutes(router)
|
||||
initArticlesRoutes(router)
|
||||
|
||||
r.Run(":" + apiPort)
|
||||
}
|
||||
|
||||
func main() {
|
||||
initEnvVariables()
|
||||
initJWT()
|
||||
initGin()
|
||||
initJWT()
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
module github.com/gotest
|
||||
module github.com/Floriansylvain/GohCMS
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/appleboy/gin-jwt/v2 v2.9.1
|
||||
github.com/gin-gonic/gin v1.8.1
|
||||
github.com/gin-gonic/gin v1.8.2
|
||||
github.com/joho/godotenv v1.4.0
|
||||
go.mongodb.org/mongo-driver v1.11.1
|
||||
)
|
||||
@@ -14,7 +14,6 @@ require (
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.11.1 // indirect
|
||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||
github.com/goccy/go-json v0.10.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
@@ -22,13 +21,12 @@ require (
|
||||
github.com/klauspost/compress v1.15.13 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.15 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/montanaflynn/stats v0.6.6 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.7 // indirect
|
||||
github.com/ugorji/go/codec v1.2.8 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
|
||||
@@ -1,79 +1,76 @@
|
||||
github.com/appleboy/gin-jwt/v2 v2.9.1 h1:l29et8iLW6omcHltsOP6LLk4s3v4g2FbFs0koxGWVZs=
|
||||
github.com/appleboy/gin-jwt/v2 v2.9.1/go.mod h1:jwcPZJ92uoC9nOUTOKWoN/f6JZOgMSKlFSHw5/FrRUk=
|
||||
github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4=
|
||||
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
|
||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||
github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY=
|
||||
github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
|
||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
|
||||
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
|
||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
|
||||
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.13 h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexDMMOV0=
|
||||
github.com/klauspost/compress v1.15.13/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/montanaflynn/stats v0.6.6 h1:Duep6KMIDpY4Yo11iFsvyqJDyfzLF9+sndUKT+v64GQ=
|
||||
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@@ -83,59 +80,52 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
|
||||
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
github.com/ugorji/go/codec v1.2.8 h1:sgBJS6COt0b/P40VouWKdseidkDgHxYGm0SAglUHfP0=
|
||||
github.com/ugorji/go/codec v1.2.8/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.10.3 h1:XDQEvmh6z1EUsXuIkXE9TaVeqHw6SwS1uf93jFs0HBA=
|
||||
go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8=
|
||||
go.mongodb.org/mongo-driver v1.11.1 h1:QP0znIRTuL0jf1oBQoAoM0C6ZJfBK4kx0Uumtv1A7w8=
|
||||
go.mongodb.org/mongo-driver v1.11.1/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -145,7 +135,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -157,9 +146,7 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
@@ -168,18 +155,20 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/Floriansylvain/GohCMS/internal/database"
|
||||
jwt "github.com/appleboy/gin-jwt/v2"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Email string `json:"email" bson:"email"`
|
||||
Password string `json:"password" bson:"password"`
|
||||
}
|
||||
|
||||
var UsersLocation = database.Location{Database: "gohcms", Collection: "users"}
|
||||
|
||||
var AuthMiddleware, _ = jwt.New(&jwt.GinJWTMiddleware{
|
||||
Realm: "GohCMS",
|
||||
Key: []byte(os.Getenv("APP_JWT_SECRET")),
|
||||
SendCookie: true,
|
||||
CookieHTTPOnly: true,
|
||||
CookieSameSite: http.SameSiteStrictMode,
|
||||
Timeout: time.Hour,
|
||||
MaxRefresh: time.Hour,
|
||||
LoginResponse: JWTLoginResponse,
|
||||
Authenticator: JWTAuthenticator,
|
||||
})
|
||||
|
||||
func JWTLoginResponse(c *gin.Context, code int, message string, expire time.Time) {
|
||||
if code == http.StatusOK {
|
||||
c.JSON(code, gin.H{"code": code, "message": "Successfully logged in!", "expire": expire.Format(time.RFC3339)})
|
||||
} else {
|
||||
c.JSON(code, gin.H{"code": code, "message": "Something wrong has happened."})
|
||||
}
|
||||
}
|
||||
|
||||
func JWTAuthenticator(c *gin.Context) (interface{}, error) {
|
||||
var user = User{}
|
||||
err := c.BindJSON(&user)
|
||||
if err != nil {
|
||||
return nil, errors.New("wrong credentials json format.")
|
||||
}
|
||||
|
||||
_, err = database.GetUniqueDocument(UsersLocation, bson.D{
|
||||
{Key: "email", Value: user.Email},
|
||||
{Key: "password", Value: user.Password},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.New("wrong email or password.")
|
||||
}
|
||||
|
||||
return gin.H{"email": user.Email}, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
@@ -0,0 +1,41 @@
|
||||
package articles
|
||||
|
||||
import (
|
||||
"github.com/Floriansylvain/GohCMS/internal/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
type Article struct {
|
||||
TitleID string `json:"titleID" bson:"titleID"`
|
||||
Title string `json:"title" bson:"title"`
|
||||
Date int64 `json:"date" bson:"date"`
|
||||
Content gin.H `json:"content" bson:"content"`
|
||||
Tags []string `json:"tags" bson:"tags"`
|
||||
Online bool `json:"online" bson:"online"`
|
||||
}
|
||||
|
||||
var articlesLocation = database.Location{Database: "gohcms", Collection: "articles"}
|
||||
|
||||
func ParseArticlesFromBytesToArray(documents [][]byte) []Article {
|
||||
var articles = []Article{}
|
||||
|
||||
for i := 0; i < len(documents); i++ {
|
||||
var newArticle Article
|
||||
bson.Unmarshal(documents[i], &newArticle)
|
||||
articles = append(articles, newArticle)
|
||||
}
|
||||
|
||||
return articles
|
||||
}
|
||||
|
||||
func IsArticleIdAlreadyUsed(id string, documents [][]byte) bool {
|
||||
for i := 0; i < len(documents); i++ {
|
||||
var newArticle Article
|
||||
bson.Unmarshal(documents[i], &newArticle)
|
||||
if newArticle.TitleID == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package articles
|
||||
|
||||
import (
|
||||
"log"
|
||||
@@ -9,25 +9,29 @@ import (
|
||||
)
|
||||
|
||||
var Article1, _ = bson.Marshal(Article{
|
||||
IdName: "test_article_1",
|
||||
TitleID: "test_article_1",
|
||||
Date: 1671482492,
|
||||
Content: gin.H{},
|
||||
Tags: []string{"blog"},
|
||||
Online: false,
|
||||
})
|
||||
|
||||
var Article2, _ = bson.Marshal(Article{
|
||||
IdName: "test_article_2",
|
||||
TitleID: "test_article_2",
|
||||
Date: 1671899112,
|
||||
Content: gin.H{},
|
||||
Tags: []string{"blog"},
|
||||
Online: false,
|
||||
})
|
||||
|
||||
var BSONConvertedArticles = [][]byte{Article1, Article2}
|
||||
|
||||
func TestGetAllArticlesBusiness(t *testing.T) {
|
||||
documents := GetAllArticlesBusiness(BSONConvertedArticles)
|
||||
documents := ParseArticlesFromBytesToArray(BSONConvertedArticles)
|
||||
article := documents[0]
|
||||
|
||||
if article.IdName != "test_article_1" {
|
||||
log.Fatalf(`Excepted "test_article_1" as IdName, found "%v"`, article.IdName)
|
||||
if article.TitleID != "test_article_1" {
|
||||
log.Fatalf(`Excepted "test_article_1" as IdName, found "%v"`, article.TitleID)
|
||||
} else if article.Date != 1671482492 {
|
||||
log.Fatalf(`Excepted 1671482492 as Date, found "%v"`, article.Date)
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package articles
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/Floriansylvain/GohCMS/internal/api"
|
||||
"github.com/Floriansylvain/GohCMS/internal/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
func GetArticleHandler(c *gin.Context) {
|
||||
articleID := c.Params.ByName("id")
|
||||
|
||||
filter := gin.H{}
|
||||
if articleID != "" {
|
||||
filter["titleID"] = articleID
|
||||
}
|
||||
|
||||
articles, err := database.GetDocuments(articlesLocation, filter)
|
||||
if err != nil {
|
||||
api.SendBadRequest(c, fmt.Sprintf("The ID '%v' doesn't match any article.", articleID))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, ParseArticlesFromBytesToArray(articles))
|
||||
}
|
||||
|
||||
func AddArticleHandler(c *gin.Context) {
|
||||
var article Article
|
||||
article.TitleID = c.Params.ByName("id")
|
||||
if c.BindJSON(&article) != nil {
|
||||
api.SendBadRequest(c, "Could not correctly parse the article.")
|
||||
return
|
||||
}
|
||||
|
||||
document, err := bson.Marshal(article)
|
||||
if err != nil {
|
||||
api.SendBadRequest(c, "Could not correctly marshal the article.")
|
||||
return
|
||||
}
|
||||
|
||||
documents, _ := database.GetDocuments(articlesLocation, gin.H{})
|
||||
if IsArticleIdAlreadyUsed(article.TitleID, documents) {
|
||||
api.SendBadRequest(c, fmt.Sprintf("Article ID '%v' already used.", article.TitleID))
|
||||
return
|
||||
}
|
||||
|
||||
err = database.PushDocument(articlesLocation, document)
|
||||
if err != nil {
|
||||
api.SendBadRequest(c, fmt.Sprintf(`Could not insert document(s) into DB: %v`, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
api.SendOk(c, "Article successfully added!")
|
||||
}
|
||||
|
||||
func DeleteArticleHandler(c *gin.Context) {
|
||||
id := c.Params.ByName("id")
|
||||
|
||||
deleteCount, err := database.DeleteDocument(articlesLocation, gin.H{"titleID": id})
|
||||
if err != nil {
|
||||
api.SendBadRequest(c, fmt.Sprintf(`Could not delete document(s) from DB: %v`, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if deleteCount != 0 {
|
||||
api.SendOk(c, fmt.Sprintf("%d article(s) was/were successfully deleted!", deleteCount))
|
||||
} else {
|
||||
api.SendOk(c, "No articles were deleted.")
|
||||
}
|
||||
}
|
||||
|
||||
func EditArticleHandler(c *gin.Context) {
|
||||
id := c.Params.ByName("id")
|
||||
|
||||
var articleUpdate database.DocumentUpdate
|
||||
articleUpdate.Filter = gin.H{"titleID": id}
|
||||
c.BindJSON(&articleUpdate.Update)
|
||||
|
||||
editCount, err := database.EditDocument(articlesLocation, articleUpdate)
|
||||
if err != nil {
|
||||
api.SendBadRequest(c, fmt.Sprintf(`Could not edit document(s) from DB: %v`, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if editCount != 0 {
|
||||
api.SendOk(c, fmt.Sprintf("%d article(s) was/were successfully edited!", editCount))
|
||||
} else {
|
||||
api.SendOk(c, "No articles were edited.")
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
type Article struct {
|
||||
IdName string `json:"id_name" bson:"id_name"`
|
||||
Date int64 `json:"date" bson:"date"`
|
||||
Content gin.H `json:"content" bson:"content"`
|
||||
}
|
||||
|
||||
var articlesLocation = Location{Database: "gohcms", Collection: "articles"}
|
||||
|
||||
func GetAllArticlesBusiness(documents [][]byte) []Article {
|
||||
var articles = []Article{}
|
||||
|
||||
for i := 0; i < len(documents); i++ {
|
||||
var newArticle Article
|
||||
bson.Unmarshal(documents[i], &newArticle)
|
||||
articles = append(articles, newArticle)
|
||||
}
|
||||
|
||||
return articles
|
||||
}
|
||||
|
||||
func IsArticleIdAlreadyUsed(id string, documents [][]byte) bool {
|
||||
for i := 0; i < len(documents); i++ {
|
||||
var newArticle Article
|
||||
bson.Unmarshal(documents[i], &newArticle)
|
||||
if newArticle.IdName == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
func GetAllArticlesHandler(c *gin.Context) {
|
||||
documents, err := getDocuments(articlesLocation, gin.H{})
|
||||
if err != nil {
|
||||
SendBadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, GetAllArticlesBusiness(documents))
|
||||
}
|
||||
|
||||
func GetArticleHandler(c *gin.Context) {
|
||||
articleID := c.Params.ByName("id")
|
||||
article, err := getUniqueDocument(articlesLocation,
|
||||
gin.H{"id_name": articleID})
|
||||
if err != nil {
|
||||
SendBadRequest(c, "The ID provided doesn't match any article.")
|
||||
return
|
||||
}
|
||||
var parsedArticle Article
|
||||
bson.Unmarshal(article, &parsedArticle)
|
||||
c.JSON(http.StatusOK, parsedArticle)
|
||||
}
|
||||
|
||||
func AddArticleHandler(c *gin.Context) {
|
||||
var article Article
|
||||
article.IdName = c.Params.ByName("id")
|
||||
if c.BindJSON(&article) != nil {
|
||||
SendBadRequest(c, "Could not correctly parse the article.")
|
||||
return
|
||||
}
|
||||
|
||||
document, err := bson.Marshal(article)
|
||||
if err != nil {
|
||||
SendBadRequest(c, "Could not correctly marshal the article.")
|
||||
return
|
||||
}
|
||||
|
||||
documents, _ := getDocuments(articlesLocation, gin.H{})
|
||||
if IsArticleIdAlreadyUsed(article.IdName, documents) {
|
||||
SendBadRequest(c, "Article ID already used.")
|
||||
return
|
||||
}
|
||||
|
||||
err = pushDocument(articlesLocation, document)
|
||||
if err != nil {
|
||||
SendBadRequest(c, fmt.Sprintf(`Could not insert document into DB: %v`, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
SendOk(c, "Article successfully added!")
|
||||
}
|
||||
|
||||
func DeleteArticleHandler(c *gin.Context) {
|
||||
id := c.Params.ByName("id")
|
||||
|
||||
deleteCount, err := deleteDocument(articlesLocation, gin.H{"id_name": id})
|
||||
if err != nil {
|
||||
SendBadRequest(c, "Could not delete document into DB.")
|
||||
return
|
||||
}
|
||||
|
||||
if deleteCount != 0 {
|
||||
SendOk(c, fmt.Sprintf("%d articles were successfully deleted!", deleteCount))
|
||||
} else {
|
||||
SendOk(c, "No articles were deleted.")
|
||||
}
|
||||
}
|
||||
|
||||
func EditArticleHandler(c *gin.Context) {
|
||||
id := c.Params.ByName("id")
|
||||
|
||||
var articleUpdate DocumentUpdate
|
||||
articleUpdate.Filter = gin.H{"id_name": id}
|
||||
c.BindJSON(&articleUpdate.Update)
|
||||
|
||||
editCount, err := editDocument(articlesLocation, articleUpdate)
|
||||
if err != nil {
|
||||
SendBadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if editCount != 0 {
|
||||
SendOk(c, fmt.Sprintf("%d articles were successfully edited!", editCount))
|
||||
} else {
|
||||
SendOk(c, "No articles were edited.")
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
jwt "github.com/appleboy/gin-jwt/v2"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Email string `json:"email" bson:"email"`
|
||||
Password string `json:"password" bson:"password"`
|
||||
}
|
||||
|
||||
var UsersLocation = Location{Database: "gohcms", Collection: "users"}
|
||||
|
||||
var AuthMiddleware, _ = jwt.New(&jwt.GinJWTMiddleware{
|
||||
Realm: "GohCMS",
|
||||
Key: []byte(os.Getenv("APP_JWT_SECRET")),
|
||||
Timeout: time.Hour,
|
||||
MaxRefresh: time.Hour,
|
||||
Authenticator: JWTAuthenticator,
|
||||
})
|
||||
|
||||
func JWTAuthenticator(c *gin.Context) (interface{}, error) {
|
||||
var user = User{}
|
||||
err := c.BindJSON(&user)
|
||||
if err != nil {
|
||||
return nil, errors.New("wrong credentials json format.")
|
||||
}
|
||||
|
||||
_, err = getUniqueDocument(UsersLocation, bson.D{
|
||||
{Key: "email", Value: user.Email},
|
||||
{Key: "password", Value: user.Password},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.New("wrong email or password.")
|
||||
}
|
||||
|
||||
return gin.H{"email": user.Email}, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -19,7 +19,7 @@ type DocumentUpdate struct {
|
||||
Update gin.H `json:"update"`
|
||||
}
|
||||
|
||||
func getNewClient() *mongo.Client {
|
||||
func GetNewClient() *mongo.Client {
|
||||
client, err := mongo.Connect(
|
||||
context.TODO(),
|
||||
options.Client().ApplyURI("mongodb://db:27017/"))
|
||||
@@ -29,8 +29,8 @@ func getNewClient() *mongo.Client {
|
||||
return client
|
||||
}
|
||||
|
||||
func pushDocument(location Location, document interface{}) error {
|
||||
client := getNewClient()
|
||||
func PushDocument(location Location, document interface{}) error {
|
||||
client := GetNewClient()
|
||||
collection := client.Database(location.Database).Collection(location.Collection)
|
||||
defer client.Disconnect(context.TODO())
|
||||
|
||||
@@ -41,8 +41,8 @@ func pushDocument(location Location, document interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDocuments(location Location, filter interface{}) ([][]byte, error) {
|
||||
client := getNewClient()
|
||||
func GetDocuments(location Location, filter interface{}) ([][]byte, error) {
|
||||
client := GetNewClient()
|
||||
collection := client.Database(location.Database).Collection(location.Collection)
|
||||
defer client.Disconnect(context.TODO())
|
||||
|
||||
@@ -58,8 +58,8 @@ func getDocuments(location Location, filter interface{}) ([][]byte, error) {
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func getUniqueDocument(location Location, filter interface{}) ([]byte, error) {
|
||||
client := getNewClient()
|
||||
func GetUniqueDocument(location Location, filter interface{}) ([]byte, error) {
|
||||
client := GetNewClient()
|
||||
collection := client.Database(location.Database).Collection(location.Collection)
|
||||
defer client.Disconnect(context.TODO())
|
||||
|
||||
@@ -70,8 +70,8 @@ func getUniqueDocument(location Location, filter interface{}) ([]byte, error) {
|
||||
return singleResult.DecodeBytes()
|
||||
}
|
||||
|
||||
func deleteDocument(location Location, filter interface{}) (int64, error) {
|
||||
client := getNewClient()
|
||||
func DeleteDocument(location Location, filter interface{}) (int64, error) {
|
||||
client := GetNewClient()
|
||||
collection := client.Database(location.Database).Collection(location.Collection)
|
||||
defer client.Disconnect(context.TODO())
|
||||
|
||||
@@ -83,8 +83,8 @@ func deleteDocument(location Location, filter interface{}) (int64, error) {
|
||||
return result.DeletedCount, nil
|
||||
}
|
||||
|
||||
func editDocument(location Location, jsons DocumentUpdate) (int64, error) {
|
||||
client := getNewClient()
|
||||
func EditDocument(location Location, jsons DocumentUpdate) (int64, error) {
|
||||
client := GetNewClient()
|
||||
collection := client.Database(location.Database).Collection(location.Collection)
|
||||
defer client.Disconnect(context.TODO())
|
||||
|
||||
+13
-4
@@ -4,20 +4,29 @@ const db = conn.getDB("gohcms")
|
||||
db.createCollection('articles', {
|
||||
validator: {
|
||||
$jsonSchema: {
|
||||
required: ['content', 'date', 'id_name'],
|
||||
required: ['titleID', 'title', 'content', 'date', 'tags', 'online'],
|
||||
properties: {
|
||||
_id: {
|
||||
bsonType: 'objectId'
|
||||
},
|
||||
titleID: {
|
||||
bsonType: 'string',
|
||||
pattern: '^[-a-z]+$'
|
||||
},
|
||||
title: {
|
||||
bsonType: 'string'
|
||||
},
|
||||
content: {
|
||||
bsonType: 'object'
|
||||
},
|
||||
date: {
|
||||
bsonType: 'number'
|
||||
},
|
||||
id_name: {
|
||||
bsonType: 'string',
|
||||
pattern: '^.+$'
|
||||
tags: {
|
||||
bsonType: 'array'
|
||||
},
|
||||
online: {
|
||||
bsonType: 'bool'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+52
-166
@@ -8,13 +8,15 @@
|
||||
"name": "admin-gui",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@tinymce/tinymce-vue": "^4.0.7",
|
||||
"pinia": "^2.0.28",
|
||||
"tabulator-tables": "^5.4.3",
|
||||
"vue": "^3.2.38",
|
||||
"vue-editor-js": "^2.0.2",
|
||||
"vue-router": "^4.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.56",
|
||||
"@types/tabulator-tables": "^5.4.2",
|
||||
"@vitejs/plugin-vue": "^3.0.3",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
@@ -34,23 +36,6 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@codexteam/icons": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@codexteam/icons/-/icons-0.1.0.tgz",
|
||||
"integrity": "sha512-jW1fWnwtWzcP4FBGsaodbJY3s1ZaRU+IJy1pvJ7ygNQxkQinybJcwXoyt0a5mWwu/4w30A42EWhCrZn8lp4fdw=="
|
||||
},
|
||||
"node_modules/@editorjs/editorjs": {
|
||||
"version": "2.26.4",
|
||||
"resolved": "https://registry.npmjs.org/@editorjs/editorjs/-/editorjs-2.26.4.tgz",
|
||||
"integrity": "sha512-yuJ2NM1Y5+8DDNWr4C00tHMVHKy0uCqK1HS4pwFPVcXUawgJnU2Li2vKGvPLuf0Jj2ir7MVgADO6oC1TbYBOYQ==",
|
||||
"dependencies": {
|
||||
"@codexteam/icons": "0.1.0",
|
||||
"codex-notifier": "^1.1.2",
|
||||
"codex-tooltip": "^1.0.5",
|
||||
"html-janitor": "^2.0.4",
|
||||
"nanoid": "^3.1.22"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
|
||||
@@ -83,12 +68,29 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@tinymce/tinymce-vue": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@tinymce/tinymce-vue/-/tinymce-vue-4.0.7.tgz",
|
||||
"integrity": "sha512-1esB8wGWrjPCY+rK8vy3QB1cxwXo7HLJWuNrcyPl6LOVR+QJjub0OiV/C+TUEsLN6OpCtRv+QnIqMC5vXz783Q==",
|
||||
"dependencies": {
|
||||
"tinymce": "^5.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.18.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.10.tgz",
|
||||
"integrity": "sha512-XU1+v7h81p7145ddPfjv7jtWvkSilpcnON3mQ+bDi9Yuf7OI56efOglXRyXWgQ57xH3fEQgh7WOJMncRHVew5w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/tabulator-tables": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/tabulator-tables/-/tabulator-tables-5.4.2.tgz",
|
||||
"integrity": "sha512-Nw6ilGg3SqJWQ6UUwJ8VL9NtIeRhYKrmzy8hjx3dpfHwccK0pSCUj3G+CNTnoHD4QaIfXq8JaAwQ+dzO4FeHqA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vitejs/plugin-vue": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz",
|
||||
@@ -354,16 +356,6 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/codex-notifier": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/codex-notifier/-/codex-notifier-1.1.2.tgz",
|
||||
"integrity": "sha512-DCp6xe/LGueJ1N5sXEwcBc3r3PyVkEEDNWCVigfvywAkeXcZMk9K41a31tkEFBW0Ptlwji6/JlAb49E3Yrxbtg=="
|
||||
},
|
||||
"node_modules/codex-tooltip": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/codex-tooltip/-/codex-tooltip-1.0.5.tgz",
|
||||
"integrity": "sha512-IuA8LeyLU5p1B+HyhOsqR6oxyFQ11k3i9e9aXw40CrHFTRO2Y1npNBVU3W1SvhKAbUU7R/YikUBdcYFP0RcJag=="
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
@@ -1043,11 +1035,6 @@
|
||||
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/html-janitor": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/html-janitor/-/html-janitor-2.0.4.tgz",
|
||||
"integrity": "sha512-92J5h9jNZRk30PMHapjHEJfkrBWKCOy0bq3oW2pBungky6lzYSoboBGPMvxl1XRKB2q+kniQmsLsPbdpY7RM2g=="
|
||||
},
|
||||
"node_modules/internal-slot": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz",
|
||||
@@ -1785,10 +1772,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
"node_modules/tabulator-tables": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tabulator-tables/-/tabulator-tables-5.4.3.tgz",
|
||||
"integrity": "sha512-XnQcfwd2LzHWKAo8ZzUVglKaQnzn3wZwH48ouYr1dDbfUcQiU1ESJjVhmVxPMr9tf0oDcV6qPViEHinAi/tqbw=="
|
||||
},
|
||||
"node_modules/tinymce": {
|
||||
"version": "5.10.7",
|
||||
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-5.10.7.tgz",
|
||||
"integrity": "sha512-9UUjaO0R7FxcFo0oxnd1lMs7H+D0Eh+dDVo5hKbVe1a+VB0nit97vOqlinj+YwgoBDt6/DSCUoWqAYlLI8BLYA=="
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.7.4",
|
||||
@@ -1889,53 +1881,6 @@
|
||||
"@vue/shared": "3.2.45"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-editor-js": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vue-editor-js/-/vue-editor-js-2.0.2.tgz",
|
||||
"integrity": "sha512-Y07q/Nj4/BJOQlvlKN5R4UFCMUVgnDbJxDSZvMGXNCnMJyT1TEQmS2HAuc9euCp8EDGo/sJnm3y0NUQ+gonx2w==",
|
||||
"dependencies": {
|
||||
"@editorjs/editorjs": "^2.18.0",
|
||||
"@vue/composition-api": "^0.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-editor-js/node_modules/@vue/compiler-sfc": {
|
||||
"version": "2.7.14",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz",
|
||||
"integrity": "sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.18.4",
|
||||
"postcss": "^8.4.14",
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-editor-js/node_modules/@vue/composition-api": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@vue/composition-api/-/composition-api-0.5.0.tgz",
|
||||
"integrity": "sha512-9QDFWq7q839G1CTTaxeruPOTrrVOPSaVipJ2TxxK9QAruePNTHOGbOOFRpc8WLl4YPsu1/c29yBhMVmrXz8BZw==",
|
||||
"dependencies": {
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^2.5.22"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-editor-js/node_modules/csstype": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
|
||||
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/vue-editor-js/node_modules/vue": {
|
||||
"version": "2.7.14",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.7.14.tgz",
|
||||
"integrity": "sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-sfc": "2.7.14",
|
||||
"csstype": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-router": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz",
|
||||
@@ -2011,23 +1956,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz",
|
||||
"integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA=="
|
||||
},
|
||||
"@codexteam/icons": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@codexteam/icons/-/icons-0.1.0.tgz",
|
||||
"integrity": "sha512-jW1fWnwtWzcP4FBGsaodbJY3s1ZaRU+IJy1pvJ7ygNQxkQinybJcwXoyt0a5mWwu/4w30A42EWhCrZn8lp4fdw=="
|
||||
},
|
||||
"@editorjs/editorjs": {
|
||||
"version": "2.26.4",
|
||||
"resolved": "https://registry.npmjs.org/@editorjs/editorjs/-/editorjs-2.26.4.tgz",
|
||||
"integrity": "sha512-yuJ2NM1Y5+8DDNWr4C00tHMVHKy0uCqK1HS4pwFPVcXUawgJnU2Li2vKGvPLuf0Jj2ir7MVgADO6oC1TbYBOYQ==",
|
||||
"requires": {
|
||||
"@codexteam/icons": "0.1.0",
|
||||
"codex-notifier": "^1.1.2",
|
||||
"codex-tooltip": "^1.0.5",
|
||||
"html-janitor": "^2.0.4",
|
||||
"nanoid": "^3.1.22"
|
||||
}
|
||||
},
|
||||
"@esbuild/android-arm": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
|
||||
@@ -2042,12 +1970,26 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@tinymce/tinymce-vue": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@tinymce/tinymce-vue/-/tinymce-vue-4.0.7.tgz",
|
||||
"integrity": "sha512-1esB8wGWrjPCY+rK8vy3QB1cxwXo7HLJWuNrcyPl6LOVR+QJjub0OiV/C+TUEsLN6OpCtRv+QnIqMC5vXz783Q==",
|
||||
"requires": {
|
||||
"tinymce": "^5.5.0"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "16.18.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.10.tgz",
|
||||
"integrity": "sha512-XU1+v7h81p7145ddPfjv7jtWvkSilpcnON3mQ+bDi9Yuf7OI56efOglXRyXWgQ57xH3fEQgh7WOJMncRHVew5w==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/tabulator-tables": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/tabulator-tables/-/tabulator-tables-5.4.2.tgz",
|
||||
"integrity": "sha512-Nw6ilGg3SqJWQ6UUwJ8VL9NtIeRhYKrmzy8hjx3dpfHwccK0pSCUj3G+CNTnoHD4QaIfXq8JaAwQ+dzO4FeHqA==",
|
||||
"dev": true
|
||||
},
|
||||
"@vitejs/plugin-vue": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz",
|
||||
@@ -2287,16 +2229,6 @@
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"codex-notifier": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/codex-notifier/-/codex-notifier-1.1.2.tgz",
|
||||
"integrity": "sha512-DCp6xe/LGueJ1N5sXEwcBc3r3PyVkEEDNWCVigfvywAkeXcZMk9K41a31tkEFBW0Ptlwji6/JlAb49E3Yrxbtg=="
|
||||
},
|
||||
"codex-tooltip": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/codex-tooltip/-/codex-tooltip-1.0.5.tgz",
|
||||
"integrity": "sha512-IuA8LeyLU5p1B+HyhOsqR6oxyFQ11k3i9e9aXw40CrHFTRO2Y1npNBVU3W1SvhKAbUU7R/YikUBdcYFP0RcJag=="
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
@@ -2710,11 +2642,6 @@
|
||||
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
|
||||
"dev": true
|
||||
},
|
||||
"html-janitor": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/html-janitor/-/html-janitor-2.0.4.tgz",
|
||||
"integrity": "sha512-92J5h9jNZRk30PMHapjHEJfkrBWKCOy0bq3oW2pBungky6lzYSoboBGPMvxl1XRKB2q+kniQmsLsPbdpY7RM2g=="
|
||||
},
|
||||
"internal-slot": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz",
|
||||
@@ -3220,10 +3147,15 @@
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"dev": true
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
"tabulator-tables": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tabulator-tables/-/tabulator-tables-5.4.3.tgz",
|
||||
"integrity": "sha512-XnQcfwd2LzHWKAo8ZzUVglKaQnzn3wZwH48ouYr1dDbfUcQiU1ESJjVhmVxPMr9tf0oDcV6qPViEHinAi/tqbw=="
|
||||
},
|
||||
"tinymce": {
|
||||
"version": "5.10.7",
|
||||
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-5.10.7.tgz",
|
||||
"integrity": "sha512-9UUjaO0R7FxcFo0oxnd1lMs7H+D0Eh+dDVo5hKbVe1a+VB0nit97vOqlinj+YwgoBDt6/DSCUoWqAYlLI8BLYA=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.7.4",
|
||||
@@ -3278,52 +3210,6 @@
|
||||
"@vue/shared": "3.2.45"
|
||||
}
|
||||
},
|
||||
"vue-editor-js": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vue-editor-js/-/vue-editor-js-2.0.2.tgz",
|
||||
"integrity": "sha512-Y07q/Nj4/BJOQlvlKN5R4UFCMUVgnDbJxDSZvMGXNCnMJyT1TEQmS2HAuc9euCp8EDGo/sJnm3y0NUQ+gonx2w==",
|
||||
"requires": {
|
||||
"@editorjs/editorjs": "^2.18.0",
|
||||
"@vue/composition-api": "^0.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/compiler-sfc": {
|
||||
"version": "2.7.14",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz",
|
||||
"integrity": "sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@babel/parser": "^7.18.4",
|
||||
"postcss": "^8.4.14",
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"@vue/composition-api": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@vue/composition-api/-/composition-api-0.5.0.tgz",
|
||||
"integrity": "sha512-9QDFWq7q839G1CTTaxeruPOTrrVOPSaVipJ2TxxK9QAruePNTHOGbOOFRpc8WLl4YPsu1/c29yBhMVmrXz8BZw==",
|
||||
"requires": {
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"csstype": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
|
||||
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==",
|
||||
"peer": true
|
||||
},
|
||||
"vue": {
|
||||
"version": "2.7.14",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.7.14.tgz",
|
||||
"integrity": "sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@vue/compiler-sfc": "2.7.14",
|
||||
"csstype": "^3.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-router": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz",
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
"type-check": "vue-tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tinymce/tinymce-vue": "^4.0.7",
|
||||
"pinia": "^2.0.28",
|
||||
"tabulator-tables": "^5.4.3",
|
||||
"vue": "^3.2.38",
|
||||
"vue-editor-js": "^2.0.2",
|
||||
"vue-router": "^4.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.56",
|
||||
"@types/tabulator-tables": "^5.4.2",
|
||||
"@vitejs/plugin-vue": "^3.0.3",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
This is where language files should be placed.
|
||||
|
||||
Please DO NOT translate these directly use this service: https://www.transifex.com/projects/p/tinymce/
|
||||
@@ -0,0 +1,412 @@
|
||||
/*!
|
||||
* TinyMCE Language Pack
|
||||
*
|
||||
* Copyright (c) 2022 Ephox Corporation DBA Tiny Technologies, Inc.
|
||||
* Licensed under the Tiny commercial license. See https://www.tiny.cloud/legal/
|
||||
*/
|
||||
tinymce.addI18n('fr_FR', {
|
||||
"Redo": "Rétablir",
|
||||
"Undo": "Annuler",
|
||||
"Cut": "Couper",
|
||||
"Copy": "Copier",
|
||||
"Paste": "Coller",
|
||||
"Select all": "Sélectionner tout",
|
||||
"New document": "Nouveau document",
|
||||
"Ok": "OK",
|
||||
"Cancel": "Annuler",
|
||||
"Visual aids": "Aides visuelles",
|
||||
"Bold": "Gras",
|
||||
"Italic": "Italique",
|
||||
"Underline": "Souligné",
|
||||
"Strikethrough": "Barré",
|
||||
"Superscript": "Exposant",
|
||||
"Subscript": "Indice",
|
||||
"Clear formatting": "Effacer la mise en forme",
|
||||
"Remove": "Retiré",
|
||||
"Align left": "Aligner à gauche",
|
||||
"Align center": "Centrer",
|
||||
"Align right": "Aligner à droite",
|
||||
"No alignment": "Aucun alignement",
|
||||
"Justify": "Justifier",
|
||||
"Bullet list": "Liste à puces",
|
||||
"Numbered list": "Liste numérotée",
|
||||
"Decrease indent": "Réduire le retrait",
|
||||
"Increase indent": "Augmenter le retrait",
|
||||
"Close": "Fermer",
|
||||
"Formats": "Formats",
|
||||
"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.": "Votre navigateur ne supporte pas l’accès direct au presse-papiers. Merci d'utiliser les raccourcis clavier Ctrl+X/C/V.",
|
||||
"Headings": "Titres",
|
||||
"Heading 1": "Titre 1",
|
||||
"Heading 2": "Titre 2",
|
||||
"Heading 3": "Titre 3",
|
||||
"Heading 4": "Titre 4",
|
||||
"Heading 5": "Titre 5",
|
||||
"Heading 6": "Titre 6",
|
||||
"Preformatted": "Préformaté",
|
||||
"Div": "Div",
|
||||
"Pre": "Préformaté",
|
||||
"Code": "Code",
|
||||
"Paragraph": "Paragraphe",
|
||||
"Blockquote": "Bloc de citation",
|
||||
"Inline": "En ligne",
|
||||
"Blocks": "Blocs",
|
||||
"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Le collage est maintenant en mode texte brut. Les contenus seront collés sans retenir les formatages jusqu'à ce que vous désactivez cette option.",
|
||||
"Fonts": "Polices",
|
||||
"Font sizes": "Tailles de police",
|
||||
"Class": "Classe",
|
||||
"Browse for an image": "Rechercher une image",
|
||||
"OR": "OU",
|
||||
"Drop an image here": "Déposer une image ici",
|
||||
"Upload": "Télécharger",
|
||||
"Uploading image": "Téléversement d'une image",
|
||||
"Block": "Bloc",
|
||||
"Align": "Aligner",
|
||||
"Default": "Par défaut",
|
||||
"Circle": "Cercle",
|
||||
"Disc": "Disque",
|
||||
"Square": "Carré",
|
||||
"Lower Alpha": "Alphabet en minuscules",
|
||||
"Lower Greek": "Alphabet grec en minuscules",
|
||||
"Lower Roman": "Chiffre romain inférieur",
|
||||
"Upper Alpha": "Alphabet en majuscules",
|
||||
"Upper Roman": "Chiffre romain supérieur",
|
||||
"Anchor...": "Ancre...",
|
||||
"Anchor": "Ancre",
|
||||
"Name": "Nom",
|
||||
"ID": "ID",
|
||||
"ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "L'ID doit commencer par une lettre, suivie uniquement par des lettres, numéros, tirets, points, deux-points et underscores.",
|
||||
"You have unsaved changes are you sure you want to navigate away?": "Vous avez des modifications non enregistrées, êtes-vous sûr de vouloir quitter la page ?",
|
||||
"Restore last draft": "Restaurer le dernier brouillon",
|
||||
"Special character...": "Caractère spécial...",
|
||||
"Special Character": "Caractère spécial",
|
||||
"Source code": "Code source",
|
||||
"Insert/Edit code sample": "Insérer / modifier une exemple de code",
|
||||
"Language": "Langue",
|
||||
"Code sample...": "Exemple de code...",
|
||||
"Left to right": "De gauche à droite",
|
||||
"Right to left": "De droite à gauche",
|
||||
"Title": "Titre",
|
||||
"Fullscreen": "Plein écran",
|
||||
"Action": "Action",
|
||||
"Shortcut": "Raccourci",
|
||||
"Help": "Aide",
|
||||
"Address": "Adresse",
|
||||
"Focus to menubar": "Mettre le focus sur la barre de menu",
|
||||
"Focus to toolbar": "Mettre le focus sur la barre d'outils",
|
||||
"Focus to element path": "Mettre le focus sur le chemin vers l'élément",
|
||||
"Focus to contextual toolbar": "Mettre le focus sur la barre d'outils contextuelle",
|
||||
"Insert link (if link plugin activated)": "Insérer un lien (si le plug-in link est activé)",
|
||||
"Save (if save plugin activated)": "Enregistrer (si le plug-in save est activé)",
|
||||
"Find (if searchreplace plugin activated)": "Rechercher (si le plug-in searchreplace est activé)",
|
||||
"Plugins installed ({0}):": "Plug-ins installés ({0}) :",
|
||||
"Premium plugins:": "Plug-ins premium :",
|
||||
"Learn more...": "En savoir plus...",
|
||||
"You are using {0}": "Vous utilisez {0}",
|
||||
"Plugins": "Plug-ins",
|
||||
"Handy Shortcuts": "Raccourcis utiles",
|
||||
"Horizontal line": "Ligne horizontale",
|
||||
"Insert/edit image": "Insérer/modifier image",
|
||||
"Alternative description": "Description alternative",
|
||||
"Accessibility": "Accessibilité",
|
||||
"Image is decorative": "L'image est décorative",
|
||||
"Source": "Source",
|
||||
"Dimensions": "Dimensions",
|
||||
"Constrain proportions": "Limiter les proportions",
|
||||
"General": "Général",
|
||||
"Advanced": "Options avancées",
|
||||
"Style": "Style",
|
||||
"Vertical space": "Espace vertical",
|
||||
"Horizontal space": "Espace horizontal",
|
||||
"Border": "Bordure",
|
||||
"Insert image": "Insérer une image",
|
||||
"Image...": "Image...",
|
||||
"Image list": "Liste des images",
|
||||
"Resize": "Redimensionner",
|
||||
"Insert date/time": "Insérer date/heure",
|
||||
"Date/time": "Date/heure",
|
||||
"Insert/edit link": "Insérer/modifier lien",
|
||||
"Text to display": "Texte à afficher",
|
||||
"Url": "URL",
|
||||
"Open link in...": "Ouvrir le lien dans...",
|
||||
"Current window": "Fenêtre active",
|
||||
"None": "Aucun",
|
||||
"New window": "Nouvelle fenêtre",
|
||||
"Open link": "Ouvrir le lien",
|
||||
"Remove link": "Enlever le lien",
|
||||
"Anchors": "Ancres",
|
||||
"Link...": "Lien...",
|
||||
"Paste or type a link": "Coller ou taper un lien",
|
||||
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "L'URL que vous avez saisi semble être une adresse e-mail. Souhaitez-vous y ajouter le préfixe requis mailto: ?",
|
||||
"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?": "L'URL que vous avez saisi semble être un lien externe. Souhaitez-vous y ajouter le préfixe requis mailto: ?",
|
||||
"The URL you entered seems to be an external link. Do you want to add the required https:// prefix?": "L'URL que vous avez saisie semble être un lien externe. Voulez-vous ajouter le préfixe https:// requis ?",
|
||||
"Link list": "Liste des liens",
|
||||
"Insert video": "Insérer une vidéo",
|
||||
"Insert/edit video": "Insérer/modifier une vidéo",
|
||||
"Insert/edit media": "Insérer/modifier un média",
|
||||
"Alternative source": "Source alternative",
|
||||
"Alternative source URL": "URL de la source alternative",
|
||||
"Media poster (Image URL)": "Affiche de média (URL de l'image)",
|
||||
"Paste your embed code below:": "Collez votre code incorporé ci-dessous :",
|
||||
"Embed": "Incorporer",
|
||||
"Media...": "Média...",
|
||||
"Nonbreaking space": "Espace insécable",
|
||||
"Page break": "Saut de page",
|
||||
"Paste as text": "Coller comme texte",
|
||||
"Preview": "Aperçu",
|
||||
"Print": "Imprimer",
|
||||
"Print...": "Imprimer...",
|
||||
"Save": "Enregistrer",
|
||||
"Find": "Rechercher",
|
||||
"Replace with": "Remplacer par",
|
||||
"Replace": "Remplacer",
|
||||
"Replace all": "Remplacer tout",
|
||||
"Previous": "Précédente",
|
||||
"Next": "Suivante",
|
||||
"Find and Replace": "Trouver et remplacer",
|
||||
"Find and replace...": "Trouver et remplacer...",
|
||||
"Could not find the specified string.": "Impossible de trouver la chaîne spécifiée.",
|
||||
"Match case": "Respecter la casse",
|
||||
"Find whole words only": "Mot entier",
|
||||
"Find in selection": "Trouver dans la sélection",
|
||||
"Insert table": "Insérer un tableau",
|
||||
"Table properties": "Propriétés du tableau",
|
||||
"Delete table": "Supprimer le tableau",
|
||||
"Cell": "Cellule",
|
||||
"Row": "Ligne",
|
||||
"Column": "Colonne",
|
||||
"Cell properties": "Propriétés de la cellule",
|
||||
"Merge cells": "Fusionner les cellules",
|
||||
"Split cell": "Diviser la cellule",
|
||||
"Insert row before": "Insérer une ligne avant",
|
||||
"Insert row after": "Insérer une ligne après",
|
||||
"Delete row": "Supprimer la ligne",
|
||||
"Row properties": "Propriétés de la ligne",
|
||||
"Cut row": "Couper la ligne",
|
||||
"Cut column": "Couper la colonne",
|
||||
"Copy row": "Copier la ligne",
|
||||
"Copy column": "Copier la colonne",
|
||||
"Paste row before": "Coller la ligne avant",
|
||||
"Paste column before": "Coller la colonne avant",
|
||||
"Paste row after": "Coller la ligne après",
|
||||
"Paste column after": "Coller la colonne après",
|
||||
"Insert column before": "Insérer une colonne avant",
|
||||
"Insert column after": "Insérer une colonne après",
|
||||
"Delete column": "Supprimer la colonne",
|
||||
"Cols": "Colonnes",
|
||||
"Rows": "Lignes",
|
||||
"Width": "Largeur",
|
||||
"Height": "Hauteur",
|
||||
"Cell spacing": "Espacement entre les cellules",
|
||||
"Cell padding": "Marge intérieure des cellules",
|
||||
"Row clipboard actions": "Actions du presse-papiers des lignes",
|
||||
"Column clipboard actions": "Actions du presse-papiers des colonnes",
|
||||
"Table styles": "Style tableau",
|
||||
"Cell styles": "Type de cellule",
|
||||
"Column header": "En-tête de colonne",
|
||||
"Row header": "En-tête de ligne",
|
||||
"Table caption": "Légende de tableau",
|
||||
"Caption": "Légende",
|
||||
"Show caption": "Afficher une légende",
|
||||
"Left": "Gauche",
|
||||
"Center": "Centre",
|
||||
"Right": "Droite",
|
||||
"Cell type": "Type de cellule",
|
||||
"Scope": "Étendue",
|
||||
"Alignment": "Alignement",
|
||||
"Horizontal align": "Alignement horizontal",
|
||||
"Vertical align": "Alignement vertical",
|
||||
"Top": "En haut",
|
||||
"Middle": "Au milieu",
|
||||
"Bottom": "En bas",
|
||||
"Header cell": "Cellule d'en-tête",
|
||||
"Row group": "Groupe de lignes",
|
||||
"Column group": "Groupe de colonnes",
|
||||
"Row type": "Type de ligne",
|
||||
"Header": "En-tête",
|
||||
"Body": "Corps",
|
||||
"Footer": "Pied de page",
|
||||
"Border color": "Couleur de bordure",
|
||||
"Solid": "Trait continu",
|
||||
"Dotted": "Pointillé",
|
||||
"Dashed": "Tirets",
|
||||
"Double": "Deux traits continus",
|
||||
"Groove": "Sculpté",
|
||||
"Ridge": "Extrudé",
|
||||
"Inset": "Incrusté",
|
||||
"Outset": "Relief",
|
||||
"Hidden": "Masqué",
|
||||
"Insert template...": "Insérer un modèle...",
|
||||
"Templates": "Modèles",
|
||||
"Template": "Modèle",
|
||||
"Insert Template": "Insérer le modèle",
|
||||
"Text color": "Couleur du texte",
|
||||
"Background color": "Couleur d'arrière-plan",
|
||||
"Custom...": "Personnalisée...",
|
||||
"Custom color": "Couleur personnalisée",
|
||||
"No color": "Aucune couleur",
|
||||
"Remove color": "Supprimer la couleur",
|
||||
"Show blocks": "Afficher les blocs",
|
||||
"Show invisible characters": "Afficher les caractères invisibles",
|
||||
"Word count": "Nombre de mots",
|
||||
"Count": "Total",
|
||||
"Document": "Document",
|
||||
"Selection": "Sélection",
|
||||
"Words": "Mots",
|
||||
"Words: {0}": "Mots : {0}",
|
||||
"{0} words": "{0} mots",
|
||||
"File": "Fichier",
|
||||
"Edit": "Modifier",
|
||||
"Insert": "Insérer",
|
||||
"View": "Afficher",
|
||||
"Format": "Format",
|
||||
"Table": "Tableau",
|
||||
"Tools": "Outils",
|
||||
"Powered by {0}": "Avec {0}",
|
||||
"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Zone de Texte Riche. Appuyez sur ALT-F9 pour le menu. Appuyez sur ALT-F10 pour la barre d'outils. Appuyez sur ALT-0 pour l'aide",
|
||||
"Image title": "Titre d'image",
|
||||
"Border width": "Épaisseur de la bordure",
|
||||
"Border style": "Style de la bordure",
|
||||
"Error": "Erreur",
|
||||
"Warn": "Avertir",
|
||||
"Valid": "Valide",
|
||||
"To open the popup, press Shift+Enter": "Pour ouvrir la popup, appuyez sur Maj+Entrée",
|
||||
"Rich Text Area": "Zone de Texte Riche",
|
||||
"Rich Text Area. Press ALT-0 for help.": "Zone de Texte Riche. Appuyez sur ALT-0 pour l'aide.",
|
||||
"System Font": "Police système",
|
||||
"Failed to upload image: {0}": "Échec d'envoi de l'image : {0}",
|
||||
"Failed to load plugin: {0} from url {1}": "Échec de chargement du plug-in : {0} à partir de l’URL {1}",
|
||||
"Failed to load plugin url: {0}": "Échec de chargement de l'URL du plug-in : {0}",
|
||||
"Failed to initialize plugin: {0}": "Échec d'initialisation du plug-in : {0}",
|
||||
"example": "exemple",
|
||||
"Search": "Rechercher",
|
||||
"All": "Tout",
|
||||
"Currency": "Devise",
|
||||
"Text": "Texte",
|
||||
"Quotations": "Citations",
|
||||
"Mathematical": "Opérateurs mathématiques",
|
||||
"Extended Latin": "Latin étendu",
|
||||
"Symbols": "Symboles",
|
||||
"Arrows": "Flèches",
|
||||
"User Defined": "Défini par l'utilisateur",
|
||||
"dollar sign": "Symbole dollar",
|
||||
"currency sign": "Symbole devise",
|
||||
"euro-currency sign": "Symbole euro",
|
||||
"colon sign": "Symbole colón",
|
||||
"cruzeiro sign": "Symbole cruzeiro",
|
||||
"french franc sign": "Symbole franc français",
|
||||
"lira sign": "Symbole lire",
|
||||
"mill sign": "Symbole millième",
|
||||
"naira sign": "Symbole naira",
|
||||
"peseta sign": "Symbole peseta",
|
||||
"rupee sign": "Symbole roupie",
|
||||
"won sign": "Symbole won",
|
||||
"new sheqel sign": "Symbole nouveau chékel",
|
||||
"dong sign": "Symbole dong",
|
||||
"kip sign": "Symbole kip",
|
||||
"tugrik sign": "Symbole tougrik",
|
||||
"drachma sign": "Symbole drachme",
|
||||
"german penny symbol": "Symbole pfennig",
|
||||
"peso sign": "Symbole peso",
|
||||
"guarani sign": "Symbole guarani",
|
||||
"austral sign": "Symbole austral",
|
||||
"hryvnia sign": "Symbole hryvnia",
|
||||
"cedi sign": "Symbole cedi",
|
||||
"livre tournois sign": "Symbole livre tournois",
|
||||
"spesmilo sign": "Symbole spesmilo",
|
||||
"tenge sign": "Symbole tenge",
|
||||
"indian rupee sign": "Symbole roupie indienne",
|
||||
"turkish lira sign": "Symbole lire turque",
|
||||
"nordic mark sign": "Symbole du mark nordique",
|
||||
"manat sign": "Symbole manat",
|
||||
"ruble sign": "Symbole rouble",
|
||||
"yen character": "Sinogramme Yen",
|
||||
"yuan character": "Sinogramme Yuan",
|
||||
"yuan character, in hong kong and taiwan": "Sinogramme Yuan, Hong Kong et Taiwan",
|
||||
"yen/yuan character variant one": "Sinogramme Yen/Yuan, première variante",
|
||||
"Emojis": "Émojis",
|
||||
"Emojis...": "Émojis...",
|
||||
"Loading emojis...": "Chargement des emojis...",
|
||||
"Could not load emojis": "Impossible de charger les emojis",
|
||||
"People": "Personnes",
|
||||
"Animals and Nature": "Animaux & nature",
|
||||
"Food and Drink": "Nourriture & boissons",
|
||||
"Activity": "Activité",
|
||||
"Travel and Places": "Voyages & lieux",
|
||||
"Objects": "Objets",
|
||||
"Flags": "Drapeaux",
|
||||
"Characters": "Caractères",
|
||||
"Characters (no spaces)": "Caractères (espaces non compris)",
|
||||
"{0} characters": "{0} caractères",
|
||||
"Error: Form submit field collision.": "Erreur : conflit de champs lors de la soumission du formulaire.",
|
||||
"Error: No form element found.": "Erreur : aucun élément de formulaire trouvé.",
|
||||
"Color swatch": "Échantillon de couleurs",
|
||||
"Color Picker": "Sélecteur de couleurs",
|
||||
"Invalid hex color code: {0}": "Code couleur hexadécimal invalide : {0}",
|
||||
"Invalid input": "Entrée invalide",
|
||||
"R": "R",
|
||||
"Red component": "Composant rouge",
|
||||
"G": "V",
|
||||
"Green component": "Composant vert",
|
||||
"B": "B",
|
||||
"Blue component": "Composant bleu",
|
||||
"#": "#",
|
||||
"Hex color code": "Code couleur hexadécimal",
|
||||
"Range 0 to 255": "Plage de 0 à 255",
|
||||
"Turquoise": "Turquoise",
|
||||
"Green": "Vert",
|
||||
"Blue": "Bleu",
|
||||
"Purple": "Violet",
|
||||
"Navy Blue": "Bleu marine",
|
||||
"Dark Turquoise": "Turquoise foncé",
|
||||
"Dark Green": "Vert foncé",
|
||||
"Medium Blue": "Bleu moyen",
|
||||
"Medium Purple": "Violet moyen",
|
||||
"Midnight Blue": "Bleu de minuit",
|
||||
"Yellow": "Jaune",
|
||||
"Orange": "Orange",
|
||||
"Red": "Rouge",
|
||||
"Light Gray": "Gris clair",
|
||||
"Gray": "Gris",
|
||||
"Dark Yellow": "Jaune foncé",
|
||||
"Dark Orange": "Orange foncé",
|
||||
"Dark Red": "Rouge foncé",
|
||||
"Medium Gray": "Gris moyen",
|
||||
"Dark Gray": "Gris foncé",
|
||||
"Light Green": "Vert clair",
|
||||
"Light Yellow": "Jaune clair",
|
||||
"Light Red": "Rouge clair",
|
||||
"Light Purple": "Violet clair",
|
||||
"Light Blue": "Bleu clair",
|
||||
"Dark Purple": "Violet foncé",
|
||||
"Dark Blue": "Bleu foncé",
|
||||
"Black": "Noir",
|
||||
"White": "Blanc",
|
||||
"Switch to or from fullscreen mode": "Passer en ou quitter le mode plein écran",
|
||||
"Open help dialog": "Ouvrir la boîte de dialogue d'aide",
|
||||
"history": "historique",
|
||||
"styles": "styles",
|
||||
"formatting": "mise en forme",
|
||||
"alignment": "alignement",
|
||||
"indentation": "retrait",
|
||||
"Font": "Police",
|
||||
"Size": "Taille",
|
||||
"More...": "Plus...",
|
||||
"Select...": "Sélectionner...",
|
||||
"Preferences": "Préférences",
|
||||
"Yes": "Oui",
|
||||
"No": "Non",
|
||||
"Keyboard Navigation": "Navigation au clavier",
|
||||
"Version": "Version",
|
||||
"Code view": "Affichage du code",
|
||||
"Open popup menu for split buttons": "Ouvrir le menu contextuel pour les boutons partagés",
|
||||
"List Properties": "Propriétés de la liste",
|
||||
"List properties...": "Lister les propriétés...",
|
||||
"Start list at number": "Liste de départ au numéro",
|
||||
"Line height": "Hauteur de la ligne",
|
||||
"Dropped file type is not supported": "Le type de fichier déposé n'est pas pris en charge",
|
||||
"Loading...": "Chargement...",
|
||||
"ImageProxy HTTP error: Rejected request": "Erreur HTTP d'ImageProxy : Requête rejetée",
|
||||
"ImageProxy HTTP error: Could not find Image Proxy": "Erreur HTTP d'ImageProxy : Impossible de trouver ImageProxy",
|
||||
"ImageProxy HTTP error: Incorrect Image Proxy URL": "Erreur HTTP d'ImageProxy : URL de ImageProxy incorrecte",
|
||||
"ImageProxy HTTP error: Unknown ImageProxy error": "Erreur HTTP d'ImageProxy : Erreur ImageProxy inconnue"
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Ephox Corporation DBA Tiny Technologies, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=(t,e,r)=>{const s="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(s,!1,!1===r?null:{"list-style-type":r})},r=t=>e=>e.options.get(t),s=r("advlist_number_styles"),n=r("advlist_bullet_styles"),l=t=>null==t,i=t=>!l(t);var o=tinymce.util.Tools.resolve("tinymce.util.Tools");class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return i(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=t=>i(t)&&/^(TH|TD)$/.test(t.nodeName),d=t=>l(t)||"default"===t?"":t,g=(t,e)=>r=>{const s=s=>{r.setActive(((t,e,r)=>{const s=((t,e)=>{for(let r=0;r<t.length;r++)if(e(t[r]))return r;return-1})(e.parents,u),n=-1!==s?e.parents.slice(0,s):e.parents,l=o.grep(n,(t=>e=>i(e)&&/^(OL|UL|DL)$/.test(e.nodeName)&&((t,e)=>t.dom.isChildOf(e,t.getBody()))(t,e))(t));return l.length>0&&l[0].nodeName===r})(t,s,e)),r.setEnabled(!((t,e)=>{const r=t.dom.getParent(e,"ol,ul,dl");return((t,e)=>null!==e&&"false"===t.dom.getContentEditableParent(e))(t,r)})(t,s.element))};return t.on("NodeChange",s),()=>t.off("NodeChange",s)},h=(t,r,s,n,l,i)=>{i.length>1?((t,r,s,n,l,i)=>{t.ui.registry.addSplitButton(r,{tooltip:s,icon:"OL"===l?"ordered-list":"unordered-list",presets:"listpreview",columns:3,fetch:t=>{t(o.map(i,(t=>{const e="OL"===l?"num":"bull",r="disc"===t||"decimal"===t?"default":t,s=d(t),n=(t=>t.replace(/\-/g," ").replace(/\b\w/g,(t=>t.toUpperCase())))(t);return{type:"choiceitem",value:s,icon:"list-"+e+"-"+r,text:n}})))},onAction:()=>t.execCommand(n),onItemAction:(r,s)=>{e(t,l,s)},select:e=>{const r=(t=>{const e=t.dom.getParent(t.selection.getNode(),"ol,ul"),r=t.dom.getStyle(e,"listStyleType");return a.from(r)})(t);return r.map((t=>e===t)).getOr(!1)},onSetup:g(t,l)})})(t,r,s,n,l,i):((t,r,s,n,l,i)=>{t.ui.registry.addToggleButton(r,{active:!1,tooltip:s,icon:"OL"===l?"ordered-list":"unordered-list",onSetup:g(t,l),onAction:()=>t.queryCommandState(n)||""===i?t.execCommand(n):e(t,l,i)})})(t,r,s,n,l,d(i[0]))};t.add("advlist",(t=>{t.hasPlugin("lists")?((t=>{const e=t.options.register;e("advlist_number_styles",{processor:"string[]",default:"default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")}),e("advlist_bullet_styles",{processor:"string[]",default:"default,circle,square".split(",")})})(t),(t=>{h(t,"numlist","Numbered list","InsertOrderedList","OL",s(t)),h(t,"bullist","Bullet list","InsertUnorderedList","UL",n(t))})(t),(t=>{t.addCommand("ApplyUnorderedListStyle",((r,s)=>{e(t,"UL",s["list-style-type"])})),t.addCommand("ApplyOrderedListStyle",((r,s)=>{e(t,"OL",s["list-style-type"])}))})(t)):console.error("Please use the Lists plugin together with the Advanced List plugin.")}))}();
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=("allow_html_in_named_anchor",e=>e.options.get("allow_html_in_named_anchor"));const a="a:not([href])",r=e=>!e,i=e=>e.getAttribute("id")||e.getAttribute("name")||"",l=e=>(e=>"a"===e.nodeName.toLowerCase())(e)&&!e.getAttribute("href")&&""!==i(e),s=e=>e.dom.getParent(e.selection.getStart(),a),d=(e,a)=>{const r=s(e);r?((e,t,o)=>{o.removeAttribute("name"),o.id=t,e.addVisual(),e.undoManager.add()})(e,a,r):((e,a)=>{e.undoManager.transact((()=>{n(e)||e.selection.collapse(!0),e.selection.isCollapsed()?e.insertContent(e.dom.createHTML("a",{id:a})):((e=>{const n=e.dom;t(n).walk(e.selection.getRng(),(e=>{o.each(e,(e=>{var t;l(t=e)&&!t.firstChild&&n.remove(e,!1)}))}))})(e),e.formatter.remove("namedAnchor",void 0,void 0,!0),e.formatter.apply("namedAnchor",{value:a}),e.addVisual())}))})(e,a),e.focus()},c=e=>(e=>r(e.attr("href"))&&!r(e.attr("id")||e.attr("name")))(e)&&!e.firstChild,m=e=>t=>{for(let o=0;o<t.length;o++){const n=t[o];c(n)&&n.attr("contenteditable",e)}};e.add("anchor",(e=>{(e=>{(0,e.options.register)("allow_html_in_named_anchor",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreInit",(()=>{e.parser.addNodeFilter("a",m("false")),e.serializer.addNodeFilter("a",m(null))}))})(e),(e=>{e.addCommand("mceAnchor",(()=>{(e=>{const t=(e=>{const t=s(e);return t?i(t):""})(e);e.windowManager.open({title:"Anchor",size:"normal",body:{type:"panel",items:[{name:"id",type:"input",label:"ID",placeholder:"example"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{id:t},onSubmit:t=>{((e,t)=>/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(t)?(d(e,t),!0):(e.windowManager.alert("ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."),!1))(e,t.getData().id)&&t.close()}})})(e)}))})(e),(e=>{const t=()=>e.execCommand("mceAnchor");e.ui.registry.addToggleButton("anchor",{icon:"bookmark",tooltip:"Anchor",onAction:t,onSetup:t=>e.selection.selectorChangedWithUnbind("a:not([href])",t.setActive).unbind}),e.ui.registry.addMenuItem("anchor",{icon:"bookmark",text:"Anchor...",onAction:t})})(e),e.on("PreInit",(()=>{(e=>{e.formatter.register("namedAnchor",{inline:"a",selector:a,remove:"all",split:!0,deep:!0,attributes:{id:"%value"},onmatch:(e,t,o)=>l(e)})})(e)}))}))}();
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),n=t("autolink_pattern"),o=t("link_default_target"),r=t("link_default_protocol"),a=t("allow_unsafe_link_target"),s=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(a=o.constructor)||void 0===a?void 0:a.name)===r.name)?"string":t;var n,o,r,a})(e));const l=(void 0,e=>undefined===e);const i=e=>!(e=>null==e)(e),c=Object.hasOwnProperty,d=e=>"\ufeff"===e;var u=tinymce.util.Tools.resolve("tinymce.dom.TextSeeker");const f=e=>/^[(\[{ \u00a0]$/.test(e),g=(e,t,n)=>{for(let o=t-1;o>=0;o--){const t=e.charAt(o);if(!d(t)&&n(t))return o}return-1},m=(e,t)=>{var o;const a=e.schema.getVoidElements(),s=n(e),{dom:i,selection:d}=e;if(null!==i.getParent(d.getNode(),"a[href]"))return null;const m=d.getRng(),k=u(i,(e=>{return i.isBlock(e)||(t=a,n=e.nodeName.toLowerCase(),c.call(t,n))||"false"===i.getContentEditable(e);var t,n})),{container:p,offset:y}=((e,t)=>{let n=e,o=t;for(;1===n.nodeType&&n.childNodes[o];)n=n.childNodes[o],o=3===n.nodeType?n.data.length:n.childNodes.length;return{container:n,offset:o}})(m.endContainer,m.endOffset),h=null!==(o=i.getParent(p,i.isBlock))&&void 0!==o?o:i.getRoot(),w=k.backwards(p,y+t,((e,t)=>{const n=e.data,o=g(n,t,(r=f,e=>!r(e)));var r,a;return-1===o||(a=n[o],/[?!,.;:]/.test(a))?o:o+1}),h);if(!w)return null;let v=w.container;const _=k.backwards(w.container,w.offset,((e,t)=>{v=e;const n=g(e.data,t,f);return-1===n?n:n+1}),h),A=i.createRng();_?A.setStart(_.container,_.offset):A.setStart(v,0),A.setEnd(w.container,w.offset);const C=A.toString().replace(/\uFEFF/g,"").match(s);if(C){let t=C[0];return $="www.",(b=t).length>=$.length&&b.substr(0,0+$.length)===$?t=r(e)+"://"+t:((e,t,n=0,o)=>{const r=e.indexOf(t,n);return-1!==r&&(!!l(o)||r+t.length<=o)})(t,"@")&&!(e=>/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(e))(t)&&(t="mailto:"+t),{rng:A,url:t}}var b,$;return null},k=(e,t)=>{const{dom:n,selection:r}=e,{rng:l,url:i}=t,c=r.getBookmark();r.setRng(l);const d="createlink",u={command:d,ui:!1,value:i};if(!e.dispatch("BeforeExecCommand",u).isDefaultPrevented()){e.getDoc().execCommand(d,!1,i),e.dispatch("ExecCommand",u);const t=o(e);if(s(t)){const o=r.getNode();n.setAttrib(o,"target",t),"_blank"!==t||a(e)||n.setAttrib(o,"rel","noopener")}}r.moveToBookmark(c),e.nodeChanged()},p=e=>{const t=m(e,-1);i(t)&&k(e,t)},y=p;e.add("autolink",(e=>{(e=>{const t=e.options.register;t("autolink_pattern",{processor:"regexp",default:new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i")}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"})})(e),(e=>{e.on("keydown",(t=>{13!==t.keyCode||t.isDefaultPrevented()||(e=>{const t=m(e,0);i(t)&&k(e,t)})(e)})),e.on("keyup",(t=>{32===t.keyCode?p(e):(48===t.keyCode&&t.shiftKey||221===t.keyCode)&&y(e)}))})(e)}))}();
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env");const o=e=>t=>t.options.get(e),n=o("min_height"),s=o("max_height"),i=o("autoresize_overflow_padding"),r=o("autoresize_bottom_margin"),l=(e,t)=>{const o=e.getBody();o&&(o.style.overflowY=t?"":"hidden",t||(o.scrollTop=0))},a=(e,t,o,n)=>{var s;const i=parseInt(null!==(s=e.getStyle(t,o,n))&&void 0!==s?s:"",10);return isNaN(i)?0:i},g=(e,o,i)=>{var c;const u=e.dom,d=e.getDoc();if(!d)return;if((e=>e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen())(e))return void l(e,!0);const f=d.documentElement,m=r(e),p=null!==(c=n(e))&&void 0!==c?c:e.getElement().offsetHeight;let h=p;const v=a(u,f,"margin-top",!0),y=a(u,f,"margin-bottom",!0);let C=f.offsetHeight+v+y+m;C<0&&(C=0);const S=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight;C+S>p&&(h=C+S);const z=s(e);if(z&&h>z?(h=z,l(e,!0)):l(e,!1),h!==o.get()){const n=h-o.get();if(u.setStyle(e.getContainer(),"height",h+"px"),o.set(h),(e=>{e.dispatch("ResizeEditor")})(e),t.browser.isSafari()&&(t.os.isMacOS()||t.os.isiOS())){const t=e.getWin();t.scrollTo(t.pageXOffset,t.pageYOffset)}e.hasFocus()&&(e=>{if("setcontent"===(null==e?void 0:e.type.toLowerCase())){const t=e;return!0===t.selection||!0===t.paste}return!1})(i)&&e.selection.scrollIntoView(),(t.browser.isSafari()||t.browser.isChromium())&&n<0&&g(e,o,i)}};e.add("autoresize",(e=>{if((e=>{const t=e.options.register;t("autoresize_overflow_padding",{processor:"number",default:1}),t("autoresize_bottom_margin",{processor:"number",default:50})})(e),e.options.isSet("resize")||e.options.set("resize",!1),!e.inline){const t=(e=>{let t=0;return{get:()=>t,set:e=>{t=e}}})();((e,t)=>{e.addCommand("mceAutoResize",(()=>{g(e,t)}))})(e,t),((e,t)=>{e.on("init",(()=>{const t=i(e),o=e.dom;o.setStyles(e.getDoc().documentElement,{height:"auto"}),o.setStyles(e.getBody(),{paddingLeft:t,paddingRight:t,"min-height":0})})),e.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",(o=>{g(e,t,o)}))})(e,t)}}))}();
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=("string",t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(r=o=t,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":e;var r,o,a,s})(t));const r=(void 0,t=>undefined===t);var o=tinymce.util.Tools.resolve("tinymce.util.Delay"),a=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),s=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=t=>{const e=/^(\d+)([ms]?)$/.exec(t);return(e&&e[2]?{s:1e3,m:6e4}[e[2]]:1)*parseInt(t,10)},i=t=>e=>e.options.get(t),u=i("autosave_ask_before_unload"),l=i("autosave_restore_when_empty"),c=i("autosave_interval"),d=i("autosave_retention"),m=t=>{const e=document.location;return t.options.get("autosave_prefix").replace(/{path}/g,e.pathname).replace(/{query}/g,e.search).replace(/{hash}/g,e.hash).replace(/{id}/g,t.id)},v=(t,e)=>{if(r(e))return t.dom.isEmpty(t.getBody());{const r=s.trim(e);if(""===r)return!0;{const e=(new DOMParser).parseFromString(r,"text/html");return t.dom.isEmpty(e)}}},f=t=>{var e;const r=parseInt(null!==(e=a.getItem(m(t)+"time"))&&void 0!==e?e:"0",10)||0;return!((new Date).getTime()-r>d(t)&&(p(t,!1),1))},p=(t,e)=>{const r=m(t);a.removeItem(r+"draft"),a.removeItem(r+"time"),!1!==e&&(t=>{t.dispatch("RemoveDraft")})(t)},g=t=>{const e=m(t);!v(t)&&t.isDirty()&&(a.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),a.setItem(e+"time",(new Date).getTime().toString()),(t=>{t.dispatch("StoreDraft")})(t))},y=t=>{var e;const r=m(t);f(t)&&(t.setContent(null!==(e=a.getItem(r+"draft"))&&void 0!==e?e:"",{format:"raw"}),(t=>{t.dispatch("RestoreDraft")})(t))};var D=tinymce.util.Tools.resolve("tinymce.EditorManager");const h=t=>e=>{e.setEnabled(f(t));const r=()=>e.setEnabled(f(t));return t.on("StoreDraft RestoreDraft RemoveDraft",r),()=>t.off("StoreDraft RestoreDraft RemoveDraft",r)};t.add("autosave",(t=>((t=>{const r=t.options.register,o=t=>{const r=e(t);return r?{value:n(t),valid:r}:{valid:!1,message:"Must be a string."}};r("autosave_ask_before_unload",{processor:"boolean",default:!0}),r("autosave_prefix",{processor:"string",default:"tinymce-autosave-{path}{query}{hash}-{id}-"}),r("autosave_restore_when_empty",{processor:"boolean",default:!1}),r("autosave_interval",{processor:o,default:"30s"}),r("autosave_retention",{processor:o,default:"20m"})})(t),(t=>{t.editorManager.on("BeforeUnload",(t=>{let e;s.each(D.get(),(t=>{t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&u(t)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))})),e&&(t.preventDefault(),t.returnValue=e)}))})(t),(t=>{(t=>{const e=c(t);o.setEditorInterval(t,(()=>{g(t)}),e)})(t);const e=()=>{(t=>{t.undoManager.transact((()=>{y(t),p(t)})),t.focus()})(t)};t.ui.registry.addButton("restoredraft",{tooltip:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)}),t.ui.registry.addMenuItem("restoredraft",{text:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)})})(t),t.on("init",(()=>{l(t)&&t.dom.isEmpty(t.getBody())&&y(t)})),(t=>({hasDraft:()=>f(t),storeDraft:()=>g(t),restoreDraft:()=>y(t),removeDraft:e=>p(t,e),isEmpty:e=>v(t,e)}))(t))))}();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const o=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:o},onSubmit:o=>{((e,o)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(o)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,o.getData().code),o.close()}})})(e)}))})(e),(e=>{const o=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:o}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:o})})(e),{})))}();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>typeof e===t,o=t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(o=r=t,(n=String).prototype.isPrototypeOf(o)||(null===(i=r.constructor)||void 0===i?void 0:i.name)===n.name)?"string":e;var o,r,n,i})(t),r=e("boolean"),n=t=>!(t=>null==t)(t),i=e("function"),s=e("number"),l=(!1,()=>false);class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return n(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=(t,e)=>{for(let o=0,r=t.length;o<r;o++)e(t[o],o)},c=t=>{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},d=c,h=(t,e)=>{const o=t.dom;if(1!==o.nodeType)return!1;{const t=o;if(void 0!==t.matches)return t.matches(e);if(void 0!==t.msMatchesSelector)return t.msMatchesSelector(e);if(void 0!==t.webkitMatchesSelector)return t.webkitMatchesSelector(e);if(void 0!==t.mozMatchesSelector)return t.mozMatchesSelector(e);throw new Error("Browser lacks native selectors")}};"undefined"!=typeof window?window:Function("return this;")();const m=t=>e=>(t=>t.dom.nodeType)(e)===t,g=m(1),f=m(3),v=m(9),p=m(11),y=(t,e)=>{t.dom.removeAttribute(e)},w=i(Element.prototype.attachShadow)&&i(Node.prototype.getRootNode)?t=>d(t.dom.getRootNode()):t=>v(t)?t:d(t.dom.ownerDocument),N=t=>d(t.dom.host),b=t=>{const e=f(t)?t.dom.parentNode:t.dom;if(null==e||null===e.ownerDocument)return!1;const o=e.ownerDocument;return(t=>{const e=w(t);return p(o=e)&&n(o.dom.host)?a.some(e):a.none();var o})(d(e)).fold((()=>o.body.contains(e)),(r=b,i=N,t=>r(i(t))));var r,i},S=t=>"rtl"===((t,e)=>{const o=t.dom,r=window.getComputedStyle(o).getPropertyValue(e);return""!==r||b(t)?r:((t,e)=>(t=>void 0!==t.style&&i(t.style.getPropertyValue))(t)?t.style.getPropertyValue(e):"")(o,e)})(t,"direction")?"rtl":"ltr",A=(t,e)=>((t,o)=>((t,e)=>{const o=[];for(let r=0,n=t.length;r<n;r++){const n=t[r];e(n,r)&&o.push(n)}return o})(((t,e)=>{const o=t.length,r=new Array(o);for(let n=0;n<o;n++){const o=t[n];r[n]=e(o,n)}return r})(t.dom.childNodes,d),(t=>h(t,e))))(t),T=("li",t=>g(t)&&"li"===t.dom.nodeName.toLowerCase());const C=(t,e)=>{const n=t.selection.getSelectedBlocks();n.length>0&&(u(n,(t=>{const n=d(t),c=T(n),m=((t,e)=>{return(e?(o=t,r="ol,ul",((t,e,o)=>{let n=t.dom;const s=i(o)?o:l;for(;n.parentNode;){n=n.parentNode;const t=d(n);if(h(t,r))return a.some(t);if(s(t))break}return a.none()})(o,0,n)):a.some(t)).getOr(t);var o,r,n})(n,c);var f;(f=m,(t=>a.from(t.dom.parentNode).map(d))(f).filter(g)).each((t=>{if(S(t)!==e?((t,e,n)=>{((t,e,n)=>{if(!(o(n)||r(n)||s(n)))throw console.error("Invalid call to Attribute.set. Key ",e,":: Value ",n,":: Element ",t),new Error("Attribute value was not simple");t.setAttribute(e,n+"")})(t.dom,e,n)})(m,"dir",e):S(m)!==e&&y(m,"dir"),c){const t=A(m,"li[dir]");u(t,(t=>y(t,"dir")))}}))})),t.nodeChanged())},D=(t,e)=>o=>{const r=t=>{const r=d(t.element);o.setActive(S(r)===e)};return t.on("NodeChange",r),()=>t.off("NodeChange",r)};t.add("directionality",(t=>{(t=>{t.addCommand("mceDirectionLTR",(()=>{C(t,"ltr")})),t.addCommand("mceDirectionRTL",(()=>{C(t,"rtl")}))})(t),(t=>{t.ui.registry.addToggleButton("ltr",{tooltip:"Left to right",icon:"ltr",onAction:()=>t.execCommand("mceDirectionLTR"),onSetup:D(t,"ltr")}),t.ui.registry.addToggleButton("rtl",{tooltip:"Right to left",icon:"rtl",onAction:()=>t.execCommand("mceDirectionRTL"),onSetup:D(t,"rtl")})})(t)}))}();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(s=r=e,(o=String).prototype.isPrototypeOf(s)||(null===(n=r.constructor)||void 0===n?void 0:n.name)===o.name)?"string":t;var s,r,o,n})(t)===e,s=t("string"),r=t("object"),o=t("array"),n=("function",e=>"function"==typeof e);var c=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),i=tinymce.util.Tools.resolve("tinymce.EditorManager"),l=tinymce.util.Tools.resolve("tinymce.Env"),a=tinymce.util.Tools.resolve("tinymce.util.Tools");const p=e=>t=>t.options.get(e),u=p("importcss_merge_classes"),m=p("importcss_exclusive"),f=p("importcss_selector_converter"),y=p("importcss_selector_filter"),d=p("importcss_groups"),h=p("importcss_append"),_=p("importcss_file_filter"),g=p("skin"),v=p("skin_url"),b=Array.prototype.push,x=/^\.(?:ephox|tiny-pageembed|mce)(?:[.-]+\w+)+$/,T=e=>s(e)?t=>-1!==t.indexOf(e):e instanceof RegExp?t=>e.test(t):e,S=(e,t)=>{let s={};const r=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(t);if(!r)return;const o=r[1],n=r[2].substr(1).split(".").join(" "),c=a.makeMap("a,img");return r[1]?(s={title:t},e.schema.getTextBlockElements()[o]?s.block=o:e.schema.getBlockElements()[o]||c[o.toLowerCase()]?s.selector=o:s.inline=o):r[2]&&(s={inline:"span",title:t.substr(1),classes:n}),u(e)?s.classes=n:s.attributes={class:n},s},k=(e,t)=>null===t||m(e),w=e=>{e.on("init",(()=>{const t=(()=>{const e=[],t=[],s={};return{addItemToGroup:(e,r)=>{s[e]?s[e].push(r):(t.push(e),s[e]=[r])},addItem:t=>{e.push(t)},toFormats:()=>{return(r=t,n=e=>{const t=s[e];return 0===t.length?[]:[{title:e,items:t}]},(e=>{const t=[];for(let s=0,r=e.length;s<r;++s){if(!o(e[s]))throw new Error("Arr.flatten item "+s+" was not an array, input: "+e);b.apply(t,e[s])}return t})(((e,t)=>{const s=e.length,r=new Array(s);for(let o=0;o<s;o++){const s=e[o];r[o]=t(s,o)}return r})(r,n))).concat(e);var r,n}}})(),r={},n=T(y(e)),p=(e=>a.map(e,(e=>a.extend({},e,{original:e,selectors:{},filter:T(e.filter)}))))(d(e)),u=(t,s)=>{if(((e,t,s,r)=>!(k(e,s)?t in r:t in s.selectors))(e,t,s,r)){((e,t,s,r)=>{k(e,s)?r[t]=!0:s.selectors[t]=!0})(e,t,s,r);const o=((e,t,s,r)=>{let o;const n=f(e);return o=r&&r.selector_converter?r.selector_converter:n||(()=>S(e,s)),o.call(t,s,r)})(e,e.plugins.importcss,t,s);if(o){const t=o.name||c.DOM.uniqueId();return e.formatter.register(t,o),{title:o.title,format:t}}}return null};a.each(((e,t,r)=>{const o=[],n={},c=(t,n)=>{let p,u=t.href;if(u=(e=>{const t=l.cacheSuffix;return s(e)&&(e=e.replace("?"+t,"").replace("&"+t,"")),e})(u),u&&(!r||r(u,n))&&!((e,t)=>{const s=g(e);if(s){const r=v(e),o=r?e.documentBaseURI.toAbsolute(r):i.baseURL+"/skins/ui/"+s,n=i.baseURL+"/skins/content/";return t===o+"/content"+(e.inline?".inline":"")+".min.css"||-1!==t.indexOf(n)}return!1})(e,u)){a.each(t.imports,(e=>{c(e,!0)}));try{p=t.cssRules||t.rules}catch(e){}a.each(p,(e=>{e.styleSheet?c(e.styleSheet,!0):e.selectorText&&a.each(e.selectorText.split(","),(e=>{o.push(a.trim(e))}))}))}};a.each(e.contentCSS,(e=>{n[e]=!0})),r||(r=(e,t)=>t||n[e]);try{a.each(t.styleSheets,(e=>{c(e)}))}catch(e){}return o})(e,e.getDoc(),T(_(e))),(e=>{if(!x.test(e)&&(!n||n(e))){const s=((e,t)=>a.grep(e,(e=>!e.filter||e.filter(t))))(p,e);if(s.length>0)a.each(s,(s=>{const r=u(e,s);r&&t.addItemToGroup(s.title,r)}));else{const s=u(e,null);s&&t.addItem(s)}}}));const m=t.toFormats();e.dispatch("addStyleModifications",{items:m,replace:!h(e)})}))};e.add("importcss",(e=>((e=>{const t=e.options.register,o=e=>s(e)||n(e)||r(e);t("importcss_merge_classes",{processor:"boolean",default:!0}),t("importcss_exclusive",{processor:"boolean",default:!0}),t("importcss_selector_converter",{processor:"function"}),t("importcss_selector_filter",{processor:o}),t("importcss_file_filter",{processor:o}),t("importcss_groups",{processor:"object[]"}),t("importcss_append",{processor:"boolean",default:!1})})(e),w(e),(e=>({convertSelectorToFormat:t=>S(e,t)}))(e))))}();
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),a=t("insertdatetime_dateformat"),r=t("insertdatetime_timeformat"),n=t("insertdatetime_formats"),s=t("insertdatetime_element"),i="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),o="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),l="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),m="January February March April May June July August September October November December".split(" "),c=(e,t)=>{if((e=""+e).length<t)for(let a=0;a<t-e.length;a++)e="0"+e;return e},d=(e,t,a=new Date)=>(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=t.replace("%D","%m/%d/%Y")).replace("%r","%I:%M:%S %p")).replace("%Y",""+a.getFullYear())).replace("%y",""+a.getYear())).replace("%m",c(a.getMonth()+1,2))).replace("%d",c(a.getDate(),2))).replace("%H",""+c(a.getHours(),2))).replace("%M",""+c(a.getMinutes(),2))).replace("%S",""+c(a.getSeconds(),2))).replace("%I",""+((a.getHours()+11)%12+1))).replace("%p",a.getHours()<12?"AM":"PM")).replace("%B",""+e.translate(m[a.getMonth()]))).replace("%b",""+e.translate(l[a.getMonth()]))).replace("%A",""+e.translate(o[a.getDay()]))).replace("%a",""+e.translate(i[a.getDay()]))).replace("%%","%"),u=(e,t)=>{if(s(e)){const a=d(e,t);let r;r=/%[HMSIp]/.test(t)?d(e,"%Y-%m-%dT%H:%M"):d(e,"%Y-%m-%d");const n=e.dom.getParent(e.selection.getStart(),"time");n?((e,t,a,r)=>{const n=e.dom.create("time",{datetime:a},r);e.dom.replace(n,t),e.selection.select(n,!0),e.selection.collapse(!1)})(e,n,r,a):e.insertContent('<time datetime="'+r+'">'+a+"</time>")}else e.insertContent(d(e,t))};var p=tinymce.util.Tools.resolve("tinymce.util.Tools");e.add("insertdatetime",(e=>{(e=>{const t=e.options.register;t("insertdatetime_dateformat",{processor:"string",default:e.translate("%Y-%m-%d")}),t("insertdatetime_timeformat",{processor:"string",default:e.translate("%H:%M:%S")}),t("insertdatetime_formats",{processor:"string[]",default:["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"]}),t("insertdatetime_element",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mceInsertDate",((t,r)=>{u(e,null!=r?r:a(e))})),e.addCommand("mceInsertTime",((t,a)=>{u(e,null!=a?a:r(e))}))})(e),(e=>{const t=n(e),a=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})((e=>{const t=n(e);return t.length>0?t[0]:r(e)})(e)),s=t=>e.execCommand("mceInsertDate",!1,t);e.ui.registry.addSplitButton("insertdatetime",{icon:"insert-time",tooltip:"Insert date/time",select:e=>e===a.get(),fetch:a=>{a(p.map(t,(t=>({type:"choiceitem",text:d(e,t),value:t}))))},onAction:e=>{s(a.get())},onItemAction:(e,t)=>{a.set(t),s(t)}});const i=e=>()=>{a.set(e),s(e)};e.ui.registry.addNestedMenuItem("insertdatetime",{icon:"insert-time",text:"Date/time",getSubmenuItems:()=>p.map(t,(t=>({type:"menuitem",text:d(e,t),onAction:i(t)})))})})(e)}))}();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=n=>e=>typeof e===n,a=e("boolean"),o=e("number"),t=n=>e=>e.options.get(n),i=t("nonbreaking_force_tab"),r=t("nonbreaking_wrap"),s=(n,e)=>{let a="";for(let o=0;o<e;o++)a+=n;return a},c=(n,e)=>{const a=r(n)||n.plugins.visualchars?`<span class="${(n=>!!n.plugins.visualchars&&n.plugins.visualchars.isEnabled())(n)?"mce-nbsp-wrap mce-nbsp":"mce-nbsp-wrap"}" contenteditable="false">${s(" ",e)}</span>`:s(" ",e);n.undoManager.transact((()=>n.insertContent(a)))};var l=tinymce.util.Tools.resolve("tinymce.util.VK");n.add("nonbreaking",(n=>{(n=>{const e=n.options.register;e("nonbreaking_force_tab",{processor:n=>a(n)?{value:n?3:0,valid:!0}:o(n)?{value:n,valid:!0}:{valid:!1,message:"Must be a boolean or number."},default:!1}),e("nonbreaking_wrap",{processor:"boolean",default:!0})})(n),(n=>{n.addCommand("mceNonBreaking",(()=>{c(n,1)}))})(n),(n=>{const e=()=>n.execCommand("mceNonBreaking");n.ui.registry.addButton("nonbreaking",{icon:"non-breaking",tooltip:"Nonbreaking space",onAction:e}),n.ui.registry.addMenuItem("nonbreaking",{icon:"non-breaking",text:"Nonbreaking space",onAction:e})})(n),(n=>{const e=i(n);e>0&&n.on("keydown",(a=>{if(a.keyCode===l.TAB&&!a.isDefaultPrevented()){if(a.shiftKey)return;a.preventDefault(),a.stopImmediatePropagation(),c(n,e)}}))})(n)}))}();
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.Env");const t=e=>a=>a.options.get(e),r=t("pagebreak_separator"),n=t("pagebreak_split_block"),o="mce-pagebreak",s=e=>{const t=`<img src="${a.transparentSrc}" class="mce-pagebreak" data-mce-resize="false" data-mce-placeholder />`;return e?`<p>${t}</p>`:t};e.add("pagebreak",(e=>{(e=>{const a=e.options.register;a("pagebreak_separator",{processor:"string",default:"\x3c!-- pagebreak --\x3e"}),a("pagebreak_split_block",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mcePageBreak",(()=>{e.insertContent(s(n(e)))}))})(e),(e=>{const a=()=>e.execCommand("mcePageBreak");e.ui.registry.addButton("pagebreak",{icon:"page-break",tooltip:"Page break",onAction:a}),e.ui.registry.addMenuItem("pagebreak",{text:"Page break",icon:"page-break",onAction:a})})(e),(e=>{const a=r(e),t=()=>n(e),c=new RegExp(a.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,(e=>"\\"+e)),"gi");e.on("BeforeSetContent",(e=>{e.content=e.content.replace(c,s(t()))})),e.on("PreInit",(()=>{e.serializer.addNodeFilter("img",(r=>{let n,s,c=r.length;for(;c--;)if(n=r[c],s=n.attr("class"),s&&-1!==s.indexOf(o)){const r=n.parent;if(r&&e.schema.getBlockElements()[r.name]&&t()){r.type=3,r.value=a,r.raw=!0,n.remove();continue}n.type=3,n.value=a,n.raw=!0}}))}))})(e),(e=>{e.on("ResolveName",(a=>{"IMG"===a.target.nodeName&&e.dom.hasClass(a.target,o)&&(a.name="pagebreak")}))})(e)}))}();
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=e=>t=>t.options.get(e),i=n("content_style"),s=n("content_css_cors"),c=n("body_class"),r=n("body_id");e.add("preview",(e=>{(e=>{e.addCommand("mcePreview",(()=>{(e=>{const n=(e=>{var n;let l="";const a=e.dom.encode,d=null!==(n=i(e))&&void 0!==n?n:"";l+='<base href="'+a(e.documentBaseURI.getURI())+'">';const m=s(e)?' crossorigin="anonymous"':"";o.each(e.contentCSS,(t=>{l+='<link type="text/css" rel="stylesheet" href="'+a(e.documentBaseURI.toAbsolute(t))+'"'+m+">"})),d&&(l+='<style type="text/css">'+d+"</style>");const y=r(e),u=c(e),v='<script>document.addEventListener && document.addEventListener("click", function(e) {for (var elm = e.target; elm; elm = elm.parentNode) {if (elm.nodeName === "A" && !('+(t.os.isMacOS()||t.os.isiOS()?"e.metaKey":"e.ctrlKey && !e.altKey")+")) {e.preventDefault();}}}, false);<\/script> ",p=e.getBody().dir,w=p?' dir="'+a(p)+'"':"";return"<!DOCTYPE html><html><head>"+l+'</head><body id="'+a(y)+'" class="mce-content-body '+a(u)+'"'+w+">"+e.getContent()+v+"</body></html>"})(e);e.windowManager.open({title:"Preview",size:"large",body:{type:"panel",items:[{name:"preview",type:"iframe",sandboxed:!0,transparent:!1}]},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{preview:n}}).focus("close")})(e)}))})(e),(e=>{const t=()=>e.execCommand("mcePreview");e.ui.registry.addButton("preview",{icon:"preview",tooltip:"Preview",onAction:t}),e.ui.registry.addMenuItem("preview",{icon:"preview",text:"Preview",onAction:t})})(e)}))}();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const n=("function",e=>"function"==typeof e);var o=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),t=tinymce.util.Tools.resolve("tinymce.util.Tools");const a=e=>n=>n.options.get(e),c=a("save_enablewhendirty"),i=a("save_onsavecallback"),s=a("save_oncancelcallback"),r=(e,n)=>{e.notificationManager.open({text:n,type:"error"})},l=e=>n=>{const o=()=>{n.setEnabled(!c(e)||e.isDirty())};return o(),e.on("NodeChange dirty",o),()=>e.off("NodeChange dirty",o)};e.add("save",(e=>{(e=>{const n=e.options.register;n("save_enablewhendirty",{processor:"boolean",default:!0}),n("save_onsavecallback",{processor:"function"}),n("save_oncancelcallback",{processor:"function"})})(e),(e=>{e.ui.registry.addButton("save",{icon:"save",tooltip:"Save",enabled:!1,onAction:()=>e.execCommand("mceSave"),onSetup:l(e)}),e.ui.registry.addButton("cancel",{icon:"cancel",tooltip:"Cancel",enabled:!1,onAction:()=>e.execCommand("mceCancel"),onSetup:l(e)}),e.addShortcut("Meta+S","","mceSave")})(e),(e=>{e.addCommand("mceSave",(()=>{(e=>{const t=o.DOM.getParent(e.id,"form");if(c(e)&&!e.isDirty())return;e.save();const a=i(e);if(n(a))return a.call(e,e),void e.nodeChanged();t?(e.setDirty(!1),t.onsubmit&&!t.onsubmit()||("function"==typeof t.submit?t.submit():r(e,"Error: Form submit field collision.")),e.nodeChanged()):r(e,"Error: No form element found.")})(e)})),e.addCommand("mceCancel",(()=>{(e=>{const o=t.trim(e.startContent),a=s(e);n(a)?a.call(e,e):e.resetContent(o)})(e)}))})(e)}))}();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 6.3.1 (2022-12-06)
|
||||
*/
|
||||
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const s=(t,s,o)=>{t.dom.toggleClass(t.getBody(),"mce-visualblocks"),o.set(!o.get()),((t,s)=>{t.dispatch("VisualBlocks",{state:s})})(t,o.get())},o=("visualblocks_default_state",t=>t.options.get("visualblocks_default_state"));const e=(t,s)=>o=>{o.setActive(s.get());const e=t=>o.setActive(t.state);return t.on("VisualBlocks",e),()=>t.off("VisualBlocks",e)};t.add("visualblocks",((t,l)=>{(t=>{(0,t.options.register)("visualblocks_default_state",{processor:"boolean",default:!1})})(t);const a=(t=>{let s=!1;return{get:()=>s,set:t=>{s=t}}})();((t,o,e)=>{t.addCommand("mceVisualBlocks",(()=>{s(t,0,e)}))})(t,0,a),((t,s)=>{const o=()=>t.execCommand("mceVisualBlocks");t.ui.registry.addToggleButton("visualblocks",{icon:"visualblocks",tooltip:"Show blocks",onAction:o,onSetup:e(t,s)}),t.ui.registry.addToggleMenuItem("visualblocks",{text:"Show blocks",icon:"visualblocks",onAction:o,onSetup:e(t,s)})})(t,a),((t,e,l)=>{t.on("PreviewFormats AfterPreviewFormats",(s=>{l.get()&&t.dom.toggleClass(t.getBody(),"mce-visualblocks","afterpreviewformats"===s.type)})),t.on("init",(()=>{o(t)&&s(t,0,l)}))})(t,0,a)}))}();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
body{background-color:#222f3e;color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}
|
||||
@@ -0,0 +1 @@
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}
|
||||
@@ -0,0 +1 @@
|
||||
@media screen{html{background:#f4f4f4;min-height:100%}}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif}@media screen{body{background-color:#fff;box-shadow:0 0 4px rgba(0,0,0,.15);box-sizing:border-box;margin:1rem auto 0;max-width:820px;min-height:calc(100vh - 1rem);padding:4rem 6rem 6rem 6rem}}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure figcaption{color:#999;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}
|
||||
@@ -0,0 +1 @@
|
||||
body{background-color:#2f3742;color:#dfe0e4;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}
|
||||
@@ -0,0 +1 @@
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}
|
||||
@@ -0,0 +1 @@
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem auto;max-width:900px}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}
|
||||
File diff suppressed because one or more lines are too long
+3116
File diff suppressed because it is too large
Load Diff
+4
File diff suppressed because one or more lines are too long
@@ -4,6 +4,16 @@ import Navbar from './components/Navbar.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<Navbar v-if="useRoute().name !== 'login'"></Navbar>
|
||||
<RouterView />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.app-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
||||
@@ -15,6 +15,7 @@
|
||||
--primary: #2CD358;
|
||||
--primary-dark: #00BA2A;
|
||||
--primary-light: #97E6A2;
|
||||
--primary-verylight: #ecffef;
|
||||
--secondary: #D32CA6;
|
||||
--secondary-dark: #BA0094;
|
||||
--secondary-light: #E88DCA;
|
||||
@@ -34,18 +35,43 @@ h1 {
|
||||
font-family: 'Frank Ruhl Libre', serif;
|
||||
font-size: 40px;
|
||||
}
|
||||
h2 { font-size: 32px; }
|
||||
h3 { font-size: 24px; }
|
||||
h4 { font-size: 18px; }
|
||||
h2, h3, h4, h5, h6 {
|
||||
|
||||
h2 {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: 'Nunito', sans-serif;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
p,
|
||||
a,
|
||||
input,
|
||||
label,
|
||||
button,
|
||||
span,
|
||||
li,
|
||||
td,
|
||||
th,
|
||||
.tabulator {
|
||||
font-family: 'Hind', sans-serif;
|
||||
color: var(--neutral-dark);
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.label-input,
|
||||
@@ -77,6 +103,27 @@ h2, h3, h4, h5, h6 {
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.tags li,
|
||||
.tags .tag {
|
||||
background-color: var(--neutral-verylight);
|
||||
border-radius: var(--radius);
|
||||
|
||||
padding: 4px 16px;
|
||||
}
|
||||
|
||||
.tags li::marker {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.label-input-error input {
|
||||
border: solid 1.75px var(--error);
|
||||
}
|
||||
@@ -86,6 +133,7 @@ h2, h3, h4, h5, h6 {
|
||||
}
|
||||
|
||||
.button-primary,
|
||||
.button-secondary,
|
||||
.button-disabled {
|
||||
border-radius: var(--radius);
|
||||
border: none;
|
||||
@@ -94,13 +142,31 @@ h2, h3, h4, h5, h6 {
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--medium-weight);
|
||||
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
|
||||
background-color: var(--primary);
|
||||
|
||||
transition: background-color 150ms;
|
||||
transition: background-color 150ms, color 150ms;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button-secondary {
|
||||
color: var(--primary-dark);
|
||||
border: solid 1.5px var(--primary-dark);
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.button-secondary:hover {
|
||||
background-color: var(--primary-verylight);
|
||||
}
|
||||
|
||||
.button-secondary:active {
|
||||
background-color: var(--primary-light);
|
||||
color: var(--neutral-dark);
|
||||
}
|
||||
|
||||
.button-primary:hover {
|
||||
background-color: var(--primary-light);
|
||||
}
|
||||
@@ -114,3 +180,8 @@ h2, h3, h4, h5, h6 {
|
||||
background-color: var(--neutral-light);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.tox-tinymce {
|
||||
border: none !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
+2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -2,13 +2,20 @@
|
||||
import { useAuthStore } from '@/stores/AuthStore';
|
||||
import { deleteCookie } from '@/utils/cookies';
|
||||
import { RouterLink, useRouter } from 'vue-router'
|
||||
import { baseApiUrl } from "@/utils/api"
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
function logout() {
|
||||
deleteCookie('JWTtoken')
|
||||
deleteCookie('JWTexpire')
|
||||
deleteCookie('jwt_expire')
|
||||
useAuthStore().clearAll()
|
||||
|
||||
fetch(`${baseApiUrl}/logout`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
})
|
||||
.catch(error => console.error(error))
|
||||
|
||||
router.push('/')
|
||||
}
|
||||
</script>
|
||||
@@ -26,6 +33,9 @@ function logout() {
|
||||
|
||||
<style scoped>
|
||||
header {
|
||||
position: relative;
|
||||
z-index: 50;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
|
||||
@@ -5,6 +5,7 @@ import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
import '@/assets/base.css'
|
||||
import '@/assets/tabulator_bootstrap5.min.css'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { createRouter, createWebHistory, type NavigationGuard } from 'vue-router'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { useAuthStore } from '@/stores/AuthStore'
|
||||
import { nextTick } from 'vue'
|
||||
import Debug from '@/views/Debug.vue'
|
||||
import Login from '@/views/Login.vue'
|
||||
import Home from '@/views/Home.vue'
|
||||
import Articles from '@/views/Articles.vue'
|
||||
import ArticlesEdit from '@/views/ArticlesEdit.vue'
|
||||
import ArticlesNew from '@/views/ArticlesNew.vue'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
@@ -17,14 +18,6 @@ const router = createRouter({
|
||||
title: 'GohCMS - Connexion'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/debug',
|
||||
name: 'debug',
|
||||
component: Debug,
|
||||
meta: {
|
||||
title: 'GohCMS - Debug'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/home',
|
||||
name: 'home',
|
||||
@@ -41,17 +34,33 @@ const router = createRouter({
|
||||
title: 'GohCMS - Articles'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/articles/edit/:articleID',
|
||||
name: 'edition',
|
||||
component: ArticlesEdit,
|
||||
meta: {
|
||||
title: 'GohCMS - Edition'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/articles/new',
|
||||
name: 'new',
|
||||
component: ArticlesNew,
|
||||
meta: {
|
||||
title: 'GohCMS - Nouveau'
|
||||
}
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
router.beforeEach(async (to, from) => {
|
||||
const isTokenValid = useAuthStore().isValid()
|
||||
const isJwtExpired = useAuthStore().isExpired()
|
||||
if (to.name === 'login') {
|
||||
if (isTokenValid) return {
|
||||
if (!isJwtExpired) return {
|
||||
name: 'home'
|
||||
}
|
||||
} else {
|
||||
if (!isTokenValid) {
|
||||
if (isJwtExpired) {
|
||||
return {
|
||||
name: 'login',
|
||||
}
|
||||
|
||||
@@ -6,23 +6,18 @@ import { useErrorsStore } from "./ErrorsStore";
|
||||
export interface jwtFormat {
|
||||
code: number,
|
||||
expire: string,
|
||||
token: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export const useAuthStore = defineStore("AuthStore", () => {
|
||||
const expire = ref('')
|
||||
const token = ref('')
|
||||
|
||||
function clearAll(): void {
|
||||
expire.value = ''
|
||||
token.value = ''
|
||||
}
|
||||
|
||||
function isSet(): boolean {
|
||||
return token.value !== undefined && token.value !== ''
|
||||
}
|
||||
|
||||
function isExpired(): boolean {
|
||||
if (expire.value === '') return true;
|
||||
const tokenDate = new Date(expire.value)
|
||||
const currentDate = new Date()
|
||||
|
||||
@@ -33,20 +28,14 @@ export const useAuthStore = defineStore("AuthStore", () => {
|
||||
return false
|
||||
}
|
||||
|
||||
function isValid(): boolean {
|
||||
return isSet() && !isExpired()
|
||||
}
|
||||
|
||||
function initStore(): void {
|
||||
const JWTtoken = getCookie('JWTtoken')
|
||||
const JWTexpire = getCookie('JWTexpire')
|
||||
if (JWTtoken !== "" && JWTexpire !== "") {
|
||||
token.value = JWTtoken
|
||||
const JWTexpire = getCookie('jwt_expire')
|
||||
if (JWTexpire !== "") {
|
||||
expire.value = JWTexpire
|
||||
}
|
||||
}
|
||||
|
||||
initStore()
|
||||
|
||||
return { expire, token, isValid, clearAll }
|
||||
return { expire, clearAll, isExpired}
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
export const baseApiUrl = `${__APP_ENV__.APP_API_ADDRESS}`
|
||||
@@ -0,0 +1,35 @@
|
||||
import { baseApiUrl } from "@/utils/api"
|
||||
|
||||
export interface Article {
|
||||
titleID: string,
|
||||
title: string,
|
||||
date: number,
|
||||
content: {
|
||||
html: string
|
||||
},
|
||||
tags: Array<string>,
|
||||
online: boolean
|
||||
}
|
||||
|
||||
export async function getArticles(id: string) : Promise<Array<Article>> {
|
||||
return await fetch(`${baseApiUrl}/articles/${id}`, {
|
||||
credentials: 'include',
|
||||
method: 'GET',
|
||||
})
|
||||
.then(result => result.json())
|
||||
.catch(error => {
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
|
||||
export async function postArticle(article: Article) : Promise<object> {
|
||||
return await fetch(`${baseApiUrl}/articles/${article.titleID}`, {
|
||||
credentials: 'include',
|
||||
method: 'POST',
|
||||
body: JSON.stringify(article)
|
||||
})
|
||||
.then(result => result.json())
|
||||
.catch(error => {
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
@@ -1,11 +1,109 @@
|
||||
<script setup lang="ts">
|
||||
import { getArticles, type Article } from '@/utils/database';
|
||||
import { onMounted, ref, type Ref } from 'vue';
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { TabulatorFull as Tabulator } from 'tabulator-tables'
|
||||
|
||||
const articles: Ref<Array<Article>> = ref([])
|
||||
|
||||
const table = ref<HTMLInputElement | string>('')
|
||||
const tabulator: Ref<Tabulator | undefined> = ref(undefined)
|
||||
|
||||
onMounted(async () => {
|
||||
articles.value = await getArticles('')
|
||||
tabulator.value = new Tabulator(table.value, {
|
||||
data: articles.value,
|
||||
reactiveData: true,
|
||||
layout: 'fitColumns',
|
||||
columns: [
|
||||
{
|
||||
title: 'Titre',
|
||||
field: 'title',
|
||||
},
|
||||
{
|
||||
title: 'Date création',
|
||||
field: 'date',
|
||||
formatter: function (cell) {
|
||||
return new Date(cell.getValue()).toLocaleDateString('fr-FR')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Tags',
|
||||
field: 'tags',
|
||||
formatter: function (cell) {
|
||||
return cell.getValue().join(' ')
|
||||
},
|
||||
sorter: 'alphanum'
|
||||
},
|
||||
{
|
||||
title: 'Statut',
|
||||
field: 'online',
|
||||
formatter: function (cell) {
|
||||
return cell.getValue() as boolean ? '🟢' : '🔴'
|
||||
},
|
||||
headerSort: false
|
||||
},
|
||||
{
|
||||
title: 'Actions',
|
||||
field: 'titleID',
|
||||
formatter: function (cell) {
|
||||
const container = document.createElement('div')
|
||||
|
||||
const editButton = document.createElement('a')
|
||||
const deleteButton = document.createElement('a')
|
||||
editButton.classList.add('button-secondary')
|
||||
deleteButton.classList.add('button-secondary')
|
||||
editButton.textContent = '✏️'
|
||||
deleteButton.textContent = '🗑️'
|
||||
|
||||
editButton.href = `/articles/edit/${cell.getValue()}`
|
||||
|
||||
container.append(editButton, deleteButton)
|
||||
return container
|
||||
},
|
||||
headerSort: false
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p>articles page</p>
|
||||
<main>
|
||||
<RouterLink class="button-primary" to="/articles/new">Créer un article</RouterLink>
|
||||
<div id="table" ref="table"></div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
main>a {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
#table {
|
||||
width: 100%;
|
||||
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin: auto;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.action-buttons>* {
|
||||
margin: 0 6px;
|
||||
}
|
||||
|
||||
.status {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,75 @@
|
||||
<script setup lang="ts">
|
||||
import { getArticles, type Article } from '@/utils/database';
|
||||
import Editor from '@tinymce/tinymce-vue';
|
||||
import { onMounted, ref, type Ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const article: Ref<Article | void> = ref()
|
||||
const editorData: Ref<string> = ref('')
|
||||
|
||||
onMounted(async () => {
|
||||
const articleFetch = await getArticles(useRoute().params.articleID as string)
|
||||
article.value = articleFetch[0]
|
||||
editorData.value = article.value.content.html
|
||||
})
|
||||
|
||||
function abort() {
|
||||
}
|
||||
|
||||
function saveContent() {
|
||||
console.log(editorData.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<div id="editor">
|
||||
<Editor tinymce-script-src="/tinymce/tinymce.min.js"
|
||||
:init="{ promotion: false, language: 'fr_FR', resize: false, height: '100%', }"
|
||||
:plugins="['link', 'codesample']"
|
||||
toolbar="undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | outdent indent | codesample link"
|
||||
v-model="editorData">
|
||||
</Editor>
|
||||
</div>
|
||||
<aside class="buttons">
|
||||
<button @click="saveContent()" class="button-primary">Enregistrer</button>
|
||||
<button @click="abort()" class="button-secondary">Annuler</button>
|
||||
</aside>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#editor {
|
||||
padding-top: 16px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tox-tinymce {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: right;
|
||||
align-content: center;
|
||||
gap: 16px;
|
||||
|
||||
width: fit-content;
|
||||
padding: 32px 16px;
|
||||
|
||||
box-shadow: #0002 0 0 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,101 @@
|
||||
<script setup lang="ts">
|
||||
import { postArticle, type Article } from '@/utils/database';
|
||||
import { ref, type Ref } from 'vue';
|
||||
import { RouterLink, useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const defaultData = `<h1>Bienvenue</h1><p>Vous êtes en mode <em>édition</em> d'article.</p><p>Celui-ci semble encore neuf ! Supprimez ces lignes et laissez libre cours à votre imagination :)</p><p>Pour plus d'infos, rendez-vous sur la <a title="Attention, rickroll incoming" href="https:/www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank" rel="noopener">page d'aide</a>.</p>`
|
||||
const title = ref('')
|
||||
const rawTags = ref('')
|
||||
const tags: Ref<string[]> = ref([])
|
||||
|
||||
const regexAccents = /[\u0300-\u036f]/g
|
||||
const regexSymbols = /([-!$%^&*()_+|~=`{}\[\]:";'<>?,.\/])+/g
|
||||
|
||||
function updateUniqueTags(): void {
|
||||
tags.value = rawTags.value.split(/[,\s]+/g)
|
||||
tags.value = Array.from(new Set(tags.value.filter(x => x !== '')))
|
||||
}
|
||||
|
||||
function generateTitleID(title: string): string {
|
||||
return title.toLowerCase().normalize('NFD')
|
||||
.replace(regexAccents, '')
|
||||
.replace(regexSymbols, '')
|
||||
.replace(/\s/g, '-')
|
||||
}
|
||||
|
||||
function isFormEmpty(): boolean {
|
||||
return title.value === '' || rawTags.value === ''
|
||||
}
|
||||
|
||||
function createArticle() {
|
||||
const article: Article = {
|
||||
titleID: generateTitleID(title.value),
|
||||
title: title.value,
|
||||
date: new Date().getTime(),
|
||||
content: {
|
||||
html: defaultData
|
||||
},
|
||||
online: false,
|
||||
tags: tags.value
|
||||
}
|
||||
postArticle(article)
|
||||
router.push(`/articles/edit/${article.titleID}`)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main>
|
||||
<h2>Créer un nouvel article</h2>
|
||||
<form @submit.prevent="createArticle()">
|
||||
<div class="inputs-group">
|
||||
<div class="label-input">
|
||||
<label for="title">Titre de l'article</label>
|
||||
<input id="title" name="title" placeholder="Titre de l'article" type="text" v-model="title">
|
||||
<p>Son URL d'accès ressemblera à: {{ generateTitleID(title) }}</p>
|
||||
</div>
|
||||
<div class="label-input">
|
||||
<label for="tags">Tags</label>
|
||||
<input id="tags" name="tags" placeholder="Tags" type="text" v-model="rawTags"
|
||||
@input="updateUniqueTags">
|
||||
<p>Spéparez les mots-clés par des virgules ou espaces.</p>
|
||||
<ul class="tags" v-if="tags.length !== 0">
|
||||
<li v-for="tag in tags">{{ tag }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons-group">
|
||||
<RouterLink class="button-secondary" type="submit" to="/articles">Annuler</RouterLink>
|
||||
<button :class="`button-${isFormEmpty() ? 'disabled' : 'primary'}`" type="submit"
|
||||
:disabled="isFormEmpty()">Créer</button>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
main {
|
||||
padding: 0 64px;
|
||||
max-width: 100%;
|
||||
width: 560px;
|
||||
}
|
||||
|
||||
.buttons-group {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.buttons-group a,
|
||||
.buttons-group button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.inputs-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,71 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
// import EditorJS from '@editorjs/editorjs';
|
||||
import { useAuthStore, type jwtFormat } from '@/stores/AuthStore';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
|
||||
const baseURL = `http://${__APP_ENV__.APP_HOST_ADDRESS}:${__APP_ENV__.APP_API_PORT}`
|
||||
|
||||
function getArticles() {
|
||||
fetch(`${baseURL}/articles/`, {
|
||||
headers: { "Authorization": `Bearer ${useAuthStore().token}` }
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => console.log(result))
|
||||
}
|
||||
|
||||
function ping() {
|
||||
fetch(`${baseURL}/ping/`, {
|
||||
headers: { "Authorization": `Bearer ${useAuthStore().token}` }
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => console.log(result))
|
||||
}
|
||||
|
||||
function jwtHandler(apiResponse: jwtFormat): void {
|
||||
if (apiResponse.code !== 200) {
|
||||
console.log(apiResponse)
|
||||
return
|
||||
}
|
||||
useAuthStore().token = apiResponse.token
|
||||
useAuthStore().expire = apiResponse.expire
|
||||
console.log('success! logged in.')
|
||||
}
|
||||
|
||||
function login(email: string, password: string): void {
|
||||
fetch(`${baseURL}/login/`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
password: password
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => jwtHandler(result))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h2>Connexion</h2>
|
||||
|
||||
<form @submit.prevent="login(email, password)">
|
||||
<div>
|
||||
<label for="email">Email address</label>
|
||||
<input id="email" name="email" placeholder="email" type="text" v-model="email">
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password</label>
|
||||
<input id="password" name="password" placeholder="password" type="password" v-model="password">
|
||||
</div>
|
||||
<button type="submit">Se connecter</button>
|
||||
</form>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<button class="button-primary" @click="getArticles()">get all articles</button>
|
||||
<button class="button-primary" @click="ping()">ping</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { useAuthStore, type jwtFormat } from '@/stores/AuthStore';
|
||||
import { useErrorsStore } from '@/stores/ErrorsStore';
|
||||
import { baseApiUrl } from '@/utils/api';
|
||||
import { setCookie } from '@/utils/cookies';
|
||||
import { ref, type Ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
@@ -20,12 +21,7 @@ function updateJWTcookies(JWTdata: jwtFormat): void {
|
||||
cookieExpire.setDate(cookieExpire.getDate() + 1)
|
||||
|
||||
setCookie({
|
||||
key: 'JWTtoken',
|
||||
value: JWTdata.token,
|
||||
expire: cookieExpire.toString()
|
||||
})
|
||||
setCookie({
|
||||
key: 'JWTexpire',
|
||||
key: 'jwt_expire',
|
||||
value: JWTdata.expire,
|
||||
expire: cookieExpire.toString()
|
||||
})
|
||||
@@ -43,14 +39,14 @@ function jwtHandler(apiResponse: jwtFormat): void {
|
||||
}
|
||||
updateJWTcookies(apiResponse)
|
||||
disableErrors()
|
||||
authStore.token = apiResponse.token
|
||||
authStore.expire = apiResponse.expire
|
||||
isTokenOK.value = true
|
||||
}
|
||||
|
||||
function login(email: string, password: string): void {
|
||||
fetch(`http://${__APP_ENV__.APP_HOST_ADDRESS}:${__APP_ENV__.APP_API_PORT}/login/`, {
|
||||
method: "POST",
|
||||
fetch(`${baseApiUrl}/login/`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
password: password
|
||||
@@ -79,12 +75,14 @@ function login(email: string, password: string): void {
|
||||
</div>
|
||||
<div :class="`label-input${isTokenOK === false ? '-error' : ''}`">
|
||||
<label for="password">Mot de passe</label>
|
||||
<input id="password" name="password" placeholder="Mot de passe" type="password" v-model="password">
|
||||
<input id="password" name="password" placeholder="Mot de passe" type="password"
|
||||
v-model="password">
|
||||
<p v-if="isTokenOK === false">❌ E-mail et/ou mot de passe incorrect(s).</p>
|
||||
<p v-else-if="useErrorsStore().sessionExpired">⌛ Votre session a expiré.</p>
|
||||
</div>
|
||||
</div>
|
||||
<button :class="`button-${isFormEmpty() ? 'disabled' : 'primary'}`" type="submit" :disabled="isFormEmpty()">
|
||||
<button :class="`button-${isFormEmpty() ? 'disabled' : 'primary'}`" type="submit"
|
||||
:disabled="isFormEmpty()">
|
||||
Se connecter
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { fileURLToPath, URL } from "node:url"
|
||||
import { defineConfig, loadEnv } from "vite"
|
||||
import vue from "@vitejs/plugin-vue"
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ command, mode }) => {
|
||||
@@ -11,7 +11,7 @@ export default defineConfig(({ command, mode }) => {
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
}
|
||||
},
|
||||
define: {
|
||||
@@ -22,6 +22,7 @@ export default defineConfig(({ command, mode }) => {
|
||||
},
|
||||
server: {
|
||||
port: env1.APP_FRONT_PORT,
|
||||
}
|
||||
},
|
||||
base: env1.APP_BASE_FRONT_PATH ?? "/"
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user