More work on Cosora, we have a screenshot of it up now, although it's super experimental at the moment.

This commit might be a little broken, another is coming to fix things up!

The topics list is now paginated.
Refactored the error handling system.
Added the Trumboyg WYSIWYG editor for Cosora.
Moved Delete() out of the TopicStore and into *Topic
You can now bulk delete and bulk lock topics on Cosora.
h1s are now formatted properly on Firefox.
Added more ARIA Labels.
SuperModOnly is now a piece of middleware for the Control Panel routes.
Refactored and extended the router generator.
Improved the SEO for the paginators.
Added bits of Microdata to improve SEO further.
Wrote benchmarks for users.Get() and users.BypassGet()
More errors are caught now.
You can now attach pcss files to posts.
Improved the error logging for JavaScript.
Topic list avatars now link to the associated profiles.
Added last poster avatars to the forum list.
This commit is contained in:
Azareal 2017-10-30 09:57:08 +00:00
parent f7942b42ac
commit 14a14b7e80
134 changed files with 10343 additions and 2925 deletions

View File

@ -162,6 +162,8 @@ We're looking for ways to clean-up the plugin system so that all of them (except
![Tempra Conflux Mobile](https://github.com/Azareal/Gosora/blob/master/images/tempra-conflux-mobile-320px.png) ![Tempra Conflux Mobile](https://github.com/Azareal/Gosora/blob/master/images/tempra-conflux-mobile-320px.png)
![Cosora Prototype WIP](https://github.com/Azareal/Gosora/blob/master/images/cosora-wip.png)
More images in the /images/ folder. Beware though, some of them are *really* outdated. More images in the /images/ folder. Beware though, some of them are *really* outdated.
# Dependencies # Dependencies

View File

@ -152,7 +152,7 @@ func (auth *DefaultAuth) SessionCheck(w http.ResponseWriter, r *http.Request) (u
if err == ErrNoRows { if err == ErrNoRows {
return &guestUser, false return &guestUser, false
} else if err != nil { } else if err != nil {
InternalError(err, w) InternalError(err, w, r)
return &guestUser, true return &guestUser, true
} }

153
errors.go
View File

@ -14,6 +14,52 @@ var errorBuffer []error
//var notfoundCountPerSecond int //var notfoundCountPerSecond int
//var nopermsCountPerSecond int //var nopermsCountPerSecond int
// WIP, a new system to propagate errors up from routes
type RouteError interface {
Type() string
Error() string
Json() bool
Handled() bool
}
type RouteErrorImpl struct {
text string
system bool
json bool
handled bool
}
/*func NewRouteError(msg string, system bool, json bool) RouteError {
return &RouteErrorImpl{msg, system, json, false}
}*/
func (err *RouteErrorImpl) Type() string {
// System errors may contain sensitive information we don't want the user to see
if err.system {
return "system"
} else {
return "user"
}
}
func (err *RouteErrorImpl) Error() string {
return err.text
}
// Respond with JSON?
func (err *RouteErrorImpl) Json() bool {
return err.json
}
// Has this error been dealt with elsewhere?
func (err *RouteErrorImpl) Handled() bool {
return err.handled
}
func HandledRouteError() RouteError {
return &RouteErrorImpl{"", false, false, true}
}
// LogError logs internal handler errors which can't be handled with InternalError() as a wrapper for log.Fatal(), we might do more with it in the future. // LogError logs internal handler errors which can't be handled with InternalError() as a wrapper for log.Fatal(), we might do more with it in the future.
func LogError(err error) { func LogError(err error) {
LogWarning(err) LogWarning(err)
@ -28,9 +74,10 @@ func LogWarning(err error) {
errorBuffer = append(errorBuffer, err) errorBuffer = append(errorBuffer, err)
} }
// TODO: Dump the request?
// InternalError is the main function for handling internal errors, while simultaneously printing out a page for the end-user to let them know that *something* has gone wrong // InternalError is the main function for handling internal errors, while simultaneously printing out a page for the end-user to let them know that *something* has gone wrong
// ? - Add a user parameter? // ? - Add a user parameter?
func InternalError(err error, w http.ResponseWriter) { func InternalError(err error, w http.ResponseWriter, r *http.Request) RouteError {
log.Print(err) log.Print(err)
debug.PrintStack() debug.PrintStack()
@ -46,167 +93,180 @@ func InternalError(err error, w http.ResponseWriter) {
defer errorBufferMutex.Unlock() defer errorBufferMutex.Unlock()
errorBuffer = append(errorBuffer, err) errorBuffer = append(errorBuffer, err)
log.Fatal("") log.Fatal("")
return HandledRouteError()
} }
// InternalErrorJSQ is the JSON "maybe" version of InternalError which can handle both JSON and normal requests // InternalErrorJSQ is the JSON "maybe" version of InternalError which can handle both JSON and normal requests
// ? - Add a user parameter? // ? - Add a user parameter?
func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, isJs bool) { func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, isJs bool) RouteError {
if !isJs { if !isJs {
InternalError(err, w) return InternalError(err, w, r)
} else { } else {
InternalErrorJS(err, w, r) return InternalErrorJS(err, w, r)
} }
} }
// InternalErrorJS is the JSON version of InternalError on routes we know will only be requested via JSON. E.g. An API. // InternalErrorJS is the JSON version of InternalError on routes we know will only be requested via JSON. E.g. An API.
// ? - Add a user parameter? // ? - Add a user parameter?
func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) { func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(500) w.WriteHeader(500)
_, _ = w.Write([]byte(`{"errmsg":"A problem has occured in the system."}`)) _, _ = w.Write([]byte(`{"errmsg":"A problem has occurred in the system."}`))
errorBufferMutex.Lock() errorBufferMutex.Lock()
defer errorBufferMutex.Unlock() defer errorBufferMutex.Unlock()
errorBuffer = append(errorBuffer, err) errorBuffer = append(errorBuffer, err)
log.Fatal(err) log.Fatal(err)
return HandledRouteError()
} }
// ? - Where is this used? Is it actually used? Should we use it more? // ? - Where is this used? Should we use it more?
// LoginRequired is an error shown to the end-user when they try to access an area which requires them to login // LoginRequired is an error shown to the end-user when they try to access an area which requires them to login
func LoginRequired(w http.ResponseWriter, r *http.Request, user User) { func LoginRequired(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(401) w.WriteHeader(401)
pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, "You need to login to do that."} pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, "You need to login to do that."}
if preRenderHooks["pre_render_error"] != nil { if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
return return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
return HandledRouteError()
} }
func PreError(errmsg string, w http.ResponseWriter, r *http.Request) { func PreError(errmsg string, w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(500) w.WriteHeader(500)
user := User{ID: 0, Group: 6, Perms: GuestPerms} user := User{ID: 0, Group: 6, Perms: GuestPerms}
pi := Page{"Error", user, getDefaultHeaderVar(), tList, errmsg} pi := Page{"Error", user, getDefaultHeaderVar(), tList, errmsg}
if preRenderHooks["pre_render_error"] != nil { if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
return return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
return HandledRouteError()
} }
func PreErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) { func PreErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(500) w.WriteHeader(500)
_, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`)) _, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
return HandledRouteError()
} }
func PreErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, isJs bool) { func PreErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, isJs bool) RouteError {
if !isJs { if !isJs {
PreError(errmsg, w, r) return PreError(errmsg, w, r)
} else { } else {
PreErrorJS(errmsg, w, r) return PreErrorJS(errmsg, w, r)
} }
} }
// LocalError is an error shown to the end-user when something goes wrong and it's not the software's fault // LocalError is an error shown to the end-user when something goes wrong and it's not the software's fault
func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) { func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(500) w.WriteHeader(500)
pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, errmsg} pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, errmsg}
if preRenderHooks["pre_render_error"] != nil { if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
return return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
return HandledRouteError()
} }
func LocalErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, user User, isJs bool) { func LocalErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, user User, isJs bool) RouteError {
if !isJs { if !isJs {
LocalError(errmsg, w, r, user) return LocalError(errmsg, w, r, user)
} else { } else {
LocalErrorJS(errmsg, w, r) return LocalErrorJS(errmsg, w, r)
} }
} }
func LocalErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) { func LocalErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(500) w.WriteHeader(500)
_, _ = w.Write([]byte(`{'errmsg': '` + errmsg + `'}`)) _, _ = w.Write([]byte(`{'errmsg': '` + errmsg + `'}`))
return HandledRouteError()
} }
// TODO: We might want to centralise the error logic in the future and just return what the error handler needs to construct the response rather than handling it here
// NoPermissions is an error shown to the end-user when they try to access an area which they aren't authorised to access // NoPermissions is an error shown to the end-user when they try to access an area which they aren't authorised to access
func NoPermissions(w http.ResponseWriter, r *http.Request, user User) { func NoPermissions(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(403) w.WriteHeader(403)
pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, "You don't have permission to do that."} pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, "You don't have permission to do that."}
// TODO: What to do about this hook?
if preRenderHooks["pre_render_error"] != nil { if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
return return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
return HandledRouteError()
} }
func NoPermissionsJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) { func NoPermissionsJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) RouteError {
if !isJs { if !isJs {
NoPermissions(w, r, user) return NoPermissions(w, r, user)
} else { } else {
NoPermissionsJS(w, r, user) return NoPermissionsJS(w, r, user)
} }
} }
func NoPermissionsJS(w http.ResponseWriter, r *http.Request, user User) { func NoPermissionsJS(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(403) w.WriteHeader(403)
_, _ = w.Write([]byte(`{"errmsg":"You don't have permission to do that."}`)) _, _ = w.Write([]byte(`{"errmsg":"You don't have permission to do that."}`))
return HandledRouteError()
} }
// ? - Is this actually used? Should it be used? A ban in Gosora should be more of a permission revocation to stop them posting rather than something which spits up an error page, right? // ? - Is this actually used? Should it be used? A ban in Gosora should be more of a permission revocation to stop them posting rather than something which spits up an error page, right?
func Banned(w http.ResponseWriter, r *http.Request, user User) { func Banned(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(403) w.WriteHeader(403)
pi := Page{"Banned", user, getDefaultHeaderVar(), tList, "You have been banned from this site."} pi := Page{"Banned", user, getDefaultHeaderVar(), tList, "You have been banned from this site."}
if preRenderHooks["pre_render_error"] != nil { if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
return return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
return HandledRouteError()
} }
// nolint // nolint
// BannedJSQ is the version of the banned error page which handles both JavaScript requests and normal page loads // BannedJSQ is the version of the banned error page which handles both JavaScript requests and normal page loads
func BannedJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) { func BannedJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) RouteError {
if !isJs { if !isJs {
Banned(w, r, user) return Banned(w, r, user)
} else { } else {
BannedJS(w, r, user) return BannedJS(w, r, user)
} }
} }
func BannedJS(w http.ResponseWriter, r *http.Request, user User) { func BannedJS(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(403) w.WriteHeader(403)
_, _ = w.Write([]byte(`{"errmsg":"You have been banned from this site."}`)) _, _ = w.Write([]byte(`{"errmsg":"You have been banned from this site."}`))
return HandledRouteError()
} }
// nolint // nolint
func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) { func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) RouteError {
w.WriteHeader(401) w.WriteHeader(401)
if !isJs { if !isJs {
pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, "You need to login to do that."} pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, "You need to login to do that."}
if preRenderHooks["pre_render_error"] != nil { if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
return return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := templates.ExecuteTemplate(w, "error.html", pi)
@ -216,28 +276,30 @@ func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bo
} else { } else {
_, _ = w.Write([]byte(`{"errmsg":"You need to login to do that."}`)) _, _ = w.Write([]byte(`{"errmsg":"You need to login to do that."}`))
} }
return HandledRouteError()
} }
// SecurityError is used whenever a session mismatch is found // SecurityError is used whenever a session mismatch is found
// ? - Should we add JS and JSQ versions of this? // ? - Should we add JS and JSQ versions of this?
func SecurityError(w http.ResponseWriter, r *http.Request, user User) { func SecurityError(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(403) w.WriteHeader(403)
pi := Page{"Security Error", user, getDefaultHeaderVar(), tList, "There was a security issue with your request."} pi := Page{"Security Error", user, getDefaultHeaderVar(), tList, "There was a security issue with your request."}
if preRenderHooks["pre_render_security_error"] != nil { if preRenderHooks["pre_render_security_error"] != nil {
if runPreRenderHook("pre_render_security_error", w, r, &user, &pi) { if runPreRenderHook("pre_render_security_error", w, r, &user, &pi) {
return return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
return HandledRouteError()
} }
// NotFound is used when the requested page doesn't exist // NotFound is used when the requested page doesn't exist
// ? - Add a JSQ and JS version of this? // ? - Add a JSQ and JS version of this?
// ? - Add a user parameter? // ? - Add a user parameter?
func NotFound(w http.ResponseWriter, r *http.Request) { func NotFound(w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(404) w.WriteHeader(404)
// TODO: Centralise the user struct somewhere else // TODO: Centralise the user struct somewhere else
user := User{0, "guest", "Guest", "", 0, false, false, false, false, false, false, GuestPerms, nil, "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0} user := User{0, "guest", "Guest", "", 0, false, false, false, false, false, false, GuestPerms, nil, "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0}
@ -246,34 +308,37 @@ func NotFound(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
return HandledRouteError()
} }
// CustomError lets us make custom error types which aren't covered by the generic functions above // CustomError lets us make custom error types which aren't covered by the generic functions above
func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) { func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(errcode) w.WriteHeader(errcode)
pi := Page{errtitle, user, getDefaultHeaderVar(), tList, errmsg} pi := Page{errtitle, user, getDefaultHeaderVar(), tList, errmsg}
if preRenderHooks["pre_render_error"] != nil { if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
return return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
return HandledRouteError()
} }
// CustomErrorJSQ is a version of CustomError which lets us handle both JSON and regular pages depending on how it's being accessed // CustomErrorJSQ is a version of CustomError which lets us handle both JSON and regular pages depending on how it's being accessed
func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User, isJs bool) { func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User, isJs bool) RouteError {
if !isJs { if !isJs {
CustomError(errmsg, errcode, errtitle, w, r, user) return CustomError(errmsg, errcode, errtitle, w, r, user)
} else { } else {
CustomErrorJS(errmsg, errcode, errtitle, w, r, user) return CustomErrorJS(errmsg, errcode, errtitle, w, r, user)
} }
} }
// CustomErrorJS is the pure JSON version of CustomError // CustomErrorJS is the pure JSON version of CustomError
func CustomErrorJS(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) { func CustomErrorJS(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(errcode) w.WriteHeader(errcode)
_, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`)) _, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
return HandledRouteError()
} }

View File

@ -112,6 +112,7 @@ var setTempGroupStmt *sql.Stmt
var updateWordFilterStmt *sql.Stmt var updateWordFilterStmt *sql.Stmt
var bumpSyncStmt *sql.Stmt var bumpSyncStmt *sql.Stmt
var deleteUserStmt *sql.Stmt var deleteUserStmt *sql.Stmt
var deleteTopicStmt *sql.Stmt
var deleteReplyStmt *sql.Stmt var deleteReplyStmt *sql.Stmt
var deleteProfileReplyStmt *sql.Stmt var deleteProfileReplyStmt *sql.Stmt
var deleteActivityStreamMatchStmt *sql.Stmt var deleteActivityStreamMatchStmt *sql.Stmt
@ -862,6 +863,13 @@ func _gen_mssql() (err error) {
return err return err
} }
log.Print("Preparing deleteTopic statement.")
deleteTopicStmt, err = db.Prepare("DELETE FROM [topics] WHERE [tid] = ?")
if err != nil {
log.Print("Bad Query: ","DELETE FROM [topics] WHERE [tid] = ?")
return err
}
log.Print("Preparing deleteReply statement.") log.Print("Preparing deleteReply statement.")
deleteReplyStmt, err = db.Prepare("DELETE FROM [replies] WHERE [rid] = ?") deleteReplyStmt, err = db.Prepare("DELETE FROM [replies] WHERE [rid] = ?")
if err != nil { if err != nil {

View File

@ -114,6 +114,7 @@ var setTempGroupStmt *sql.Stmt
var updateWordFilterStmt *sql.Stmt var updateWordFilterStmt *sql.Stmt
var bumpSyncStmt *sql.Stmt var bumpSyncStmt *sql.Stmt
var deleteUserStmt *sql.Stmt var deleteUserStmt *sql.Stmt
var deleteTopicStmt *sql.Stmt
var deleteReplyStmt *sql.Stmt var deleteReplyStmt *sql.Stmt
var deleteProfileReplyStmt *sql.Stmt var deleteProfileReplyStmt *sql.Stmt
var deleteActivityStreamMatchStmt *sql.Stmt var deleteActivityStreamMatchStmt *sql.Stmt
@ -759,6 +760,12 @@ func _gen_mysql() (err error) {
return err return err
} }
log.Print("Preparing deleteTopic statement.")
deleteTopicStmt, err = db.Prepare("DELETE FROM `topics` WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing deleteReply statement.") log.Print("Preparing deleteReply statement.")
deleteReplyStmt, err = db.Prepare("DELETE FROM `replies` WHERE `rid` = ?") deleteReplyStmt, err = db.Prepare("DELETE FROM `replies` WHERE `rid` = ?")
if err != nil { if err != nil {

View File

@ -12,7 +12,7 @@ var ErrNoRoute = errors.New("That route doesn't exist.")
type GenRouter struct { type GenRouter struct {
UploadHandler func(http.ResponseWriter, *http.Request) UploadHandler func(http.ResponseWriter, *http.Request)
extra_routes map[string]func(http.ResponseWriter, *http.Request, User) extra_routes map[string]func(http.ResponseWriter, *http.Request, User) RouteError
sync.RWMutex sync.RWMutex
} }
@ -20,14 +20,26 @@ type GenRouter struct {
func NewGenRouter(uploads http.Handler) *GenRouter { func NewGenRouter(uploads http.Handler) *GenRouter {
return &GenRouter{ return &GenRouter{
UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP, UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP,
extra_routes: make(map[string]func(http.ResponseWriter, *http.Request, User)), extra_routes: make(map[string]func(http.ResponseWriter, *http.Request, User) RouteError),
} }
} }
func (router *GenRouter) handleError(err RouteError, w http.ResponseWriter, r *http.Request, user User) {
if err.Handled() {
return
}
if err.Type() == "system" {
InternalErrorJSQ(err,w,r,err.Json())
return
}
LocalErrorJSQ(err.Error(),w,r,user,err.Json())
}
func (router *GenRouter) Handle(_ string, _ http.Handler) { func (router *GenRouter) Handle(_ string, _ http.Handler) {
} }
func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, User)) { func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, User) RouteError) {
router.Lock() router.Lock()
router.extra_routes[pattern] = handle router.extra_routes[pattern] = handle
router.Unlock() router.Unlock()
@ -91,144 +103,135 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
log.Print("after PreRoute") log.Print("after PreRoute")
} }
var err RouteError
switch(prefix) { switch(prefix) {
case "/api": case "/api":
routeAPI(w,req,user) err = routeAPI(w,req,user)
return if err != nil {
router.handleError(err,w,req,user)
}
case "/overview": case "/overview":
routeOverview(w,req,user) err = routeOverview(w,req,user)
return if err != nil {
router.handleError(err,w,req,user)
}
case "/forums": case "/forums":
routeForums(w,req,user) err = routeForums(w,req,user)
return if err != nil {
router.handleError(err,w,req,user)
}
case "/forum": case "/forum":
routeForum(w,req,user,extra_data) err = routeForum(w,req,user,extra_data)
return if err != nil {
router.handleError(err,w,req,user)
}
case "/theme": case "/theme":
routeChangeTheme(w,req,user) err = routeChangeTheme(w,req,user)
return if err != nil {
router.handleError(err,w,req,user)
}
case "/attachs": case "/attachs":
routeShowAttachment(w,req,user,extra_data) err = routeShowAttachment(w,req,user,extra_data)
return if err != nil {
router.handleError(err,w,req,user)
}
case "/report": case "/report":
switch(req.URL.Path) { switch(req.URL.Path) {
case "/report/submit/": case "/report/submit/":
routeReportSubmit(w,req,user,extra_data) err = routeReportSubmit(w,req,user,extra_data)
return }
if err != nil {
router.handleError(err,w,req,user)
} }
case "/topics": case "/topics":
switch(req.URL.Path) { switch(req.URL.Path) {
case "/topics/create/": case "/topics/create/":
routeTopicCreate(w,req,user,extra_data) err = routeTopicCreate(w,req,user,extra_data)
return
default: default:
routeTopics(w,req,user) err = routeTopics(w,req,user)
return }
if err != nil {
router.handleError(err,w,req,user)
} }
case "/panel": case "/panel":
err = SuperModOnly(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
switch(req.URL.Path) { switch(req.URL.Path) {
case "/panel/forums/": case "/panel/forums/":
routePanelForums(w,req,user) err = routePanelForums(w,req,user)
return
case "/panel/forums/create/": case "/panel/forums/create/":
routePanelForumsCreateSubmit(w,req,user) err = routePanelForumsCreateSubmit(w,req,user)
return
case "/panel/forums/delete/": case "/panel/forums/delete/":
routePanelForumsDelete(w,req,user,extra_data) err = routePanelForumsDelete(w,req,user,extra_data)
return
case "/panel/forums/delete/submit/": case "/panel/forums/delete/submit/":
routePanelForumsDeleteSubmit(w,req,user,extra_data) err = routePanelForumsDeleteSubmit(w,req,user,extra_data)
return
case "/panel/forums/edit/": case "/panel/forums/edit/":
routePanelForumsEdit(w,req,user,extra_data) err = routePanelForumsEdit(w,req,user,extra_data)
return
case "/panel/forums/edit/submit/": case "/panel/forums/edit/submit/":
routePanelForumsEditSubmit(w,req,user,extra_data) err = routePanelForumsEditSubmit(w,req,user,extra_data)
return
case "/panel/forums/edit/perms/submit/": case "/panel/forums/edit/perms/submit/":
routePanelForumsEditPermsSubmit(w,req,user,extra_data) err = routePanelForumsEditPermsSubmit(w,req,user,extra_data)
return
case "/panel/settings/": case "/panel/settings/":
routePanelSettings(w,req,user) err = routePanelSettings(w,req,user)
return
case "/panel/settings/edit/": case "/panel/settings/edit/":
routePanelSetting(w,req,user,extra_data) err = routePanelSetting(w,req,user,extra_data)
return
case "/panel/settings/edit/submit/": case "/panel/settings/edit/submit/":
routePanelSettingEdit(w,req,user,extra_data) err = routePanelSettingEdit(w,req,user,extra_data)
return
case "/panel/settings/word-filters/": case "/panel/settings/word-filters/":
routePanelWordFilters(w,req,user) err = routePanelWordFilters(w,req,user)
return
case "/panel/settings/word-filters/create/": case "/panel/settings/word-filters/create/":
routePanelWordFiltersCreate(w,req,user) err = routePanelWordFiltersCreate(w,req,user)
return
case "/panel/settings/word-filters/edit/": case "/panel/settings/word-filters/edit/":
routePanelWordFiltersEdit(w,req,user,extra_data) err = routePanelWordFiltersEdit(w,req,user,extra_data)
return
case "/panel/settings/word-filters/edit/submit/": case "/panel/settings/word-filters/edit/submit/":
routePanelWordFiltersEditSubmit(w,req,user,extra_data) err = routePanelWordFiltersEditSubmit(w,req,user,extra_data)
return
case "/panel/settings/word-filters/delete/submit/": case "/panel/settings/word-filters/delete/submit/":
routePanelWordFiltersDeleteSubmit(w,req,user,extra_data) err = routePanelWordFiltersDeleteSubmit(w,req,user,extra_data)
return
case "/panel/themes/": case "/panel/themes/":
routePanelThemes(w,req,user) err = routePanelThemes(w,req,user)
return
case "/panel/themes/default/": case "/panel/themes/default/":
routePanelThemesSetDefault(w,req,user,extra_data) err = routePanelThemesSetDefault(w,req,user,extra_data)
return
case "/panel/plugins/": case "/panel/plugins/":
routePanelPlugins(w,req,user) err = routePanelPlugins(w,req,user)
return
case "/panel/plugins/activate/": case "/panel/plugins/activate/":
routePanelPluginsActivate(w,req,user,extra_data) err = routePanelPluginsActivate(w,req,user,extra_data)
return
case "/panel/plugins/deactivate/": case "/panel/plugins/deactivate/":
routePanelPluginsDeactivate(w,req,user,extra_data) err = routePanelPluginsDeactivate(w,req,user,extra_data)
return
case "/panel/plugins/install/": case "/panel/plugins/install/":
routePanelPluginsInstall(w,req,user,extra_data) err = routePanelPluginsInstall(w,req,user,extra_data)
return
case "/panel/users/": case "/panel/users/":
routePanelUsers(w,req,user) err = routePanelUsers(w,req,user)
return
case "/panel/users/edit/": case "/panel/users/edit/":
routePanelUsersEdit(w,req,user,extra_data) err = routePanelUsersEdit(w,req,user,extra_data)
return
case "/panel/users/edit/submit/": case "/panel/users/edit/submit/":
routePanelUsersEditSubmit(w,req,user,extra_data) err = routePanelUsersEditSubmit(w,req,user,extra_data)
return
case "/panel/groups/": case "/panel/groups/":
routePanelGroups(w,req,user) err = routePanelGroups(w,req,user)
return
case "/panel/groups/edit/": case "/panel/groups/edit/":
routePanelGroupsEdit(w,req,user,extra_data) err = routePanelGroupsEdit(w,req,user,extra_data)
return
case "/panel/groups/edit/perms/": case "/panel/groups/edit/perms/":
routePanelGroupsEditPerms(w,req,user,extra_data) err = routePanelGroupsEditPerms(w,req,user,extra_data)
return
case "/panel/groups/edit/submit/": case "/panel/groups/edit/submit/":
routePanelGroupsEditSubmit(w,req,user,extra_data) err = routePanelGroupsEditSubmit(w,req,user,extra_data)
return
case "/panel/groups/edit/perms/submit/": case "/panel/groups/edit/perms/submit/":
routePanelGroupsEditPermsSubmit(w,req,user,extra_data) err = routePanelGroupsEditPermsSubmit(w,req,user,extra_data)
return
case "/panel/groups/create/": case "/panel/groups/create/":
routePanelGroupsCreateSubmit(w,req,user) err = routePanelGroupsCreateSubmit(w,req,user)
return
case "/panel/backups/": case "/panel/backups/":
routePanelBackups(w,req,user,extra_data) err = routePanelBackups(w,req,user,extra_data)
return
case "/panel/logs/mod/": case "/panel/logs/mod/":
routePanelLogsMod(w,req,user) err = routePanelLogsMod(w,req,user)
return
case "/panel/debug/": case "/panel/debug/":
routePanelDebug(w,req,user) err = routePanelDebug(w,req,user)
return
default: default:
routePanel(w,req,user) err = routePanel(w,req,user)
return }
if err != nil {
router.handleError(err,w,req,user)
} }
case "/uploads": case "/uploads":
if extra_data == "" { if extra_data == "" {
@ -236,14 +239,17 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return return
} }
req.URL.Path += extra_data req.URL.Path += extra_data
// TODO: Find a way to propagate errors up from this?
router.UploadHandler(w,req) router.UploadHandler(w,req)
return
case "": case "":
// Stop the favicons, robots.txt file, etc. resolving to the topics list // Stop the favicons, robots.txt file, etc. resolving to the topics list
// TODO: Add support for favicons and robots.txt files // TODO: Add support for favicons and robots.txt files
switch(extra_data) { switch(extra_data) {
case "robots.txt": case "robots.txt":
routeRobotsTxt(w,req) err = routeRobotsTxt(w,req)
if err != nil {
router.handleError(err,w,req,user)
}
return return
} }
@ -252,10 +258,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return return
} }
config.DefaultRoute(w,req,user) config.DefaultRoute(w,req,user)
return default:
//default: NotFound(w,req)
}
// A fallback for the routes which haven't been converted to the new router yet or plugins // A fallback for the routes which haven't been converted to the new router yet or plugins
router.RLock() router.RLock()
handle, ok := router.extra_routes[req.URL.Path] handle, ok := router.extra_routes[req.URL.Path]
@ -263,8 +266,12 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if ok { if ok {
req.URL.Path += extra_data req.URL.Path += extra_data
handle(w,req,user) err = handle(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
}
return return
} }
NotFound(w,req) NotFound(w,req)
}
} }

View File

@ -2,14 +2,14 @@
package main package main
var dbTablePrimaryKeys = map[string]string{ var dbTablePrimaryKeys = map[string]string{
"users_groups":"gid", "replies":"rid",
"users_groups_scheduler":"uid", "attachments":"attachID",
"topics":"tid",
"users_replies":"rid", "users_replies":"rid",
"activity_stream":"asid", "activity_stream":"asid",
"word_filters":"wfid", "word_filters":"wfid",
"users":"uid",
"forums":"fid", "forums":"fid",
"replies":"rid", "users_groups":"gid",
"attachments":"attachID", "users_groups_scheduler":"uid",
"topics":"tid",
"users":"uid",
} }

View File

@ -550,6 +550,49 @@ func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
}) })
} }
func BenchmarkUserGet(b *testing.B) {
b.ReportAllocs()
if !gloinited {
err := gloinit()
if err != nil {
b.Fatal(err)
}
}
b.RunParallel(func(pb *testing.PB) {
var err error
for pb.Next() {
_, err = users.Get(1)
if err != nil {
b.Fatal(err)
return
}
}
})
}
func BenchmarkUserBypassGet(b *testing.B) {
b.ReportAllocs()
if !gloinited {
err := gloinit()
if err != nil {
b.Fatal(err)
}
}
// Bypass the cache and always hit the database
b.RunParallel(func(pb *testing.PB) {
var err error
for pb.Next() {
_, err = users.BypassGet(1)
if err != nil {
b.Fatal(err)
return
}
}
})
}
func BenchmarkQueriesSerial(b *testing.B) { func BenchmarkQueriesSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
var tu TopicUser var tu TopicUser

BIN
images/cosora-wip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -46,7 +46,7 @@ type StringList []string
var allowedFileExts = StringList{ var allowedFileExts = StringList{
"png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng", // images "png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng", // images
"txt", "xml", "json", "yaml", "toml", "ini", "md", "html", "rtf", "js", "py", "rb", "css", "scss", "less", "eqcss", "java", "ts", "cs", "c", "cc", "cpp", "cxx", "C", "c++", "h", "hh", "hpp", "hxx", "h++", "rs", "rlib", "htaccess", "gitignore", // text "txt", "xml", "json", "yaml", "toml", "ini", "md", "html", "rtf", "js", "py", "rb", "css", "scss", "less", "eqcss", "pcss", "java", "ts", "cs", "c", "cc", "cpp", "cxx", "C", "c++", "h", "hh", "hpp", "hxx", "h++", "rs", "rlib", "htaccess", "gitignore", // text
"mp3", "mp4", "avi", "wmv", "webm", // video "mp3", "mp4", "avi", "wmv", "webm", // video

File diff suppressed because it is too large Load Diff

View File

@ -279,11 +279,11 @@ func userStoreTest(t *testing.T, newUserID int) {
expect(t, user.IsMod, "Sam should be a mod") expect(t, user.IsMod, "Sam should be a mod")
expect(t, !user.IsBanned, "Sam should not be banned") expect(t, !user.IsBanned, "Sam should not be banned")
_, success := forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID) _, ferr := forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, user.Perms.ViewTopic, "Admins should be able to access the reports forum") expect(t, user.Perms.ViewTopic, "Admins should be able to access the reports forum")
_, success = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID) _, ferr = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum") expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum")
err = user.ChangeGroup(2) err = user.ChangeGroup(2)
@ -302,11 +302,11 @@ func userStoreTest(t *testing.T, newUserID int) {
expect(t, user.IsMod, "Sam should be a mod") expect(t, user.IsMod, "Sam should be a mod")
expect(t, !user.IsBanned, "Sam should not be banned") expect(t, !user.IsBanned, "Sam should not be banned")
_, success = forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID) _, ferr = forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, user.Perms.ViewTopic, "Mods should be able to access the reports forum") expect(t, user.Perms.ViewTopic, "Mods should be able to access the reports forum")
_, success = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID) _, ferr = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum") expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum")
err = user.ChangeGroup(3) err = user.ChangeGroup(3)
@ -325,11 +325,11 @@ func userStoreTest(t *testing.T, newUserID int) {
expect(t, !user.IsMod, "Sam should not be a mod") expect(t, !user.IsMod, "Sam should not be a mod")
expect(t, !user.IsBanned, "Sam should not be banned") expect(t, !user.IsBanned, "Sam should not be banned")
_, success = forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID) _, ferr = forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, !user.Perms.ViewTopic, "Members shouldn't be able to access the reports forum") expect(t, !user.Perms.ViewTopic, "Members shouldn't be able to access the reports forum")
_, success = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID) _, ferr = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum") expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum")
expect(t, user.Perms.ViewTopic != user2.Perms.ViewTopic, "user.Perms.ViewTopic and user2.Perms.ViewTopic should never match") expect(t, user.Perms.ViewTopic != user2.Perms.ViewTopic, "user.Perms.ViewTopic and user2.Perms.ViewTopic should never match")
@ -349,11 +349,11 @@ func userStoreTest(t *testing.T, newUserID int) {
expect(t, !user.IsMod, "Sam should not be a mod") expect(t, !user.IsMod, "Sam should not be a mod")
expect(t, user.IsBanned, "Sam should be banned") expect(t, user.IsBanned, "Sam should be banned")
_, success = forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID) _, ferr = forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, !user.Perms.ViewTopic, "Members shouldn't be able to access the reports forum") expect(t, !user.Perms.ViewTopic, "Members shouldn't be able to access the reports forum")
_, success = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID) _, ferr = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum") expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum")
err = user.ChangeGroup(5) err = user.ChangeGroup(5)
@ -372,11 +372,11 @@ func userStoreTest(t *testing.T, newUserID int) {
expect(t, !user.IsMod, "Sam should not be a mod") expect(t, !user.IsMod, "Sam should not be a mod")
expect(t, !user.IsBanned, "Sam should not be banned") expect(t, !user.IsBanned, "Sam should not be banned")
_, success = forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID) _, ferr = forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, !user.Perms.ViewTopic, "Members shouldn't be able to access the reports forum") expect(t, !user.Perms.ViewTopic, "Members shouldn't be able to access the reports forum")
_, success = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID) _, ferr = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum") expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum")
err = user.ChangeGroup(6) err = user.ChangeGroup(6)
@ -395,11 +395,11 @@ func userStoreTest(t *testing.T, newUserID int) {
expect(t, !user.IsMod, "Sam should not be a mod") expect(t, !user.IsMod, "Sam should not be a mod")
expect(t, !user.IsBanned, "Sam should not be banned") expect(t, !user.IsBanned, "Sam should not be banned")
_, success = forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID) _, ferr = forumUserCheck(dummyResponseRecorder, dummyRequest1, user, reportsForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, !user.Perms.ViewTopic, "Members shouldn't be able to access the reports forum") expect(t, !user.Perms.ViewTopic, "Members shouldn't be able to access the reports forum")
_, success = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID) _, ferr = forumUserCheck(dummyResponseRecorder, dummyRequest2, user2, generalForumID)
expect(t, success, "There shouldn't be any errors in forumUserCheck") expect(t, ferr == nil, "There shouldn't be any errors in forumUserCheck")
expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum") expect(t, user2.Perms.ViewTopic, "Sam should be able to access the general forum")
err = user.ChangeGroup(config.DefaultGroup) err = user.ChangeGroup(config.DefaultGroup)

File diff suppressed because it is too large Load Diff

View File

@ -234,7 +234,7 @@ type PanelEditGroupPermsPage struct {
type backupItem struct { type backupItem struct {
SQLURL string SQLURL string
// TODO: Add an easier to parse format here for Gosora to be able to more easily reimport portions of the dump and to strip unneccesary data (e.g. table defs and parsed post data) // TODO: Add an easier to parse format here for Gosora to be able to more easily reimport portions of the dump and to strip unneccessary data (e.g. table defs and parsed post data)
Timestamp time.Time Timestamp time.Time
} }

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ func init() {
The Deactivate field is for the handler which is called by the software when the admin hits the Deactivate button in the control panel. You should clean-up any resources you have allocated, remove any hooks, close any statements, etc. within this handler. The Deactivate field is for the handler which is called by the software when the admin hits the Deactivate button in the control panel. You should clean-up any resources you have allocated, remove any hooks, close any statements, etc. within this handler.
The Installation field is for one-off installation logic such as creating tables. You will need to run the seperate uninstallation function for that. The Installation field is for one-off installation logic such as creating tables. You will need to run the separate uninstallation function for that.
That Uninstallation field which is currently unused is for not only deactivating this plugin, but for purging any data associated with it such a new tables or data produced by the end-user. That Uninstallation field which is currently unused is for not only deactivating this plugin, but for purging any data associated with it such a new tables or data produced by the end-user.
*/ */

View File

@ -281,17 +281,16 @@ func socialgroupsGroupWidgets(headerVars *HeaderVars, sgItem *SocialGroup) (succ
Custom Pages Custom Pages
*/ */
func socialgroupsGroupList(w http.ResponseWriter, r *http.Request, user User) { func socialgroupsGroupList(w http.ResponseWriter, r *http.Request, user User) RouteError {
headerVars, ok := UserCheck(w, r, &user) headerVars, ferr := UserCheck(w, r, &user)
if !ok { if ferr != nil {
return return ferr
} }
socialgroupsCommonAreaWidgets(headerVars) socialgroupsCommonAreaWidgets(headerVars)
rows, err := socialgroupsListStmt.Query() rows, err := socialgroupsListStmt.Query()
if err != nil && err != ErrNoRows { if err != nil && err != ErrNoRows {
InternalError(err, w) return InternalError(err, w, r)
return
} }
var sgList []*SocialGroup var sgList []*SocialGroup
@ -299,24 +298,23 @@ func socialgroupsGroupList(w http.ResponseWriter, r *http.Request, user User) {
sgItem := &SocialGroup{ID: 0} sgItem := &SocialGroup{ID: 0}
err := rows.Scan(&sgItem.ID, &sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &sgItem.CreatedAt, &sgItem.LastUpdateTime) err := rows.Scan(&sgItem.ID, &sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
return
} }
sgItem.Link = socialgroupsBuildGroupURL(nameToSlug(sgItem.Name), sgItem.ID) sgItem.Link = socialgroupsBuildGroupURL(nameToSlug(sgItem.Name), sgItem.ID)
sgList = append(sgList, sgItem) sgList = append(sgList, sgItem)
} }
err = rows.Err() err = rows.Err()
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
return
} }
rows.Close() rows.Close()
pi := SocialGroupListPage{"Group List", user, headerVars, sgList} pi := SocialGroupListPage{"Group List", user, headerVars, sgList}
err = templates.ExecuteTemplate(w, "socialgroups_group_list.html", pi) err = templates.ExecuteTemplate(w, "socialgroups_group_list.html", pi)
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
} }
return nil
} }
func socialgroupsGetGroup(sgid int) (sgItem *SocialGroup, err error) { func socialgroupsGetGroup(sgid int) (sgItem *SocialGroup, err error) {
@ -325,7 +323,7 @@ func socialgroupsGetGroup(sgid int) (sgItem *SocialGroup, err error) {
return sgItem, err return sgItem, err
} }
func socialgroupsViewGroup(w http.ResponseWriter, r *http.Request, user User) { func socialgroupsViewGroup(w http.ResponseWriter, r *http.Request, user User) RouteError {
// SEO URLs... // SEO URLs...
halves := strings.Split(r.URL.Path[len("/group/"):], ".") halves := strings.Split(r.URL.Path[len("/group/"):], ".")
if len(halves) < 2 { if len(halves) < 2 {
@ -333,48 +331,45 @@ func socialgroupsViewGroup(w http.ResponseWriter, r *http.Request, user User) {
} }
sgid, err := strconv.Atoi(halves[1]) sgid, err := strconv.Atoi(halves[1])
if err != nil { if err != nil {
PreError("Not a valid group ID", w, r) return PreError("Not a valid group ID", w, r)
return
} }
sgItem, err := socialgroupsGetGroup(sgid) sgItem, err := socialgroupsGetGroup(sgid)
if err != nil { if err != nil {
LocalError("Bad group", w, r, user) return LocalError("Bad group", w, r, user)
return
} }
if !sgItem.Active { if !sgItem.Active {
NotFound(w, r) return NotFound(w, r)
} }
// Re-route the request to routeForums // Re-route the request to routeForums
var ctx = context.WithValue(r.Context(), "socialgroups_current_group", sgItem) var ctx = context.WithValue(r.Context(), "socialgroups_current_group", sgItem)
routeForum(w, r.WithContext(ctx), user, strconv.Itoa(sgItem.MainForumID)) return routeForum(w, r.WithContext(ctx), user, strconv.Itoa(sgItem.MainForumID))
} }
func socialgroupsCreateGroup(w http.ResponseWriter, r *http.Request, user User) { func socialgroupsCreateGroup(w http.ResponseWriter, r *http.Request, user User) RouteError {
headerVars, ok := UserCheck(w, r, &user) headerVars, ferr := UserCheck(w, r, &user)
if !ok { if ferr != nil {
return return ferr
} }
// TODO: Add an approval queue mode for group creation // TODO: Add an approval queue mode for group creation
if !user.Loggedin || !user.PluginPerms["CreateSocialGroup"] { if !user.Loggedin || !user.PluginPerms["CreateSocialGroup"] {
NoPermissions(w, r, user) return NoPermissions(w, r, user)
return
} }
socialgroupsCommonAreaWidgets(headerVars) socialgroupsCommonAreaWidgets(headerVars)
pi := Page{"Create Group", user, headerVars, tList, nil} pi := Page{"Create Group", user, headerVars, tList, nil}
err := templates.ExecuteTemplate(w, "socialgroups_create_group.html", pi) err := templates.ExecuteTemplate(w, "socialgroups_create_group.html", pi)
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
} }
return nil
} }
func socialgroupsCreateGroupSubmit(w http.ResponseWriter, r *http.Request, user User) { func socialgroupsCreateGroupSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError {
// TODO: Add an approval queue mode for group creation // TODO: Add an approval queue mode for group creation
if !user.Loggedin || !user.PluginPerms["CreateSocialGroup"] { if !user.Loggedin || !user.PluginPerms["CreateSocialGroup"] {
NoPermissions(w, r, user) return NoPermissions(w, r, user)
return
} }
var groupActive = true var groupActive = true
@ -397,41 +392,37 @@ func socialgroupsCreateGroupSubmit(w http.ResponseWriter, r *http.Request, user
// Create the backing forum // Create the backing forum
fid, err := fstore.Create(groupName, "", true, "") fid, err := fstore.Create(groupName, "", true, "")
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
return
} }
res, err := socialgroupsCreateGroupStmt.Exec(groupName, groupDesc, groupActive, groupPrivacy, user.ID, fid) res, err := socialgroupsCreateGroupStmt.Exec(groupName, groupDesc, groupActive, groupPrivacy, user.ID, fid)
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
return
} }
lastID, err := res.LastInsertId() lastID, err := res.LastInsertId()
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
return
} }
// Add the main backing forum to the forum list // Add the main backing forum to the forum list
err = socialgroupsAttachForum(int(lastID), fid) err = socialgroupsAttachForum(int(lastID), fid)
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
return
} }
_, err = socialgroupsAddMemberStmt.Exec(lastID, user.ID, 2) _, err = socialgroupsAddMemberStmt.Exec(lastID, user.ID, 2)
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
return
} }
http.Redirect(w, r, socialgroupsBuildGroupURL(nameToSlug(groupName), int(lastID)), http.StatusSeeOther) http.Redirect(w, r, socialgroupsBuildGroupURL(nameToSlug(groupName), int(lastID)), http.StatusSeeOther)
return nil
} }
func socialgroupsMemberList(w http.ResponseWriter, r *http.Request, user User) { func socialgroupsMemberList(w http.ResponseWriter, r *http.Request, user User) RouteError {
headerVars, ok := UserCheck(w, r, &user) headerVars, ferr := UserCheck(w, r, &user)
if !ok { if ferr != nil {
return return ferr
} }
// SEO URLs... // SEO URLs...
@ -441,16 +432,14 @@ func socialgroupsMemberList(w http.ResponseWriter, r *http.Request, user User) {
} }
sgid, err := strconv.Atoi(halves[1]) sgid, err := strconv.Atoi(halves[1])
if err != nil { if err != nil {
PreError("Not a valid group ID", w, r) return PreError("Not a valid group ID", w, r)
return
} }
var sgItem = &SocialGroup{ID: sgid} var sgItem = &SocialGroup{ID: sgid}
var mainForum int // Unused var mainForum int // Unused
err = socialgroupsGetGroupStmt.QueryRow(sgid).Scan(&sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &mainForum, &sgItem.Backdrop, &sgItem.CreatedAt, &sgItem.LastUpdateTime) err = socialgroupsGetGroupStmt.QueryRow(sgid).Scan(&sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &mainForum, &sgItem.Backdrop, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
if err != nil { if err != nil {
LocalError("Bad group", w, r, user) return LocalError("Bad group", w, r, user)
return
} }
sgItem.Link = socialgroupsBuildGroupURL(nameToSlug(sgItem.Name), sgItem.ID) sgItem.Link = socialgroupsBuildGroupURL(nameToSlug(sgItem.Name), sgItem.ID)
@ -458,8 +447,7 @@ func socialgroupsMemberList(w http.ResponseWriter, r *http.Request, user User) {
rows, err := socialgroupsMemberListJoinStmt.Query(sgid) rows, err := socialgroupsMemberListJoinStmt.Query(sgid)
if err != nil && err != ErrNoRows { if err != nil && err != ErrNoRows {
InternalError(err, w) return InternalError(err, w, r)
return
} }
var sgMembers []SocialGroupMember var sgMembers []SocialGroupMember
@ -467,8 +455,7 @@ func socialgroupsMemberList(w http.ResponseWriter, r *http.Request, user User) {
sgMember := SocialGroupMember{PostCount: 0} sgMember := SocialGroupMember{PostCount: 0}
err := rows.Scan(&sgMember.User.ID, &sgMember.Rank, &sgMember.PostCount, &sgMember.JoinedAt, &sgMember.User.Name, &sgMember.User.Avatar) err := rows.Scan(&sgMember.User.ID, &sgMember.Rank, &sgMember.PostCount, &sgMember.JoinedAt, &sgMember.User.Name, &sgMember.User.Avatar)
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
return
} }
sgMember.Link = buildProfileURL(nameToSlug(sgMember.User.Name), sgMember.User.ID) sgMember.Link = buildProfileURL(nameToSlug(sgMember.User.Name), sgMember.User.ID)
if sgMember.User.Avatar != "" { if sgMember.User.Avatar != "" {
@ -495,8 +482,7 @@ func socialgroupsMemberList(w http.ResponseWriter, r *http.Request, user User) {
} }
err = rows.Err() err = rows.Err()
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
return
} }
rows.Close() rows.Close()
@ -504,13 +490,14 @@ func socialgroupsMemberList(w http.ResponseWriter, r *http.Request, user User) {
// A plugin with plugins. Pluginception! // A plugin with plugins. Pluginception!
if preRenderHooks["pre_render_socialgroups_member_list"] != nil { if preRenderHooks["pre_render_socialgroups_member_list"] != nil {
if runPreRenderHook("pre_render_socialgroups_member_list", w, r, &user, &pi) { if runPreRenderHook("pre_render_socialgroups_member_list", w, r, &user, &pi) {
return return nil
} }
} }
err = templates.ExecuteTemplate(w, "socialgroups_member_list.html", pi) err = templates.ExecuteTemplate(w, "socialgroups_member_list.html", pi)
if err != nil { if err != nil {
InternalError(err, w) return InternalError(err, w, r)
} }
return nil
} }
func socialgroupsAttachForum(sgid int, fid int) error { func socialgroupsAttachForum(sgid int, fid int) error {
@ -587,7 +574,7 @@ func socialgroupsForumCheck(args ...interface{}) (skip interface{}) {
if !ok { if !ok {
sgItem, err = socialgroupsGetGroup(forum.ParentID) sgItem, err = socialgroupsGetGroup(forum.ParentID)
if err != nil { if err != nil {
InternalError(errors.New("Unable to find the parent group for a forum"), w) InternalError(errors.New("Unable to find the parent group for a forum"), w, r)
*success = false *success = false
return false return false
} }
@ -614,7 +601,7 @@ func socialgroupsForumCheck(args ...interface{}) (skip interface{}) {
err = socialgroupsGetMemberStmt.QueryRow(sgItem.ID, user.ID).Scan(&rank, &posts, &joinedAt) err = socialgroupsGetMemberStmt.QueryRow(sgItem.ID, user.ID).Scan(&rank, &posts, &joinedAt)
if err != nil && err != ErrNoRows { if err != nil && err != ErrNoRows {
*success = false *success = false
InternalError(err, w) InternalError(err, w, r)
return false return false
} else if err != nil { } else if err != nil {
return true return true

651
public/EQCSS.js Normal file
View File

@ -0,0 +1,651 @@
/*
# EQCSS
## version 1.7.0
A JavaScript plugin to read EQCSS syntax to provide:
scoped styles, element queries, container queries,
meta-selectors, eval(), and element-based units.
- github.com/eqcss/eqcss
- elementqueries.com
Authors: Tommy Hodgins, Maxime Euzière, Azareal
License: MIT
*/
// Uses Node, AMD or browser globals to create a module
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD: Register as an anonymous module
define([], factory);
} else if (typeof module === 'object' && module.exports) {
// Node: Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node
module.exports = factory();
} else {
// Browser globals (root is window)
root.EQCSS = factory();
}
}(this, function() {
var EQCSS = {
data: []
}
/*
* EQCSS.load()
* Called automatically on page load.
* Call it manually after adding EQCSS code in the page.
* Loads and parses all the EQCSS code.
*/
EQCSS.load = function() {
// Retrieve all style blocks
var styles = document.getElementsByTagName('style');
for (var i = 0; i < styles.length; i++) {
// Test if the style is not read yet
if (styles[i].getAttribute('data-eqcss-read') === null) {
// Mark the style block as read
styles[i].setAttribute('data-eqcss-read', 'true');
EQCSS.process(styles[i].innerHTML);
}
}
// Retrieve all link tags
var link = document.getElementsByTagName('link');
for (i = 0; i < link.length; i++) {
// Test if the link is not read yet, and has rel=stylesheet
if (link[i].getAttribute('data-eqcss-read') === null && link[i].rel === 'stylesheet') {
// retrieve the file content with AJAX and process it
if (link[i].href) {
(function() {
var xhr = new XMLHttpRequest;
xhr.open('GET', link[i].href, true);
xhr.send(null);
xhr.onreadystatechange = function() {
EQCSS.process(xhr.responseText);
}
})();
}
// Mark the link as read
link[i].setAttribute('data-eqcss-read', 'true');
}
}
}
/*
* EQCSS.parse()
* Called by load for each script / style / link resource.
* Generates data for each Element Query found
*/
EQCSS.parse = function(code) {
var parsed_queries = new Array();
// Cleanup
code = code.replace(/\s+/g, ' '); // reduce spaces and line breaks
code = code.replace(/\/\*[\w\W]*?\*\//g, ''); // remove comments
code = code.replace(/@element/g, '\n@element'); // one element query per line
code = code.replace(/(@element.*?\{([^}]*?\{[^}]*?\}[^}]*?)*\}).*/g, '$1'); // Keep the queries only (discard regular css written around them)
// Parse
// For each query
code.replace(/(@element.*(?!@element))/g, function(string, query) {
// Create a data entry
var dataEntry = {};
// Extract the selector
query.replace(/(@element)\s*(".*?"|'.*?'|.*?)\s*(and\s*\(|{)/g, function(string, atrule, selector, extra) {
// Strip outer quotes if present
selector = selector.replace(/^\s?['](.*)[']/, '$1');
selector = selector.replace(/^\s?["](.*)["]/, '$1');
dataEntry.selector = selector;
})
// Extract the conditions (measure, value, unit)
dataEntry.conditions = [];
query.replace(/and ?\( ?([^:]*) ?: ?([^)]*) ?\)/g, function(string, measure, value) {
// Separate value and unit if it's possible
var unit = null;
unit = value.replace(/^(\d*\.?\d+)(\D+)$/, '$2');
if (unit === value) {
unit = null;
}
value = value.replace(/^(\d*\.?\d+)\D+$/, '$1');
dataEntry.conditions.push({measure: measure, value: value, unit: unit});
});
// Extract the styles
query.replace(/{(.*)}/g, function(string, style) {
dataEntry.style = style;
});
parsed_queries.push(dataEntry);
});
return parsed_queries;
}
/*
* EQCSS.register()
* Add a single object, or an array of objects to EQCSS.data
*
*/
EQCSS.register = function(queries) {
if (Object.prototype.toString.call(queries) === '[object Object]') {
EQCSS.data.push(queries);
EQCSS.apply();
}
if (Object.prototype.toString.call(queries) === '[object Array]') {
for (var i=0; i<queries.length; i++) {
EQCSS.data.push(queries[i]);
}
EQCSS.apply();
}
}
/*
* EQCSS.process()
* Parse and Register queries with `EQCSS.data`
*/
EQCSS.process = function(code) {
var queries = EQCSS.parse(code)
return EQCSS.register(queries)
}
/*
* EQCSS.apply()
* Called on load, on resize and manually on DOM update
* Enable the Element Queries in which the conditions are true
*/
EQCSS.apply = function() {
var elements; // Elements targeted by each query
var element_guid; // GUID for current element
var css_block; // CSS block corresponding to each targeted element
var element_guid_parent; // GUID for current element's parent
var element_guid_prev; // GUID for current element's previous sibling element
var element_guid_next; // GUID for current element's next sibling element
var css_code; // CSS code to write in each CSS block (one per targeted element)
var element_width, parent_width; // Computed widths
var element_height, parent_height;// Computed heights
var element_line_height; // Computed line-height
var test; // Query's condition test result
var computed_style; // Each targeted element's computed style
var parent_computed_style; // Each targeted element parent's computed style
// Loop on all element queries
for (var i = 0; i < EQCSS.data.length; i++) {
// Find all the elements targeted by the query
elements = document.querySelectorAll(EQCSS.data[i].selector);
// Loop on all the elements
for (var j = 0; j < elements.length; j++) {
// Create a guid for this element
// Pattern: 'EQCSS_{element-query-index}_{matched-element-index}'
element_guid = 'data-eqcss-' + i + '-' + j;
// Add this guid as an attribute to the element
elements[j].setAttribute(element_guid, '');
// Create a guid for the parent of this element
// Pattern: 'EQCSS_{element-query-index}_{matched-element-index}_parent'
element_guid_parent = 'data-eqcss-' + i + '-' + j + '-parent';
// Add this guid as an attribute to the element's parent (except if element is the root element)
if (elements[j] != document.documentElement) {
elements[j].parentNode.setAttribute(element_guid_parent, '');
}
// Get the CSS block associated to this element (or create one in the <HEAD> if it doesn't exist)
css_block = document.querySelector('#' + element_guid);
if (!css_block) {
css_block = document.createElement('style');
css_block.id = element_guid;
css_block.setAttribute('data-eqcss-read', 'true');
document.querySelector('head').appendChild(css_block);
}
css_block = document.querySelector('#' + element_guid);
// Reset the query test's result (first, we assume that the selector is matched)
test = true;
// Loop on the conditions
test_conditions: for (var k = 0; k < EQCSS.data[i].conditions.length; k++) {
// Reuse element and parent's computed style instead of computing it everywhere
computed_style = window.getComputedStyle(elements[j], null);
parent_computed_style = null;
if (elements[j] != document.documentElement) {
parent_computed_style = window.getComputedStyle(elements[j].parentNode, null);
}
// Do we have to reconvert the size in px at each call?
// This is true only for vw/vh/vmin/vmax
var recomputed = false;
// If the condition's unit is vw, convert current value in vw, in px
if (EQCSS.data[i].conditions[k].unit === 'vw') {
recomputed = true;
var value = parseInt(EQCSS.data[i].conditions[k].value);
EQCSS.data[i].conditions[k].recomputed_value = value * window.innerWidth / 100;
}
// If the condition's unit is vh, convert current value in vh, in px
else if (EQCSS.data[i].conditions[k].unit === 'vh') {
recomputed = true;
var value = parseInt(EQCSS.data[i].conditions[k].value);
EQCSS.data[i].conditions[k].recomputed_value = value * window.innerHeight / 100;
}
// If the condition's unit is vmin, convert current value in vmin, in px
else if (EQCSS.data[i].conditions[k].unit === 'vmin') {
recomputed = true;
var value = parseInt(EQCSS.data[i].conditions[k].value);
EQCSS.data[i].conditions[k].recomputed_value = value * Math.min(window.innerWidth, window.innerHeight) / 100;
}
// If the condition's unit is vmax, convert current value in vmax, in px
else if (EQCSS.data[i].conditions[k].unit === 'vmax') {
recomputed = true;
var value = parseInt(EQCSS.data[i].conditions[k].value);
EQCSS.data[i].conditions[k].recomputed_value = value * Math.max(window.innerWidth, window.innerHeight) / 100;
}
// If the condition's unit is set and is not px or %, convert it into pixels
else if (EQCSS.data[i].conditions[k].unit != null && EQCSS.data[i].conditions[k].unit != 'px' && EQCSS.data[i].conditions[k].unit != '%') {
// Create a hidden DIV, sibling of the current element (or its child, if the element is <html>)
// Set the given measure and unit to the DIV's width
// Measure the DIV's width in px
// Remove the DIV
var div = document.createElement('div');
div.style.visibility = 'hidden';
div.style.border = '1px solid red';
div.style.width = EQCSS.data[i].conditions[k].value + EQCSS.data[i].conditions[k].unit;
var position = elements[j];
if (elements[j] != document.documentElement) {
position = elements[j].parentNode;
}
position.appendChild(div);
EQCSS.data[i].conditions[k].value = parseInt(window.getComputedStyle(div, null).getPropertyValue('width'));
EQCSS.data[i].conditions[k].unit = 'px';
position.removeChild(div);
}
// Store the good value in final_value depending if the size is recomputed or not
var final_value = recomputed ? EQCSS.data[i].conditions[k].recomputed_value : parseInt(EQCSS.data[i].conditions[k].value);
// Check each condition for this query and this element
// If at least one condition is false, the element selector is not matched
switch (EQCSS.data[i].conditions[k].measure) {
case 'min-width':
// Min-width in px
if (recomputed === true || EQCSS.data[i].conditions[k].unit === 'px') {
element_width = parseInt(computed_style.getPropertyValue('width'));
if (!(element_width >= final_value)) {
test = false;
break test_conditions;
}
}
// Min-width in %
if (EQCSS.data[i].conditions[k].unit === '%') {
element_width = parseInt(computed_style.getPropertyValue('width'));
parent_width = parseInt(parent_computed_style.getPropertyValue('width'));
if (!(parent_width / element_width <= 100 / final_value)) {
test = false;
break test_conditions;
}
}
break;
case 'max-width':
// Max-width in px
if (recomputed === true || EQCSS.data[i].conditions[k].unit === 'px') {
element_width = parseInt(computed_style.getPropertyValue('width'));
if (!(element_width <= final_value)) {
test = false;
break test_conditions;
}
}
// Max-width in %
if (EQCSS.data[i].conditions[k].unit === '%') {
element_width = parseInt(computed_style.getPropertyValue('width'));
parent_width = parseInt(parent_computed_style.getPropertyValue('width'));
if (!(parent_width / element_width >= 100 / final_value)) {
test = false;
break test_conditions;
}
}
break;
case 'min-height':
// Min-height in px
if (recomputed === true || EQCSS.data[i].conditions[k].unit === 'px') {
element_height = parseInt(computed_style.getPropertyValue('height'));
if (!(element_height >= final_value)) {
test = false;
break test_conditions;
}
}
// Min-height in %
if (EQCSS.data[i].conditions[k].unit === '%') {
element_height = parseInt(computed_style.getPropertyValue('height'));
parent_height = parseInt(parent_computed_style.getPropertyValue('height'));
if (!(parent_height / element_height <= 100 / final_value)) {
test = false;
break test_conditions;
}
}
break;
case 'max-height':
// Max-height in px
if (recomputed === true || EQCSS.data[i].conditions[k].unit === 'px') {
element_height = parseInt(computed_style.getPropertyValue('height'));
if (!(element_height <= final_value)) {
test = false;
break test_conditions;
}
}
// Max-height in %
if (EQCSS.data[i].conditions[k].unit === '%') {
element_height = parseInt(computed_style.getPropertyValue('height'));
parent_height = parseInt(parent_computed_style.getPropertyValue('height'));
if (!(parent_height / element_height >= 100 / final_value)) {
test = false;
break test_conditions;
}
}
break;
// Min-characters
case 'min-characters':
// form inputs
if (elements[j].value) {
if (!(elements[j].value.length >= final_value)) {
test = false;
break test_conditions;
}
}
// blocks
else {
if (!(elements[j].textContent.length >= final_value)) {
test = false;
break test_conditions;
}
}
break;
// Max-characters
case 'max-characters':
// form inputs
if (elements[j].value) {
if (!(elements[j].value.length <= final_value)) {
test = false;
break test_conditions;
}
}
// blocks
else {
if (!(elements[j].textContent.length <= final_value)) {
test = false;
break test_conditions;
}
}
break;
// Min-children
case 'min-children':
if (!(elements[j].children.length >= final_value)) {
test = false;
break test_conditions;
}
break;
// Max-children
case 'max-children':
if (!(elements[j].children.length <= final_value)) {
test = false;
break test_conditions;
}
break;
// Min-lines
case 'min-lines':
element_height =
parseInt(computed_style.getPropertyValue('height'))
- parseInt(computed_style.getPropertyValue('border-top-width'))
- parseInt(computed_style.getPropertyValue('border-bottom-width'))
- parseInt(computed_style.getPropertyValue('padding-top'))
- parseInt(computed_style.getPropertyValue('padding-bottom'));
element_line_height = computed_style.getPropertyValue('line-height');
if (element_line_height === 'normal') {
var element_font_size = parseInt(computed_style.getPropertyValue('font-size'));
element_line_height = element_font_size * 1.125;
} else {
element_line_height = parseInt(element_line_height);
}
if (!(element_height / element_line_height >= final_value)) {
test = false;
break test_conditions;
}
break;
// Max-lines
case 'max-lines':
element_height =
parseInt(computed_style.getPropertyValue('height'))
- parseInt(computed_style.getPropertyValue('border-top-width'))
- parseInt(computed_style.getPropertyValue('border-bottom-width'))
- parseInt(computed_style.getPropertyValue('padding-top'))
- parseInt(computed_style.getPropertyValue('padding-bottom'));
element_line_height = computed_style.getPropertyValue('line-height');
if (element_line_height === 'normal') {
var element_font_size = parseInt(computed_style.getPropertyValue('font-size'));
element_line_height = element_font_size * 1.125;
} else {
element_line_height = parseInt(element_line_height);
}
if (!(element_height / element_line_height + 1 <= final_value)) {
test = false;
break test_conditions;
}
break;
}
}
// Update CSS block:
// If all conditions are met: copy the CSS code from the query to the corresponding CSS block
if (test === true) {
// Get the CSS code to apply to the element
css_code = EQCSS.data[i].style;
// Replace eval('xyz') with the result of try{with(element){eval(xyz)}} in JS
css_code = css_code.replace(
/eval\( *((".*?")|('.*?')) *\)/g,
function(string, match) {
return EQCSS.tryWithEval(elements[j], match);
}
);
// Replace '$this' or 'eq_this' with '[element_guid]'
css_code = css_code.replace(/(\$|eq_)this/gi, '[' + element_guid + ']');
// Replace '$parent' or 'eq_parent' with '[element_guid_parent]'
css_code = css_code.replace(/(\$|eq_)parent/gi, '[' + element_guid_parent + ']');
if(css_block.innerHTML != css_code){
css_block.innerHTML = css_code;
}
}
// If condition is not met: empty the CSS block
else if(css_block.innerHTML != '') {
css_block.innerHTML = '';
}
}
}
}
/*
* Eval('') and $it
* (yes with() was necessary, and eval() too!)
*/
EQCSS.tryWithEval = function(element, string) {
var $it = element;
var ret = '';
try {
with ($it) { ret = eval(string.slice(1, -1)) }
}
catch(e) {
ret = '';
}
return ret;
}
/*
* EQCSS.reset
* Deletes parsed queries removes EQCSS-generated tags and attributes
* To reload EQCSS again after running EQCSS.reset() use EQCSS.load()
*/
EQCSS.reset = function() {
// Reset EQCSS.data, removing previously parsed queries
EQCSS.data = [];
// Remove EQCSS-generated style tags from head
var style_tag = document.querySelectorAll('head style[id^="data-eqcss-"]');
for (var i = 0; i < style_tag.length; i++) {
style_tag[i].parentNode.removeChild(style_tag[i]);
}
// Remove EQCSS-generated attributes from all tags
var tag = document.querySelectorAll('*');
// For each tag in the document
for (var j = 0; j < tag.length; j++) {
// Loop through all attributes
for (var k = 0; k < tag[j].attributes.length; k++) {
// If an attribute begins with 'data-eqcss-'
if (tag[j].attributes[k].name.indexOf('data-eqcss-') === 0) {
// Remove the attribute from the tag
tag[j].removeAttribute(tag[j].attributes[k].name)
}
}
}
}
/*
* 'DOM Ready' cross-browser polyfill / Diego Perini / MIT license
* Forked from: https://github.com/dperini/ContentLoaded/blob/master/src/contentloaded.js
*/
EQCSS.domReady = function(fn) {
var done = false;
var top = true;
var doc = window.document;
var root = doc.documentElement;
var modern = !~navigator.userAgent.indexOf('MSIE 8');
var add = modern ? 'addEventListener' : 'attachEvent';
var rem = modern ? 'removeEventListener' : 'detachEvent';
var pre = modern ? '' : 'on';
var init = function(e) {
if (e.type === 'readystatechange' && doc.readyState !== 'complete') return;
(e.type === 'load' ? window : doc)[rem](pre + e.type, init, false);
if (!done && (done = true)) fn.call(window, e.type || e);
},
poll = function() {
try {
root.doScroll('left');
}
catch(e) {
setTimeout(poll, 50);
return;
}
init('poll');
};
if (doc.readyState === 'complete') {
fn.call(window, 'lazy');
return;
}
if (!modern && root.doScroll) {
try {
top = !window.frameElement;
}
catch(e) {}
if (top) poll();
}
doc[add](pre + 'DOMContentLoaded', init, false);
doc[add](pre + 'readystatechange', init, false);
window[add](pre + 'load', init, false);
}
/*
* EQCSS.throttle
* Ensures EQCSS.apply() is not called more than once every (EQCSS_timeout)ms
*/
var EQCSS_throttle_available = true;
var EQCSS_throttle_queued = false;
var EQCSS_mouse_down = false;
var EQCSS_timeout = 200;
EQCSS.throttle = function() {
/* if (EQCSS_throttle_available) {*/
EQCSS.apply();
/*EQCSS_throttle_available = false;
setTimeout(function() {
EQCSS_throttle_available = true;
if (EQCSS_throttle_queued) {
EQCSS_throttle_queued = false;
EQCSS.apply();
}
}, EQCSS_timeout);
} else {
EQCSS_throttle_queued = true;
}*/
}
// Call load (and apply, indirectly) on page load
EQCSS.domReady(function() {
EQCSS.load();
EQCSS.throttle();
});
// On resize, click, call EQCSS.throttle.
window.addEventListener('resize', EQCSS.throttle);
window.addEventListener('click', EQCSS.throttle);
// Debug: here's a shortcut for console.log
function l(a) { console.log(a) }
return EQCSS;
}));

View File

@ -3,24 +3,38 @@ var form_vars = {};
var alertList = []; var alertList = [];
var alertCount = 0; var alertCount = 0;
var conn; var conn;
var selectedTopics = [];
var attachItemCallback = function(){}
function post_link(event) // TODO: Write a friendlier error handler which uses a .notice or something, we could have a specialised one for alerts
{ function ajaxError(xhr,status,errstr) {
event.preventDefault(); console.log("The AJAX request failed");
var form_action = $(event.target).closest('a').attr("href"); console.log("xhr", xhr);
//console.log("Form Action: " + form_action); console.log("status", status);
$.ajax({ url: form_action, type: "POST", dataType: "json", data: {js: "1"} }); console.log("errstr", errstr);
if(status=="parsererror") {
console.log("The server didn't respond with a valid JSON response");
}
console.trace();
} }
function bind_to_alerts() { function postLink(event)
{
event.preventDefault();
let formAction = $(event.target).closest('a').attr("href");
//console.log("Form Action: " + formAction);
$.ajax({ url: formAction, type: "POST", dataType: "json", error: ajaxError, data: {js: "1"} });
}
function bindToAlerts() {
$(".alertItem.withAvatar a").click(function(event) { $(".alertItem.withAvatar a").click(function(event) {
event.stopPropagation(); event.stopPropagation();
$.ajax({ url: "/api/?action=set&module=dismiss-alert", type: "POST", dataType: "json", data: { asid: $(this).attr("data-asid") } }); $.ajax({ url: "/api/?action=set&module=dismiss-alert", type: "POST", dataType: "json", error: ajaxError, data: { asid: $(this).attr("data-asid") } });
}); });
} }
// TODO: Add the ability for users to dismiss alerts // TODO: Add the ability for users to dismiss alerts
function load_alerts(menu_alerts) function loadAlerts(menu_alerts)
{ {
var alertListNode = menu_alerts.getElementsByClassName("alertList")[0]; var alertListNode = menu_alerts.getElementsByClassName("alertList")[0];
var alertCounterNode = menu_alerts.getElementsByClassName("alert_counter")[0]; var alertCounterNode = menu_alerts.getElementsByClassName("alert_counter")[0];
@ -69,7 +83,7 @@ function load_alerts(menu_alerts)
} }
alertCount = data.msgCount; alertCount = data.msgCount;
bind_to_alerts(); bindToAlerts();
}, },
error: function(magic,theStatus,error) { error: function(magic,theStatus,error) {
var errtxt var errtxt
@ -124,7 +138,7 @@ $(document).ready(function(){
console.log("The WebSockets connection was closed"); console.log("The WebSockets connection was closed");
} }
conn.onmessage = function(event) { conn.onmessage = function(event) {
//console.log("WS_Message: ",event.data); //console.log("WS_Message:", event.data);
if(event.data[0] == "{") { if(event.data[0] == "{") {
try { try {
var data = JSON.parse(event.data); var data = JSON.parse(event.data);
@ -165,7 +179,7 @@ $(document).ready(function(){
setTimeout(n.close.bind(n), 8000); setTimeout(n.close.bind(n), 8000);
} }
bind_to_alerts(); bindToAlerts();
} }
} }
@ -216,6 +230,7 @@ $(document).ready(function(){
url: formAction, url: formAction,
type: "POST", type: "POST",
dataType: "json", dataType: "json",
error: ajaxError,
data: { data: {
topic_name: topicNameInput, topic_name: topicNameInput,
topic_status: topicStatusInput, topic_status: topicStatusInput,
@ -227,7 +242,7 @@ $(document).ready(function(){
$(".delete_item").click(function(event) $(".delete_item").click(function(event)
{ {
post_link(event); postLink(event);
$(this).closest('.deletable_block').remove(); $(this).closest('.deletable_block').remove();
}); });
@ -248,7 +263,7 @@ $(document).ready(function(){
var formAction = $(this).closest('a').attr("href"); var formAction = $(this).closest('a').attr("href");
//console.log("Form Action:",formAction); //console.log("Form Action:",formAction);
$.ajax({ url: formAction, type: "POST", dataType: "json", data: { isJs: "1", edit_item: newContent } $.ajax({ url: formAction, type: "POST", error: ajaxError, dataType: "json", data: { isJs: "1", edit_item: newContent }
}); });
}); });
}); });
@ -273,6 +288,7 @@ $(document).ready(function(){
url: formAction + "?session=" + session, url: formAction + "?session=" + session,
type: "POST", type: "POST",
dataType: "json", dataType: "json",
error: ajaxError,
data: { isJs: "1", edit_item: newContent } data: { isJs: "1", edit_item: newContent }
}); });
}); });
@ -283,37 +299,37 @@ $(document).ready(function(){
event.preventDefault(); event.preventDefault();
if($(this).find("input").length !== 0) return; if($(this).find("input").length !== 0) return;
//console.log("clicked .edit_fields"); //console.log("clicked .edit_fields");
var block_parent = $(this).closest('.editable_parent'); var blockParent = $(this).closest('.editable_parent');
//console.log(block_parent); //console.log(blockParent);
block_parent.find('.hide_on_edit').hide(); blockParent.find('.hide_on_edit').hide();
block_parent.find('.show_on_edit').show(); blockParent.find('.show_on_edit').show();
block_parent.find('.editable_block').show(); blockParent.find('.editable_block').show();
block_parent.find('.editable_block').each(function(){ blockParent.find('.editable_block').each(function(){
var field_name = this.getAttribute("data-field"); var fieldName = this.getAttribute("data-field");
var field_type = this.getAttribute("data-type"); var fieldType = this.getAttribute("data-type");
if(field_type=="list") if(fieldType=="list")
{ {
var field_value = this.getAttribute("data-value"); var fieldValue = this.getAttribute("data-value");
if(field_name in form_vars) var it = form_vars[field_name]; if(fieldName in form_vars) var it = form_vars[fieldName];
else var it = ['No','Yes']; else var it = ['No','Yes'];
var itLen = it.length; var itLen = it.length;
var out = ""; var out = "";
//console.log("Field Name:",field_name); //console.log("Field Name:",fieldName);
//console.log("Field Type:",field_type); //console.log("Field Type:",fieldType);
//console.log("Field Value:",field_value); //console.log("Field Value:",fieldValue);
for (var i = 0; i < itLen; i++) { for (var i = 0; i < itLen; i++) {
var sel = ""; var sel = "";
if(field_value == i || field_value == it[i]) { if(fieldValue == i || fieldValue == it[i]) {
sel = "selected "; sel = "selected ";
this.classList.remove(field_name + '_' + it[i]); this.classList.remove(fieldName + '_' + it[i]);
this.innerHTML = ""; this.innerHTML = "";
} }
out += "<option "+sel+"value='"+i+"'>"+it[i]+"</option>"; out += "<option "+sel+"value='"+i+"'>"+it[i]+"</option>";
} }
this.innerHTML = "<select data-field='"+field_name+"' name='"+field_name+"'>"+out+"</select>"; this.innerHTML = "<select data-field='"+fieldName+"' name='"+fieldName+"'>"+out+"</select>";
} }
else if(field_type=="hidden") {} else if(fieldType=="hidden") {}
else this.innerHTML = "<input name='"+field_name+"' value='"+this.textContent+"' type='text'/>"; else this.innerHTML = "<input name='"+fieldName+"' value='"+this.textContent+"' type='text'/>";
}); });
// Remove any handlers already attached to the submitter // Remove any handlers already attached to the submitter
@ -323,31 +339,31 @@ $(document).ready(function(){
{ {
event.preventDefault(); event.preventDefault();
//console.log("running .submit_edit event"); //console.log("running .submit_edit event");
var out_data = {isJs: "1"} var outData = {isJs: "1"}
var block_parent = $(this).closest('.editable_parent'); var blockParent = $(this).closest('.editable_parent');
block_parent.find('.editable_block').each(function() { blockParent.find('.editable_block').each(function() {
var field_name = this.getAttribute("data-field"); var fieldName = this.getAttribute("data-field");
var field_type = this.getAttribute("data-type"); var fieldType = this.getAttribute("data-type");
if(field_type=="list") { if(fieldType=="list") {
var newContent = $(this).find('select :selected').text(); var newContent = $(this).find('select :selected').text();
this.classList.add(field_name + '_' + newContent); this.classList.add(fieldName + '_' + newContent);
this.innerHTML = ""; this.innerHTML = "";
} else if(field_type=="hidden") { } else if(fieldType=="hidden") {
var newContent = $(this).val(); var newContent = $(this).val();
} else { } else {
var newContent = $(this).find('input').eq(0).val(); var newContent = $(this).find('input').eq(0).val();
this.innerHTML = newContent; this.innerHTML = newContent;
} }
this.setAttribute("data-value",newContent); this.setAttribute("data-value",newContent);
out_data[field_name] = newContent; outData[fieldName] = newContent;
}); });
var form_action = $(this).closest('a').attr("href"); var formAction = $(this).closest('a').attr("href");
//console.log("Form Action:", form_action); //console.log("Form Action:", formAction);
//console.log(out_data); //console.log(outData);
$.ajax({ url: form_action + "?session=" + session, type:"POST", dataType:"json", data: out_data }); $.ajax({ url: formAction + "?session=" + session, type:"POST", dataType:"json", data: outData, error: ajaxError });
block_parent.find('.hide_on_edit').show(); blockParent.find('.hide_on_edit').show();
block_parent.find('.show_on_edit').hide(); blockParent.find('.show_on_edit').hide();
}); });
}); });
@ -357,7 +373,7 @@ $(document).ready(function(){
var ip = this.textContent; var ip = this.textContent;
if(ip.length > 10){ if(ip.length > 10){
this.innerHTML = "Show IP"; this.innerHTML = "Show IP";
this.onclick = function(event){ this.onclick = function(event) {
event.preventDefault(); event.preventDefault();
this.textContent = ip; this.textContent = ip;
}; };
@ -369,23 +385,23 @@ $(document).ready(function(){
$("#back").removeClass("alertActive"); $("#back").removeClass("alertActive");
}); });
$(".alert_bell").click(function(){ $(".alert_bell").click(function(){
var menu_alerts = $(this).parent(); var menuAlerts = $(this).parent();
if(menu_alerts.hasClass("selectedAlert")) { if(menuAlerts.hasClass("selectedAlert")) {
event.stopPropagation(); event.stopPropagation();
menu_alerts.removeClass("selectedAlert"); menuAlerts.removeClass("selectedAlert");
$("#back").removeClass("alertActive"); $("#back").removeClass("alertActive");
} }
}); });
var alert_menu_list = document.getElementsByClassName("menu_alerts"); var alertMenuList = document.getElementsByClassName("menu_alerts");
for(var i = 0; i < alert_menu_list.length; i++) { for(var i = 0; i < alertMenuList.length; i++) {
load_alerts(alert_menu_list[i]); loadAlerts(alertMenuList[i]);
} }
$(".menu_alerts").click(function(event) { $(".menu_alerts").click(function(event) {
event.stopPropagation(); event.stopPropagation();
if($(this).hasClass("selectedAlert")) return; if($(this).hasClass("selectedAlert")) return;
if(!conn) load_alerts(this); if(!conn) loadAlerts(this);
this.className += " selectedAlert"; this.className += " selectedAlert";
document.getElementById("back").className += " alertActive" document.getElementById("back").className += " alertActive"
}); });
@ -405,7 +421,6 @@ $(document).ready(function(){
function uploadFileHandler() { function uploadFileHandler() {
var fileList = this.files; var fileList = this.files;
// Truncate the number of files to 5 // Truncate the number of files to 5
let files = []; let files = [];
for(var i = 0; i < fileList.length && i < 5; i++) for(var i = 0; i < fileList.length && i < 5; i++)
@ -441,11 +456,16 @@ $(document).ready(function(){
}).then(function(hash) { }).then(function(hash) {
console.log("hash",hash); console.log("hash",hash);
let content = document.getElementById("input_content") let content = document.getElementById("input_content")
console.log("content.value",content.value); console.log("content.value", content.value);
if(content.value == "") content.value = content.value + "//" + siteURL + "/attachs/" + hash + "." + ext; let attachItem;
else content.value = content.value + "\r\n//" + siteURL + "/attachs/" + hash + "." + ext; if(content.value == "") attachItem = "//" + siteURL + "/attachs/" + hash + "." + ext;
console.log("content.value",content.value); else attachItem = "\r\n//" + siteURL + "/attachs/" + hash + "." + ext;
content.value = content.value + attachItem;
console.log("content.value", content.value);
// For custom / third party text editors
attachItemCallback(attachItem);
}); });
} }
reader.readAsArrayBuffer(files[i]); reader.readAsArrayBuffer(files[i]);
@ -459,6 +479,43 @@ $(document).ready(function(){
uploadFiles.addEventListener("change", uploadFileHandler, false); uploadFiles.addEventListener("change", uploadFileHandler, false);
} }
$(".moderate_link").click(function(event) {
event.preventDefault();
$(".pre_opt").removeClass("auto_hide");
$(".topic_row").each(function(){
$(this).click(function(){
selectedTopics.push(parseInt($(this).attr("data-tid"),10));
if(selectedTopics.length==1) {
$(".mod_floater_head span").html("What do you want to do with this topic?");
} else {
$(".mod_floater_head span").html("What do you want to do with these "+selectedTopics.length+" topics?");
}
$(this).addClass("topic_selected");
$(".mod_floater").removeClass("auto_hide");
});
});
$(".mod_floater_submit").click(function(event){
event.preventDefault();
let selectNode = this.form.querySelector(".mod_floater_options");
let optionNode = selectNode.options[selectNode.selectedIndex];
let action = optionNode.getAttribute("val");
//console.log("action",action);
let url = "/topic/"+action+"/submit/";
//console.log("JSON.stringify(selectedTopics) ", JSON.stringify(selectedTopics));
$.ajax({
url: url,
type: "POST",
data: JSON.stringify(selectedTopics),
contentType: "application/json",
error: ajaxError,
success: function() {
window.location.reload();
}
});
});
});
$("#themeSelectorSelect").change(function(){ $("#themeSelectorSelect").change(function(){
console.log("Changing the theme to " + this.options[this.selectedIndex].getAttribute("val")); console.log("Changing the theme to " + this.options[this.selectedIndex].getAttribute("val"));
$.ajax({ $.ajax({
@ -466,22 +523,13 @@ $(document).ready(function(){
type: "POST", type: "POST",
dataType: "json", dataType: "json",
data: { "newTheme": this.options[this.selectedIndex].getAttribute("val"), isJs: "1" }, data: { "newTheme": this.options[this.selectedIndex].getAttribute("val"), isJs: "1" },
error: ajaxError,
success: function (data, status, xhr) { success: function (data, status, xhr) {
console.log("Theme successfully switched"); console.log("Theme successfully switched");
console.log("data",data); console.log("data", data);
console.log("status",status); console.log("status", status);
console.log("xhr",xhr); console.log("xhr", xhr);
window.location.reload(); window.location.reload();
},
// TODO: Use a standard error handler for the AJAX calls in here which throws up the response (if JSON) in a .notice? Might be difficult to trace errors in the console, if we reuse the same function every-time
error: function(xhr,status,errstr) {
console.log("The AJAX request failed");
console.log("xhr",xhr);
console.log("status",status);
console.log("errstr",errstr);
if(status=="parsererror") {
console.log("The server didn't respond with a valid JSON response");
}
} }
}); });
}); });

File diff suppressed because one or more lines are too long

11
public/trumbowyg/langs/ar.min.js vendored Normal file
View File

@ -0,0 +1,11 @@
/* ===========================================================
* ar.js
* Arabic translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Abo Mokh ahmed (abomokhahmed)
* Github : https://github.com/abomokhahmed
* Reviewed by : Abdellah Chadidi (chadidi)
* Github : https://github.com/chadidi
*/
jQuery.trumbowyg.langs.ar={_dir:"rtl",viewHTML:"إعرض-HTML",undo:"تراجع",redo:"إعادة",formatting:"تنسيق",p:"فقرة",blockquote:"اقتباس",code:"كود",header:"رأس",bold:"عريض",italic:"مائل",strikethrough:"مشطوب",underline:"خطّ سفلي",strong:"بارز",em:"تغميق",del:"حذف",superscript:"الأس",subscript:"أس سفلي",unorderedList:"قائمة غير مرتّبة",orderedList:"قائمة مرتّبة",insertImage:"إدراج صورة",insertVideo:"إدراج فيديو",link:"رابط",createLink:"انشاء رابط",unlink:"حذف رابط",justifyLeft:"تصحيح للشمال",justifyCenter:"توسيط",justifyRight:"تصحيح لليمين",justifyFull:"تصحيح لكلا الإتّجاهين",horizontalRule:"إدراج خطّ أفقي",fullscreen:"ملء الشاشة",close:"إغلاق",submit:"إرسال",reset:"إعادة تعيين",required:"إلزامي",description:"وصف",title:"عنوان",text:"نصّ",target:"الهدف"};

8
public/trumbowyg/langs/bg.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* ===========================================================
* bg.js
* Bulgarian translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Aleksandar Dimitrov
*/
jQuery.trumbowyg.langs.bg={viewHTML:"Прегледай HTML",formatting:"Форматиране",p:"Параграф",blockquote:"Цитат",code:"Код",header:"Заглавие",bold:"Удебелен",italic:"Наклонен",strikethrough:"Зачеркнат",underline:"Подчертан",strong:"Удебелен",em:"Наклонен",del:"Зачеркнат",unorderedList:"Обикновен списък",orderedList:"Номериран списък",insertImage:"Добави изображение",insertVideo:"Добави видео",link:"Връзка",createLink:"Създай връзка",unlink:"Премахни връзката",justifyLeft:"Подравни от ляво",justifyCenter:"Центрирай",justifyRight:"Подравни от дясно",justifyFull:"Подравни по ширина",horizontalRule:"Хоризонтална линия",fullscreen:"На цял екран",close:"Затвори",submit:"Впиши",reset:"Отмени",required:"Задължително",description:"Описание",title:"Заглавие",text:"Текст"};

8
public/trumbowyg/langs/by.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* ===========================================================
* by.js
* Belarusian translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Yury Karalkou
*/
jQuery.trumbowyg.langs.by={viewHTML:"Паглядзець HTML",undo:"Скасаваць",redo:"Паўтарыць",formatting:"Фарматаванне",p:"Звычайны",blockquote:"Цытата",code:"Код",header:"Загаловак",bold:"Паўтлусты",italic:"Курсіў",strikethrough:"Закрэслены",underline:"Падкрэслены",strong:"Паўтлусты",em:"Курсіў",del:"Закрэслены",superscript:"Верхні індэкс",subscript:"Індэкс",unorderedList:"Звычайны спіс",orderedList:"Нумараваны спіс",insertImage:"Уставіць выяву",insertVideo:"Уставіць відэа",link:"Спасылка",createLink:"Уставіць спасылку",unlink:"Выдаліць спасылку",justifyLeft:"Па леваму боку",justifyCenter:"У цэнтры",justifyRight:"Па праваму боку",justifyFull:"Па шырыні",horizontalRule:"Гарызантальная лінія",removeformat:"Ачысціць фарматаванне",fullscreen:"На ўвесь экран",close:"Зачыніць",submit:"Уставіць",reset:"Скасаваць",required:"Абавязкова",description:"Апісанне",title:"Падказка",text:"Тэкст"};

11
public/trumbowyg/langs/ca.min.js vendored Normal file
View File

@ -0,0 +1,11 @@
/* ===========================================================
* ca.js
* Catalan translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Àlfons Sánchez (alsanan)
* Twitter : @alsanan
* Website : about.me/alsanan
* Github : https://github.com/alsanan
*/
jQuery.trumbowyg.langs.ca={viewHTML:"Veure HTML",formatting:"Formatar",p:"Paragraf",blockquote:"Citació",code:"Codi",header:"Títol",bold:"Negreta",italic:"Itàlica",strikethrough:"Suprimir",underline:"Subratllat",strong:"Forta",em:"Èmfasi",del:"Apagar",unorderedList:"Lista desordenada",orderedList:"Lista ordenada",insertImage:"Inserir imatge",insertVideo:"Inserir vídeo",link:"Enllaç",createLink:"Crear un enllaç",unlink:"Eliminar enllaç",justifyLeft:"Alinear a esquerra",justifyCenter:"Centrar",justifyRight:"Alinear a dreta",justifyFull:"Justificar",horizontalRule:"Inserir separador horitzontal",fullscreen:"Pantalla completa",close:"Tancar",submit:"Enviar",reset:"Reiniciar",required:"Obligatori",description:"Descripció",title:"Títol",text:"Text"};

8
public/trumbowyg/langs/cs.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* ===========================================================
* cs.js
* Czech translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Jan Svoboda (https://github.com/svoboda-jan)
*/
jQuery.trumbowyg.langs.cs={viewHTML:"Zobrazit HTML",formatting:"Formátování",p:"Odstavec",blockquote:"Citace",code:"Kód",header:"Nadpis",bold:"Tučné",italic:"Kurzíva",strikethrough:"Přeškrtnuté",underline:"Podtržené",strong:"Tučné",em:"Zvýraznit",del:"Smazat",unorderedList:"Netříděný seznam",orderedList:"Tříděný seznam",insertImage:"Vložit obrázek",insertVideo:"Vložit video",link:"Odkaz",createLink:"Vložit odkaz",unlink:"Smazat odkaz",justifyLeft:"Zarovnat doleva",justifyCenter:"Zarovnat na střed",justifyRight:"Zarovnat doprava",justifyFull:"Zarovnat do bloku",horizontalRule:"Vložit vodorovnou čáru",fullscreen:"Režim celé obrazovky",close:"Zavřít",submit:"Potvrdit",reset:"Zrušit",required:"Povinné",description:"Popis",title:"Nadpis",text:"Text"};

9
public/trumbowyg/langs/da.min.js vendored Normal file
View File

@ -0,0 +1,9 @@
/* ===========================================================
* da.js
* Danish translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Christian Pedersen
* Github : https://github.com/chripede
*/
jQuery.trumbowyg.langs.da={viewHTML:"Vis HTML",formatting:"Formatter",p:"Afsnit",blockquote:"Citat",code:"Kode",header:"Overskrift",bold:"Fed",italic:"Kursiv",strikethrough:"Gennemstreg",underline:"Understreg",strong:"Vigtig",em:"Fremhæv",del:"Slettet",unorderedList:"Uordnet liste",orderedList:"Ordnet liste",insertImage:"Indsæt billede",insertVideo:"Indsæt video",link:"Link",createLink:"Indsæt link",unlink:"Fjern link",justifyLeft:"Venstrestil",justifyCenter:"Centrer",justifyRight:"Højrestil",justifyFull:"Lige margener",horizontalRule:"Horisontal linie",fullscreen:"Fuld skærm",close:"Luk",submit:"Bekræft",reset:"Annuller",required:"Påkrævet",description:"Beskrivelse",title:"Titel",text:"Tekst"};

9
public/trumbowyg/langs/de.min.js vendored Normal file
View File

@ -0,0 +1,9 @@
/* ===========================================================
* de.js
* German translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Manfred Timm
* Github : https://github.com/Manfred62
*/
jQuery.trumbowyg.langs.de={viewHTML:"HTML anzeigen",formatting:"Formatieren",p:"Absatz",blockquote:"Zitat",code:"Code",header:"Überschrift",bold:"Fett",italic:"Kursiv",strikethrough:"Durchgestrichen",underline:"Unterstrichen",strong:"Wichtig",em:"Betont",del:"Gelöscht",unorderedList:"Ungeordnete Liste",orderedList:"Geordnete Liste",insertImage:"Bild einfügen",insertVideo:"Video einfügen",link:"Link",createLink:"Link einfügen",unlink:"Link entfernen",justifyLeft:"Links ausrichten",justifyCenter:"Zentrieren",justifyRight:"Rechts ausrichten",justifyFull:"Blocksatz",horizontalRule:"Horizontale Linie einfügen",fullscreen:"Vollbild",close:"Schliessen",submit:"Bestätigen",reset:"Rücksetzen",required:"Erforderlich",description:"Beschreibung",title:"Titel",text:"Text"};

12
public/trumbowyg/langs/el.min.js vendored Normal file
View File

@ -0,0 +1,12 @@
/* ===========================================================
* el.js
* Greek translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Merianos Nikos
* Twitter : @_webresources
* Website : http://www.wp-lion.com
* LinkedIn: https://gr.linkedin.com/in/merianosnikos
* Behance: https://www.behance.net/web_design_blog
*/
jQuery.trumbowyg.langs.el={viewHTML:"Προβολή κώδικα HTML",formatting:"Μορφοποίηση",p:"Παράγραφος",blockquote:"Παράθεση",code:"Κώδικας",header:"Επικεφαλίδα",bold:"Έντονα",italic:"Πλάγια",strikethrough:"Διαγραφή",underline:"Υπογράμμιση",strong:"Έντονα",em:"Πλάγια",del:"Διαγραφή",unorderedList:"Αταξινόμητη λίστα",orderedList:"Ταξινομημένη λίστα",insertImage:"Εισαγωγή εικόνας",insertVideo:"Εισαγωγή βίντεο",link:"Σύνδεσμος",createLink:"Δημιουργία συνδέσμου",unlink:"Διαγραφή συνδέσμου",justifyLeft:"Στοίχιση αριστερά",justifyCenter:"Στοίχιση στο κέντρο",justifyRight:"Στοίχιση δεξιά",justifyFull:"Πλήρης στοίχιση",horizontalRule:"Οριζόντια γραμμή",removeformat:"Καθαρισμός μορφοποίησης",fullscreen:"Πλήρης οθόνη",close:"Κλείσιμο",submit:"Υποβολή",reset:"Επαναφορά",required:"Απαραίτητο",description:"Περιγραφή",title:"Τίτλος",text:"Κείμενο"};

9
public/trumbowyg/langs/es.min.js vendored Normal file
View File

@ -0,0 +1,9 @@
/* ===========================================================
* es.js
* Spanish translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Moisés Márquez
* Email : moises.marquez.g@gmail.com
*/
jQuery.trumbowyg.langs.es={viewHTML:"Ver HTML",undo:"Deshacer",redo:"Rehacer",formatting:"Formato",p:"Párrafo",blockquote:"Cita",code:"Código",header:"Título",bold:"Negrita",italic:"Cursiva",strikethrough:"Tachado",underline:"Subrayado",strong:"Negrita",em:"Énfasis",del:"Borrar",superscript:"Sobrescrito",subscript:"Subíndice",unorderedList:"Lista Desordenada",orderedList:"Lista Ordenada",insertImage:"Insertar una imagen",insertVideo:"Insertar un vídeo",link:"Enlace",createLink:"Insertar un enlace",unlink:"Suprimir un enlace",justifyLeft:"Izquierda",justifyCenter:"Centrar",justifyRight:"Derecha",justifyFull:"Justificado",horizontalRule:"Insertar separador horizontal",removeformat:"Eliminar formato",fullscreen:"Pantalla completa",close:"Cerrar",submit:"Enviar",reset:"Cancelar",required:"Obligatorio",description:"Descripción",title:"Título",text:"Texto",target:"Target"};

10
public/trumbowyg/langs/es_ar.min.js vendored Normal file
View File

@ -0,0 +1,10 @@
/* ===========================================================
* es_ar.js
* Spanish (Argentina) translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Félix Vera
* Email : felix.vera@gmail.com
*/
// jshint camelcase:false
jQuery.trumbowyg.langs.es_ar={viewHTML:"Ver HTML",formatting:"Formato",p:"Párrafo",blockquote:"Cita",code:"Código",header:"Título",bold:"Negrita",italic:"Itálica",strikethrough:"Tachado",underline:"Subrayado",strong:"Fuere",em:"Énfasis",del:"Borrar",unorderedList:"Lista Desordenada",orderedList:"Lista Ordenada",insertImage:"Insertar una imagen",insertVideo:"Insertar un video",link:"Vínculo",createLink:"Insertar un vínculo",unlink:"Suprimir un vínculo",justifyLeft:"Alinear a la Izquierda",justifyCenter:"Centrar",justifyRight:"Alinear a la Derecha",justifyFull:"Justificado",horizontalRule:"Insertar separado Horizontal",fullscreen:"Pantalla Completa",close:"Cerrar",submit:"Enviar",reset:"Cancelar",required:"Obligatorio",description:"Descripción",title:"Título",text:"Texto"};

10
public/trumbowyg/langs/fa.min.js vendored Normal file
View File

@ -0,0 +1,10 @@
/* ===========================================================
* fa.js
* Persian translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Kiarash Soleimanzadeh
* Github : https://github.com/kiyarash
* Email : kiarash.s@hotmail.com
*/
jQuery.trumbowyg.langs.fa={viewHTML:"نمایش کد اچ تی ام ال",formatting:"قالب بندی",p:"پاراگراف",blockquote:"نقل قول",code:"کد",header:"سر تیتر",bold:"ضخیم",italic:"مورب",strikethrough:"میان خط دار",underline:"زیر خط دار",strong:"برجسته",em:"مورب",del:"حذف شده",unorderedList:"لیست نامرتب",orderedList:"لیست مرتب",insertImage:"درج تصویر",insertVideo:"درج ویدئو",link:"لینک",createLink:"درج لینک",unlink:"حذف لینک",justifyLeft:"تراز به چپ",justifyCenter:"تراز به وسط",justifyRight:"تراز به راست",justifyFull:"تراز به چپ و راست",horizontalRule:"درج خط افقی",fullscreen:"تمام صفحه",close:"بستن",submit:"تائید",reset:"انصراف",required:"اجباری",description:"توضیحات",title:"عنوان",text:"متن"};

9
public/trumbowyg/langs/fi.min.js vendored Normal file
View File

@ -0,0 +1,9 @@
/* ===========================================================
* fi.js
* Finnish translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Teppo Koivula (teppokoivula)
* Github : https://github.com/teppokoivula
*/
jQuery.trumbowyg.langs.fi={viewHTML:"Näytä HTML",undo:"Kumoa",redo:"Tee uudelleen",formatting:"Muotoilu",p:"Kappale",blockquote:"Lainaus",code:"Koodi",header:"Otsikko",bold:"Lihavointi",italic:"Kursivointi",strikethrough:"Yliviivaus",underline:"Allevivaus",strong:"Vahvennus",em:"Painotus",del:"Poistettu",unorderedList:"Luettelo",orderedList:"Numeroitu luettelo",insertImage:"Lisää kuva",insertVideo:"Lisää video",link:"Linkki",createLink:"Luo linkki",unlink:"Poista linkki",justifyLeft:"Tasaa vasemmalle",justifyCenter:"Keskitä",justifyRight:"Tasaa oikealle",justifyFull:"Tasaa",horizontalRule:"Vaakaviiva",fullscreen:"Kokoruutu",close:"Sulje",submit:"Lisää",reset:"Palauta",required:"Pakollinen",description:"Kuvaus",title:"Otsikko",text:"Teksti"};

10
public/trumbowyg/langs/fr.min.js vendored Normal file
View File

@ -0,0 +1,10 @@
/* ===========================================================
* fr.js
* French translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Alexandre Demode (Alex-D)
* Twitter : @AlexandreDemode
* Website : alex-d.fr
*/
jQuery.trumbowyg.langs.fr={viewHTML:"Voir le HTML",undo:"Annuler",redo:"Refaire",formatting:"Format",p:"Paragraphe",blockquote:"Citation",code:"Code",header:"Titre",bold:"Gras",italic:"Italique",strikethrough:"Rayé",underline:"Souligné",strong:"Fort",em:"Emphase",del:"Supprimé",superscript:"Exposant",subscript:"Indice",unorderedList:"Liste à puces",orderedList:"Liste ordonnée",insertImage:"Insérer une image",insertVideo:"Insérer une video",link:"Lien",createLink:"Insérer un lien",unlink:"Supprimer le lien",justifyLeft:"Aligner à gauche",justifyCenter:"Centrer",justifyRight:"Aligner à droite",justifyFull:"Justifier",horizontalRule:"Insérer un séparateur horizontal",removeformat:"Supprimer formatage",fullscreen:"Plein écran",close:"Fermer",submit:"Valider",reset:"Annuler",required:"Obligatoire",description:"Description",title:"Titre",text:"Texte",target:"Cible"};

9
public/trumbowyg/langs/he.min.js vendored Normal file
View File

@ -0,0 +1,9 @@
/* ===========================================================
* he.js
* Hebrew translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Udi Doron (udidoron)
* Github : https://github.com/udidoron
*/
jQuery.trumbowyg.langs.he={_dir:"rtl",viewHTML:"צפה ב-HTML",formatting:"פורמט",p:"פסקה",blockquote:"ציטוט",code:"קוד",header:"ראשית",bold:"מודגש",italic:"נטוי",strikethrough:"קו חוצה",underline:"קו תחתון",strong:"בולט",em:"הדגשה",del:"נמחק",unorderedList:"רשימה ללא סדר",orderedList:"רשימה מסודרת",insertImage:"הכנס תמונה",insertVideo:"הכנס סרטון",link:"קישור",createLink:"צור קישור",unlink:"הסר קישור",justifyLeft:"ישר לשמאל",justifyCenter:"מרכז",justifyRight:"ישר לימין",justifyFull:"ישר לשני הצדדים",horizontalRule:"הכנס קו אופקי",fullscreen:"מסך מלא",close:"סגור",submit:"שלח",reset:"אתחל מחדש",required:"נחוץ",description:"תיאור",title:"כותרת",text:"טקסט"};

9
public/trumbowyg/langs/hr.min.js vendored Normal file
View File

@ -0,0 +1,9 @@
/* ===========================================================
* hr.js
* Croatian translation for Trumbowyg
* https://www.github.com/Buda9
* ===========================================================
* Author : Davor Budimir (https://www.github.com/Buda9)
*/
// jshint camelcase:false
jQuery.trumbowyg.langs.hr={viewHTML:"Poglеdaj HTML kód",formatting:"Formatiranjе",p:"Odlomak",blockquote:"Citat",code:"Kód",header:"Zaglavlje",bold:"Podеbljano",italic:"Nakošeno",strikethrough:"Prеcrtano",underline:"Podvučеno",strong:"Podеbljano",em:"Istaknuto",del:"Obrisano",unorderedList:"Neuređen popis",orderedList:"Uređen popis",insertImage:"Dodaj sliku",insertVideo:"Dodaj vidеo",link:"Povezica",createLink:"Dodaj povezicu",unlink:"Ukloni povezicu",justifyLeft:"Lijеvo poravnanjе",justifyCenter:"Središnje poravnanjе",justifyRight:"Dеsno poravnanjе",justifyFull:"Obostrano poravnanjе",horizontalRule:"Horizontalna crta",fullscreen:"Puni zaslon",close:"Zatvori",submit:"Unеsi",reset:"Otkaži",required:"Obavеzno poljе",description:"Opis",title:"Naslov",text:"Tеkst"};

10
public/trumbowyg/langs/hu.min.js vendored Normal file
View File

@ -0,0 +1,10 @@
/* ===========================================================
* hu.js
* Hungarian translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Peter MATO
* Web: http://fixme.hu
* GitHub: https://github.com/matopeter
*/
jQuery.trumbowyg.langs.hu={viewHTML:"HTML nézet",formatting:"Stílusok",p:"Bekezdés",blockquote:"Idézet",code:"Kód",header:"Címsor",bold:"Félkövér",italic:"Dőlt",strikethrough:"Áthúzott",underline:"Aláhúzott",strong:"Vastag",em:"Kiemelt",del:"Törölt",unorderedList:"Felsorolás",orderedList:"Számozás",insertImage:"Kép beszúrása",insertVideo:"Video beszúrása",link:"Link",createLink:"Link létrehozása",unlink:"Link eltávolítása",justifyLeft:"Balra igazítás",justifyCenter:"Középre igazítás",justifyRight:"Jobbra igazítás",justifyFull:"Sorkizárt",horizontalRule:"Vízszintes vonal",fullscreen:"Teljes képernyő",close:"Bezár",submit:"Beküldés",reset:"Alaphelyzet",required:"Kötelező",description:"Leírás",title:"Cím",text:"Szöveg",removeformat:"Formázás eltávolítása"};

11
public/trumbowyg/langs/id.min.js vendored Normal file
View File

@ -0,0 +1,11 @@
/* ===========================================================
* id.js
* Indonesian translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Rezha Julio (kimiamania)
* Twitter : @kimiamania
* Website : http://rezhajulio.web.id
* Github : https://github.com/kimiamania
*/
jQuery.trumbowyg.langs.id={viewHTML:"Lihat HTML",formatting:"Penyusunan",p:"Paragraf",blockquote:"Kutipan",code:"Kode",header:"Kepala",bold:"Tebal",italic:"Miring",strikethrough:"Coret",underline:"Garis bawah",strong:"Tebal",em:"Miring",del:"Dicoret",unorderedList:"Daftar tak teratur",orderedList:"Daftar teratur",insertImage:"Sisipkan gambar",insertVideo:"Sisipkan video",link:"Tautan",createLink:"Sisipkan Tautan",unlink:"Singkirkan tautan",justifyLeft:"Rata kiri",justifyCenter:"Rata Tengah",justifyRight:"Rata kanan",justifyFull:"Rata kiri dan kanan",horizontalRule:"Sisipkan garis mendatar",fullscreen:"Layar penuh",close:"Tutup",submit:"Setuju",reset:"Batal",required:"Diperlukan",description:"Deskripsi",title:"Judul",text:"Teks"};

8
public/trumbowyg/langs/it.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* ===========================================================
* it.js
* Italian translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Mirko Buffoni
*/
jQuery.trumbowyg.langs.it={viewHTML:"Mostra HTML",formatting:"Formattazione",p:"Paragrafo",blockquote:"Citazione",code:"Codice",header:"Intestazione",bold:"Grassetto",italic:"Italico",strikethrough:"Barrato",underline:"Sottolineato",strong:"Rafforza",em:"Enfatizza",del:"Cancella",unorderedList:"Elenco puntato",orderedList:"Elenco numerato",insertImage:"Inserisci immagine",insertVideo:"Inserisci video",link:"Collegamento",createLink:"Crea un collegamento",unlink:"Elimina collegamento",justifyLeft:"Allinea a sinistra",justifyCenter:"Centra",justifyRight:"Allinea a destra",justifyFull:"Giustifica",horizontalRule:"Inserisci un separatore orizzontale",fullscreen:"Schermo intero",close:"Chiudi",submit:"Invia",reset:"Annulla",required:"Obbligatorio",description:"Descrizione",title:"Titolo",text:"Testo",removeformat:"Rimuovi Formattazione",superscript:"Apice",subscript:"Pedice"};

10
public/trumbowyg/langs/ja.min.js vendored Normal file
View File

@ -0,0 +1,10 @@
/* ===========================================================
* ja.js
* Japanese translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Kouta Fukuhara (foo9)
* Twitter : @foo9
* Website : https://github.com/foo9
*/
jQuery.trumbowyg.langs.ja={viewHTML:"HTML表示",undo:"元に戻す",redo:"やり直す",formatting:"フォーマット",p:"段落",blockquote:"引用",code:"コード",header:"見出し",bold:"太字",italic:"斜体",strikethrough:"取り消し線",underline:"下線",strong:"太字",em:"斜体",del:"取り消し線",superscript:"上付き文字",subscript:"下付き文字",unorderedList:"順序なしリスト",orderedList:"順序ありリスト",insertImage:"画像の挿入",link:"リンク",createLink:"リンクの作成",unlink:"リンクの削除",justifyLeft:"左揃え",justifyCenter:"中央揃え",justifyRight:"右揃え",justifyFull:"両端揃え",horizontalRule:"横罫線",removeformat:"フォーマットの削除",fullscreen:"全画面表示",close:"閉じる",submit:"送信",reset:"キャンセル",required:"必須",description:"説明",title:"タイトル",text:"テキスト",target:"ターゲット"};

10
public/trumbowyg/langs/ko.min.js vendored Normal file
View File

@ -0,0 +1,10 @@
/* ===========================================================
* ko.js
* Korean translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : JoongSeob Vito Kim (dorajistyle)
* Blog : http://dorajistyle.pe.kr
* Github : https://github.com/dorajistyle
*/
jQuery.trumbowyg.langs.ko={viewHTML:"HTML로 보기",formatting:"양식",p:"문단",blockquote:"인용부호",code:"코드",header:"머릿말",bold:"진하게",italic:"기울임",strikethrough:"취소선",underline:"밑줄",strong:"굵게",em:"강조",del:"취소",unorderedList:"순차 목록",orderedList:"비순차 목록",insertImage:"이미지 넣기",insertVideo:"비디오 넣기",link:"링크",createLink:"링크 넣기",unlink:"링크 없애기",justifyLeft:"왼쪽 정렬",justifyCenter:"가운데 정렬",justifyRight:"오른쪽 정렬",justifyFull:"혼합 정렬",horizontalRule:"가로줄 넣기",fullscreen:"전체 화면",close:"닫기",submit:"전송",reset:"초기화",required:"꼭 입력해야 합니다.",description:"설명",title:"제목",text:"본문 내용"};

8
public/trumbowyg/langs/mn.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* ===========================================================
* mn.js
* Mongolian translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Ganbayar.B (ganbayar13)
*/
jQuery.trumbowyg.langs.mn={viewHTML:"HTML харах",undo:"Буцаах",redo:"Дахих",formatting:"Формат",p:"Догол мөр",blockquote:"Ишлэл",code:"Код",header:"Гарчиг",bold:"Тод",italic:"Налуу",strikethrough:"Дундуур зураас",underline:"Доогуур зураас",strong:"Тод",em:"Налуу",del:"Дундуур зураас",superscript:"Дээд индекс",subscript:"Доод индекс",unorderedList:"Дугаарлаагүй жагсаалт",orderedList:"Дугаарласан жагсаалт",insertImage:"Зураг оруулах",insertVideo:"Видео оруулах",link:"Холбоос",createLink:"Холбоос үүсгэх",unlink:"Холбоос цуцлах",justifyLeft:"Зүүн тийш шахах",justifyCenter:"Голлуулах",justifyRight:"Баруун Баруун тийш шахах",justifyFull:"Тэгшитгэх",horizontalRule:"Хөндлөн шугам",removeformat:"Формат арилгах",fullscreen:"Дэлгэц дүүргэх",close:"Хаах",submit:"Оруулах",reset:"Цуцлах",required:"Шаардлагатай",description:"Тайлбар",title:"Гарчиг",text:"Текст",target:"Бай"};

8
public/trumbowyg/langs/my.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* ===========================================================
* my.js
* Malaysian translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : JohnPozy
*/
jQuery.trumbowyg.langs.id={viewHTML:"Lihat HTML",formatting:"Pemformatan",p:"Perenggan",blockquote:"Blockquote",code:"Kod",header:"Pengepala",bold:"Tebal",italic:"Condong",strikethrough:"Garis batal",underline:"Garis bawah",strong:"Kuat",em:"Condong",del:"Hapus",unorderedList:"Senarai tidak tertib",orderedList:"Senarai tertib",insertImage:"Masukkan imej",insertVideo:"Masukkan video",link:"Pautan",createLink:"Cipta pautan",unlink:"Hapus pautan",justifyLeft:"Mengimbangkan ke kiri",justifyCenter:"Mengimbangkan ke tengah",justifyRight:"Mengimbangkan ke kanan",justifyFull:"Mengimbangkan ke kiri dan kanan",horizontalRule:"Masukkan garis mendatar",fullscreen:"Skrin penuh",close:"Tutup",submit:"Hantar",reset:"Batal",required:"Diperlukan",description:"Perihal",title:"Tajuk",text:"Teks"};

9
public/trumbowyg/langs/nl.min.js vendored Normal file
View File

@ -0,0 +1,9 @@
/* ===========================================================
* nl.js
* Dutch translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Danny Hiemstra
* Github : https://github.com/dhiemstra
*/
jQuery.trumbowyg.langs.nl={viewHTML:"HTML bekijken",formatting:"Opmaak",p:"Paragraaf",blockquote:"Citaat",code:"Code",header:"Kop",bold:"Vet",italic:"Cursief",strikethrough:"Doorhalen",underline:"Onderlijnen",strong:"Sterk",em:"Nadruk",del:"Verwijderd",unorderedList:"Ongenummerde lijst",orderedList:"Genummerde lijst",insertImage:"Afbeelding invoegen",insertVideo:"Video invoegen",link:"Link",createLink:"Link maken",unlink:"Link verwijderen",justifyLeft:"Links uitlijnen",justifyCenter:"Centreren",justifyRight:"Rechts uitlijnen",justifyFull:"Uitvullen",horizontalRule:"Horizontale lijn",removeFormat:"Opmaak verwijderen",fullscreen:"Volledig scherm",close:"Sluiten",submit:"Verzenden",reset:"Herstellen",required:"Verplicht",description:"Omschrijving",title:"Titel",text:"Tekst"};

10
public/trumbowyg/langs/no_nb.min.js vendored Normal file
View File

@ -0,0 +1,10 @@
/* ===========================================================
* no_nb.js
* Norwegian Bokmål translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Jon Severin Eivik Jakobsen
* Github : https://github.com/jsejakobsen
*/
// jshint camelcase:false
jQuery.trumbowyg.langs.no_nb={viewHTML:"Vis HTML",formatting:"Formater",p:"Avsnitt",blockquote:"Sitat",code:"Kode",header:"Overskrift",bold:"Fet",italic:"Kursiv",strikethrough:"Gjennomstreking",underline:"Understreking",strong:"Viktig",em:"Fremhevet",del:"Slettet",unorderedList:"Uordnet liste",orderedList:"Ordnet liste",insertImage:"Sett inn bilde",insertVideo:"Sett inn video",link:"Lenke",createLink:"Sett inn lenke",unlink:"Fjern lenke",justifyLeft:"Venstrejuster",justifyCenter:"Midtstill",justifyRight:"Høyrejuster",justifyFull:"Blokkjuster",horizontalRule:"Horisontal linje",fullscreen:"Full skjerm",close:"Lukk",submit:"Bekreft",reset:"Avbryt",required:"Påkrevd",description:"Beskrivelse",title:"Tittel",text:"Tekst"};

8
public/trumbowyg/langs/ph.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* ===========================================================
* ph.js
* Filipino translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : @leogono
*/
jQuery.trumbowyg.langs.ph={viewHTML:"Tumingin sa HTML",formatting:"Formatting",p:"Talata",blockquote:"Blockquote",code:"Kowd",header:"Header",bold:"Makapal",italic:"Hilig",strikethrough:"Strikethrough",underline:"Salungguhit",strong:"Malakas",em:"Hilig",del:"Tinanggal",unorderedList:"Hindi nakahanay na listahan",orderedList:"Nakahanay na listahan",insertImage:"Ilagay ang larawan",insertVideo:"Ilagay ang video",link:"Koneksyon",createLink:"Iugnay",unlink:"Tanggalin ang koneksyon",justifyLeft:"Ihanay sa kaliwa",justifyCenter:"Ihanay sa gitna",justifyRight:"Ihanay sa kanan",justifyFull:"Ihanay sa kaliwa at kanan",horizontalRule:"Pahalang na linya",fullscreen:"Fullscreen",close:"Isara",submit:"Ipasa",reset:"I-reset",required:"Kailangan",description:"Paglalarawan",title:"Pamagat",text:"Teksto"};

9
public/trumbowyg/langs/pl.min.js vendored Normal file
View File

@ -0,0 +1,9 @@
/* ===========================================================
* pl.js
* Polish translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Paweł Abramowicz
* Github : https://github.com/pawelabrams
*/
jQuery.trumbowyg.langs.pl={viewHTML:"Pokaż HTML",formatting:"Format",p:"Akapit",blockquote:"Cytat",code:"Kod",header:"Nagłówek",bold:"Pogrubienie",italic:"Pochylenie",strikethrough:"Przekreślenie",underline:"Podkreślenie",strong:"Wytłuszczenie",em:"Uwydatnienie",del:"Usunięte",unorderedList:"Lista nieuporządkowana",orderedList:"Lista uporządkowana",insertImage:"Wstaw obraz",insertVideo:"Wstaw film",link:"Link",createLink:"Wstaw link",unlink:"Usuń link",justifyLeft:"Wyrównaj do lewej",justifyCenter:"Wyśrodkuj",justifyRight:"Wyrównaj do prawej",justifyFull:"Wyjustuj",horizontalRule:"Odkreśl linią",fullscreen:"Pełny ekran",close:"Zamknij",submit:"Zastosuj",reset:"Przywróć",required:"Wymagane",description:"Opis",title:"Tytuł",text:"Tekst"};

11
public/trumbowyg/langs/pt.min.js vendored Normal file
View File

@ -0,0 +1,11 @@
/* ===========================================================
* pt.js
* Portuguese translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Ramiro Varandas Jr (ramirovjr)
* Twitter : @ramirovjnr
* Website : about.me/ramirovjnr
* Github : https://github.com/ramirovjr
*/
jQuery.trumbowyg.langs.pt={viewHTML:"Ver HTML",undo:"Desfazer",redo:"Refazer",formatting:"Formatar",p:"Paragráfo",blockquote:"Citação",code:"Código",header:"Título",bold:"Negrito",italic:"Itálico",strikethrough:"Suprimir",underline:"Sublinhado",strong:"Negrito",em:"Ênfase",del:"Apagar",superscript:"Sobrescrito",subscript:"Subscrito",unorderedList:"Lista não ordenada",orderedList:"Lista ordenada",insertImage:"Inserir imagem",insertVideo:"Inserir vídeo",link:"Link",createLink:"Criar um link",unlink:"Remover link",justifyLeft:"Alinhar a esquerda",justifyCenter:"Centralizar",justifyRight:"Alinhar a direita",justifyFull:"Justificar",horizontalRule:"Inserir separador horizontal",removeformat:"Remover formatação",fullscreen:"Tela cheia",close:"Fechar",submit:"Enviar",reset:"Limpar",required:"Obrigatório",description:"Descrição",title:"Título",text:"Texto",target:"Target"};

11
public/trumbowyg/langs/pt_br.min.js vendored Normal file
View File

@ -0,0 +1,11 @@
/* ===========================================================
* pt_br.js
* Portuguese Brazilian translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Alex Gotardi (alexgotardi)
* Twitter : @alexgotardi
* Github : https://github.com/alexgotardi
*/
// jshint camelcase:false
jQuery.trumbowyg.langs.pt_br={viewHTML:"Ver HTML",undo:"Desfazer",redo:"Refazer",formatting:"Formatar",p:"Parágrafo",blockquote:"Citação",code:"Código",header:"Título",bold:"Negrito",italic:"Itálico",strikethrough:"Tachado",underline:"Sublinhado",strong:"Negrito",em:"Ênfase",del:"Apagar",superscript:"Sobrescrito",subscript:"Subscrito",unorderedList:"Lista não ordenada",orderedList:"Lista ordenada",insertImage:"Inserir imagem",insertVideo:"Inserir vídeo",link:"Link",createLink:"Criar um link",unlink:"Remover link",justifyLeft:"Alinhar a esquerda",justifyCenter:"Centralizar",justifyRight:"Alinhar a direita",justifyFull:"Justificar",horizontalRule:"Inserir separador horizontal",removeformat:"Remover formatação",fullscreen:"Tela cheia",close:"Fechar",submit:"Enviar",reset:"Limpar",required:"Obrigatório",description:"Descrição",title:"Título",text:"Texto",target:"Target"};

12
public/trumbowyg/langs/ro.min.js vendored Normal file
View File

@ -0,0 +1,12 @@
/* ===========================================================
* ro.js
* Romanian translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Vladut Radulescu (pacMakaveli)
* Email: pacMakaveli90@gmail.com
* Twitter : @pacMakaveli90
* Website : creative-studio51.co.uk
* Github : https://github.com/pacMakaveli
*/
jQuery.trumbowyg.langs.ro={viewHTML:"Vizualizare HTML",formatting:"Format",p:"Paragraf",blockquote:"Citație",code:"Cod",header:"Titlu",bold:"Bold",italic:"Italic",strikethrough:"Tăiat",underline:"Subliniat",strong:"Puternic",em:"Accentuat",del:"Sterge",unorderedList:"Lista dezordonată",orderedList:"Liste ordonată",insertImage:"Adăugare Imagine",insertVideo:"Adăugare Video",link:"Link",createLink:"Crează link",unlink:"Remover link",justifyLeft:"Aliniază stânga",justifyCenter:"Aliniază centru",justifyRight:"Aliniază dreapta",justifyFull:"Justificare",horizontalRule:"Linie orizontală",fullscreen:"Tot ecranul",close:"Închide",submit:"Procesează",reset:"Resetează",required:"Obligatoriu",description:"Descriere",title:"Titlu",text:"Text"};

8
public/trumbowyg/langs/rs.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* ===========================================================
* rs.js
* Serbian (Cyrlic) translation for Trumbowyg
* https://www.github.com/johonunu
* ===========================================================
* Author : Nikola Trifunovic (https://www.github.com/johonunu)
*/
jQuery.trumbowyg.langs.rs={viewHTML:"Погледај HTML кóд",formatting:"Форматирање",p:"Параграф",blockquote:"Цитат",code:"Кóд",header:"Наслов",bold:"Подебљано",italic:"Курзив",strikethrough:"Прецртано",underline:"Подвучено",strong:"Подебљано",em:"Истакнуто",del:"Обрисано",unorderedList:"Ненабројива листа",orderedList:"Набројива листа",insertImage:"Унеси слику",insertVideo:"Унеси видео",link:"Линк",createLink:"Унеси линк",unlink:"Уклони линк",justifyLeft:"Лево равнање",justifyCenter:"Централно равнање",justifyRight:"Десно равнање",justifyFull:"Обострано равнање",horizontalRule:"Хоризонтална линија",fullscreen:"Режим читавог екрана",close:"Затвори",submit:"Унеси",reset:"Откажи",required:"Обавезно поље",description:"Опис",title:"Наслов",text:"Текст"};

View File

@ -0,0 +1,9 @@
/* ===========================================================
* rs_latin.js
* Serbian (Latin) translation for Trumbowyg
* https://www.github.com/johonunu
* ===========================================================
* Author : Nikola Trifunovic (https://www.github.com/johonunu)
*/
// jshint camelcase:false
jQuery.trumbowyg.langs.rs_latin={viewHTML:"Poglеdaj HTML kód",formatting:"Formatiranjе",p:"Paragraf",blockquote:"Citat",code:"Kód",header:"Naslov",bold:"Podеbljano",italic:"Kurziv",strikethrough:"Prеcrtano",underline:"Podvučеno",strong:"Podеbljano",em:"Istaknuto",del:"Obrisano",unorderedList:"Nеnabrojiva lista",orderedList:"Nabrojiva lista",insertImage:"Unеsi sliku",insertVideo:"Unеsi vidеo",link:"Link",createLink:"Unеsi link",unlink:"Ukloni link",justifyLeft:"Lеvo ravnanjе",justifyCenter:"Cеntralno ravnanjе",justifyRight:"Dеsno ravnanjе",justifyFull:"Obostrano ravnanjе",horizontalRule:"Horizontalna linija",fullscreen:"Rеžim čitavog еkrana",close:"Zatvori",submit:"Unеsi",reset:"Otkaži",required:"Obavеzno poljе",description:"Opis",title:"Naslov",text:"Tеkst"};

8
public/trumbowyg/langs/ru.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* ===========================================================
* ru.js
* Russion translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Yuri Lya
*/
jQuery.trumbowyg.langs.ru={viewHTML:"Посмотреть HTML",undo:"Отменить",redo:"Повторить",formatting:"Форматирование",p:"Обычный",blockquote:"Цитата",code:"Код",header:"Заголовок",bold:"Полужирный",italic:"Курсив",strikethrough:"Зачеркнутый",underline:"Подчеркнутый",strong:"Полужирный",em:"Курсив",del:"Зачеркнутый",superscript:"Надстрочный",subscript:"Подстрочный",unorderedList:"Обычный список",orderedList:"Нумерованный список",insertImage:"Вставить изображение",insertVideo:"Вставить видео",link:"Ссылка",createLink:"Вставить ссылку",unlink:"Удалить ссылку",justifyLeft:"По левому краю",justifyCenter:"По центру",justifyRight:"По правому краю",justifyFull:"По ширине",horizontalRule:"Горизонтальная линия",removeformat:"Очистить форматирование",fullscreen:"Во весь экран",close:"Закрыть",submit:"Вставить",reset:"Отменить",required:"Обязательное",description:"Описание",title:"Подсказка",text:"Текст"};

8
public/trumbowyg/langs/sk.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* ===========================================================
* sk.js
* Slovak translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : VeeeneX (https://github.com/VeeeneX)
*/
jQuery.trumbowyg.langs.sk={viewHTML:"Zobraziť HTML",formatting:"Formátovanie",p:"Paragraf",blockquote:"Citácia",code:"Kód",header:"Nadpis",bold:"Tučné",italic:"Kurzíva",strikethrough:"Preškrtnuté",underline:"Podčiarknuté",strong:"Tučné",em:"Zvýrazniť",del:"Zmazať",unorderedList:"Netriedený zoznam",orderedList:"Triedený zoznam",insertImage:"Vložiť obrázok",insertVideo:"Vložiť video",link:"Odkaz",createLink:"Vložiť odkaz",unlink:"Zmazať odkaz",justifyLeft:"Zarovnať doľava",justifyCenter:"Zarovnať na stred",justifyRight:"Zarovnať doprava",justifyFull:"Zarovnať do bloku",horizontalRule:"Vložit vodorovnú čiaru",fullscreen:"Režim celej obrazovky",close:"Zavrieť",submit:"Potvrdiť",reset:"Zrušiť",required:"Povinné",description:"Popis",title:"Nadpis",text:"Text"};

12
public/trumbowyg/langs/sv.min.js vendored Normal file
View File

@ -0,0 +1,12 @@
/* ===========================================================
* sv.js
* Swedish translation for Trumbowyg
* http://www.tim-international.net
* ===========================================================
* Author : T. Almroth
* Github : https://github.com/timint
*
* Review : M Hagberg
* Github : https://github.com/pestbarn
*/
jQuery.trumbowyg.langs.sv={viewHTML:"Visa HTML",formatting:"Formatering",p:"Paragraf",blockquote:"Citat",code:"Kod",header:"Rubrik",bold:"Fet",italic:"Kursiv",strikethrough:"Genomstruken",underline:"Understruken",strong:"Fet",em:"Kursiv",del:"Rensa formatering",unorderedList:"Punktlista",orderedList:"Numrerad lista",insertImage:"Infoga bild",insertVideo:"Infoga video",link:"Länk",createLink:"Infoga länk",unlink:"Ta bort länk",justifyLeft:"Vänsterjustera",justifyCenter:"Centrera",justifyRight:"Högerjustera",justifyFull:"Marginaljustera",horizontalRule:"Horisontell linje",fullscreen:"Fullskärm",close:"Stäng",submit:"Bekräfta",reset:"Återställ",required:"Obligatorisk",description:"Beskrivning",title:"Titel",text:"Text"};

9
public/trumbowyg/langs/tr.min.js vendored Normal file
View File

@ -0,0 +1,9 @@
/* ===========================================================
* tr.js
* Turkish translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Emrah Bilbay (munzur)
* Github : https://github.com/munzur
*/
jQuery.trumbowyg.langs.tr={viewHTML:"HTML Kodu",formatting:"Biçimlendirme",p:"Paragraf",blockquote:"Alıntı",code:"Kod",header:"Başlık",bold:"Kalın",italic:"İtalik",strikethrough:"Üzeri çizgili",underline:"Altı çizgili",strong:"Koyu",em:"Vurgulu",del:"Üzeri çizgili",unorderedList:"Simgeli liste",orderedList:"Numaralı liste",insertImage:"Resim yerleştir",insertVideo:"Video yerleştir",link:"Link",createLink:"Link yerleştir",unlink:"Linki sil",justifyLeft:"Sola hizala",justifyCenter:"Ortaya hizala",justifyRight:"Sağa hizala",justifyFull:"Yasla",horizontalRule:"Yatay satır ekle",fullscreen:"Tam ekran",close:"Kapat",submit:"Onayla",reset:"Sıfırla",required:"Gerekli",description:"Açıklama",title:"Başlık",text:"Metin"};

8
public/trumbowyg/langs/ua.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* ===========================================================
* ua.js
* Ukrainian translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Igor Buksha
*/
jQuery.trumbowyg.langs.ua={viewHTML:"Подивитись HTML",formatting:"Форматування",p:"Звичайний",blockquote:"Витяг",code:"Код",header:"Заголовок",bold:"Напівжирний",italic:"Курсив",strikethrough:"Закреслений",underline:"Підкреслений",strong:"Напівжирний",em:"Курсив",del:"Закреслений",unorderedList:"Звичайний список",orderedList:"Нумерований список",insertImage:"Вставити зображення",insertVideo:"Вставити відео",link:"Посилання",createLink:"Вставити посилання",unlink:"Видалити посилання",justifyLeft:"По лівому краю",justifyCenter:"В центрі",justifyRight:"По правому краю",justifyFull:"По ширині",horizontalRule:"Горизонтальна лінія",fullscreen:"На весь екран",close:"Закрити",submit:"Вставити",reset:"Скасувати",required:"Обов'язкове",description:"Опис",title:"Підказка",text:"Текст"};

9
public/trumbowyg/langs/vi.min.js vendored Normal file
View File

@ -0,0 +1,9 @@
/* ===========================================================
* vi.js
* Vietnamese translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : heocoi
* Github: https://github.com/heocoi
*/
jQuery.trumbowyg.langs.vi={viewHTML:"Hiển thị HTML",formatting:"Định dạng",p:"Đoạn",blockquote:"Trích dẫn",code:"Code",header:"Đầu trang",bold:"In đậm",italic:"In nghiêng",strikethrough:"Gạch ngang",underline:"Gạch chân",strong:"In đậm",em:"In nghiêng",del:"Gạch ngang",unorderedList:"Danh sách không thứ tự",orderedList:"Danh sách có thứ tự",insertImage:"Chèn hình ảnh",insertVideo:"Chèn video",link:"Đường dẫn",createLink:"Tạo đường dẫn",unlink:"Hủy đường dẫn",justifyLeft:"Canh lề trái",justifyCenter:"Canh giữa",justifyRight:"Canh lề phải",justifyFull:"Canh đều",horizontalRule:"Thêm đường kẻ ngang",fullscreen:"Toàn màn hình",close:"Đóng",submit:"Đồng ý",reset:"Hủy bỏ",required:"Bắt buộc",description:"Mô tả",title:"Tiêu đề",text:"Nội dung"};

11
public/trumbowyg/langs/zh_cn.min.js vendored Normal file
View File

@ -0,0 +1,11 @@
/* ===========================================================
* zh_cn.js
* Simplified Chinese translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Liu Kai (akai)
* Twitter : @akai404
* Github : https://github.com/akai
*/
// jshint camelcase:false
jQuery.trumbowyg.langs.zh_cn={viewHTML:"源代码",formatting:"格式",p:"段落",blockquote:"引用",code:"代码",header:"标题",bold:"加粗",italic:"斜体",strikethrough:"删除线",underline:"下划线",strong:"加粗",em:"斜体",del:"删除线",unorderedList:"无序列表",orderedList:"有序列表",insertImage:"插入图片",insertVideo:"插入视频",link:"超链接",createLink:"插入链接",unlink:"取消链接",justifyLeft:"居左对齐",justifyCenter:"居中对齐",justifyRight:"居右对齐",justifyFull:"两端对齐",horizontalRule:"插入分隔线",fullscreen:"全屏",close:"关闭",submit:"确定",reset:"取消",required:"必需的",description:"描述",title:"标题",text:"文字"};

11
public/trumbowyg/langs/zh_tw.min.js vendored Normal file
View File

@ -0,0 +1,11 @@
/* ===========================================================
* zh_tw.js
* Traditional Chinese translation for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Peter Dave Hello (PeterDaveHello)
* Twitter : @PeterDaveHello
* Github : https://github.com/PeterDaveHello
*/
// jshint camelcase:false
jQuery.trumbowyg.langs.zh_tw={viewHTML:"原始碼",formatting:"格式",p:"段落",blockquote:"引用",code:"代碼",header:"標題",bold:"加粗",italic:"斜體",strikethrough:"刪除線",underline:"底線",strong:"加粗",em:"斜體",del:"刪除線",unorderedList:"無序列表",orderedList:"有序列表",insertImage:"插入圖片",insertVideo:"插入影片",link:"超連結",createLink:"插入連結",unlink:"取消連結",justifyLeft:"靠左對齊",justifyCenter:"置中對齊",justifyRight:"靠右對齊",justifyFull:"左右對齊",horizontalRule:"插入分隔線",fullscreen:"全螢幕",close:"關閉",submit:"確定",reset:"取消",required:"必需的",description:"描述",title:"標題",text:"文字"};

View File

@ -0,0 +1,121 @@
/* ===========================================================
* trumbowyg.base64.js v1.0
* Base64 plugin for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Cyril Biencourt (lizardK)
*/
(function ($) {
'use strict';
var isSupported = function () {
return typeof FileReader !== 'undefined';
};
var isValidImage = function (type) {
return /^data:image\/[a-z]?/i.test(type);
};
$.extend(true, $.trumbowyg, {
langs: {
// jshint camelcase:false
en: {
base64: 'Image as base64',
file: 'File',
errFileReaderNotSupported: 'FileReader is not supported by your browser.',
errInvalidImage: 'Invalid image file.'
},
fr: {
base64: 'Image en base64',
file: 'Fichier'
},
cs: {
base64: 'Vložit obrázek',
file: 'Soubor'
},
zh_cn: {
base64: '图片Base64编码',
file: '文件'
},
nl: {
errFileReaderNotSupported: 'Uw browser ondersteunt deze functionaliteit niet.',
errInvalidImage: 'De gekozen afbeelding is ongeldig.'
},
ru: {
base64: 'Изображение как код в base64',
file: 'Файл',
errFileReaderNotSupported: 'FileReader не поддерживается вашим браузером.',
errInvalidImage: 'Недопустимый файл изображения.'
},
ja: {
base64: '画像 (Base64形式)',
file: 'ファイル',
errFileReaderNotSupported: 'あなたのブラウザーはFileReaderをサポートしていません',
errInvalidImage: '画像形式が正しくありません'
}
},
// jshint camelcase:true
plugins: {
base64: {
shouldInit: isSupported,
init: function (trumbowyg) {
var btnDef = {
isSupported: isSupported,
fn: function () {
trumbowyg.saveRange();
var file;
var $modal = trumbowyg.openModalInsert(
// Title
trumbowyg.lang.base64,
// Fields
{
file: {
type: 'file',
required: true,
attributes: {
accept: 'image/*'
}
},
alt: {
label: 'description',
value: trumbowyg.getRangeText()
}
},
// Callback
function (values) {
var fReader = new FileReader();
fReader.onloadend = function (e) {
if (isValidImage(e.target.result)) {
trumbowyg.execCmd('insertImage', fReader.result);
$(['img[src="', fReader.result, '"]:not([alt])'].join(''), trumbowyg.$box).attr('alt', values.alt);
trumbowyg.closeModal();
} else {
trumbowyg.addErrorOnModalField(
$('input[type=file]', $modal),
trumbowyg.lang.errInvalidImage
);
}
};
fReader.readAsDataURL(file);
}
);
$('input[type=file]').on('change', function (e) {
file = e.target.files[0];
});
}
};
trumbowyg.addBtnDef('base64', btnDef);
}
}
}
});
})(jQuery);

View File

@ -0,0 +1 @@
!function(e){"use strict";var a=function(){return"undefined"!=typeof FileReader},r=function(e){return/^data:image\/[a-z]?/i.test(e)};e.extend(!0,e.trumbowyg,{langs:{en:{base64:"Image as base64",file:"File",errFileReaderNotSupported:"FileReader is not supported by your browser.",errInvalidImage:"Invalid image file."},fr:{base64:"Image en base64",file:"Fichier"},cs:{base64:"Vložit obrázek",file:"Soubor"},zh_cn:{base64:"图片Base64编码",file:"文件"},nl:{errFileReaderNotSupported:"Uw browser ondersteunt deze functionaliteit niet.",errInvalidImage:"De gekozen afbeelding is ongeldig."},ru:{base64:"Изображение как код в base64",file:"Файл",errFileReaderNotSupported:"FileReader не поддерживается вашим браузером.",errInvalidImage:"Недопустимый файл изображения."},ja:{base64:"画像 (Base64形式)",file:"ファイル",errFileReaderNotSupported:"あなたのブラウザーはFileReaderをサポートしていません",errInvalidImage:"画像形式が正しくありません"}},plugins:{base64:{shouldInit:a,init:function(i){var t={isSupported:a,fn:function(){i.saveRange();var a,t=i.openModalInsert(i.lang.base64,{file:{type:"file",required:!0,attributes:{accept:"image/*"}},alt:{label:"description",value:i.getRangeText()}},function(n){var l=new FileReader;l.onloadend=function(a){r(a.target.result)?(i.execCmd("insertImage",l.result),e(['img[src="',l.result,'"]:not([alt])'].join(""),i.$box).attr("alt",n.alt),i.closeModal()):i.addErrorOnModalField(e("input[type=file]",t),i.lang.errInvalidImage)},l.readAsDataURL(a)});e("input[type=file]").on("change",function(e){a=e.target.files[0]})}};i.addBtnDef("base64",t)}}}})}(jQuery);

View File

@ -0,0 +1,179 @@
/* ===========================================================
* trumbowyg.cleanpaste.js v1.0
* Font Clean paste plugin for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Eric Radin
*/
/**
* This plugin will perform a "cleaning" on any paste, in particular
* it will clean pasted content of microsoft word document tags and classes.
*/
(function ($) {
'use strict';
function reverse(sentString) {
var theString = '';
for (var i = sentString.length - 1; i >= 0; i -= 1) {
theString += sentString.charAt(i);
}
return theString;
}
function checkValidTags(snippet) {
var theString = snippet;
// Replace uppercase element names with lowercase
theString = theString.replace(/<[^> ]*/g, function (match) {
return match.toLowerCase();
});
// Replace uppercase attribute names with lowercase
theString = theString.replace(/<[^>]*>/g, function (match) {
match = match.replace(/ [^=]+=/g, function (match2) {
return match2.toLowerCase();
});
return match;
});
// Put quotes around unquoted attributes
theString = theString.replace(/<[^>]*>/g, function (match) {
match = match.replace(/( [^=]+=)([^"][^ >]*)/g, '$1\"$2\"');
return match;
});
return theString;
}
function cleanIt(htmlBefore, htmlAfter) {
var matchedHead = '';
var matchedTail = '';
var afterStart;
var afterFinish;
var newSnippet;
// we need to extract the inserted block
for (afterStart = 0; htmlAfter.charAt(afterStart) === htmlBefore.charAt(afterStart); afterStart += 1) {
matchedHead += htmlAfter.charAt(afterStart);
}
// If afterStart is inside a HTML tag, move to opening brace of tag
for (var i = afterStart; i >= 0; i -= 1) {
if (htmlBefore.charAt(i) === '<') {
afterStart = i;
matchedHead = htmlBefore.substring(0, afterStart);
break;
} else if (htmlBefore.charAt(i) === '>') {
break;
}
}
// now reverse string and work from the end in
htmlAfter = reverse(htmlAfter);
htmlBefore = reverse(htmlBefore);
// Find end of both strings that matches
for (afterFinish = 0; htmlAfter.charAt(afterFinish) === htmlBefore.charAt(afterFinish); afterFinish += 1) {
matchedTail += htmlAfter.charAt(afterFinish);
}
// If afterFinish is inside a HTML tag, move to closing brace of tag
for (var j = afterFinish; j >= 0; j -= 1) {
if (htmlBefore.charAt(j) === '>') {
afterFinish = j;
matchedTail = htmlBefore.substring(0, afterFinish);
break;
} else if (htmlBefore.charAt(j) === '<') {
break;
}
}
matchedTail = reverse(matchedTail);
// If there's no difference in pasted content
if (afterStart === (htmlAfter.length - afterFinish)) {
return false;
}
htmlAfter = reverse(htmlAfter);
newSnippet = htmlAfter.substring(afterStart, htmlAfter.length - afterFinish);
// first make sure all tags and attributes are made valid
newSnippet = checkValidTags(newSnippet);
// Replace opening bold tags with strong
newSnippet = newSnippet.replace(/<b(\s+|>)/g, '<strong$1');
// Replace closing bold tags with closing strong
newSnippet = newSnippet.replace(/<\/b(\s+|>)/g, '</strong$1');
// Replace italic tags with em
newSnippet = newSnippet.replace(/<i(\s+|>)/g, '<em$1');
// Replace closing italic tags with closing em
newSnippet = newSnippet.replace(/<\/i(\s+|>)/g, '</em$1');
// strip out comments -cgCraft
newSnippet = newSnippet.replace(/<!(?:--[\s\S]*?--\s*)?>\s*/g, '');
// strip out &nbsp; -cgCraft
newSnippet = newSnippet.replace(/&nbsp;/gi, ' ');
// strip out extra spaces -cgCraft
newSnippet = newSnippet.replace(/ <\//gi, '</');
while (newSnippet.indexOf(' ') !== -1) {
var anArray = newSnippet.split(' ');
newSnippet = anArray.join(' ');
}
// strip &nbsp; -cgCraft
newSnippet = newSnippet.replace(/^\s*|\s*$/g, '');
// Strip out unaccepted attributes
newSnippet = newSnippet.replace(/<[^>]*>/g, function (match) {
match = match.replace(/ ([^=]+)="[^"]*"/g, function (match2, attributeName) {
if (['alt', 'href', 'src', 'title'].indexOf(attributeName) !== -1) {
return match2;
}
return '';
});
return match;
});
// Final cleanout for MS Word crud
newSnippet = newSnippet.replace(/<\?xml[^>]*>/g, '');
newSnippet = newSnippet.replace(/<[^ >]+:[^>]*>/g, '');
newSnippet = newSnippet.replace(/<\/[^ >]+:[^>]*>/g, '');
// remove unwanted tags
newSnippet = newSnippet.replace(/<(div|span|style|meta|link){1}.*?>/gi, '');
htmlAfter = matchedHead + newSnippet + matchedTail;
return htmlAfter;
}
// clean editor
// this will clean the inserted contents
// it does a compare, before and after paste to determine the
// pasted contents
$.extend(true, $.trumbowyg, {
plugins: {
cleanPaste: {
init: function (trumbowyg) {
trumbowyg.pasteHandlers.push(function () {
try {
var contentBefore = trumbowyg.$ed.html();
setTimeout(function () {
var contentAfter = trumbowyg.$ed.html();
contentAfter = cleanIt(contentBefore, contentAfter);
trumbowyg.$ed.html(contentAfter);
}, 0);
} catch (c) {
}
});
}
}
}
});
})(jQuery);

View File

@ -0,0 +1 @@
!function(r){"use strict";function e(r){for(var e="",t=r.length-1;t>=0;t-=1)e+=r.charAt(t);return e}function t(r){var e=r;return e=e.replace(/<[^> ]*/g,function(r){return r.toLowerCase()}),e=e.replace(/<[^>]*>/g,function(r){return r=r.replace(/ [^=]+=/g,function(r){return r.toLowerCase()})}),e=e.replace(/<[^>]*>/g,function(r){return r=r.replace(/( [^=]+=)([^"][^ >]*)/g,'$1"$2"')})}function n(r,n){var a,c,i,l="",s="";for(a=0;n.charAt(a)===r.charAt(a);a+=1)l+=n.charAt(a);for(var u=a;u>=0;u-=1){if("<"===r.charAt(u)){a=u,l=r.substring(0,a);break}if(">"===r.charAt(u))break}for(n=e(n),r=e(r),c=0;n.charAt(c)===r.charAt(c);c+=1)s+=n.charAt(c);for(var g=c;g>=0;g-=1){if(">"===r.charAt(g)){c=g,s=r.substring(0,c);break}if("<"===r.charAt(g))break}if(s=e(s),a===n.length-c)return!1;for(n=e(n),i=n.substring(a,n.length-c),i=t(i),i=i.replace(/<b(\s+|>)/g,"<strong$1"),i=i.replace(/<\/b(\s+|>)/g,"</strong$1"),i=i.replace(/<i(\s+|>)/g,"<em$1"),i=i.replace(/<\/i(\s+|>)/g,"</em$1"),i=i.replace(/<!(?:--[\s\S]*?--\s*)?>\s*/g,""),i=i.replace(/&nbsp;/gi," "),i=i.replace(/ <\//gi,"</");-1!==i.indexOf(" ");){var o=i.split(" ");i=o.join(" ")}return i=i.replace(/^\s*|\s*$/g,""),i=i.replace(/<[^>]*>/g,function(r){return r=r.replace(/ ([^=]+)="[^"]*"/g,function(r,e){return-1!==["alt","href","src","title"].indexOf(e)?r:""})}),i=i.replace(/<\?xml[^>]*>/g,""),i=i.replace(/<[^ >]+:[^>]*>/g,""),i=i.replace(/<\/[^ >]+:[^>]*>/g,""),i=i.replace(/<(div|span|style|meta|link){1}.*?>/gi,""),n=l+i+s}r.extend(!0,r.trumbowyg,{plugins:{cleanPaste:{init:function(r){r.pasteHandlers.push(function(){try{var e=r.$ed.html();setTimeout(function(){var t=r.$ed.html();t=n(e,t),r.$ed.html(t)},0)}catch(t){}})}}}})}(jQuery);

View File

@ -0,0 +1,176 @@
/* ===========================================================
* trumbowyg.colors.js v1.2
* Colors picker plugin for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Alexandre Demode (Alex-D)
* Twitter : @AlexandreDemode
* Website : alex-d.fr
*/
(function ($) {
'use strict';
$.extend(true, $.trumbowyg, {
langs: {
// jshint camelcase:false
cs: {
foreColor: 'Barva textu',
backColor: 'Barva pozadí'
},
en: {
foreColor: 'Text color',
backColor: 'Background color'
},
fr: {
foreColor: 'Couleur du texte',
backColor: 'Couleur de fond'
},
sk: {
foreColor: 'Farba textu',
backColor: 'Farba pozadia'
},
zh_cn: {
foreColor: '文字颜色',
backColor: '背景颜色'
},
ru: {
foreColor: 'Цвет текста',
backColor: 'Цвет выделения текста'
},
ja: {
foreColor: '文字色',
backColor: '背景色'
}
}
});
// jshint camelcase:true
function hex(x) {
return ('0' + parseInt(x).toString(16)).slice(-2);
}
function colorToHex(rgb) {
if (rgb.search('rgb') === -1) {
return rgb.replace('#', '');
} else if (rgb === 'rgba(0, 0, 0, 0)') {
return 'transparent';
} else {
rgb = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))?\)$/);
return hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
}
}
function colorTagHandler(element, trumbowyg) {
var tags = [];
if(!element.style){
return tags;
}
// background color
if (element.style.backgroundColor !== '') {
var backColor = colorToHex(element.style.backgroundColor);
if (trumbowyg.o.plugins.colors.colorList.indexOf(backColor) >= 0) {
tags.push('backColor' + backColor);
} else {
tags.push('backColorFree');
}
}
// text color
var foreColor;
if (element.style.color !== '') {
foreColor = colorToHex(element.style.color);
} else if (element.hasAttribute('color')) {
foreColor = colorToHex(element.getAttribute('color'));
}
if (foreColor) {
if (trumbowyg.o.plugins.colors.colorList.indexOf(foreColor) >= 0) {
tags.push('foreColor' + foreColor);
} else {
tags.push('foreColorFree');
}
}
return tags;
}
var defaultOptions = {
colorList: ['ffffff', '000000', 'eeece1', '1f497d', '4f81bd', 'c0504d', '9bbb59', '8064a2', '4bacc6', 'f79646', 'ffff00', 'f2f2f2', '7f7f7f', 'ddd9c3', 'c6d9f0', 'dbe5f1', 'f2dcdb', 'ebf1dd', 'e5e0ec', 'dbeef3', 'fdeada', 'fff2ca', 'd8d8d8', '595959', 'c4bd97', '8db3e2', 'b8cce4', 'e5b9b7', 'd7e3bc', 'ccc1d9', 'b7dde8', 'fbd5b5', 'ffe694', 'bfbfbf', '3f3f3f', '938953', '548dd4', '95b3d7', 'd99694', 'c3d69b', 'b2a2c7', 'b7dde8', 'fac08f', 'f2c314', 'a5a5a5', '262626', '494429', '17365d', '366092', '953734', '76923c', '5f497a', '92cddc', 'e36c09', 'c09100', '7f7f7f', '0c0c0c', '1d1b10', '0f243e', '244061', '632423', '4f6128', '3f3151', '31859b', '974806', '7f6000']
};
// Add all colors in two dropdowns
$.extend(true, $.trumbowyg, {
plugins: {
color: {
init: function (trumbowyg) {
trumbowyg.o.plugins.colors = trumbowyg.o.plugins.colors || defaultOptions;
var foreColorBtnDef = {
dropdown: buildDropdown('foreColor', trumbowyg)
},
backColorBtnDef = {
dropdown: buildDropdown('backColor', trumbowyg)
};
trumbowyg.addBtnDef('foreColor', foreColorBtnDef);
trumbowyg.addBtnDef('backColor', backColorBtnDef);
},
tagHandler: colorTagHandler
}
}
});
function buildDropdown(fn, trumbowyg) {
var dropdown = [];
$.each(trumbowyg.o.plugins.colors.colorList, function (i, color) {
var btn = fn + color,
btnDef = {
fn: fn,
forceCss: true,
param: '#' + color,
style: 'background-color: #' + color + ';'
};
trumbowyg.addBtnDef(btn, btnDef);
dropdown.push(btn);
});
var removeColorButtonName = fn + 'Remove',
removeColorBtnDef = {
fn: 'removeFormat',
param: fn,
style: 'background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAG0lEQVQIW2NkQAAfEJMRmwBYhoGBYQtMBYoAADziAp0jtJTgAAAAAElFTkSuQmCC);'
};
trumbowyg.addBtnDef(removeColorButtonName, removeColorBtnDef);
dropdown.push(removeColorButtonName);
// add free color btn
var freeColorButtonName = fn + 'Free',
freeColorBtnDef = {
fn: function () {
trumbowyg.openModalInsert(trumbowyg.lang[fn],
{
color: {
label: fn,
value: '#FFFFFF'
}
},
// callback
function (values) {
trumbowyg.execCmd(fn, values.color);
return true;
}
);
},
text: '#',
// style adjust for displaying the text
style: 'text-indent: 0;line-height: 20px;padding: 0 5px;'
};
trumbowyg.addBtnDef(freeColorButtonName, freeColorBtnDef);
dropdown.push(freeColorButtonName);
return dropdown;
}
})(jQuery);

View File

@ -0,0 +1 @@
!function(o){"use strict";function r(o){return("0"+parseInt(o).toString(16)).slice(-2)}function e(o){return-1===o.search("rgb")?o.replace("#",""):"rgba(0, 0, 0, 0)"===o?"transparent":(o=o.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))?\)$/),r(o[1])+r(o[2])+r(o[3]))}function f(o,r){var f=[];if(!o.style)return f;if(""!==o.style.backgroundColor){var c=e(o.style.backgroundColor);r.o.plugins.colors.colorList.indexOf(c)>=0?f.push("backColor"+c):f.push("backColorFree")}var a;return""!==o.style.color?a=e(o.style.color):o.hasAttribute("color")&&(a=e(o.getAttribute("color"))),a&&(r.o.plugins.colors.colorList.indexOf(a)>=0?f.push("foreColor"+a):f.push("foreColorFree")),f}function c(r,e){var f=[];o.each(e.o.plugins.colors.colorList,function(o,c){var a=r+c,d={fn:r,forceCss:!0,param:"#"+c,style:"background-color: #"+c+";"};e.addBtnDef(a,d),f.push(a)});var c=r+"Remove",a={fn:"removeFormat",param:r,style:"background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAG0lEQVQIW2NkQAAfEJMRmwBYhoGBYQtMBYoAADziAp0jtJTgAAAAAElFTkSuQmCC);"};e.addBtnDef(c,a),f.push(c);var d=r+"Free",l={fn:function(){e.openModalInsert(e.lang[r],{color:{label:r,value:"#FFFFFF"}},function(o){return e.execCmd(r,o.color),!0})},text:"#",style:"text-indent: 0;line-height: 20px;padding: 0 5px;"};return e.addBtnDef(d,l),f.push(d),f}o.extend(!0,o.trumbowyg,{langs:{cs:{foreColor:"Barva textu",backColor:"Barva pozadí"},en:{foreColor:"Text color",backColor:"Background color"},fr:{foreColor:"Couleur du texte",backColor:"Couleur de fond"},sk:{foreColor:"Farba textu",backColor:"Farba pozadia"},zh_cn:{foreColor:"文字颜色",backColor:"背景颜色"},ru:{foreColor:"Цвет текста",backColor:"Цвет выделения текста"},ja:{foreColor:"文字色",backColor:"背景色"}}});var a={colorList:["ffffff","000000","eeece1","1f497d","4f81bd","c0504d","9bbb59","8064a2","4bacc6","f79646","ffff00","f2f2f2","7f7f7f","ddd9c3","c6d9f0","dbe5f1","f2dcdb","ebf1dd","e5e0ec","dbeef3","fdeada","fff2ca","d8d8d8","595959","c4bd97","8db3e2","b8cce4","e5b9b7","d7e3bc","ccc1d9","b7dde8","fbd5b5","ffe694","bfbfbf","3f3f3f","938953","548dd4","95b3d7","d99694","c3d69b","b2a2c7","b7dde8","fac08f","f2c314","a5a5a5","262626","494429","17365d","366092","953734","76923c","5f497a","92cddc","e36c09","c09100","7f7f7f","0c0c0c","1d1b10","0f243e","244061","632423","4f6128","3f3151","31859b","974806","7f6000"]};o.extend(!0,o.trumbowyg,{plugins:{color:{init:function(o){o.o.plugins.colors=o.o.plugins.colors||a;var r={dropdown:c("foreColor",o)},e={dropdown:c("backColor",o)};o.addBtnDef("foreColor",r),o.addBtnDef("backColor",e)},tagHandler:f}}})}(jQuery);

View File

@ -0,0 +1,49 @@
/**
* Trumbowyg v2.8.1 - A lightweight WYSIWYG editor
* Default stylesheet for Trumbowyg editor plugin
* ------------------------
* @link http://alex-d.github.io/Trumbowyg
* @license MIT
* @author Alexandre Demode (Alex-D)
* Twitter : @AlexandreDemode
* Website : alex-d.fr
*/
.trumbowyg-dropdown-foreColor,
.trumbowyg-dropdown-backColor {
width: 276px;
padding: 7px 5px;
svg {
display: none !important;
}
button {
display: block;
position: relative;
float: left;
text-indent: -9999px;
height: 20px;
width: 20px;
border: 1px solid #333;
padding: 0;
margin: 2px;
&:hover,
&:focus {
&::after {
content: " ";
display: block;
position: absolute;
top: -5px;
left: -5px;
height: 27px;
width: 27px;
background: inherit;
border: 1px solid #FFF;
box-shadow: #000 0 0 2px;
z-index: 10;
}
}
}
}

View File

@ -0,0 +1,43 @@
/**
* Trumbowyg v2.8.1 - A lightweight WYSIWYG editor
* Trumbowyg plugin stylesheet
* ------------------------
* @link http://alex-d.github.io/Trumbowyg
* @license MIT
* @author Alexandre Demode (Alex-D)
* Twitter : @AlexandreDemode
* Website : alex-d.fr
*/
.trumbowyg-dropdown-foreColor,
.trumbowyg-dropdown-backColor {
width: 276px;
padding: 7px 5px; }
.trumbowyg-dropdown-foreColor svg,
.trumbowyg-dropdown-backColor svg {
display: none !important; }
.trumbowyg-dropdown-foreColor button,
.trumbowyg-dropdown-backColor button {
display: block;
position: relative;
float: left;
text-indent: -9999px;
height: 20px;
width: 20px;
border: 1px solid #333;
padding: 0;
margin: 2px; }
.trumbowyg-dropdown-foreColor button:hover::after, .trumbowyg-dropdown-foreColor button:focus::after,
.trumbowyg-dropdown-backColor button:hover::after,
.trumbowyg-dropdown-backColor button:focus::after {
content: " ";
display: block;
position: absolute;
top: -5px;
left: -5px;
height: 27px;
width: 27px;
background: inherit;
border: 1px solid #FFF;
box-shadow: #000 0 0 2px;
z-index: 10; }

View File

@ -0,0 +1,2 @@
/** Trumbowyg v2.8.1 - A lightweight WYSIWYG editor - alex-d.github.io/Trumbowyg - License MIT - Author : Alexandre Demode (Alex-D) / alex-d.fr */
.trumbowyg-dropdown-backColor,.trumbowyg-dropdown-foreColor{width:276px;padding:7px 5px}.trumbowyg-dropdown-backColor svg,.trumbowyg-dropdown-foreColor svg{display:none!important}.trumbowyg-dropdown-backColor button,.trumbowyg-dropdown-foreColor button{display:block;position:relative;float:left;text-indent:-9999px;height:20px;width:20px;border:1px solid #333;padding:0;margin:2px}.trumbowyg-dropdown-backColor button:focus::after,.trumbowyg-dropdown-backColor button:hover::after,.trumbowyg-dropdown-foreColor button:focus::after,.trumbowyg-dropdown-foreColor button:hover::after{content:" ";display:block;position:absolute;top:-5px;left:-5px;height:27px;width:27px;background:inherit;border:1px solid #FFF;box-shadow:#000 0 0 2px;z-index:10}

View File

@ -0,0 +1,965 @@
/* ===========================================================
* trumbowyg.emoji.js v0.1
* Emoji picker plugin for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Nicolas Pion
* Twitter : @nicolas_pion
*/
(function ($) {
'use strict';
var defaultOptions = {
emojiList: [
':bowtie:',
':smile:',
':laughing:',
':blush:',
':smiley:',
':relaxed:',
':smirk:',
':heart_eyes:',
':kissing_heart:',
':kissing_closed_eyes:',
':flushed:',
':relieved:',
':satisfied:',
':grin:',
':wink:',
':stuck_out_tongue_winking_eye:',
':stuck_out_tongue_closed_eyes:',
':grinning:',
':kissing:',
':kissing_smiling_eyes:',
':stuck_out_tongue:',
':sleeping:',
':worried:',
':frowning:',
':anguished:',
':open_mouth:',
':grimacing:',
':confused:',
':hushed:',
':expressionless:',
':unamused:',
':sweat_smile:',
':sweat:',
':disappointed_relieved:',
':weary:',
':pensive:',
':disappointed:',
':confounded:',
':fearful:',
':cold_sweat:',
':persevere:',
':cry:',
':sob:',
':joy:',
':astonished:',
':scream:',
':neckbeard:',
':tired_face:',
':angry:',
':rage:',
':triumph:',
':sleepy:',
':yum:',
':mask:',
':sunglasses:',
':dizzy_face:',
':imp:',
':smiling_imp:',
':neutral_face:',
':no_mouth:',
':innocent:',
':alien:',
':yellow_heart:',
':blue_heart:',
':purple_heart:',
':heart:',
':green_heart:',
':broken_heart:',
':heartbeat:',
':heartpulse:',
':two_hearts:',
':revolving_hearts:',
':cupid:',
':sparkling_heart:',
':sparkles:',
':star:',
':star2:',
':dizzy:',
':boom:',
':collision:',
':anger:',
':exclamation:',
':question:',
':grey_exclamation:',
':grey_question:',
':zzz:',
':dash:',
':sweat_drops:',
':notes:',
':musical_note:',
':fire:',
':hankey:',
':poop:',
':shit:',
':+1:',
':thumbsup:',
':-1:',
':thumbsdown:',
':ok_hand:',
':punch:',
':facepunch:',
':fist:',
':v:',
':wave:',
':hand:',
':raised_hand:',
':open_hands:',
':point_up:',
':point_down:',
':point_left:',
':point_right:',
':raised_hands:',
':pray:',
':point_up_2:',
':clap:',
':muscle:',
':metal:',
':fu:',
':runner:',
':running:',
':couple:',
':family:',
':two_men_holding_hands:',
':two_women_holding_hands:',
':dancer:',
':dancers:',
':ok_woman:',
':no_good:',
':information_desk_person:',
':raising_hand:',
':bride_with_veil:',
':person_with_pouting_face:',
':person_frowning:',
':bow:',
':couplekiss:',
':couple_with_heart:',
':massage:',
':haircut:',
':nail_care:',
':boy:',
':girl:',
':woman:',
':man:',
':baby:',
':older_woman:',
':older_man:',
':person_with_blond_hair:',
':man_with_gua_pi_mao:',
':man_with_turban:',
':construction_worker:',
':cop:',
':angel:',
':princess:',
':smiley_cat:',
':smile_cat:',
':heart_eyes_cat:',
':kissing_cat:',
':smirk_cat:',
':scream_cat:',
':crying_cat_face:',
':joy_cat:',
':pouting_cat:',
':japanese_ogre:',
':japanese_goblin:',
':see_no_evil:',
':hear_no_evil:',
':speak_no_evil:',
':guardsman:',
':skull:',
':feet:',
':lips:',
':kiss:',
':droplet:',
':ear:',
':eyes:',
':nose:',
':tongue:',
':love_letter:',
':bust_in_silhouette:',
':busts_in_silhouette:',
':speech_balloon:',
':thought_balloon:',
':feelsgood:',
':finnadie:',
':goberserk:',
':godmode:',
':hurtrealbad:',
':rage1:',
':rage2:',
':rage3:',
':rage4:',
':suspect:',
':trollface:',
':sunny:',
':umbrella:',
':cloud:',
':snowflake:',
':snowman:',
':zap:',
':cyclone:',
':foggy:',
':ocean:',
':cat:',
':dog:',
':mouse:',
':hamster:',
':rabbit:',
':wolf:',
':frog:',
':tiger:',
':koala:',
':bear:',
':pig:',
':pig_nose:',
':cow:',
':boar:',
':monkey_face:',
':monkey:',
':horse:',
':racehorse:',
':camel:',
':sheep:',
':elephant:',
':panda_face:',
':snake:',
':bird:',
':baby_chick:',
':hatched_chick:',
':hatching_chick:',
':chicken:',
':penguin:',
':turtle:',
':bug:',
':honeybee:',
':ant:',
':beetle:',
':snail:',
':octopus:',
':tropical_fish:',
':fish:',
':whale:',
':whale2:',
':dolphin:',
':cow2:',
':ram:',
':rat:',
':water_buffalo:',
':tiger2:',
':rabbit2:',
':dragon:',
':goat:',
':rooster:',
':dog2:',
':pig2:',
':mouse2:',
':ox:',
':dragon_face:',
':blowfish:',
':crocodile:',
':dromedary_camel:',
':leopard:',
':cat2:',
':poodle:',
':paw_prints:',
':bouquet:',
':cherry_blossom:',
':tulip:',
':four_leaf_clover:',
':rose:',
':sunflower:',
':hibiscus:',
':maple_leaf:',
':leaves:',
':fallen_leaf:',
':herb:',
':mushroom:',
':cactus:',
':palm_tree:',
':evergreen_tree:',
':deciduous_tree:',
':chestnut:',
':seedling:',
':blossom:',
':ear_of_rice:',
':shell:',
':globe_with_meridians:',
':sun_with_face:',
':full_moon_with_face:',
':new_moon_with_face:',
':new_moon:',
':waxing_crescent_moon:',
':first_quarter_moon:',
':waxing_gibbous_moon:',
':full_moon:',
':waning_gibbous_moon:',
':last_quarter_moon:',
':waning_crescent_moon:',
':last_quarter_moon_with_face:',
':first_quarter_moon_with_face:',
':crescent_moon:',
':earth_africa:',
':earth_americas:',
':earth_asia:',
':volcano:',
':milky_way:',
':partly_sunny:',
':octocat:',
':squirrel:',
':bamboo:',
':gift_heart:',
':dolls:',
':school_satchel:',
':mortar_board:',
':flags:',
':fireworks:',
':sparkler:',
':wind_chime:',
':rice_scene:',
':jack_o_lantern:',
':ghost:',
':santa:',
':christmas_tree:',
':gift:',
':bell:',
':no_bell:',
':tanabata_tree:',
':tada:',
':confetti_ball:',
':balloon:',
':crystal_ball:',
':cd:',
':dvd:',
':floppy_disk:',
':camera:',
':video_camera:',
':movie_camera:',
':computer:',
':tv:',
':iphone:',
':phone:',
':telephone:',
':telephone_receiver:',
':pager:',
':fax:',
':minidisc:',
':vhs:',
':sound:',
':speaker:',
':mute:',
':loudspeaker:',
':mega:',
':hourglass:',
':hourglass_flowing_sand:',
':alarm_clock:',
':watch:',
':radio:',
':satellite:',
':loop:',
':mag:',
':mag_right:',
':unlock:',
':lock:',
':lock_with_ink_pen:',
':closed_lock_with_key:',
':key:',
':bulb:',
':flashlight:',
':high_brightness:',
':low_brightness:',
':electric_plug:',
':battery:',
':calling:',
':email:',
':mailbox:',
':postbox:',
':bath:',
':bathtub:',
':shower:',
':toilet:',
':wrench:',
':nut_and_bolt:',
':hammer:',
':seat:',
':moneybag:',
':yen:',
':dollar:',
':pound:',
':euro:',
':credit_card:',
':money_with_wings:',
':e-mail:',
':inbox_tray:',
':outbox_tray:',
':envelope:',
':incoming_envelope:',
':postal_horn:',
':mailbox_closed:',
':mailbox_with_mail:',
':mailbox_with_no_mail:',
':package:',
':door:',
':smoking:',
':bomb:',
':gun:',
':hocho:',
':pill:',
':syringe:',
':page_facing_up:',
':page_with_curl:',
':bookmark_tabs:',
':bar_chart:',
':chart_with_upwards_trend:',
':chart_with_downwards_trend:',
':scroll:',
':clipboard:',
':calendar:',
':date:',
':card_index:',
':file_folder:',
':open_file_folder:',
':scissors:',
':pushpin:',
':paperclip:',
':black_nib:',
':pencil2:',
':straight_ruler:',
':triangular_ruler:',
':closed_book:',
':green_book:',
':blue_book:',
':orange_book:',
':notebook:',
':notebook_with_decorative_cover:',
':ledger:',
':books:',
':bookmark:',
':name_badge:',
':microscope:',
':telescope:',
':newspaper:',
':football:',
':basketball:',
':soccer:',
':baseball:',
':tennis:',
':8ball:',
':rugby_football:',
':bowling:',
':golf:',
':mountain_bicyclist:',
':bicyclist:',
':horse_racing:',
':snowboarder:',
':swimmer:',
':surfer:',
':ski:',
':spades:',
':hearts:',
':clubs:',
':diamonds:',
':gem:',
':ring:',
':trophy:',
':musical_score:',
':musical_keyboard:',
':violin:',
':space_invader:',
':video_game:',
':black_joker:',
':flower_playing_cards:',
':game_die:',
':dart:',
':mahjong:',
':clapper:',
':memo:',
':pencil:',
':book:',
':art:',
':microphone:',
':headphones:',
':trumpet:',
':saxophone:',
':guitar:',
':shoe:',
':sandal:',
':high_heel:',
':lipstick:',
':boot:',
':shirt:',
':tshirt:',
':necktie:',
':womans_clothes:',
':dress:',
':running_shirt_with_sash:',
':jeans:',
':kimono:',
':bikini:',
':ribbon:',
':tophat:',
':crown:',
':womans_hat:',
':mans_shoe:',
':closed_umbrella:',
':briefcase:',
':handbag:',
':pouch:',
':purse:',
':eyeglasses:',
':fishing_pole_and_fish:',
':coffee:',
':tea:',
':sake:',
':baby_bottle:',
':beer:',
':beers:',
':cocktail:',
':tropical_drink:',
':wine_glass:',
':fork_and_knife:',
':pizza:',
':hamburger:',
':fries:',
':poultry_leg:',
':meat_on_bone:',
':spaghetti:',
':curry:',
':fried_shrimp:',
':bento:',
':sushi:',
':fish_cake:',
':rice_ball:',
':rice_cracker:',
':rice:',
':ramen:',
':stew:',
':oden:',
':dango:',
':egg:',
':bread:',
':doughnut:',
':custard:',
':icecream:',
':ice_cream:',
':shaved_ice:',
':birthday:',
':cake:',
':cookie:',
':chocolate_bar:',
':candy:',
':lollipop:',
':honey_pot:',
':apple:',
':green_apple:',
':tangerine:',
':lemon:',
':cherries:',
':grapes:',
':watermelon:',
':strawberry:',
':peach:',
':melon:',
':banana:',
':pear:',
':pineapple:',
':sweet_potato:',
':eggplant:',
':tomato:',
':corn:',
':house:',
':house_with_garden:',
':school:',
':office:',
':post_office:',
':hospital:',
':bank:',
':convenience_store:',
':love_hotel:',
':hotel:',
':wedding:',
':church:',
':department_store:',
':european_post_office:',
':city_sunrise:',
':city_sunset:',
':japanese_castle:',
':european_castle:',
':tent:',
':factory:',
':tokyo_tower:',
':japan:',
':mount_fuji:',
':sunrise_over_mountains:',
':sunrise:',
':stars:',
':statue_of_liberty:',
':bridge_at_night:',
':carousel_horse:',
':rainbow:',
':ferris_wheel:',
':fountain:',
':roller_coaster:',
':ship:',
':speedboat:',
':boat:',
':sailboat:',
':rowboat:',
':anchor:',
':rocket:',
':airplane:',
':helicopter:',
':steam_locomotive:',
':tram:',
':mountain_railway:',
':bike:',
':aerial_tramway:',
':suspension_railway:',
':mountain_cableway:',
':tractor:',
':blue_car:',
':oncoming_automobile:',
':car:',
':red_car:',
':taxi:',
':oncoming_taxi:',
':articulated_lorry:',
':bus:',
':oncoming_bus:',
':rotating_light:',
':police_car:',
':oncoming_police_car:',
':fire_engine:',
':ambulance:',
':minibus:',
':truck:',
':train:',
':station:',
':train2:',
':bullettrain_front:',
':bullettrain_side:',
':light_rail:',
':monorail:',
':railway_car:',
':trolleybus:',
':ticket:',
':fuelpump:',
':vertical_traffic_light:',
':traffic_light:',
':warning:',
':construction:',
':beginner:',
':atm:',
':slot_machine:',
':busstop:',
':barber:',
':hotsprings:',
':checkered_flag:',
':crossed_flags:',
':izakaya_lantern:',
':moyai:',
':circus_tent:',
':performing_arts:',
':round_pushpin:',
':triangular_flag_on_post:',
':jp:',
':kr:',
':cn:',
':us:',
':fr:',
':es:',
':it:',
':ru:',
':gb:',
':uk:',
':de:',
':one:',
':two:',
':three:',
':four:',
':five:',
':six:',
':seven:',
':eight:',
':nine:',
':keycap_ten:',
':1234:',
':zero:',
':hash:',
':symbols:',
':arrow_backward:',
':arrow_down:',
':arrow_forward:',
':arrow_left:',
':capital_abcd:',
':abcd:',
':abc:',
':arrow_lower_left:',
':arrow_lower_right:',
':arrow_right:',
':arrow_up:',
':arrow_upper_left:',
':arrow_upper_right:',
':arrow_double_down:',
':arrow_double_up:',
':arrow_down_small:',
':arrow_heading_down:',
':arrow_heading_up:',
':leftwards_arrow_with_hook:',
':arrow_right_hook:',
':left_right_arrow:',
':arrow_up_down:',
':arrow_up_small:',
':arrows_clockwise:',
':arrows_counterclockwise:',
':rewind:',
':fast_forward:',
':information_source:',
':ok:',
':twisted_rightwards_arrows:',
':repeat:',
':repeat_one:',
':new:',
':top:',
':up:',
':cool:',
':free:',
':ng:',
':cinema:',
':koko:',
':signal_strength:',
':u5272:',
':u5408:',
':u55b6:',
':u6307:',
':u6708:',
':u6709:',
':u6e80:',
':u7121:',
':u7533:',
':u7a7a:',
':u7981:',
':sa:',
':restroom:',
':mens:',
':womens:',
':baby_symbol:',
':no_smoking:',
':parking:',
':wheelchair:',
':metro:',
':baggage_claim:',
':accept:',
':wc:',
':potable_water:',
':put_litter_in_its_place:',
':secret:',
':congratulations:',
':m:',
':passport_control:',
':left_luggage:',
':customs:',
':ideograph_advantage:',
':cl:',
':sos:',
':id:',
':no_entry_sign:',
':underage:',
':no_mobile_phones:',
':do_not_litter:',
':non-potable_water:',
':no_bicycles:',
':no_pedestrians:',
':children_crossing:',
':no_entry:',
':eight_spoked_asterisk:',
':sparkle:',
':eight_pointed_black_star:',
':heart_decoration:',
':vs:',
':vibration_mode:',
':mobile_phone_off:',
':chart:',
':currency_exchange:',
':aries:',
':taurus:',
':gemini:',
':cancer:',
':leo:',
':virgo:',
':libra:',
':scorpius:',
':sagittarius:',
':capricorn:',
':aquarius:',
':pisces:',
':ophiuchus:',
':six_pointed_star:',
':negative_squared_cross_mark:',
':a:',
':b:',
':ab:',
':o2:',
':diamond_shape_with_a_dot_inside:',
':recycle:',
':end:',
':back:',
':on:',
':soon:',
':clock1:',
':clock130:',
':clock10:',
':clock1030:',
':clock11:',
':clock1130:',
':clock12:',
':clock1230:',
':clock2:',
':clock230:',
':clock3:',
':clock330:',
':clock4:',
':clock430:',
':clock5:',
':clock530:',
':clock6:',
':clock630:',
':clock7:',
':clock730:',
':clock8:',
':clock830:',
':clock9:',
':clock930:',
':heavy_dollar_sign:',
':copyright:',
':registered:',
':tm:',
':x:',
':heavy_exclamation_mark:',
':bangbang:',
':interrobang:',
':o:',
':heavy_multiplication_x:',
':heavy_plus_sign:',
':heavy_minus_sign:',
':heavy_division_sign:',
':white_flower:',
':100:',
':heavy_check_mark:',
':ballot_box_with_check:',
':radio_button:',
':link:',
':curly_loop:',
':wavy_dash:',
':part_alternation_mark:',
':trident:',
':black_small_square:',
':white_small_square:',
':black_medium_small_square:',
':white_medium_small_square:',
':black_medium_square:',
':white_medium_square:',
':white_large_square:',
':white_check_mark:',
':black_square_button:',
':white_square_button:',
':black_circle:',
':white_circle:',
':red_circle:',
':large_blue_circle:',
':large_blue_diamond:',
':large_orange_diamond:',
':small_blue_diamond:',
':small_orange_diamond:',
':small_red_triangle:',
':small_red_triangle_down:',
':shipit:'
]
};
// Add all emoji in a dropdown
$.extend(true, $.trumbowyg, {
langs: {
// jshint camelcase:false
en: {
emoji: 'Add an emoji'
},
fr: {
emoji: 'Ajouter un emoji'
},
zh_cn: {
emoji: '添加表情'
},
ru: {
emoji: 'Вставить emoji'
},
ja: {
emoji: '絵文字の挿入'
}
},
// jshint camelcase:true
plugins: {
emoji: {
init: function (trumbowyg) {
trumbowyg.o.plugins.emoji = trumbowyg.o.plugins.emoji || defaultOptions;
var emojiBtnDef = {
dropdown: buildDropdown(trumbowyg)
};
trumbowyg.addBtnDef('emoji', emojiBtnDef);
}
}
}
});
function buildDropdown(trumbowyg) {
var dropdown = [];
$.each(trumbowyg.o.plugins.emoji.emojiList, function (i, emoji) {
if ($.isArray(emoji)) { // Custom emoji behaviour
var emojiCode = emoji[0],
emojiUrl = emoji[1],
emojiHtml = '<img src="' + emojiUrl + '" alt="' + emojiCode + '">',
customEmojiBtnName = 'emoji-' + emojiCode.replace(/:/g, ''),
customEmojiBtnDef = {
hasIcon: false,
text: emojiHtml,
fn: function () {
trumbowyg.execCmd('insertImage', emojiUrl, false, true);
return true;
}
};
trumbowyg.addBtnDef(customEmojiBtnName, customEmojiBtnDef);
dropdown.push(customEmojiBtnName);
} else { // Default behaviour
var btn = emoji.replace(/:/g, ''),
defaultEmojiBtnName = 'emoji-' + btn,
defaultEmojiBtnDef = {
text: emoji,
fn: function () {
trumbowyg.execCmd('insertText', emoji);
return true;
}
};
trumbowyg.addBtnDef(defaultEmojiBtnName, defaultEmojiBtnDef);
dropdown.push(defaultEmojiBtnName);
}
});
return dropdown;
}
})(jQuery);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,56 @@
/**
* Trumbowyg v2.8.1 - A lightweight WYSIWYG editor
* Default stylesheet for Trumbowyg editor plugin
* ------------------------
* @link http://alex-d.github.io/Trumbowyg
* @license MIT
* @author Alexandre Demode (Alex-D)
* Twitter : @AlexandreDemode
* Website : alex-d.fr
*/
.trumbowyg-dropdown-emoji {
width: 265px;
padding: 7px 0 7px 5px;
height: 200px;
overflow-y: scroll;
overflow-x: hidden;
}
.trumbowyg-dropdown-emoji svg {
display: none !important;
}
.trumbowyg-dropdown-emoji button {
display: block;
position: relative;
float: left;
height: 26px;
width: 26px;
padding: 0;
margin: 2px;
line-height: 24px;
text-align: center;
&:hover,
&:focus {
&::after {
display: block;
position: absolute;
top: -5px;
left: -5px;
height: 27px;
width: 27px;
background: inherit;
box-shadow: #000 0 0 2px;
z-index: 10;
background-color: transparent;
}
}
}
.trumbowyg .emoji {
width: 22px;
height: 22px;
display: inline-block;
}

View File

@ -0,0 +1,47 @@
/**
* Trumbowyg v2.8.1 - A lightweight WYSIWYG editor
* Trumbowyg plugin stylesheet
* ------------------------
* @link http://alex-d.github.io/Trumbowyg
* @license MIT
* @author Alexandre Demode (Alex-D)
* Twitter : @AlexandreDemode
* Website : alex-d.fr
*/
.trumbowyg-dropdown-emoji {
width: 265px;
padding: 7px 0 7px 5px;
height: 200px;
overflow-y: scroll;
overflow-x: hidden; }
.trumbowyg-dropdown-emoji svg {
display: none !important; }
.trumbowyg-dropdown-emoji button {
display: block;
position: relative;
float: left;
height: 26px;
width: 26px;
padding: 0;
margin: 2px;
line-height: 24px;
text-align: center; }
.trumbowyg-dropdown-emoji button:hover::after, .trumbowyg-dropdown-emoji button:focus::after {
display: block;
position: absolute;
top: -5px;
left: -5px;
height: 27px;
width: 27px;
background: inherit;
box-shadow: #000 0 0 2px;
z-index: 10;
background-color: transparent; }
.trumbowyg .emoji {
width: 22px;
height: 22px;
display: inline-block; }

View File

@ -0,0 +1,2 @@
/** Trumbowyg v2.8.1 - A lightweight WYSIWYG editor - alex-d.github.io/Trumbowyg - License MIT - Author : Alexandre Demode (Alex-D) / alex-d.fr */
.trumbowyg-dropdown-emoji{width:265px;padding:7px 0 7px 5px;height:200px;overflow-y:scroll;overflow-x:hidden}.trumbowyg-dropdown-emoji svg{display:none!important}.trumbowyg-dropdown-emoji button{display:block;position:relative;float:left;height:26px;width:26px;padding:0;margin:2px;line-height:24px;text-align:center}.trumbowyg-dropdown-emoji button:focus::after,.trumbowyg-dropdown-emoji button:hover::after{display:block;position:absolute;top:-5px;left:-5px;height:27px;width:27px;background:inherit;box-shadow:#000 0 0 2px;z-index:10;background-color:transparent}.trumbowyg .emoji{width:22px;height:22px;display:inline-block}

View File

@ -0,0 +1,83 @@
/*/* ===========================================================
* trumbowyg.insertaudio.js v1.0
* InsertAudio plugin for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Adam Hess (AdamHess)
*/
(function ($) {
'use strict';
var insertAudioOptions = {
src: {
label: 'URL',
required: true
},
autoplay: {
label: 'AutoPlay',
required: false,
type: 'checkbox'
},
muted: {
label: 'Muted',
required: false,
type: 'checkbox'
},
preload: {
label: 'preload options',
required: false
}
};
$.extend(true, $.trumbowyg, {
langs: {
en: {
insertAudio: 'Insert Audio'
},
ru: {
insertAudio: 'Вставить аудио'
},
ja: {
insertAudio: '音声の挿入'
}
},
plugins: {
insertAudio: {
init: function (trumbowyg) {
var btnDef = {
fn: function () {
var insertAudioCallback = function (v) {
// controls should always be show otherwise the audio will
// be invisible defeating the point of a wysiwyg
var html = '<audio controls';
if (v.src) {
html += ' src=\'' + v.src + '\'';
}
if (v.autoplay) {
html += ' autoplay';
}
if (v.muted) {
html += ' muted';
}
if (v.preload) {
html += ' preload=\'' + v + '\'';
}
html += '></audio>';
var node = $(html)[0];
trumbowyg.range.deleteContents();
trumbowyg.range.insertNode(node);
return true;
};
trumbowyg.openModalInsert(trumbowyg.lang.insertAudio, insertAudioOptions, insertAudioCallback);
}
};
trumbowyg.addBtnDef('insertAudio', btnDef);
}
}
}
});
})(jQuery);

View File

@ -0,0 +1 @@
!function(e){"use strict";var r={src:{label:"URL",required:!0},autoplay:{label:"AutoPlay",required:!1,type:"checkbox"},muted:{label:"Muted",required:!1,type:"checkbox"},preload:{label:"preload options",required:!1}};e.extend(!0,e.trumbowyg,{langs:{en:{insertAudio:"Insert Audio"},ru:{insertAudio:"Вставить аудио"},ja:{insertAudio:"音声の挿入"}},plugins:{insertAudio:{init:function(t){var n={fn:function(){var n=function(r){var n="<audio controls";r.src&&(n+=" src='"+r.src+"'"),r.autoplay&&(n+=" autoplay"),r.muted&&(n+=" muted"),r.preload&&(n+=" preload='"+r+"'"),n+="></audio>";var o=e(n)[0];return t.range.deleteContents(),t.range.insertNode(o),!0};t.openModalInsert(t.lang.insertAudio,r,n)}};t.addBtnDef("insertAudio",n)}}}})}(jQuery);

View File

@ -0,0 +1,101 @@
/* ===========================================================
* trumbowyg.noembed.js v1.0
* noEmbed plugin for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Jake Johns (jakejohns)
*/
(function ($) {
'use strict';
var defaultOptions = {
proxy: 'https://noembed.com/embed?nowrap=on',
urlFiled: 'url',
data: [],
success: undefined,
error: undefined
};
$.extend(true, $.trumbowyg, {
langs: {
en: {
noembed: 'Noembed',
noembedError: 'Error'
},
sk: {
noembedError: 'Chyba'
},
fr: {
noembedError: 'Erreur'
},
cs: {
noembedError: 'Chyba'
},
ru: {
noembedError: 'Ошибка'
},
ja: {
noembedError: 'エラー'
}
},
plugins: {
noembed: {
init: function (trumbowyg) {
trumbowyg.o.plugins.noembed = $.extend(true, {}, defaultOptions, trumbowyg.o.plugins.noembed || {});
var btnDef = {
fn: function () {
var $modal = trumbowyg.openModalInsert(
// Title
trumbowyg.lang.noembed,
// Fields
{
url: {
label: 'URL',
required: true
}
},
// Callback
function (data) {
$.ajax({
url: trumbowyg.o.plugins.noembed.proxy,
type: 'GET',
data: data,
cache: false,
dataType: 'json',
success: trumbowyg.o.plugins.noembed.success || function (data) {
if (data.html) {
trumbowyg.execCmd('insertHTML', data.html);
setTimeout(function () {
trumbowyg.closeModal();
}, 250);
} else {
trumbowyg.addErrorOnModalField(
$('input[type=text]', $modal),
data.error
);
}
},
error: trumbowyg.o.plugins.noembed.error || function () {
trumbowyg.addErrorOnModalField(
$('input[type=text]', $modal),
trumbowyg.lang.noembedError
);
}
});
}
);
}
};
trumbowyg.addBtnDef('noembed', btnDef);
}
}
}
});
})(jQuery);

View File

@ -0,0 +1 @@
!function(e){"use strict";var r={proxy:"https://noembed.com/embed?nowrap=on",urlFiled:"url",data:[],success:void 0,error:void 0};e.extend(!0,e.trumbowyg,{langs:{en:{noembed:"Noembed",noembedError:"Error"},sk:{noembedError:"Chyba"},fr:{noembedError:"Erreur"},cs:{noembedError:"Chyba"},ru:{noembedError:"Ошибка"},ja:{noembedError:"エラー"}},plugins:{noembed:{init:function(o){o.o.plugins.noembed=e.extend(!0,{},r,o.o.plugins.noembed||{});var n={fn:function(){var r=o.openModalInsert(o.lang.noembed,{url:{label:"URL",required:!0}},function(n){e.ajax({url:o.o.plugins.noembed.proxy,type:"GET",data:n,cache:!1,dataType:"json",success:o.o.plugins.noembed.success||function(n){n.html?(o.execCmd("insertHTML",n.html),setTimeout(function(){o.closeModal()},250)):o.addErrorOnModalField(e("input[type=text]",r),n.error)},error:o.o.plugins.noembed.error||function(){o.addErrorOnModalField(e("input[type=text]",r),o.lang.noembedError)}})})}};o.addBtnDef("noembed",n)}}}})}(jQuery);

View File

@ -0,0 +1,41 @@
/* ===========================================================
* trumbowyg.pasteimage.js v1.0
* Basic base64 paste plugin for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Alexandre Demode (Alex-D)
* Twitter : @AlexandreDemode
* Website : alex-d.fr
*/
(function ($) {
'use strict';
$.extend(true, $.trumbowyg, {
plugins: {
pasteImage: {
init: function (trumbowyg) {
trumbowyg.pasteHandlers.push(function (pasteEvent) {
try {
var items = (pasteEvent.originalEvent || pasteEvent).clipboardData.items,
reader;
for (var i = items.length -1; i >= 0; i += 1) {
if (items[i].type.match(/^image\//)) {
reader = new FileReader();
/* jshint -W083 */
reader.onloadend = function (event) {
trumbowyg.execCmd('insertImage', event.target.result, undefined, true);
};
/* jshint +W083 */
reader.readAsDataURL(items[i].getAsFile());
}
}
} catch (c) {
}
});
}
}
}
});
})(jQuery);

View File

@ -0,0 +1 @@
!function(e){"use strict";e.extend(!0,e.trumbowyg,{plugins:{pasteImage:{init:function(e){e.pasteHandlers.push(function(t){try{for(var a,n=(t.originalEvent||t).clipboardData.items,i=n.length-1;i>=0;i+=1)n[i].type.match(/^image\//)&&(a=new FileReader,a.onloadend=function(t){e.execCmd("insertImage",t.target.result,void 0,!0)},a.readAsDataURL(n[i].getAsFile()))}catch(r){}})}}}})}(jQuery);

View File

@ -0,0 +1,123 @@
/* ===========================================================
* trumbowyg.preformatted.js v1.0
* Preformatted plugin for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Casella Edoardo (Civile)
*/
(function ($) {
'use strict';
$.extend(true, $.trumbowyg, {
langs: {
// jshint camelcase:false
en: {
preformatted: 'Code sample <pre>'
},
fr: {
preformatted: 'Exemple de code'
},
it: {
preformatted: 'Codice <pre>'
},
zh_cn: {
preformatted: '代码示例 <pre>'
},
ru: {
preformatted: 'Пример кода <pre>'
},
ja: {
preformatted: 'コードサンプル <pre>'
}
},
// jshint camelcase:true
plugins: {
preformatted: {
init: function (trumbowyg) {
var btnDef = {
fn: function () {
trumbowyg.saveRange();
var text = trumbowyg.getRangeText();
if (text.replace(/\s/g, '') !== '') {
try {
var curtag = getSelectionParentElement().tagName.toLowerCase();
if (curtag === 'code' || curtag === 'pre') {
return unwrapCode();
}
else {
trumbowyg.execCmd('insertHTML', '<pre><code>' + strip(text) + '</code></pre>');
}
} catch (e) {
}
}
},
tag: 'pre'
};
trumbowyg.addBtnDef('preformatted', btnDef);
}
}
}
});
/*
* GetSelectionParentElement
*/
function getSelectionParentElement() {
var parentEl = null,
selection;
if (window.getSelection) {
selection = window.getSelection();
if (selection.rangeCount) {
parentEl = selection.getRangeAt(0).commonAncestorContainer;
if (parentEl.nodeType !== 1) {
parentEl = parentEl.parentNode;
}
}
} else if ((selection = document.selection) && selection.type !== 'Control') {
parentEl = selection.createRange().parentElement();
}
return parentEl;
}
/*
* Strip
* returns a text without HTML tags
*/
function strip(html) {
var tmp = document.createElement('DIV');
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || '';
}
/*
* UnwrapCode
* ADD/FIX: to improve, works but can be better
* "paranoic" solution
*/
function unwrapCode() {
var container = null;
if (document.selection) { //for IE
container = document.selection.createRange().parentElement();
} else {
var select = window.getSelection();
if (select.rangeCount > 0) {
container = select.getRangeAt(0).startContainer.parentNode;
}
}
//'paranoic' unwrap
var ispre = $(container).contents().closest('pre').length;
var iscode = $(container).contents().closest('code').length;
if (ispre && iscode) {
$(container).contents().unwrap('code').unwrap('pre');
} else if (ispre) {
$(container).contents().unwrap('pre');
} else if (iscode) {
$(container).contents().unwrap('code');
}
}
})(jQuery);

View File

@ -0,0 +1 @@
!function(e){"use strict";function t(){var e,t=null;return window.getSelection?(e=window.getSelection(),e.rangeCount&&(t=e.getRangeAt(0).commonAncestorContainer,1!==t.nodeType&&(t=t.parentNode))):(e=document.selection)&&"Control"!==e.type&&(t=e.createRange().parentElement()),t}function n(e){var t=document.createElement("DIV");return t.innerHTML=e,t.textContent||t.innerText||""}function r(){var t=null;if(document.selection)t=document.selection.createRange().parentElement();else{var n=window.getSelection();n.rangeCount>0&&(t=n.getRangeAt(0).startContainer.parentNode)}var r=e(t).contents().closest("pre").length,o=e(t).contents().closest("code").length;r&&o?e(t).contents().unwrap("code").unwrap("pre"):r?e(t).contents().unwrap("pre"):o&&e(t).contents().unwrap("code")}e.extend(!0,e.trumbowyg,{langs:{en:{preformatted:"Code sample <pre>"},fr:{preformatted:"Exemple de code"},it:{preformatted:"Codice <pre>"},zh_cn:{preformatted:"代码示例 <pre>"},ru:{preformatted:"Пример кода <pre>"},ja:{preformatted:"コードサンプル <pre>"}},plugins:{preformatted:{init:function(e){var o={fn:function(){e.saveRange();var o=e.getRangeText();if(""!==o.replace(/\s/g,""))try{var a=t().tagName.toLowerCase();if("code"===a||"pre"===a)return r();e.execCmd("insertHTML","<pre><code>"+n(o)+"</code></pre>")}catch(c){}},tag:"pre"};e.addBtnDef("preformatted",o)}}}})}(jQuery);

View File

@ -0,0 +1,154 @@
/* ===========================================================
* trumbowyg.table.js v1.2
* Table plugin for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Lawrence Meckan
* Twitter : @absalomedia
* Website : absalom.biz
*/
(function ($) {
'use strict';
var defaultOptions = {
rows: 0,
columns: 0,
styler: ''
};
$.extend(true, $.trumbowyg, {
langs: {
en: {
table: 'Insert table',
tableAddRow: 'Add rows',
tableAddColumn: 'Add columns',
rows: 'Rows',
columns: 'Columns',
styler: 'Table class',
error: 'Error'
},
sk: {
table: 'Vytvoriť tabuľky',
tableAddRow: 'Pridať riadok',
tableAddColumn: 'Pridať stĺpec',
rows: 'Riadky',
columns: 'Stĺpce',
styler: 'Tabuľku triedy',
error: 'Chyba'
},
fr: {
table: 'Insérer un tableau',
tableAddRow: 'Ajouter des lignes',
tableAddColumn: 'Ajouter des colonnes',
rows: 'Lignes',
columns: 'Colonnes',
styler: 'Classes CSS sur la table',
error: 'Erreur'
},
cs: {
table: 'Vytvořit příkaz Table',
tableAddRow: 'Přidat řádek',
tableAddColumn: 'Přidat sloupec',
rows: 'Řádky',
columns: 'Sloupce',
styler: 'Tabulku třída',
error: 'Chyba'
},
ru: {
table: 'Вставить таблицу',
tableAddRow: 'Добавить строки',
tableAddColumn: 'Добавить столбцы',
rows: 'Строки',
columns: 'Столбцы',
styler: 'Имя CSS класса для таблицы',
error: 'Ошибка'
},
ja: {
table: '表の挿入',
tableAddRow: '行の追加',
tableAddColumn: '列の追加',
rows: '行',
columns: '列',
styler: '表のクラス',
error: 'エラー'
}
},
plugins: {
table: {
init: function (trumbowyg) {
trumbowyg.o.plugins.table = $.extend(true, {}, defaultOptions, trumbowyg.o.plugins.table || {});
var tableBuild = {
fn: function () {
trumbowyg.saveRange();
trumbowyg.openModalInsert(
// Title
trumbowyg.lang.table,
// Fields
{
rows: {
type: 'number',
required: true
},
columns: {
type: 'number',
required: true
},
styler: {
label: trumbowyg.lang.styler,
type: 'text'
}
},
function (v) { // v is value
var tabler = $('<table></table>');
if (v.styler.length !== 0) {
tabler.addClass(v.styler);
}
for (var i = 0; i < v.rows; i += 1) {
var row = $('<tr></tr>').appendTo(tabler);
for (var j = 0; j < v.columns; j += 1) {
$('<td></td>').appendTo(row);
}
}
trumbowyg.range.deleteContents();
trumbowyg.range.insertNode(tabler[0]);
return true;
});
}
};
var addRow = {
fn: function () {
trumbowyg.saveRange();
var rower = $('<tr></tr>');
trumbowyg.range.deleteContents();
trumbowyg.range.insertNode(rower[0]);
return true;
}
};
var addColumn = {
fn: function () {
trumbowyg.saveRange();
var columner = $('<td></td>');
trumbowyg.range.deleteContents();
trumbowyg.range.insertNode(columner[0]);
return true;
}
};
trumbowyg.addBtnDef('table', tableBuild);
trumbowyg.addBtnDef('tableAddRow', addRow);
trumbowyg.addBtnDef('tableAddColumn', addColumn);
}
}
}
});
})(jQuery);

View File

@ -0,0 +1 @@
!function(e){"use strict";var t={rows:0,columns:0,styler:""};e.extend(!0,e.trumbowyg,{langs:{en:{table:"Insert table",tableAddRow:"Add rows",tableAddColumn:"Add columns",rows:"Rows",columns:"Columns",styler:"Table class",error:"Error"},sk:{table:"Vytvoriť tabuľky",tableAddRow:"Pridať riadok",tableAddColumn:"Pridať stĺpec",rows:"Riadky",columns:"Stĺpce",styler:"Tabuľku triedy",error:"Chyba"},fr:{table:"Insérer un tableau",tableAddRow:"Ajouter des lignes",tableAddColumn:"Ajouter des colonnes",rows:"Lignes",columns:"Colonnes",styler:"Classes CSS sur la table",error:"Erreur"},cs:{table:"Vytvořit příkaz Table",tableAddRow:"Přidat řádek",tableAddColumn:"Přidat sloupec",rows:"Řádky",columns:"Sloupce",styler:"Tabulku třída",error:"Chyba"},ru:{table:"Вставить таблицу",tableAddRow:"Добавить строки",tableAddColumn:"Добавить столбцы",rows:"Строки",columns:"Столбцы",styler:"Имя CSS класса для таблицы",error:"Ошибка"},ja:{table:"表の挿入",tableAddRow:"行の追加",tableAddColumn:"列の追加",rows:"行",columns:"列",styler:"表のクラス",error:"エラー"}},plugins:{table:{init:function(r){r.o.plugins.table=e.extend(!0,{},t,r.o.plugins.table||{});var l={fn:function(){r.saveRange(),r.openModalInsert(r.lang.table,{rows:{type:"number",required:!0},columns:{type:"number",required:!0},styler:{label:r.lang.styler,type:"text"}},function(t){var l=e("<table></table>");0!==t.styler.length&&l.addClass(t.styler);for(var n=0;n<t.rows;n+=1)for(var a=e("<tr></tr>").appendTo(l),o=0;o<t.columns;o+=1)e("<td></td>").appendTo(a);return r.range.deleteContents(),r.range.insertNode(l[0]),!0})}},n={fn:function(){r.saveRange();var t=e("<tr></tr>");return r.range.deleteContents(),r.range.insertNode(t[0]),!0}},a={fn:function(){r.saveRange();var t=e("<td></td>");return r.range.deleteContents(),r.range.insertNode(t[0]),!0}};r.addBtnDef("table",l),r.addBtnDef("tableAddRow",n),r.addBtnDef("tableAddColumn",a)}}}})}(jQuery);

View File

@ -0,0 +1,58 @@
(function($) {
'use strict';
// Adds the language variables
$.extend(true, $.trumbowyg, {
langs: {
en: {
template: 'Template'
},
nl: {
template: 'Sjabloon'
},
ru: {
template: 'Шаблон'
},
ja: {
template: 'テンプレート'
}
}
});
// Adds the extra button definition
$.extend(true, $.trumbowyg, {
plugins: {
template: {
shouldInit: function(trumbowyg) {
return trumbowyg.o.plugins.hasOwnProperty('templates');
},
init: function(trumbowyg) {
trumbowyg.addBtnDef('template', {
dropdown: templateSelector(trumbowyg),
hasIcon: false,
text: trumbowyg.lang.template
});
}
}
}
});
// Creates the template-selector dropdown.
function templateSelector(trumbowyg) {
var available = trumbowyg.o.plugins.templates;
var templates = [];
$.each(available, function(index, template) {
trumbowyg.addBtnDef('template_' + index, {
fn: function(){
trumbowyg.html(template.html);
},
hasIcon: false,
title: template.name
});
templates.push('template_' + index);
});
return templates;
}
})(jQuery);

View File

@ -0,0 +1 @@
!function(t){"use strict";function e(e){var n=e.o.plugins.templates,a=[];return t.each(n,function(t,n){e.addBtnDef("template_"+t,{fn:function(){e.html(n.html)},hasIcon:!1,title:n.name}),a.push("template_"+t)}),a}t.extend(!0,t.trumbowyg,{langs:{en:{template:"Template"},nl:{template:"Sjabloon"},ru:{template:"Шаблон"},ja:{template:"テンプレート"}}}),t.extend(!0,t.trumbowyg,{plugins:{template:{shouldInit:function(t){return t.o.plugins.hasOwnProperty("templates")},init:function(t){t.addBtnDef("template",{dropdown:e(t),hasIcon:!1,text:t.lang.template})}}}})}(jQuery);

View File

@ -0,0 +1,242 @@
/* ===========================================================
* trumbowyg.upload.js v1.2
* Upload plugin for Trumbowyg
* http://alex-d.github.com/Trumbowyg
* ===========================================================
* Author : Alexandre Demode (Alex-D)
* Twitter : @AlexandreDemode
* Website : alex-d.fr
* Mod by : Aleksandr-ru
* Twitter : @Aleksandr_ru
* Website : aleksandr.ru
*/
(function ($) {
'use strict';
var defaultOptions = {
serverPath: '',
fileFieldName: 'fileToUpload',
data: [], // Additional data for ajax [{name: 'key', value: 'value'}]
headers: {}, // Additional headers
xhrFields: {}, // Additional fields
urlPropertyName: 'file', // How to get url from the json response (for instance 'url' for {url: ....})
statusPropertyName: 'success', // How to get status from the json response
success: undefined, // Success callback: function (data, trumbowyg, $modal, values) {}
error: undefined // Error callback: function () {}
};
function getDeep(object, propertyParts) {
var mainProperty = propertyParts.shift(),
otherProperties = propertyParts;
if (object !== null) {
if (otherProperties.length === 0) {
return object[mainProperty];
}
if (typeof object === 'object') {
return getDeep(object[mainProperty], otherProperties);
}
}
return object;
}
addXhrProgressEvent();
$.extend(true, $.trumbowyg, {
langs: {
// jshint camelcase:false
en: {
upload: 'Upload',
file: 'File',
uploadError: 'Error'
},
sk: {
upload: 'Nahrať',
file: 'Súbor',
uploadError: 'Chyba'
},
fr: {
upload: 'Envoi',
file: 'Fichier',
uploadError: 'Erreur'
},
cs: {
upload: 'Nahrát obrázek',
file: 'Soubor',
uploadError: 'Chyba'
},
zh_cn: {
upload: '上传',
file: '文件',
uploadError: '错误'
},
zh_tw: {
upload: '上傳',
file: '文件',
uploadError: '錯誤'
},
ru: {
upload: 'Загрузка',
file: 'Файл',
uploadError: 'Ошибка'
},
ja: {
upload: 'アップロード',
file: 'ファイル',
uploadError: 'エラー'
},
pt_br: {
upload: 'Enviar do local',
file: 'Arquivo',
uploadError: 'Erro'
},
},
// jshint camelcase:true
plugins: {
upload: {
init: function (trumbowyg) {
trumbowyg.o.plugins.upload = $.extend(true, {}, defaultOptions, trumbowyg.o.plugins.upload || {});
var btnDef = {
fn: function () {
trumbowyg.saveRange();
var file,
prefix = trumbowyg.o.prefix;
var $modal = trumbowyg.openModalInsert(
// Title
trumbowyg.lang.upload,
// Fields
{
file: {
type: 'file',
required: true,
attributes: {
accept: 'image/*'
}
},
alt: {
label: 'description',
value: trumbowyg.getRangeText()
}
},
// Callback
function (values) {
var data = new FormData();
data.append(trumbowyg.o.plugins.upload.fileFieldName, file);
trumbowyg.o.plugins.upload.data.map(function (cur) {
data.append(cur.name, cur.value);
});
$.map(values, function(curr, key){
if(key !== 'file') {
data.append(key, curr);
}
});
if ($('.' + prefix + 'progress', $modal).length === 0) {
$('.' + prefix + 'modal-title', $modal)
.after(
$('<div/>', {
'class': prefix + 'progress'
}).append(
$('<div/>', {
'class': prefix + 'progress-bar'
})
)
);
}
$.ajax({
url: trumbowyg.o.plugins.upload.serverPath,
headers: trumbowyg.o.plugins.upload.headers,
xhrFields: trumbowyg.o.plugins.upload.xhrFields,
type: 'POST',
data: data,
cache: false,
dataType: 'json',
processData: false,
contentType: false,
progressUpload: function (e) {
$('.' + prefix + 'progress-bar').css('width', Math.round(e.loaded * 100 / e.total) + '%');
},
success: function (data) {
if (trumbowyg.o.plugins.upload.success) {
trumbowyg.o.plugins.upload.success(data, trumbowyg, $modal, values);
} else {
if (!!getDeep(data, trumbowyg.o.plugins.upload.statusPropertyName.split('.'))) {
var url = getDeep(data, trumbowyg.o.plugins.upload.urlPropertyName.split('.'));
trumbowyg.execCmd('insertImage', url);
$('img[src="' + url + '"]:not([alt])', trumbowyg.$box).attr('alt', values.alt);
setTimeout(function () {
trumbowyg.closeModal();
}, 250);
trumbowyg.$c.trigger('tbwuploadsuccess', [trumbowyg, data, url]);
} else {
trumbowyg.addErrorOnModalField(
$('input[type=file]', $modal),
trumbowyg.lang[data.message]
);
trumbowyg.$c.trigger('tbwuploaderror', [trumbowyg, data]);
}
}
},
error: trumbowyg.o.plugins.upload.error || function () {
trumbowyg.addErrorOnModalField(
$('input[type=file]', $modal),
trumbowyg.lang.uploadError
);
trumbowyg.$c.trigger('tbwuploaderror', [trumbowyg]);
}
});
}
);
$('input[type=file]').on('change', function (e) {
try {
// If multiple files allowed, we just get the first.
file = e.target.files[0];
} catch (err) {
// In IE8, multiple files not allowed
file = e.target.value;
}
});
}
};
trumbowyg.addBtnDef('upload', btnDef);
}
}
}
});
function addXhrProgressEvent() {
if (!$.trumbowyg.addedXhrProgressEvent) { // Avoid adding progress event multiple times
var originalXhr = $.ajaxSettings.xhr;
$.ajaxSetup({
xhr: function () {
var req = originalXhr(),
that = this;
if (req && typeof req.upload === 'object' && that.progressUpload !== undefined) {
req.upload.addEventListener('progress', function (e) {
that.progressUpload(e);
}, false);
}
return req;
}
});
$.trumbowyg.addedXhrProgressEvent = true;
}
}
})(jQuery);

View File

@ -0,0 +1 @@
!function(r){"use strict";function e(r,a){var o=a.shift(),l=a;if(null!==r){if(0===l.length)return r[o];if("object"==typeof r)return e(r[o],l)}return r}function a(){if(!r.trumbowyg.addedXhrProgressEvent){var e=r.ajaxSettings.xhr;r.ajaxSetup({xhr:function(){var r=e(),a=this;return r&&"object"==typeof r.upload&&void 0!==a.progressUpload&&r.upload.addEventListener("progress",function(r){a.progressUpload(r)},!1),r}}),r.trumbowyg.addedXhrProgressEvent=!0}}var o={serverPath:"",fileFieldName:"fileToUpload",data:[],headers:{},xhrFields:{},urlPropertyName:"file",statusPropertyName:"success",success:void 0,error:void 0};a(),r.extend(!0,r.trumbowyg,{langs:{en:{upload:"Upload",file:"File",uploadError:"Error"},sk:{upload:"Nahrať",file:"Súbor",uploadError:"Chyba"},fr:{upload:"Envoi",file:"Fichier",uploadError:"Erreur"},cs:{upload:"Nahrát obrázek",file:"Soubor",uploadError:"Chyba"},zh_cn:{upload:"上传",file:"文件",uploadError:"错误"},zh_tw:{upload:"上傳",file:"文件",uploadError:"錯誤"},ru:{upload:"Загрузка",file:"Файл",uploadError:"Ошибка"},ja:{upload:"アップロード",file:"ファイル",uploadError:"エラー"},pt_br:{upload:"Enviar do local",file:"Arquivo",uploadError:"Erro"}},plugins:{upload:{init:function(a){a.o.plugins.upload=r.extend(!0,{},o,a.o.plugins.upload||{});var l={fn:function(){a.saveRange();var o,l=a.o.prefix,t=a.openModalInsert(a.lang.upload,{file:{type:"file",required:!0,attributes:{accept:"image/*"}},alt:{label:"description",value:a.getRangeText()}},function(u){var p=new FormData;p.append(a.o.plugins.upload.fileFieldName,o),a.o.plugins.upload.data.map(function(r){p.append(r.name,r.value)}),r.map(u,function(r,e){"file"!==e&&p.append(e,r)}),0===r("."+l+"progress",t).length&&r("."+l+"modal-title",t).after(r("<div/>",{"class":l+"progress"}).append(r("<div/>",{"class":l+"progress-bar"}))),r.ajax({url:a.o.plugins.upload.serverPath,headers:a.o.plugins.upload.headers,xhrFields:a.o.plugins.upload.xhrFields,type:"POST",data:p,cache:!1,dataType:"json",processData:!1,contentType:!1,progressUpload:function(e){r("."+l+"progress-bar").css("width",Math.round(100*e.loaded/e.total)+"%")},success:function(o){if(a.o.plugins.upload.success)a.o.plugins.upload.success(o,a,t,u);else if(e(o,a.o.plugins.upload.statusPropertyName.split("."))){var l=e(o,a.o.plugins.upload.urlPropertyName.split("."));a.execCmd("insertImage",l),r('img[src="'+l+'"]:not([alt])',a.$box).attr("alt",u.alt),setTimeout(function(){a.closeModal()},250),a.$c.trigger("tbwuploadsuccess",[a,o,l])}else a.addErrorOnModalField(r("input[type=file]",t),a.lang[o.message]),a.$c.trigger("tbwuploaderror",[a,o])},error:a.o.plugins.upload.error||function(){a.addErrorOnModalField(r("input[type=file]",t),a.lang.uploadError),a.$c.trigger("tbwuploaderror",[a])}})});r("input[type=file]").on("change",function(r){try{o=r.target.files[0]}catch(e){o=r.target.value}})}};a.addBtnDef("upload",l)}}}})}(jQuery);

File diff suppressed because it is too large Load Diff

2
public/trumbowyg/trumbowyg.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,796 @@
/**
* Trumbowyg v2.8.1 - A lightweight WYSIWYG editor
* Default stylesheet for Trumbowyg editor
* ------------------------
* @link http://alex-d.github.io/Trumbowyg
* @license MIT
* @author Alexandre Demode (Alex-D)
* Twitter : @AlexandreDemode
* Website : alex-d.fr
*/
$light-color: #ecf0f1 !default;
$dark-color: #222 !default;
$modal-submit-color: #2ecc71 !default;
$modal-reset-color: #EEE !default;
$transition-duration: 150ms !default;
$slow-transition-duration: 300ms !default;
#trumbowyg-icons {
overflow: hidden;
visibility: hidden;
height: 0;
width: 0;
svg {
height: 0;
width: 0;
}
}
.trumbowyg-box {
*,
*::before,
*::after {
box-sizing: border-box;
}
svg {
width: 17px;
height: 100%;
fill: $dark-color;
}
}
.trumbowyg-box,
.trumbowyg-editor {
display: block;
position: relative;
border: 1px solid #DDD;
width: 100%;
min-height: 300px;
margin: 17px auto;
}
.trumbowyg-box .trumbowyg-editor {
margin: 0 auto;
}
.trumbowyg-box.trumbowyg-fullscreen {
background: #FEFEFE;
border: none !important;
}
.trumbowyg-editor,
.trumbowyg-textarea {
position: relative;
box-sizing: border-box;
padding: 20px;
min-height: 300px;
width: 100%;
border-style: none;
resize: none;
outline: none;
overflow: auto;
&.trumbowyg-autogrow-on-enter {
transition: height $slow-transition-duration ease-out;
}
}
.trumbowyg-box-blur .trumbowyg-editor {
*,
&::before {
color: transparent !important;
text-shadow: 0 0 7px #333;
@media screen and (min-width: 0 \0) {
color: rgba(200, 200, 200, 0.6) !important;
}
@supports (-ms-accelerator:true) {
color: rgba(200, 200, 200, 0.6) !important;
}
}
img,
hr {
opacity: 0.2;
}
}
.trumbowyg-textarea {
position: relative;
display: block;
overflow: auto;
border: none;
white-space: normal;
font-size: 14px;
font-family: "Inconsolata", "Consolas", "Courier", "Courier New", sans-serif;
line-height: 18px;
}
.trumbowyg-box.trumbowyg-editor-visible {
.trumbowyg-textarea {
height: 1px !important;
width: 25%;
min-height: 0 !important;
padding: 0 !important;
background: none;
opacity: 0 !important;
}
}
.trumbowyg-box.trumbowyg-editor-hidden {
.trumbowyg-textarea {
display: block;
}
.trumbowyg-editor {
display: none;
}
}
.trumbowyg-box.trumbowyg-disabled {
.trumbowyg-textarea {
opacity: 0.8;
background: none;
}
}
.trumbowyg-editor[contenteditable=true]:empty:not(:focus)::before {
content: attr(placeholder);
color: #999;
pointer-events: none;
}
.trumbowyg-button-pane {
width: 100%;
min-height: 36px;
background: $light-color;
border-bottom: 1px solid darken($light-color, 7%);
margin: 0;
padding: 0 5px;
position: relative;
list-style-type: none;
line-height: 10px;
backface-visibility: hidden;
z-index: 11;
&::after {
content: " ";
display: block;
position: absolute;
top: 36px;
left: 0;
right: 0;
width: 100%;
height: 1px;
background: darken($light-color, 7%);
}
.trumbowyg-button-group {
display: inline-block;
.trumbowyg-fullscreen-button svg {
color: transparent;
}
&:not(:empty) + .trumbowyg-button-group::before {
content: " ";
display: inline-block;
width: 1px;
background: darken($light-color, 7%);
margin: 0 5px;
height: 35px;
vertical-align: top;
}
}
button {
display: inline-block;
position: relative;
width: 35px;
height: 35px;
padding: 1px 6px !important;
margin-bottom: 1px;
overflow: hidden;
border: none;
cursor: pointer;
background: none;
vertical-align: middle;
transition: background-color $transition-duration, opacity $transition-duration;
&.trumbowyg-textual-button {
width: auto;
line-height: 35px;
user-select: none;
}
}
&.trumbowyg-disable button:not(.trumbowyg-not-disable):not(.trumbowyg-active),
.trumbowyg-disabled & button:not(.trumbowyg-not-disable):not(.trumbowyg-viewHTML-button) {
opacity: 0.2;
cursor: default;
}
&.trumbowyg-disable,
.trumbowyg-disabled & {
.trumbowyg-button-group::before {
background: darken($light-color, 3%);
}
}
button:not(.trumbowyg-disable):hover,
button:not(.trumbowyg-disable):focus,
button.trumbowyg-active {
background-color: #FFF;
outline: none;
}
.trumbowyg-open-dropdown {
&::after {
display: block;
content: " ";
position: absolute;
top: 25px;
right: 3px;
height: 0;
width: 0;
border: 3px solid transparent;
border-top-color: #555;
}
&.trumbowyg-textual-button {
padding-left: 10px !important;
padding-right: 18px !important;
&::after {
top: 17px;
right: 7px;
}
}
}
.trumbowyg-right {
float: right;
&::before {
display: none !important;
}
}
}
.trumbowyg-dropdown {
width: 200px;
border: 1px solid $light-color;
padding: 5px 0;
border-top: none;
background: #FFF;
margin-left: -1px;
box-shadow: rgba(0, 0, 0, .1) 0 2px 3px;
z-index: 11;
button {
display: block;
width: 100%;
height: 35px;
line-height: 35px;
text-decoration: none;
background: #FFF;
padding: 0 10px;
color: #333 !important;
border: none;
cursor: pointer;
text-align: left;
font-size: 15px;
transition: all $transition-duration;
&:hover,
&:focus {
background: $light-color;
}
svg {
float: left;
margin-right: 14px;
}
}
}
/* Modal box */
.trumbowyg-modal {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
max-width: 520px;
width: 100%;
height: 350px;
z-index: 11;
overflow: hidden;
backface-visibility: hidden;
}
.trumbowyg-modal-box {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
max-width: 500px;
width: calc(100% - 20px);
padding-bottom: 45px;
z-index: 1;
background-color: #FFF;
text-align: center;
font-size: 14px;
box-shadow: rgba(0, 0, 0, .2) 0 2px 3px;
backface-visibility: hidden;
.trumbowyg-modal-title {
font-size: 24px;
font-weight: bold;
margin: 0 0 20px;
padding: 15px 0 13px;
display: block;
border-bottom: 1px solid #EEE;
color: #333;
background: lighten($light-color, 5%);
}
.trumbowyg-progress {
width: 100%;
height: 3px;
position: absolute;
top: 58px;
.trumbowyg-progress-bar {
background: #2BC06A;
width: 0;
height: 100%;
transition: width $transition-duration linear;
}
}
label {
display: block;
position: relative;
margin: 15px 12px;
height: 29px;
line-height: 29px;
overflow: hidden;
.trumbowyg-input-infos {
display: block;
text-align: left;
height: 25px;
line-height: 25px;
transition: all 150ms;
span {
display: block;
color: darken($light-color, 45%);
background-color: lighten($light-color, 5%);
border: 1px solid #DEDEDE;
padding: 0 7px;
width: 150px;
}
span.trumbowyg-msg-error {
color: #e74c3c;
}
}
&.trumbowyg-input-error {
input,
textarea {
border: 1px solid #e74c3c;
}
.trumbowyg-input-infos {
margin-top: -27px;
}
}
input {
position: absolute;
top: 0;
right: 0;
height: 27px;
line-height: 27px;
border: 1px solid #DEDEDE;
background: #fff;
font-size: 14px;
max-width: 330px;
width: 70%;
padding: 0 7px;
transition: all $transition-duration;
&:hover,
&:focus {
outline: none;
border: 1px solid #95a5a6;
}
&:focus {
background: lighten($light-color, 5%);
}
}
}
.error {
margin-top: 25px;
display: block;
color: red;
}
.trumbowyg-modal-button {
position: absolute;
bottom: 10px;
right: 0;
text-decoration: none;
color: #FFF;
display: block;
width: 100px;
height: 35px;
line-height: 33px;
margin: 0 10px;
background-color: #333;
border: none;
cursor: pointer;
font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif;
font-size: 16px;
transition: all $transition-duration;
&.trumbowyg-modal-submit {
right: 110px;
background: darken($modal-submit-color, 3%);
&:hover,
&:focus {
background: lighten($modal-submit-color, 5%);
outline: none;
}
&:active {
background: darken($modal-submit-color, 10%);
}
}
&.trumbowyg-modal-reset {
color: #555;
background: darken($modal-reset-color, 3%);
&:hover,
&:focus {
background: lighten($modal-reset-color, 5%);
outline: none;
}
&:active {
background: darken($modal-reset-color, 10%);
}
}
}
}
.trumbowyg-overlay {
position: absolute;
background-color: rgba(255, 255, 255, 0.5);
height: 100%;
width: 100%;
left: 0;
display: none;
top: 0;
z-index: 10;
}
/**
* Fullscreen
*/
body.trumbowyg-body-fullscreen {
overflow: hidden;
}
.trumbowyg-fullscreen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
z-index: 99999;
&.trumbowyg-box,
.trumbowyg-editor {
border: none;
}
.trumbowyg-editor,
.trumbowyg-textarea {
height: calc(100% - 37px) !important;
overflow: auto;
}
.trumbowyg-overlay {
height: 100% !important;
}
.trumbowyg-button-group .trumbowyg-fullscreen-button svg {
color: $dark-color;
fill: transparent;
}
}
.trumbowyg-editor {
object,
embed,
video,
img {
max-width: 100%;
}
video,
img {
height: auto;
}
img {
cursor: move;
}
/*
* lset for resetCss option
*/
&.trumbowyg-reset-css {
background: #FEFEFE !important;
font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif !important;
font-size: 14px !important;
line-height: 1.45em !important;
white-space: normal !important;
color: #333;
a {
color: #15c !important;
text-decoration: underline !important;
}
div,
p,
ul,
ol,
blockquote {
box-shadow: none !important;
background: none !important;
margin: 0 !important;
margin-bottom: 15px !important;
line-height: 1.4em !important;
font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif !important;
font-size: 14px !important;
border: none;
}
iframe,
object,
hr {
margin-bottom: 15px !important;
}
blockquote {
margin-left: 32px !important;
font-style: italic !important;
color: #555;
}
ul,
ol {
padding-left: 20px !important;
}
ul ul,
ol ol,
ul ol,
ol ul {
border: none;
margin: 2px !important;
padding: 0 !important;
padding-left: 24px !important;
}
hr {
display: block;
height: 1px;
border: none;
border-top: 1px solid #CCC;
}
h1,
h2,
h3,
h4 {
color: #111;
background: none;
margin: 0 !important;
padding: 0 !important;
font-weight: bold;
}
h1 {
font-size: 32px !important;
line-height: 38px !important;
margin-bottom: 20px !important;
}
h2 {
font-size: 26px !important;
line-height: 34px !important;
margin-bottom: 15px !important;
}
h3 {
font-size: 22px !important;
line-height: 28px !important;
margin-bottom: 7px !important;
}
h4 {
font-size: 16px !important;
line-height: 22px !important;
margin-bottom: 7px !important;
}
}
}
/*
* Dark theme
*/
.trumbowyg-dark {
.trumbowyg-textarea {
background: #111;
color: #ddd;
}
.trumbowyg-box {
border: 1px solid lighten($dark-color, 7%);
&.trumbowyg-fullscreen {
background: #111;
}
&.trumbowyg-box-blur .trumbowyg-editor {
*,
&::before {
text-shadow: 0 0 7px #ccc;
@media screen and (min-width: 0 \0
) {
color: rgba(20, 20, 20, 0.6) !important;
}
@supports (-ms-accelerator:true) {
color: rgba(20, 20, 20, 0.6) !important;
}
}
}
svg {
fill: $light-color;
color: $light-color;
}
}
.trumbowyg-button-pane {
background-color: $dark-color;
border-bottom-color: lighten($dark-color, 7%);
&::after {
background: lighten($dark-color, 7%);
}
.trumbowyg-button-group:not(:empty) {
&::before {
background-color: lighten($dark-color, 7%);
}
.trumbowyg-fullscreen-button svg {
color: transparent;
}
}
&.trumbowyg-disable {
.trumbowyg-button-group::before {
background-color: lighten($dark-color, 3%);
}
}
button:not(.trumbowyg-disable):hover,
button:not(.trumbowyg-disable):focus,
button.trumbowyg-active {
background-color: #333;
}
.trumbowyg-open-dropdown::after {
border-top-color: #fff;
}
}
.trumbowyg-fullscreen {
.trumbowyg-button-group .trumbowyg-fullscreen-button svg {
color: $light-color;
fill: transparent;
}
}
.trumbowyg-dropdown {
border-color: $dark-color;
background: #333;
box-shadow: rgba(0, 0, 0, .3) 0 2px 3px;
button {
background: #333;
color: #fff !important;
&:hover,
&:focus {
background: $dark-color;
}
}
}
// Modal box
.trumbowyg-modal-box {
background-color: $dark-color;
.trumbowyg-modal-title {
border-bottom: 1px solid #555;
color: #fff;
background: lighten($dark-color, 10%);
}
label {
display: block;
position: relative;
margin: 15px 12px;
height: 27px;
line-height: 27px;
overflow: hidden;
.trumbowyg-input-infos {
span {
color: #eee;
background-color: lighten($dark-color, 5%);
border-color: $dark-color;
}
span.trumbowyg-msg-error {
color: #e74c3c;
}
}
&.trumbowyg-input-error {
input,
textarea {
border-color: #e74c3c;
}
}
input {
border-color: $dark-color;
color: #eee;
background: #333;
&:hover,
&:focus {
border-color: lighten($dark-color, 25%);
}
&:focus {
background-color: lighten($dark-color, 5%);
}
}
}
.trumbowyg-modal-button {
&.trumbowyg-modal-submit {
background: darken($modal-submit-color, 20%);
&:hover,
&:focus {
background: darken($modal-submit-color, 10%);
}
&:active {
background: darken($modal-submit-color, 25%);
}
}
&.trumbowyg-modal-reset {
background: #333;
color: #ccc;
&:hover,
&:focus {
background: #444;
}
&:active {
background: #111;
}
}
}
}
.trumbowyg-overlay {
background-color: rgba(15, 15, 15, 0.6);
}
}

View File

@ -0,0 +1,584 @@
/**
* Trumbowyg v2.8.1 - A lightweight WYSIWYG editor
* Default stylesheet for Trumbowyg editor
* ------------------------
* @link http://alex-d.github.io/Trumbowyg
* @license MIT
* @author Alexandre Demode (Alex-D)
* Twitter : @AlexandreDemode
* Website : alex-d.fr
*/
#trumbowyg-icons {
overflow: hidden;
visibility: hidden;
height: 0;
width: 0; }
#trumbowyg-icons svg {
height: 0;
width: 0; }
.trumbowyg-box *,
.trumbowyg-box *::before,
.trumbowyg-box *::after {
box-sizing: border-box; }
.trumbowyg-box svg {
width: 17px;
height: 100%;
fill: #222; }
.trumbowyg-box,
.trumbowyg-editor {
display: block;
position: relative;
border: 1px solid #DDD;
width: 100%;
min-height: 300px;
margin: 17px auto; }
.trumbowyg-box .trumbowyg-editor {
margin: 0 auto; }
.trumbowyg-box.trumbowyg-fullscreen {
background: #FEFEFE;
border: none !important; }
.trumbowyg-editor,
.trumbowyg-textarea {
position: relative;
box-sizing: border-box;
padding: 20px;
min-height: 300px;
width: 100%;
border-style: none;
resize: none;
outline: none;
overflow: auto; }
.trumbowyg-editor.trumbowyg-autogrow-on-enter,
.trumbowyg-textarea.trumbowyg-autogrow-on-enter {
transition: height 300ms ease-out; }
.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-box-blur .trumbowyg-editor::before {
color: transparent !important;
text-shadow: 0 0 7px #333; }
@media screen and (min-width: 0 \0) {
.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-box-blur .trumbowyg-editor::before {
color: rgba(200, 200, 200, 0.6) !important; } }
@supports (-ms-accelerator: true) {
.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-box-blur .trumbowyg-editor::before {
color: rgba(200, 200, 200, 0.6) !important; } }
.trumbowyg-box-blur .trumbowyg-editor img,
.trumbowyg-box-blur .trumbowyg-editor hr {
opacity: 0.2; }
.trumbowyg-textarea {
position: relative;
display: block;
overflow: auto;
border: none;
white-space: normal;
font-size: 14px;
font-family: "Inconsolata", "Consolas", "Courier", "Courier New", sans-serif;
line-height: 18px; }
.trumbowyg-box.trumbowyg-editor-visible .trumbowyg-textarea {
height: 1px !important;
width: 25%;
min-height: 0 !important;
padding: 0 !important;
background: none;
opacity: 0 !important; }
.trumbowyg-box.trumbowyg-editor-hidden .trumbowyg-textarea {
display: block; }
.trumbowyg-box.trumbowyg-editor-hidden .trumbowyg-editor {
display: none; }
.trumbowyg-box.trumbowyg-disabled .trumbowyg-textarea {
opacity: 0.8;
background: none; }
.trumbowyg-editor[contenteditable=true]:empty:not(:focus)::before {
content: attr(placeholder);
color: #999;
pointer-events: none; }
.trumbowyg-button-pane {
width: 100%;
min-height: 36px;
background: #ecf0f1;
border-bottom: 1px solid #d7e0e2;
margin: 0;
padding: 0 5px;
position: relative;
list-style-type: none;
line-height: 10px;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
z-index: 11; }
.trumbowyg-button-pane::after {
content: " ";
display: block;
position: absolute;
top: 36px;
left: 0;
right: 0;
width: 100%;
height: 1px;
background: #d7e0e2; }
.trumbowyg-button-pane .trumbowyg-button-group {
display: inline-block; }
.trumbowyg-button-pane .trumbowyg-button-group .trumbowyg-fullscreen-button svg {
color: transparent; }
.trumbowyg-button-pane .trumbowyg-button-group:not(:empty) + .trumbowyg-button-group::before {
content: " ";
display: inline-block;
width: 1px;
background: #d7e0e2;
margin: 0 5px;
height: 35px;
vertical-align: top; }
.trumbowyg-button-pane button {
display: inline-block;
position: relative;
width: 35px;
height: 35px;
padding: 1px 6px !important;
margin-bottom: 1px;
overflow: hidden;
border: none;
cursor: pointer;
background: none;
vertical-align: middle;
transition: background-color 150ms, opacity 150ms; }
.trumbowyg-button-pane button.trumbowyg-textual-button {
width: auto;
line-height: 35px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
.trumbowyg-button-pane.trumbowyg-disable button:not(.trumbowyg-not-disable):not(.trumbowyg-active),
.trumbowyg-disabled .trumbowyg-button-pane button:not(.trumbowyg-not-disable):not(.trumbowyg-viewHTML-button) {
opacity: 0.2;
cursor: default; }
.trumbowyg-button-pane.trumbowyg-disable .trumbowyg-button-group::before,
.trumbowyg-disabled .trumbowyg-button-pane .trumbowyg-button-group::before {
background: #e3e9eb; }
.trumbowyg-button-pane button:not(.trumbowyg-disable):hover,
.trumbowyg-button-pane button:not(.trumbowyg-disable):focus,
.trumbowyg-button-pane button.trumbowyg-active {
background-color: #FFF;
outline: none; }
.trumbowyg-button-pane .trumbowyg-open-dropdown::after {
display: block;
content: " ";
position: absolute;
top: 25px;
right: 3px;
height: 0;
width: 0;
border: 3px solid transparent;
border-top-color: #555; }
.trumbowyg-button-pane .trumbowyg-open-dropdown.trumbowyg-textual-button {
padding-left: 10px !important;
padding-right: 18px !important; }
.trumbowyg-button-pane .trumbowyg-open-dropdown.trumbowyg-textual-button::after {
top: 17px;
right: 7px; }
.trumbowyg-button-pane .trumbowyg-right {
float: right; }
.trumbowyg-button-pane .trumbowyg-right::before {
display: none !important; }
.trumbowyg-dropdown {
width: 200px;
border: 1px solid #ecf0f1;
padding: 5px 0;
border-top: none;
background: #FFF;
margin-left: -1px;
box-shadow: rgba(0, 0, 0, 0.1) 0 2px 3px;
z-index: 11; }
.trumbowyg-dropdown button {
display: block;
width: 100%;
height: 35px;
line-height: 35px;
text-decoration: none;
background: #FFF;
padding: 0 10px;
color: #333 !important;
border: none;
cursor: pointer;
text-align: left;
font-size: 15px;
transition: all 150ms; }
.trumbowyg-dropdown button:hover, .trumbowyg-dropdown button:focus {
background: #ecf0f1; }
.trumbowyg-dropdown button svg {
float: left;
margin-right: 14px; }
/* Modal box */
.trumbowyg-modal {
position: absolute;
top: 0;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
max-width: 520px;
width: 100%;
height: 350px;
z-index: 11;
overflow: hidden;
-webkit-backface-visibility: hidden;
backface-visibility: hidden; }
.trumbowyg-modal-box {
position: absolute;
top: 0;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
max-width: 500px;
width: calc(100% - 20px);
padding-bottom: 45px;
z-index: 1;
background-color: #FFF;
text-align: center;
font-size: 14px;
box-shadow: rgba(0, 0, 0, 0.2) 0 2px 3px;
-webkit-backface-visibility: hidden;
backface-visibility: hidden; }
.trumbowyg-modal-box .trumbowyg-modal-title {
font-size: 24px;
font-weight: bold;
margin: 0 0 20px;
padding: 15px 0 13px;
display: block;
border-bottom: 1px solid #EEE;
color: #333;
background: #fbfcfc; }
.trumbowyg-modal-box .trumbowyg-progress {
width: 100%;
height: 3px;
position: absolute;
top: 58px; }
.trumbowyg-modal-box .trumbowyg-progress .trumbowyg-progress-bar {
background: #2BC06A;
width: 0;
height: 100%;
transition: width 150ms linear; }
.trumbowyg-modal-box label {
display: block;
position: relative;
margin: 15px 12px;
height: 29px;
line-height: 29px;
overflow: hidden; }
.trumbowyg-modal-box label .trumbowyg-input-infos {
display: block;
text-align: left;
height: 25px;
line-height: 25px;
transition: all 150ms; }
.trumbowyg-modal-box label .trumbowyg-input-infos span {
display: block;
color: #69878f;
background-color: #fbfcfc;
border: 1px solid #DEDEDE;
padding: 0 7px;
width: 150px; }
.trumbowyg-modal-box label .trumbowyg-input-infos span.trumbowyg-msg-error {
color: #e74c3c; }
.trumbowyg-modal-box label.trumbowyg-input-error input,
.trumbowyg-modal-box label.trumbowyg-input-error textarea {
border: 1px solid #e74c3c; }
.trumbowyg-modal-box label.trumbowyg-input-error .trumbowyg-input-infos {
margin-top: -27px; }
.trumbowyg-modal-box label input {
position: absolute;
top: 0;
right: 0;
height: 27px;
line-height: 27px;
border: 1px solid #DEDEDE;
background: #fff;
font-size: 14px;
max-width: 330px;
width: 70%;
padding: 0 7px;
transition: all 150ms; }
.trumbowyg-modal-box label input:hover, .trumbowyg-modal-box label input:focus {
outline: none;
border: 1px solid #95a5a6; }
.trumbowyg-modal-box label input:focus {
background: #fbfcfc; }
.trumbowyg-modal-box .error {
margin-top: 25px;
display: block;
color: red; }
.trumbowyg-modal-box .trumbowyg-modal-button {
position: absolute;
bottom: 10px;
right: 0;
text-decoration: none;
color: #FFF;
display: block;
width: 100px;
height: 35px;
line-height: 33px;
margin: 0 10px;
background-color: #333;
border: none;
cursor: pointer;
font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif;
font-size: 16px;
transition: all 150ms; }
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit {
right: 110px;
background: #2bc06a; }
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:hover, .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:focus {
background: #40d47e;
outline: none; }
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:active {
background: #25a25a; }
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset {
color: #555;
background: #e6e6e6; }
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:hover, .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:focus {
background: #fbfbfb;
outline: none; }
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:active {
background: #d5d5d5; }
.trumbowyg-overlay {
position: absolute;
background-color: rgba(255, 255, 255, 0.5);
height: 100%;
width: 100%;
left: 0;
display: none;
top: 0;
z-index: 10; }
/**
* Fullscreen
*/
body.trumbowyg-body-fullscreen {
overflow: hidden; }
.trumbowyg-fullscreen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
z-index: 99999; }
.trumbowyg-fullscreen.trumbowyg-box,
.trumbowyg-fullscreen .trumbowyg-editor {
border: none; }
.trumbowyg-fullscreen .trumbowyg-editor,
.trumbowyg-fullscreen .trumbowyg-textarea {
height: calc(100% - 37px) !important;
overflow: auto; }
.trumbowyg-fullscreen .trumbowyg-overlay {
height: 100% !important; }
.trumbowyg-fullscreen .trumbowyg-button-group .trumbowyg-fullscreen-button svg {
color: #222;
fill: transparent; }
.trumbowyg-editor {
/*
* lset for resetCss option
*/ }
.trumbowyg-editor object,
.trumbowyg-editor embed,
.trumbowyg-editor video,
.trumbowyg-editor img {
max-width: 100%; }
.trumbowyg-editor video,
.trumbowyg-editor img {
height: auto; }
.trumbowyg-editor img {
cursor: move; }
.trumbowyg-editor.trumbowyg-reset-css {
background: #FEFEFE !important;
font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif !important;
font-size: 14px !important;
line-height: 1.45em !important;
white-space: normal !important;
color: #333; }
.trumbowyg-editor.trumbowyg-reset-css a {
color: #15c !important;
text-decoration: underline !important; }
.trumbowyg-editor.trumbowyg-reset-css div,
.trumbowyg-editor.trumbowyg-reset-css p,
.trumbowyg-editor.trumbowyg-reset-css ul,
.trumbowyg-editor.trumbowyg-reset-css ol,
.trumbowyg-editor.trumbowyg-reset-css blockquote {
box-shadow: none !important;
background: none !important;
margin: 0 !important;
margin-bottom: 15px !important;
line-height: 1.4em !important;
font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif !important;
font-size: 14px !important;
border: none; }
.trumbowyg-editor.trumbowyg-reset-css iframe,
.trumbowyg-editor.trumbowyg-reset-css object,
.trumbowyg-editor.trumbowyg-reset-css hr {
margin-bottom: 15px !important; }
.trumbowyg-editor.trumbowyg-reset-css blockquote {
margin-left: 32px !important;
font-style: italic !important;
color: #555; }
.trumbowyg-editor.trumbowyg-reset-css ul,
.trumbowyg-editor.trumbowyg-reset-css ol {
padding-left: 20px !important; }
.trumbowyg-editor.trumbowyg-reset-css ul ul,
.trumbowyg-editor.trumbowyg-reset-css ol ol,
.trumbowyg-editor.trumbowyg-reset-css ul ol,
.trumbowyg-editor.trumbowyg-reset-css ol ul {
border: none;
margin: 2px !important;
padding: 0 !important;
padding-left: 24px !important; }
.trumbowyg-editor.trumbowyg-reset-css hr {
display: block;
height: 1px;
border: none;
border-top: 1px solid #CCC; }
.trumbowyg-editor.trumbowyg-reset-css h1,
.trumbowyg-editor.trumbowyg-reset-css h2,
.trumbowyg-editor.trumbowyg-reset-css h3,
.trumbowyg-editor.trumbowyg-reset-css h4 {
color: #111;
background: none;
margin: 0 !important;
padding: 0 !important;
font-weight: bold; }
.trumbowyg-editor.trumbowyg-reset-css h1 {
font-size: 32px !important;
line-height: 38px !important;
margin-bottom: 20px !important; }
.trumbowyg-editor.trumbowyg-reset-css h2 {
font-size: 26px !important;
line-height: 34px !important;
margin-bottom: 15px !important; }
.trumbowyg-editor.trumbowyg-reset-css h3 {
font-size: 22px !important;
line-height: 28px !important;
margin-bottom: 7px !important; }
.trumbowyg-editor.trumbowyg-reset-css h4 {
font-size: 16px !important;
line-height: 22px !important;
margin-bottom: 7px !important; }
/*
* Dark theme
*/
.trumbowyg-dark .trumbowyg-textarea {
background: #111;
color: #ddd; }
.trumbowyg-dark .trumbowyg-box {
border: 1px solid #343434; }
.trumbowyg-dark .trumbowyg-box.trumbowyg-fullscreen {
background: #111; }
.trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor::before {
text-shadow: 0 0 7px #ccc; }
@media screen and (min-width: 0 \0 ) {
.trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor::before {
color: rgba(20, 20, 20, 0.6) !important; } }
@supports (-ms-accelerator: true) {
.trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor::before {
color: rgba(20, 20, 20, 0.6) !important; } }
.trumbowyg-dark .trumbowyg-box svg {
fill: #ecf0f1;
color: #ecf0f1; }
.trumbowyg-dark .trumbowyg-button-pane {
background-color: #222;
border-bottom-color: #343434; }
.trumbowyg-dark .trumbowyg-button-pane::after {
background: #343434; }
.trumbowyg-dark .trumbowyg-button-pane .trumbowyg-button-group:not(:empty)::before {
background-color: #343434; }
.trumbowyg-dark .trumbowyg-button-pane .trumbowyg-button-group:not(:empty) .trumbowyg-fullscreen-button svg {
color: transparent; }
.trumbowyg-dark .trumbowyg-button-pane.trumbowyg-disable .trumbowyg-button-group::before {
background-color: #2a2a2a; }
.trumbowyg-dark .trumbowyg-button-pane button:not(.trumbowyg-disable):hover,
.trumbowyg-dark .trumbowyg-button-pane button:not(.trumbowyg-disable):focus,
.trumbowyg-dark .trumbowyg-button-pane button.trumbowyg-active {
background-color: #333; }
.trumbowyg-dark .trumbowyg-button-pane .trumbowyg-open-dropdown::after {
border-top-color: #fff; }
.trumbowyg-dark .trumbowyg-fullscreen .trumbowyg-button-group .trumbowyg-fullscreen-button svg {
color: #ecf0f1;
fill: transparent; }
.trumbowyg-dark .trumbowyg-dropdown {
border-color: #222;
background: #333;
box-shadow: rgba(0, 0, 0, 0.3) 0 2px 3px; }
.trumbowyg-dark .trumbowyg-dropdown button {
background: #333;
color: #fff !important; }
.trumbowyg-dark .trumbowyg-dropdown button:hover, .trumbowyg-dark .trumbowyg-dropdown button:focus {
background: #222; }
.trumbowyg-dark .trumbowyg-modal-box {
background-color: #222; }
.trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-title {
border-bottom: 1px solid #555;
color: #fff;
background: #3c3c3c; }
.trumbowyg-dark .trumbowyg-modal-box label {
display: block;
position: relative;
margin: 15px 12px;
height: 27px;
line-height: 27px;
overflow: hidden; }
.trumbowyg-dark .trumbowyg-modal-box label .trumbowyg-input-infos span {
color: #eee;
background-color: #2f2f2f;
border-color: #222; }
.trumbowyg-dark .trumbowyg-modal-box label .trumbowyg-input-infos span.trumbowyg-msg-error {
color: #e74c3c; }
.trumbowyg-dark .trumbowyg-modal-box label.trumbowyg-input-error input,
.trumbowyg-dark .trumbowyg-modal-box label.trumbowyg-input-error textarea {
border-color: #e74c3c; }
.trumbowyg-dark .trumbowyg-modal-box label input {
border-color: #222;
color: #eee;
background: #333; }
.trumbowyg-dark .trumbowyg-modal-box label input:hover, .trumbowyg-dark .trumbowyg-modal-box label input:focus {
border-color: #626262; }
.trumbowyg-dark .trumbowyg-modal-box label input:focus {
background-color: #2f2f2f; }
.trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit {
background: #1b7943; }
.trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:hover, .trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:focus {
background: #25a25a; }
.trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:active {
background: #176437; }
.trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset {
background: #333;
color: #ccc; }
.trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:hover, .trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:focus {
background: #444; }
.trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:active {
background: #111; }
.trumbowyg-dark .trumbowyg-overlay {
background-color: rgba(15, 15, 15, 0.6); }

View File

@ -0,0 +1,550 @@
/**
* Trumbowyg v2.8.1 - A lightweight WYSIWYG editor
* Default stylesheet for Trumbowyg editor. Modified by Azareal.
* ------------------------
* @link http://alex-d.github.io/Trumbowyg & https://github.com/Azareal/Gosora
* @license MIT
* @author Alexandre Demode (Alex-D)
* @author Azareal
*/
#trumbowyg-icons {
overflow: hidden;
visibility: hidden;
height: 0;
width: 0;
}
#trumbowyg-icons svg {
height: 0;
width: 0;
}
.trumbowyg-box *, .trumbowyg-box *::before, .trumbowyg-box *::after {
box-sizing: border-box;
}
.trumbowyg-box svg {
width: 17px;
height: 100%;
fill: #222222;
color: #222222;
opacity: 0.5;
}
.trumbowyg-box svg:hover {
width: 17px;
height: 100%;
fill: #222222;
color: #222222;
opacity: 0.75;
}
.trumbowyg-box, .trumbowyg-editor {
display: block;
position: relative;
width: 100%;
min-height: 150px;
margin: 0;
}
.trumbowyg-box.trumbowyg-fullscreen {
background: #FEFEFE;
border: none !important;
}
.trumbowyg-editor, .trumbowyg-textarea {
position: relative;
box-sizing: border-box;
padding: 20px;
min-height: 150px;
width: 100%;
border-style: none;
resize: none;
outline: none;
border: 1px solid #DDD;
overflow: hidden;
word-wrap: break-word;
overflow-wrap: break-word;
}
.trumbowyg-editor.trumbowyg-autogrow-on-enter, .trumbowyg-textarea.trumbowyg-autogrow-on-enter {
transition: height 150ms ease-out;
}
.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-box-blur .trumbowyg-editor::before {
color: transparent !important;
text-shadow: 0 0 7px #333; }
@media screen and (min-width: 0 \0) {
.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-box-blur .trumbowyg-editor::before {
color: rgba(200, 200, 200, 0.6) !important;
}
}
.trumbowyg-box-blur .trumbowyg-editor img, .trumbowyg-box-blur .trumbowyg-editor hr {
opacity: 0.2;
}
.trumbowyg-textarea {
position: relative;
display: block;
overflow: auto;
border: none;
white-space: normal;
font-size: 14px;
font-family: "Inconsolata", "Consolas", "Courier", "Courier New", sans-serif;
line-height: 18px;
}
.trumbowyg-box.trumbowyg-editor-visible .trumbowyg-textarea {
height: 1px !important;
width: 25%;
min-height: 0 !important;
padding: 0 !important;
background: none;
opacity: 0 !important;
}
.trumbowyg-box.trumbowyg-editor-hidden .trumbowyg-textarea {
display: block;
}
.trumbowyg-box.trumbowyg-editor-hidden .trumbowyg-editor {
display: none;
}
.trumbowyg-box.trumbowyg-disabled .trumbowyg-textarea {
opacity: 0.8;
background: none;
}
.trumbowyg-editor[contenteditable=true]:empty:not(:focus)::before {
content: attr(placeholder);
color: #999;
pointer-events: none;
}
.trumbowyg-button-pane {
min-height: 36px;
margin: 0;
padding: 0px 5px;
position: relative;
list-style-type: none;
line-height: 10px;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
z-index: 11;
display: flex;
}
.trumbowyg-button-pane::after {
content: " ";
display: block;
position: absolute;
top: 36px;
left: 0;
right: 0;
width: 100%;
height: 1px;
background: #d7e0e2;
}
.trumbowyg-button-pane .trumbowyg-button-group {
display: inline-block;
}
.trumbowyg-button-pane .trumbowyg-button-group:first-child {
margin-left: 10px;
}
.trumbowyg-button-pane .trumbowyg-button-group:last-child {
margin-right: auto;
}
.trumbowyg-button-pane .trumbowyg-button-group .trumbowyg-fullscreen-button svg {
color: transparent;
}
.trumbowyg-button-pane .trumbowyg-button-group:after {
content: "";
display: inline-block;
width: 1px;
margin: 0 5px;
height: 20px;
vertical-align: top;
border-right: 1px solid #d7e0e2;
margin-top: 8px;
}
.trumbowyg-button-pane .trumbowyg-button-group:first-child:before {
content: "";
display: inline-block;
width: 1px;
margin: 0 5px;
margin-right: 5px;
margin-bottom: 0px;
margin-left: 5px;
height: 20px;
vertical-align: top;
border-right: 1px solid #d7e0e2;
margin-top: 8px;
}
.trumbowyg-button-pane button {
display: inline-block;
position: relative;
width: 35px;
height: 35px;
padding: 1px 6px !important;
margin-bottom: 1px;
overflow: hidden;
border: none;
cursor: pointer;
background: none;
vertical-align: middle;
transition: background-color 150ms, opacity 150ms;
}
.trumbowyg-button-pane button.trumbowyg-textual-button {
width: auto;
line-height: 35px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.trumbowyg-button-pane.trumbowyg-disable button:not(.trumbowyg-not-disable):not(.trumbowyg-active), .trumbowyg-disabled .trumbowyg-button-pane button:not(.trumbowyg-not-disable):not(.trumbowyg-viewHTML-button) {
opacity: 0.2;
cursor: default;
}
.trumbowyg-button-pane.trumbowyg-disable .trumbowyg-button-group::before, .trumbowyg-disabled .trumbowyg-button-pane .trumbowyg-button-group::before {
background: #e3e9eb;
}
.trumbowyg-button-pane button:not(.trumbowyg-disable):hover, .trumbowyg-button-pane button:not(.trumbowyg-disable):focus, .trumbowyg-button-pane button.trumbowyg-active {
background-color: #FFFFFF;
outline: none;
}
.trumbowyg-button-pane .trumbowyg-open-dropdown::after {
display: block;
content: " ";
position: absolute;
top: 25px;
right: 3px;
height: 0;
width: 0;
border: 3px solid transparent;
border-top-color: #555555;
}
.trumbowyg-button-pane .trumbowyg-open-dropdown.trumbowyg-textual-button {
padding-left: 10px !important;
padding-right: 18px !important;
}
.trumbowyg-button-pane .trumbowyg-open-dropdown.trumbowyg-textual-button::after {
top: 17px;
right: 7px;
}
.trumbowyg-button-pane .trumbowyg-right {
float: right;
}
.trumbowyg-button-pane .trumbowyg-right::before {
display: none !important;
}
.trumbowyg-dropdown {
width: 200px;
border: 1px solid #ecf0f1;
padding: 5px 0;
border-top: none;
background: #FFF;
margin-left: -1px;
box-shadow: rgba(0, 0, 0, 0.1) 0 2px 3px;
z-index: 11;
}
.trumbowyg-dropdown button {
display: block;
width: 100%;
height: 35px;
line-height: 35px;
text-decoration: none;
background: #FFF;
padding: 0 10px;
color: #333 !important;
border: none;
cursor: pointer;
text-align: left;
font-size: 15px;
transition: all 150ms;
}
.trumbowyg-dropdown button:hover, .trumbowyg-dropdown button:focus {
background: #ecf0f1;
}
.trumbowyg-dropdown button svg {
float: left;
margin-right: 14px;
}
/* Modal box */
.trumbowyg-modal {
position: absolute;
top: 0;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
max-width: 520px;
width: 100%;
height: 350px;
z-index: 11;
overflow: hidden;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.trumbowyg-modal-box {
position: absolute;
top: 0;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
max-width: 500px;
width: calc(100% - 20px);
padding-bottom: 45px;
z-index: 1;
background-color: #FFF;
text-align: center;
font-size: 14px;
box-shadow: rgba(0, 0, 0, 0.2) 0 2px 3px;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.trumbowyg-modal-box .trumbowyg-modal-title {
font-size: 24px;
font-weight: bold;
margin: 0 0 20px;
padding: 15px 0 13px;
display: block;
border-bottom: 1px solid #EEE;
color: #333;
background: #fbfcfc;
}
.trumbowyg-modal-box .trumbowyg-progress {
width: 100%;
height: 3px;
position: absolute;
top: 58px;
}
.trumbowyg-modal-box .trumbowyg-progress .trumbowyg-progress-bar {
background: #2BC06A;
width: 0;
height: 100%;
transition: width 150ms linear;
}
.trumbowyg-modal-box label {
display: block;
position: relative;
margin: 15px 12px;
height: 29px;
line-height: 29px;
overflow: hidden;
}
.trumbowyg-modal-box label .trumbowyg-input-infos {
display: block;
text-align: left;
height: 25px;
line-height: 25px;
transition: all 150ms;
}
.trumbowyg-modal-box label .trumbowyg-input-infos span {
display: block;
color: #69878f;
background-color: #fbfcfc;
border: 1px solid #DEDEDE;
padding: 0 7px;
width: 150px;
}
.trumbowyg-modal-box label .trumbowyg-input-infos span.trumbowyg-msg-error {
color: #e74c3c;
}
.trumbowyg-modal-box label.trumbowyg-input-error input, .trumbowyg-modal-box label.trumbowyg-input-error textarea {
border: 1px solid #e74c3c;
}
.trumbowyg-modal-box label.trumbowyg-input-error .trumbowyg-input-infos {
margin-top: -27px;
}
.trumbowyg-modal-box label input {
position: absolute;
top: 0;
right: 0;
height: 27px;
line-height: 27px;
border: 1px solid #DEDEDE;
background: #fff;
font-size: 14px;
max-width: 330px;
width: 70%;
padding: 0 7px;
transition: all 150ms;
}
.trumbowyg-modal-box label input:hover, .trumbowyg-modal-box label input:focus {
outline: none;
border: 1px solid #95a5a6;
}
.trumbowyg-modal-box label input:focus {
background: #fbfcfc;
}
.trumbowyg-modal-box .error {
margin-top: 25px;
display: block;
color: red;
}
.trumbowyg-modal-box .trumbowyg-modal-button {
position: absolute;
bottom: 10px;
right: 0;
text-decoration: none;
color: #FFF;
display: block;
width: 100px;
height: 35px;
line-height: 33px;
margin: 0 10px;
background-color: #333;
border: none;
cursor: pointer;
font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif;
font-size: 16px;
transition: all 150ms;
}
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit {
right: 110px;
background: #2bc06a;
}
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:hover, .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:focus {
background: #40d47e;
outline: none;
}
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:active {
background: #25a25a;
}
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset {
color: #555;
background: #e6e6e6;
}
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:hover, .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:focus {
background: #fbfbfb;
outline: none;
}
.trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:active {
background: #d5d5d5;
}
.trumbowyg-overlay {
position: absolute;
background-color: rgba(255, 255, 255, 0.5);
height: 100%;
width: 100%;
left: 0;
display: none;
top: 0;
z-index: 10; }
/**
* Fullscreen
*/
body.trumbowyg-body-fullscreen {
overflow: hidden; }
.trumbowyg-fullscreen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
z-index: 99999;
}
.trumbowyg-fullscreen.trumbowyg-box, .trumbowyg-fullscreen .trumbowyg-editor {
border: none;
}
.trumbowyg-fullscreen .trumbowyg-editor, .trumbowyg-fullscreen .trumbowyg-textarea {
height: calc(100% - 37px) !important;
overflow: auto;
}
.trumbowyg-fullscreen .trumbowyg-overlay {
height: 100% !important;
}
.trumbowyg-fullscreen .trumbowyg-button-group .trumbowyg-fullscreen-button svg {
color: #222;
fill: transparent;
}
.trumbowyg-editor object, .trumbowyg-editor embed, .trumbowyg-editor video, .trumbowyg-editor img {
max-width: 100%;
}
.trumbowyg-editor video, .trumbowyg-editor img {
height: auto;
}
.trumbowyg-editor img {
cursor: move;
}
.trumbowyg-editor.trumbowyg-reset-css {
background: #FEFEFE !important;
font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif !important;
font-size: 14px !important;
line-height: 1.45em !important;
white-space: normal !important;
color: #333;
}
.trumbowyg-editor.trumbowyg-reset-css a {
color: #15c !important;
text-decoration: underline !important;
}
.trumbowyg-editor.trumbowyg-reset-css div, .trumbowyg-editor.trumbowyg-reset-css p, .trumbowyg-editor.trumbowyg-reset-css ul, .trumbowyg-editor.trumbowyg-reset-css ol, .trumbowyg-editor.trumbowyg-reset-css blockquote {
box-shadow: none !important;
background: none !important;
margin: 0 !important;
margin-bottom: 15px !important;
line-height: 1.4em !important;
font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif !important;
font-size: 14px !important;
border: none;
}
.trumbowyg-editor.trumbowyg-reset-css iframe, .trumbowyg-editor.trumbowyg-reset-css object, .trumbowyg-editor.trumbowyg-reset-css hr {
margin-bottom: 15px !important;
}
.trumbowyg-editor.trumbowyg-reset-css blockquote {
margin-left: 32px !important;
font-style: italic !important;
color: #555;
}
.trumbowyg-editor.trumbowyg-reset-css ul, .trumbowyg-editor.trumbowyg-reset-css ol {
padding-left: 20px !important;
}
.trumbowyg-editor.trumbowyg-reset-css ul ul, .trumbowyg-editor.trumbowyg-reset-css ol ol, .trumbowyg-editor.trumbowyg-reset-css ul ol, .trumbowyg-editor.trumbowyg-reset-css ol ul {
border: none;
margin: 2px !important;
padding: 0 !important;
padding-left: 24px !important;
}
.trumbowyg-editor.trumbowyg-reset-css hr {
display: block;
height: 1px;
border: none;
border-top: 1px solid #CCC;
}
.trumbowyg-editor.trumbowyg-reset-css h1, .trumbowyg-editor.trumbowyg-reset-css h2, .trumbowyg-editor.trumbowyg-reset-css h3, .trumbowyg-editor.trumbowyg-reset-css h4 {
color: #111;
background: none;
margin: 0 !important;
padding: 0 !important;
font-weight: bold;
}
.trumbowyg-editor.trumbowyg-reset-css h1 {
font-size: 32px !important;
line-height: 38px !important;
margin-bottom: 20px !important;
}
.trumbowyg-editor.trumbowyg-reset-css h2 {
font-size: 26px !important;
line-height: 34px !important;
margin-bottom: 15px !important;
}
.trumbowyg-editor.trumbowyg-reset-css h3 {
font-size: 22px !important;
line-height: 28px !important;
margin-bottom: 7px !important;
}
.trumbowyg-editor.trumbowyg-reset-css h4 {
font-size: 16px !important;
line-height: 22px !important;
margin-bottom: 7px !important;
}

2
public/trumbowyg/ui/trumbowyg.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -33,6 +33,19 @@ func (build *builder) GetAdapter() DB_Adapter {
return build.adapter return build.adapter
} }
func (build *builder) Tx(handler func(*TransactionBuilder) error) error {
tx, err := build.conn.Begin()
if err != nil {
return err
}
err = handler(&TransactionBuilder{tx, build.adapter, nil})
if err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
func (build *builder) SimpleSelect(table string, columns string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) { func (build *builder) SimpleSelect(table string, columns string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby, limit) res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby, limit)
if err != nil { if err != nil {

View File

@ -10,11 +10,11 @@ import (
func init() { func init() {
DB_Registry = append(DB_Registry, DB_Registry = append(DB_Registry,
&Mssql_Adapter{Name: "mssql", Buffer: make(map[string]DB_Stmt)}, &MssqlAdapter{Name: "mssql", Buffer: make(map[string]DB_Stmt)},
) )
} }
type Mssql_Adapter struct { type MssqlAdapter struct {
Name string // ? - Do we really need this? Can't we hard-code this? Name string // ? - Do we really need this? Can't we hard-code this?
Buffer map[string]DB_Stmt Buffer map[string]DB_Stmt
BufferOrder []string // Map iteration order is random, so we need this to track the order, so we don't get huge diffs every commit BufferOrder []string // Map iteration order is random, so we need this to track the order, so we don't get huge diffs every commit
@ -22,21 +22,21 @@ type Mssql_Adapter struct {
} }
// GetName gives you the name of the database adapter. In this case, it's Mssql // GetName gives you the name of the database adapter. In this case, it's Mssql
func (adapter *Mssql_Adapter) GetName() string { func (adapter *MssqlAdapter) GetName() string {
return adapter.Name return adapter.Name
} }
func (adapter *Mssql_Adapter) GetStmt(name string) DB_Stmt { func (adapter *MssqlAdapter) GetStmt(name string) DB_Stmt {
return adapter.Buffer[name] return adapter.Buffer[name]
} }
func (adapter *Mssql_Adapter) GetStmts() map[string]DB_Stmt { func (adapter *MssqlAdapter) GetStmts() map[string]DB_Stmt {
return adapter.Buffer return adapter.Buffer
} }
// TODO: Convert any remaining stringy types to nvarchar // TODO: Convert any remaining stringy types to nvarchar
// We may need to change the CreateTable API to better suit Mssql and the other database drivers which are coming up // We may need to change the CreateTable API to better suit Mssql and the other database drivers which are coming up
func (adapter *Mssql_Adapter) CreateTable(name string, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (string, error) { func (adapter *MssqlAdapter) CreateTable(name string, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -115,7 +115,7 @@ func (adapter *Mssql_Adapter) CreateTable(name string, table string, charset str
return querystr, nil return querystr, nil
} }
func (adapter *Mssql_Adapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) { func (adapter *MssqlAdapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -162,7 +162,7 @@ func (adapter *Mssql_Adapter) SimpleInsert(name string, table string, columns st
} }
// ! DEPRECATED // ! DEPRECATED
func (adapter *Mssql_Adapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) { func (adapter *MssqlAdapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) {
log.Print("In SimpleReplace") log.Print("In SimpleReplace")
key, ok := adapter.keys[table] key, ok := adapter.keys[table]
if !ok { if !ok {
@ -197,7 +197,7 @@ func (adapter *Mssql_Adapter) SimpleReplace(name string, table string, columns s
return adapter.SimpleUpsert(name, table, columns, fields, "key = "+keyValue) return adapter.SimpleUpsert(name, table, columns, fields, "key = "+keyValue)
} }
func (adapter *Mssql_Adapter) SimpleUpsert(name string, table string, columns string, fields string, where string) (string, error) { func (adapter *MssqlAdapter) SimpleUpsert(name string, table string, columns string, fields string, where string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -293,7 +293,7 @@ func (adapter *Mssql_Adapter) SimpleUpsert(name string, table string, columns st
return querystr, nil return querystr, nil
} }
func (adapter *Mssql_Adapter) SimpleUpdate(name string, table string, set string, where string) (string, error) { func (adapter *MssqlAdapter) SimpleUpdate(name string, table string, set string, where string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -359,7 +359,7 @@ func (adapter *Mssql_Adapter) SimpleUpdate(name string, table string, set string
return querystr, nil return querystr, nil
} }
func (adapter *Mssql_Adapter) SimpleDelete(name string, table string, where string) (string, error) { func (adapter *MssqlAdapter) SimpleDelete(name string, table string, where string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -400,8 +400,8 @@ func (adapter *Mssql_Adapter) SimpleDelete(name string, table string, where stri
return querystr, nil return querystr, nil
} }
// We don't want to accidentally wipe tables, so we'll have a seperate method for purging tables instead // We don't want to accidentally wipe tables, so we'll have a separate method for purging tables instead
func (adapter *Mssql_Adapter) Purge(name string, table string) (string, error) { func (adapter *MssqlAdapter) Purge(name string, table string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -412,7 +412,7 @@ func (adapter *Mssql_Adapter) Purge(name string, table string) (string, error) {
return "DELETE FROM [" + table + "]", nil return "DELETE FROM [" + table + "]", nil
} }
func (adapter *Mssql_Adapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) { func (adapter *MssqlAdapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -518,7 +518,7 @@ func (adapter *Mssql_Adapter) SimpleSelect(name string, table string, columns st
return querystr, nil return querystr, nil
} }
func (adapter *Mssql_Adapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) { func (adapter *MssqlAdapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -647,7 +647,7 @@ func (adapter *Mssql_Adapter) SimpleLeftJoin(name string, table1 string, table2
return querystr, nil return querystr, nil
} }
func (adapter *Mssql_Adapter) SimpleInnerJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) { func (adapter *MssqlAdapter) SimpleInnerJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -778,7 +778,7 @@ func (adapter *Mssql_Adapter) SimpleInnerJoin(name string, table1 string, table2
return querystr, nil return querystr, nil
} }
func (adapter *Mssql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel DB_Select) (string, error) { func (adapter *MssqlAdapter) SimpleInsertSelect(name string, ins DB_Insert, sel DB_Select) (string, error) {
// TODO: More errors. // TODO: More errors.
// TODO: Add this to the MySQL adapter in order to make this problem more discoverable? // TODO: Add this to the MySQL adapter in order to make this problem more discoverable?
if len(sel.Orderby) == 0 && sel.Limit != "" { if len(sel.Orderby) == 0 && sel.Limit != "" {
@ -893,7 +893,7 @@ func (adapter *Mssql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel
return querystr, nil return querystr, nil
} }
func (adapter *Mssql_Adapter) simpleJoin(name string, ins DB_Insert, sel DB_Join, joinType string) (string, error) { func (adapter *MssqlAdapter) simpleJoin(name string, ins DB_Insert, sel DB_Join, joinType string) (string, error) {
// TODO: More errors. // TODO: More errors.
// TODO: Add this to the MySQL adapter in order to make this problem more discoverable? // TODO: Add this to the MySQL adapter in order to make this problem more discoverable?
if len(sel.Orderby) == 0 && sel.Limit != "" { if len(sel.Orderby) == 0 && sel.Limit != "" {
@ -1023,15 +1023,15 @@ func (adapter *Mssql_Adapter) simpleJoin(name string, ins DB_Insert, sel DB_Join
return querystr, nil return querystr, nil
} }
func (adapter *Mssql_Adapter) SimpleInsertLeftJoin(name string, ins DB_Insert, sel DB_Join) (string, error) { func (adapter *MssqlAdapter) SimpleInsertLeftJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
return adapter.simpleJoin(name, ins, sel, "LEFT") return adapter.simpleJoin(name, ins, sel, "LEFT")
} }
func (adapter *Mssql_Adapter) SimpleInsertInnerJoin(name string, ins DB_Insert, sel DB_Join) (string, error) { func (adapter *MssqlAdapter) SimpleInsertInnerJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
return adapter.simpleJoin(name, ins, sel, "INNER") return adapter.simpleJoin(name, ins, sel, "INNER")
} }
func (adapter *Mssql_Adapter) SimpleCount(name string, table string, where string, limit string) (string, error) { func (adapter *MssqlAdapter) SimpleCount(name string, table string, where string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -1077,7 +1077,7 @@ func (adapter *Mssql_Adapter) SimpleCount(name string, table string, where strin
return querystr, nil return querystr, nil
} }
func (adapter *Mssql_Adapter) Write() error { func (adapter *MssqlAdapter) Write() error {
var stmts, body string var stmts, body string
for _, name := range adapter.BufferOrder { for _, name := range adapter.BufferOrder {
if name[0] == '_' { if name[0] == '_' {
@ -1121,12 +1121,12 @@ func _gen_mssql() (err error) {
} }
// Internal methods, not exposed in the interface // Internal methods, not exposed in the interface
func (adapter *Mssql_Adapter) pushStatement(name string, stype string, querystr string) { func (adapter *MssqlAdapter) pushStatement(name string, stype string, querystr string) {
adapter.Buffer[name] = DB_Stmt{querystr, stype} adapter.Buffer[name] = DB_Stmt{querystr, stype}
adapter.BufferOrder = append(adapter.BufferOrder, name) adapter.BufferOrder = append(adapter.BufferOrder, name)
} }
func (adapter *Mssql_Adapter) stringyType(ctype string) bool { func (adapter *MssqlAdapter) stringyType(ctype string) bool {
ctype = strings.ToLower(ctype) ctype = strings.ToLower(ctype)
return ctype == "char" || ctype == "varchar" || ctype == "datetime" || ctype == "text" || ctype == "nvarchar" return ctype == "char" || ctype == "varchar" || ctype == "datetime" || ctype == "text" || ctype == "nvarchar"
} }
@ -1135,6 +1135,6 @@ type SetPrimaryKeys interface {
SetPrimaryKeys(keys map[string]string) SetPrimaryKeys(keys map[string]string)
} }
func (adapter *Mssql_Adapter) SetPrimaryKeys(keys map[string]string) { func (adapter *MssqlAdapter) SetPrimaryKeys(keys map[string]string) {
adapter.keys = keys adapter.keys = keys
} }

View File

@ -8,30 +8,30 @@ import "errors"
func init() { func init() {
DB_Registry = append(DB_Registry, DB_Registry = append(DB_Registry,
&Mysql_Adapter{Name: "mysql", Buffer: make(map[string]DB_Stmt)}, &MysqlAdapter{Name: "mysql", Buffer: make(map[string]DB_Stmt)},
) )
} }
type Mysql_Adapter struct { type MysqlAdapter struct {
Name string // ? - Do we really need this? Can't we hard-code this? Name string // ? - Do we really need this? Can't we hard-code this?
Buffer map[string]DB_Stmt Buffer map[string]DB_Stmt
BufferOrder []string // Map iteration order is random, so we need this to track the order, so we don't get huge diffs every commit BufferOrder []string // Map iteration order is random, so we need this to track the order, so we don't get huge diffs every commit
} }
// GetName gives you the name of the database adapter. In this case, it's mysql // GetName gives you the name of the database adapter. In this case, it's mysql
func (adapter *Mysql_Adapter) GetName() string { func (adapter *MysqlAdapter) GetName() string {
return adapter.Name return adapter.Name
} }
func (adapter *Mysql_Adapter) GetStmt(name string) DB_Stmt { func (adapter *MysqlAdapter) GetStmt(name string) DB_Stmt {
return adapter.Buffer[name] return adapter.Buffer[name]
} }
func (adapter *Mysql_Adapter) GetStmts() map[string]DB_Stmt { func (adapter *MysqlAdapter) GetStmts() map[string]DB_Stmt {
return adapter.Buffer return adapter.Buffer
} }
func (adapter *Mysql_Adapter) CreateTable(name string, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (string, error) { func (adapter *MysqlAdapter) CreateTable(name string, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -104,7 +104,7 @@ func (adapter *Mysql_Adapter) CreateTable(name string, table string, charset str
return querystr + ";", nil return querystr + ";", nil
} }
func (adapter *Mysql_Adapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) { func (adapter *MysqlAdapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -150,7 +150,7 @@ func (adapter *Mysql_Adapter) SimpleInsert(name string, table string, columns st
} }
// ! DEPRECATED // ! DEPRECATED
func (adapter *Mysql_Adapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) { func (adapter *MysqlAdapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -187,7 +187,7 @@ func (adapter *Mysql_Adapter) SimpleReplace(name string, table string, columns s
return querystr + ")", nil return querystr + ")", nil
} }
func (adapter *Mysql_Adapter) SimpleUpsert(name string, table string, columns string, fields string, where string) (string, error) { func (adapter *MysqlAdapter) SimpleUpsert(name string, table string, columns string, fields string, where string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -234,7 +234,7 @@ func (adapter *Mysql_Adapter) SimpleUpsert(name string, table string, columns st
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) SimpleUpdate(name string, table string, set string, where string) (string, error) { func (adapter *MysqlAdapter) SimpleUpdate(name string, table string, set string, where string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -288,7 +288,7 @@ func (adapter *Mysql_Adapter) SimpleUpdate(name string, table string, set string
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) SimpleDelete(name string, table string, where string) (string, error) { func (adapter *MysqlAdapter) SimpleDelete(name string, table string, where string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -323,8 +323,8 @@ func (adapter *Mysql_Adapter) SimpleDelete(name string, table string, where stri
return querystr, nil return querystr, nil
} }
// We don't want to accidentally wipe tables, so we'll have a seperate method for purging tables instead // We don't want to accidentally wipe tables, so we'll have a separate method for purging tables instead
func (adapter *Mysql_Adapter) Purge(name string, table string) (string, error) { func (adapter *MysqlAdapter) Purge(name string, table string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -335,7 +335,7 @@ func (adapter *Mysql_Adapter) Purge(name string, table string) (string, error) {
return "DELETE FROM `" + table + "`", nil return "DELETE FROM `" + table + "`", nil
} }
func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) { func (adapter *MysqlAdapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -399,7 +399,7 @@ func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns st
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) { func (adapter *MysqlAdapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -489,7 +489,7 @@ func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) { func (adapter *MysqlAdapter) SimpleInnerJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -579,7 +579,7 @@ func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel DB_Select) (string, error) { func (adapter *MysqlAdapter) SimpleInsertSelect(name string, ins DB_Insert, sel DB_Select) (string, error) {
/* Insert Portion */ /* Insert Portion */
var querystr = "INSERT INTO `" + ins.Table + "`(" var querystr = "INSERT INTO `" + ins.Table + "`("
@ -653,7 +653,7 @@ func (adapter *Mysql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) SimpleInsertLeftJoin(name string, ins DB_Insert, sel DB_Join) (string, error) { func (adapter *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
/* Insert Portion */ /* Insert Portion */
var querystr = "INSERT INTO `" + ins.Table + "`(" var querystr = "INSERT INTO `" + ins.Table + "`("
@ -738,7 +738,7 @@ func (adapter *Mysql_Adapter) SimpleInsertLeftJoin(name string, ins DB_Insert, s
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) SimpleInsertInnerJoin(name string, ins DB_Insert, sel DB_Join) (string, error) { func (adapter *MysqlAdapter) SimpleInsertInnerJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
/* Insert Portion */ /* Insert Portion */
var querystr = "INSERT INTO `" + ins.Table + "`(" var querystr = "INSERT INTO `" + ins.Table + "`("
@ -823,7 +823,7 @@ func (adapter *Mysql_Adapter) SimpleInsertInnerJoin(name string, ins DB_Insert,
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where string, limit string) (string, error) { func (adapter *MysqlAdapter) SimpleCount(name string, table string, where string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -836,9 +836,9 @@ func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where strin
// TODO: Add support for BETWEEN x.x // TODO: Add support for BETWEEN x.x
if len(where) != 0 { if len(where) != 0 {
querystr += " WHERE" querystr += " WHERE"
//fmt.Println("SimpleCount:",name) //log.Print("SimpleCount: ", name)
//fmt.Println("where:",where) //log.Print("where: ", where)
//fmt.Println("processWhere:",processWhere(where)) //log.Print("processWhere: ", processWhere(where))
for _, loc := range processWhere(where) { for _, loc := range processWhere(where) {
for _, token := range loc.Expr { for _, token := range loc.Expr {
switch token.Type { switch token.Type {
@ -866,7 +866,7 @@ func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where strin
return querystr, nil return querystr, nil
} }
func (adapter *Mysql_Adapter) Write() error { func (adapter *MysqlAdapter) Write() error {
var stmts, body string var stmts, body string
for _, name := range adapter.BufferOrder { for _, name := range adapter.BufferOrder {
if name[0] == '_' { if name[0] == '_' {
@ -920,12 +920,12 @@ func _gen_mysql() (err error) {
} }
// Internal methods, not exposed in the interface // Internal methods, not exposed in the interface
func (adapter *Mysql_Adapter) pushStatement(name string, stype string, querystr string) { func (adapter *MysqlAdapter) pushStatement(name string, stype string, querystr string) {
adapter.Buffer[name] = DB_Stmt{querystr, stype} adapter.Buffer[name] = DB_Stmt{querystr, stype}
adapter.BufferOrder = append(adapter.BufferOrder, name) adapter.BufferOrder = append(adapter.BufferOrder, name)
} }
func (adapter *Mysql_Adapter) stringyType(ctype string) bool { func (adapter *MysqlAdapter) stringyType(ctype string) bool {
ctype = strings.ToLower(ctype) ctype = strings.ToLower(ctype)
return ctype == "varchar" || ctype == "tinytext" || ctype == "text" || ctype == "mediumtext" || ctype == "longtext" || ctype == "char" || ctype == "datetime" || ctype == "timestamp" || ctype == "time" || ctype == "date" return ctype == "varchar" || ctype == "tinytext" || ctype == "text" || ctype == "mediumtext" || ctype == "longtext" || ctype == "char" || ctype == "datetime" || ctype == "timestamp" || ctype == "time" || ctype == "date"
} }

View File

@ -7,32 +7,32 @@ import "errors"
func init() { func init() {
DB_Registry = append(DB_Registry, DB_Registry = append(DB_Registry,
&Pgsql_Adapter{Name: "pgsql", Buffer: make(map[string]DB_Stmt)}, &PgsqlAdapter{Name: "pgsql", Buffer: make(map[string]DB_Stmt)},
) )
} }
type Pgsql_Adapter struct { type PgsqlAdapter struct {
Name string // ? - Do we really need this? Can't we hard-code this? Name string // ? - Do we really need this? Can't we hard-code this?
Buffer map[string]DB_Stmt Buffer map[string]DB_Stmt
BufferOrder []string // Map iteration order is random, so we need this to track the order, so we don't get huge diffs every commit BufferOrder []string // Map iteration order is random, so we need this to track the order, so we don't get huge diffs every commit
} }
// GetName gives you the name of the database adapter. In this case, it's pgsql // GetName gives you the name of the database adapter. In this case, it's pgsql
func (adapter *Pgsql_Adapter) GetName() string { func (adapter *PgsqlAdapter) GetName() string {
return adapter.Name return adapter.Name
} }
func (adapter *Pgsql_Adapter) GetStmt(name string) DB_Stmt { func (adapter *PgsqlAdapter) GetStmt(name string) DB_Stmt {
return adapter.Buffer[name] return adapter.Buffer[name]
} }
func (adapter *Pgsql_Adapter) GetStmts() map[string]DB_Stmt { func (adapter *PgsqlAdapter) GetStmts() map[string]DB_Stmt {
return adapter.Buffer return adapter.Buffer
} }
// TODO: Implement this // TODO: Implement this
// We may need to change the CreateTable API to better suit PGSQL and the other database drivers which are coming up // We may need to change the CreateTable API to better suit PGSQL and the other database drivers which are coming up
func (adapter *Pgsql_Adapter) CreateTable(name string, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (string, error) { func (adapter *PgsqlAdapter) CreateTable(name string, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -95,7 +95,7 @@ func (adapter *Pgsql_Adapter) CreateTable(name string, table string, charset str
} }
// TODO: Implement this // TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) { func (adapter *PgsqlAdapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -112,7 +112,7 @@ func (adapter *Pgsql_Adapter) SimpleInsert(name string, table string, columns st
} }
// TODO: Implement this // TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) { func (adapter *PgsqlAdapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -129,7 +129,7 @@ func (adapter *Pgsql_Adapter) SimpleReplace(name string, table string, columns s
} }
// TODO: Implement this // TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleUpsert(name string, table string, columns string, fields string, where string) (string, error) { func (adapter *PgsqlAdapter) SimpleUpsert(name string, table string, columns string, fields string, where string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -146,7 +146,7 @@ func (adapter *Pgsql_Adapter) SimpleUpsert(name string, table string, columns st
} }
// TODO: Implemented, but we need CreateTable and a better installer to *test* it // TODO: Implemented, but we need CreateTable and a better installer to *test* it
func (adapter *Pgsql_Adapter) SimpleUpdate(name string, table string, set string, where string) (string, error) { func (adapter *PgsqlAdapter) SimpleUpdate(name string, table string, set string, where string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -213,7 +213,7 @@ func (adapter *Pgsql_Adapter) SimpleUpdate(name string, table string, set string
} }
// TODO: Implement this // TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleDelete(name string, table string, where string) (string, error) { func (adapter *PgsqlAdapter) SimpleDelete(name string, table string, where string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -227,8 +227,8 @@ func (adapter *Pgsql_Adapter) SimpleDelete(name string, table string, where stri
} }
// TODO: Implement this // TODO: Implement this
// We don't want to accidentally wipe tables, so we'll have a seperate method for purging tables instead // We don't want to accidentally wipe tables, so we'll have a separate method for purging tables instead
func (adapter *Pgsql_Adapter) Purge(name string, table string) (string, error) { func (adapter *PgsqlAdapter) Purge(name string, table string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -239,7 +239,7 @@ func (adapter *Pgsql_Adapter) Purge(name string, table string) (string, error) {
} }
// TODO: Implement this // TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) { func (adapter *PgsqlAdapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -253,7 +253,7 @@ func (adapter *Pgsql_Adapter) SimpleSelect(name string, table string, columns st
} }
// TODO: Implement this // TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) { func (adapter *PgsqlAdapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -273,7 +273,7 @@ func (adapter *Pgsql_Adapter) SimpleLeftJoin(name string, table1 string, table2
} }
// TODO: Implement this // TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleInnerJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) { func (adapter *PgsqlAdapter) SimpleInnerJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -293,22 +293,22 @@ func (adapter *Pgsql_Adapter) SimpleInnerJoin(name string, table1 string, table2
} }
// TODO: Implement this // TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel DB_Select) (string, error) { func (adapter *PgsqlAdapter) SimpleInsertSelect(name string, ins DB_Insert, sel DB_Select) (string, error) {
return "", nil return "", nil
} }
// TODO: Implement this // TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleInsertLeftJoin(name string, ins DB_Insert, sel DB_Join) (string, error) { func (adapter *PgsqlAdapter) SimpleInsertLeftJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
return "", nil return "", nil
} }
// TODO: Implement this // TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleInsertInnerJoin(name string, ins DB_Insert, sel DB_Join) (string, error) { func (adapter *PgsqlAdapter) SimpleInsertInnerJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
return "", nil return "", nil
} }
// TODO: Implement this // TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleCount(name string, table string, where string, limit string) (string, error) { func (adapter *PgsqlAdapter) SimpleCount(name string, table string, where string, limit string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
} }
@ -318,7 +318,7 @@ func (adapter *Pgsql_Adapter) SimpleCount(name string, table string, where strin
return "", nil return "", nil
} }
func (adapter *Pgsql_Adapter) Write() error { func (adapter *PgsqlAdapter) Write() error {
var stmts, body string var stmts, body string
for _, name := range adapter.BufferOrder { for _, name := range adapter.BufferOrder {
if name[0] == '_' { if name[0] == '_' {
@ -361,12 +361,12 @@ func _gen_pgsql() (err error) {
} }
// Internal methods, not exposed in the interface // Internal methods, not exposed in the interface
func (adapter *Pgsql_Adapter) pushStatement(name string, stype string, querystr string) { func (adapter *PgsqlAdapter) pushStatement(name string, stype string, querystr string) {
adapter.Buffer[name] = DB_Stmt{querystr, stype} adapter.Buffer[name] = DB_Stmt{querystr, stype}
adapter.BufferOrder = append(adapter.BufferOrder, name) adapter.BufferOrder = append(adapter.BufferOrder, name)
} }
func (adapter *Pgsql_Adapter) stringyType(ctype string) bool { func (adapter *PgsqlAdapter) stringyType(ctype string) bool {
ctype = strings.ToLower(ctype) ctype = strings.ToLower(ctype)
return ctype == "char" || ctype == "varchar" || ctype == "timestamp" || ctype == "text" return ctype == "char" || ctype == "varchar" || ctype == "timestamp" || ctype == "text"
} }

View File

@ -477,6 +477,8 @@ func writeUpdates(adapter qgen.DB_Adapter) error {
func writeDeletes(adapter qgen.DB_Adapter) error { func writeDeletes(adapter qgen.DB_Adapter) error {
adapter.SimpleDelete("deleteUser", "users", "uid = ?") adapter.SimpleDelete("deleteUser", "users", "uid = ?")
adapter.SimpleDelete("deleteTopic", "topics", "tid = ?")
adapter.SimpleDelete("deleteReply", "replies", "rid = ?") adapter.SimpleDelete("deleteReply", "replies", "rid = ?")
adapter.SimpleDelete("deleteProfileReply", "users_replies", "rid = ?") adapter.SimpleDelete("deleteProfileReply", "users_replies", "rid = ?")

View File

@ -8,7 +8,7 @@ package main
import "errors" import "errors"
// ? - Should we add a reply store to centralise all the reply logic? Would this cover profile replies too or would that be seperate? // ? - Should we add a reply store to centralise all the reply logic? Would this cover profile replies too or would that be separate?
var rstore ReplyStore var rstore ReplyStore
var prstore ProfileReplyStore var prstore ProfileReplyStore

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