Add bookmarklet
This commit is contained in:
parent
1bc43ec2bc
commit
6690f6a70e
26 changed files with 244 additions and 48 deletions
|
@ -26,7 +26,7 @@ TODO
|
||||||
|
|
||||||
- [ ] Custom entries sorting
|
- [ ] Custom entries sorting
|
||||||
- [ ] Webpage scraper (Readability)
|
- [ ] Webpage scraper (Readability)
|
||||||
- [ ] Bookmarklet
|
- [X] Bookmarklet
|
||||||
- [ ] External integrations (Pinboard, Wallabag...)
|
- [ ] External integrations (Pinboard, Wallabag...)
|
||||||
- [ ] Gzip compression
|
- [ ] Gzip compression
|
||||||
- [ ] Integration tests
|
- [ ] Integration tests
|
||||||
|
|
|
@ -9,6 +9,10 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultBaseURL = "http://localhost"
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// 2017-11-21 15:41:59.495654213 -0800 PST m=+0.041889871
|
// 2017-11-21 19:31:59.645632989 -0800 PST m=+0.024631837
|
||||||
|
|
||||||
package locale
|
package locale
|
||||||
|
|
||||||
|
@ -139,12 +139,17 @@ var Translations = map[string]string{
|
||||||
"Work in progress...": "Travail en cours...",
|
"Work in progress...": "Travail en cours...",
|
||||||
"This user already exists.": "Cet utilisateur existe déjà.",
|
"This user already exists.": "Cet utilisateur existe déjà.",
|
||||||
"This category already exists.": "Cette catégorie existe déjà.",
|
"This category already exists.": "Cette catégorie existe déjà.",
|
||||||
"Unable to update this category.": "Impossible de mettre à jour cette catégorie."
|
"Unable to update this category.": "Impossible de mettre à jour cette catégorie.",
|
||||||
|
"Integrations": "Intégrations",
|
||||||
|
"Bookmarklet": "Bookmarklet",
|
||||||
|
"Drag and drop this link to your bookmarks.": "Glisser-déposer ce lien dans vos favoris.",
|
||||||
|
"This special link allows you to subscribe to a website directly by using a bookmark in your web browser.": "Ce lien spécial vous permet de vous abonner à un site web directement en utilisant un marque page dans votre navigateur web.",
|
||||||
|
"Add to Miniflux": "Ajouter à Miniflux"
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
var TranslationsChecksums = map[string]string{
|
var TranslationsChecksums = map[string]string{
|
||||||
"en_US": "6fe95384260941e8a5a3c695a655a932e0a8a6a572c1e45cb2b1ae8baa01b897",
|
"en_US": "6fe95384260941e8a5a3c695a655a932e0a8a6a572c1e45cb2b1ae8baa01b897",
|
||||||
"fr_FR": "5c8c2c5e35a17a7dd3c30596b73342f70950a3bbce00786d43ccba01b96ea672",
|
"fr_FR": "f1ddbcfb8ffd837a2df69e8506d023e4254ead2f0b94e518ab595df97d32c87a",
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,5 +123,10 @@
|
||||||
"Work in progress...": "Travail en cours...",
|
"Work in progress...": "Travail en cours...",
|
||||||
"This user already exists.": "Cet utilisateur existe déjà.",
|
"This user already exists.": "Cet utilisateur existe déjà.",
|
||||||
"This category already exists.": "Cette catégorie existe déjà.",
|
"This category already exists.": "Cette catégorie existe déjà.",
|
||||||
"Unable to update this category.": "Impossible de mettre à jour cette catégorie."
|
"Unable to update this category.": "Impossible de mettre à jour cette catégorie.",
|
||||||
|
"Integrations": "Intégrations",
|
||||||
|
"Bookmarklet": "Bookmarklet",
|
||||||
|
"Drag and drop this link to your bookmarks.": "Glisser-déposer ce lien dans vos favoris.",
|
||||||
|
"This special link allows you to subscribe to a website directly by using a bookmark in your web browser.": "Ce lien spécial vous permet de vous abonner à un site web directement en utilisant un marque page dans votre navigateur web.",
|
||||||
|
"Add to Miniflux": "Ajouter à Miniflux"
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,16 +18,19 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HandlerFunc is an application HTTP handler.
|
||||||
type HandlerFunc func(ctx *Context, request *Request, response *Response)
|
type HandlerFunc func(ctx *Context, request *Request, response *Response)
|
||||||
|
|
||||||
|
// Handler manages HTTP handlers and middlewares.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
store *storage.Storage
|
store *storage.Storage
|
||||||
translator *locale.Translator
|
translator *locale.Translator
|
||||||
template *template.TemplateEngine
|
template *template.Engine
|
||||||
router *mux.Router
|
router *mux.Router
|
||||||
middleware *middleware.MiddlewareChain
|
middleware *middleware.MiddlewareChain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use is a wrapper around an HTTP handler.
|
||||||
func (h *Handler) Use(f HandlerFunc) http.Handler {
|
func (h *Handler) Use(f HandlerFunc) http.Handler {
|
||||||
return h.middleware.WrapFunc(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return h.middleware.WrapFunc(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer helper.ExecutionTime(time.Now(), r.URL.Path)
|
defer helper.ExecutionTime(time.Now(), r.URL.Path)
|
||||||
|
@ -47,7 +50,8 @@ func (h *Handler) Use(f HandlerFunc) http.Handler {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(store *storage.Storage, router *mux.Router, template *template.TemplateEngine, translator *locale.Translator, middleware *middleware.MiddlewareChain) *Handler {
|
// NewHandler returns a new Handler.
|
||||||
|
func NewHandler(store *storage.Storage, router *mux.Router, template *template.Engine, translator *locale.Translator, middleware *middleware.MiddlewareChain) *Handler {
|
||||||
return &Handler{
|
return &Handler{
|
||||||
store: store,
|
store: store,
|
||||||
translator: translator,
|
translator: translator,
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
type HTMLResponse struct {
|
type HTMLResponse struct {
|
||||||
writer http.ResponseWriter
|
writer http.ResponseWriter
|
||||||
request *http.Request
|
request *http.Request
|
||||||
template *template.TemplateEngine
|
template *template.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render execute a template and send to the client the generated HTML.
|
// Render execute a template and send to the client the generated HTML.
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
type Response struct {
|
type Response struct {
|
||||||
writer http.ResponseWriter
|
writer http.ResponseWriter
|
||||||
request *http.Request
|
request *http.Request
|
||||||
template *template.TemplateEngine
|
template *template.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCookie send a cookie to the client.
|
// SetCookie send a cookie to the client.
|
||||||
|
@ -67,6 +67,6 @@ func (r *Response) commonHeaders() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResponse returns a new Response.
|
// NewResponse returns a new Response.
|
||||||
func NewResponse(w http.ResponseWriter, r *http.Request, template *template.TemplateEngine) *Response {
|
func NewResponse(w http.ResponseWriter, r *http.Request, template *template.Engine) *Response {
|
||||||
return &Response{writer: w, request: r, template: template}
|
return &Response{writer: w, request: r, template: template}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package server
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/miniflux/miniflux2/config"
|
||||||
"github.com/miniflux/miniflux2/locale"
|
"github.com/miniflux/miniflux2/locale"
|
||||||
"github.com/miniflux/miniflux2/reader/feed"
|
"github.com/miniflux/miniflux2/reader/feed"
|
||||||
"github.com/miniflux/miniflux2/reader/opml"
|
"github.com/miniflux/miniflux2/reader/opml"
|
||||||
|
@ -20,10 +21,10 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getRoutes(store *storage.Storage, feedHandler *feed.Handler) *mux.Router {
|
func getRoutes(cfg *config.Config, store *storage.Storage, feedHandler *feed.Handler) *mux.Router {
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
translator := locale.Load()
|
translator := locale.Load()
|
||||||
templateEngine := template.NewTemplateEngine(router, translator)
|
templateEngine := template.NewEngine(cfg, router, translator)
|
||||||
|
|
||||||
apiController := api_controller.NewController(store, feedHandler)
|
apiController := api_controller.NewController(store, feedHandler)
|
||||||
uiController := ui_controller.NewController(store, feedHandler, opml.NewHandler(store))
|
uiController := ui_controller.NewController(store, feedHandler, opml.NewHandler(store))
|
||||||
|
@ -110,6 +111,9 @@ func getRoutes(store *storage.Storage, feedHandler *feed.Handler) *mux.Router {
|
||||||
router.Handle("/settings", uiHandler.Use(uiController.ShowSettings)).Name("settings").Methods("GET")
|
router.Handle("/settings", uiHandler.Use(uiController.ShowSettings)).Name("settings").Methods("GET")
|
||||||
router.Handle("/settings", uiHandler.Use(uiController.UpdateSettings)).Name("updateSettings").Methods("POST")
|
router.Handle("/settings", uiHandler.Use(uiController.UpdateSettings)).Name("updateSettings").Methods("POST")
|
||||||
|
|
||||||
|
router.Handle("/bookmarklet", uiHandler.Use(uiController.Bookmarklet)).Name("bookmarklet").Methods("GET")
|
||||||
|
router.Handle("/integrations", uiHandler.Use(uiController.ShowIntegrations)).Name("integrations").Methods("GET")
|
||||||
|
|
||||||
router.Handle("/sessions", uiHandler.Use(uiController.ShowSessions)).Name("sessions").Methods("GET")
|
router.Handle("/sessions", uiHandler.Use(uiController.ShowSessions)).Name("sessions").Methods("GET")
|
||||||
router.Handle("/sessions/{sessionID}/remove", uiHandler.Use(uiController.RemoveSession)).Name("removeSession").Methods("POST")
|
router.Handle("/sessions/{sessionID}/remove", uiHandler.Use(uiController.RemoveSession)).Name("removeSession").Methods("POST")
|
||||||
|
|
||||||
|
|
|
@ -5,21 +5,23 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/miniflux/miniflux2/config"
|
|
||||||
"github.com/miniflux/miniflux2/reader/feed"
|
|
||||||
"github.com/miniflux/miniflux2/storage"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/miniflux/miniflux2/config"
|
||||||
|
"github.com/miniflux/miniflux2/reader/feed"
|
||||||
|
"github.com/miniflux/miniflux2/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewServer returns a new HTTP server.
|
||||||
func NewServer(cfg *config.Config, store *storage.Storage, feedHandler *feed.Handler) *http.Server {
|
func NewServer(cfg *config.Config, store *storage.Storage, feedHandler *feed.Handler) *http.Server {
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
ReadTimeout: 5 * time.Second,
|
ReadTimeout: 5 * time.Second,
|
||||||
WriteTimeout: 10 * time.Second,
|
WriteTimeout: 10 * time.Second,
|
||||||
IdleTimeout: 60 * time.Second,
|
IdleTimeout: 60 * time.Second,
|
||||||
Addr: cfg.Get("LISTEN_ADDR", "127.0.0.1:8080"),
|
Addr: cfg.Get("LISTEN_ADDR", "127.0.0.1:8080"),
|
||||||
Handler: getRoutes(store, feedHandler),
|
Handler: getRoutes(cfg, store, feedHandler),
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// 2017-11-21 15:41:59.461181295 -0800 PST m=+0.007416953
|
// 2017-11-21 19:31:59.626742594 -0800 PST m=+0.005741442
|
||||||
|
|
||||||
package static
|
package static
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -659,3 +659,18 @@ a.button {
|
||||||
.loading {
|
.loading {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Bookmarlet */
|
||||||
|
.bookmarklet {
|
||||||
|
border: 1px dashed #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 15px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmarklet a {
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// 2017-11-21 15:41:59.4687788 -0800 PST m=+0.015014458
|
// 2017-11-21 19:31:59.631783539 -0800 PST m=+0.010782387
|
||||||
|
|
||||||
package static
|
package static
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// 2017-11-21 15:41:59.491806442 -0800 PST m=+0.038042100
|
// 2017-11-21 19:31:59.643994492 -0800 PST m=+0.022993340
|
||||||
|
|
||||||
package template
|
package template
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
35
server/template/html/integrations.html
Normal file
35
server/template/html/integrations.html
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{{ define "title"}}{{ t "Integrations" }}{{ end }}
|
||||||
|
|
||||||
|
{{ define "content"}}
|
||||||
|
<section class="page-header">
|
||||||
|
<h1>{{ t "Integrations" }}</h1>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
|
</li>
|
||||||
|
{{ if .user.IsAdmin }}
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "users" }}">{{ t "Users" }}</a>
|
||||||
|
</li>
|
||||||
|
{{ end }}
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "about" }}">{{ t "About" }}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<h3>{{ t "Bookmarklet" }}</h3>
|
||||||
|
<p>{{ t "This special link allows you to subscribe to a website directly by using a bookmark in your web browser." }}</p>
|
||||||
|
|
||||||
|
<div class="bookmarklet">
|
||||||
|
<a href="javascript:location.href='{{ baseURL }}{{ route "bookmarklet" }}?uri='+encodeURIComponent(window.location.href)">{{ t "Add to Miniflux" }}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>{{ t "Drag and drop this link to your bookmarks." }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ end }}
|
|
@ -7,6 +7,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "users" }}">{{ t "Users" }}</a>
|
<a href="{{ route "users" }}">{{ t "Users" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
<section class="page-header">
|
<section class="page-header">
|
||||||
<h1>{{ t "Settings" }}</h1>
|
<h1>{{ t "Settings" }}</h1>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
// Copyright 2017 Frédéric Guilloe. All rights reserved.
|
||||||
// Use of this source code is governed by the Apache 2.0
|
// Use of this source code is governed by the Apache 2.0
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/miniflux/miniflux2/config"
|
||||||
"github.com/miniflux/miniflux2/errors"
|
"github.com/miniflux/miniflux2/errors"
|
||||||
"github.com/miniflux/miniflux2/locale"
|
"github.com/miniflux/miniflux2/locale"
|
||||||
"github.com/miniflux/miniflux2/server/route"
|
"github.com/miniflux/miniflux2/server/route"
|
||||||
|
@ -22,23 +23,28 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TemplateEngine struct {
|
// Engine handles the templating system.
|
||||||
|
type Engine struct {
|
||||||
templates map[string]*template.Template
|
templates map[string]*template.Template
|
||||||
router *mux.Router
|
router *mux.Router
|
||||||
translator *locale.Translator
|
translator *locale.Translator
|
||||||
currentLocale *locale.Language
|
currentLocale *locale.Language
|
||||||
|
cfg *config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TemplateEngine) ParseAll() {
|
func (e *Engine) parseAll() {
|
||||||
funcMap := template.FuncMap{
|
funcMap := template.FuncMap{
|
||||||
|
"baseURL": func() string {
|
||||||
|
return e.cfg.Get("BASE_URL", config.DefaultBaseURL)
|
||||||
|
},
|
||||||
"route": func(name string, args ...interface{}) string {
|
"route": func(name string, args ...interface{}) string {
|
||||||
return route.GetRoute(t.router, name, args...)
|
return route.GetRoute(e.router, name, args...)
|
||||||
},
|
},
|
||||||
"noescape": func(str string) template.HTML {
|
"noescape": func(str string) template.HTML {
|
||||||
return template.HTML(str)
|
return template.HTML(str)
|
||||||
},
|
},
|
||||||
"proxyFilter": func(data string) string {
|
"proxyFilter": func(data string) string {
|
||||||
return filter.ImageProxyFilter(t.router, data)
|
return filter.ImageProxyFilter(e.router, data)
|
||||||
},
|
},
|
||||||
"domain": func(websiteURL string) string {
|
"domain": func(websiteURL string) string {
|
||||||
parsedURL, err := url.Parse(websiteURL)
|
parsedURL, err := url.Parse(websiteURL)
|
||||||
|
@ -58,15 +64,15 @@ func (t *TemplateEngine) ParseAll() {
|
||||||
return ts.Format("2006-01-02 15:04:05")
|
return ts.Format("2006-01-02 15:04:05")
|
||||||
},
|
},
|
||||||
"elapsed": func(ts time.Time) string {
|
"elapsed": func(ts time.Time) string {
|
||||||
return helper.GetElapsedTime(t.currentLocale, ts)
|
return helper.GetElapsedTime(e.currentLocale, ts)
|
||||||
},
|
},
|
||||||
"t": func(key interface{}, args ...interface{}) string {
|
"t": func(key interface{}, args ...interface{}) string {
|
||||||
switch key.(type) {
|
switch key.(type) {
|
||||||
case string:
|
case string:
|
||||||
return t.currentLocale.Get(key.(string), args...)
|
return e.currentLocale.Get(key.(string), args...)
|
||||||
case errors.LocalizedError:
|
case errors.LocalizedError:
|
||||||
err := key.(errors.LocalizedError)
|
err := key.(errors.LocalizedError)
|
||||||
return err.Localize(t.currentLocale)
|
return err.Localize(e.currentLocale)
|
||||||
case error:
|
case error:
|
||||||
return key.(error).Error()
|
return key.(error).Error()
|
||||||
default:
|
default:
|
||||||
|
@ -74,7 +80,7 @@ func (t *TemplateEngine) ParseAll() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"plural": func(key string, n int, args ...interface{}) string {
|
"plural": func(key string, n int, args ...interface{}) string {
|
||||||
return t.currentLocale.Plural(key, n, args...)
|
return e.currentLocale.Plural(key, n, args...)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,16 +91,18 @@ func (t *TemplateEngine) ParseAll() {
|
||||||
|
|
||||||
for name, content := range templateViewsMap {
|
for name, content := range templateViewsMap {
|
||||||
log.Println("Parsing template:", name)
|
log.Println("Parsing template:", name)
|
||||||
t.templates[name] = template.Must(template.New("main").Funcs(funcMap).Parse(commonTemplates + content))
|
e.templates[name] = template.Must(template.New("main").Funcs(funcMap).Parse(commonTemplates + content))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TemplateEngine) SetLanguage(language string) {
|
// SetLanguage change the language for template processing.
|
||||||
t.currentLocale = t.translator.GetLanguage(language)
|
func (e *Engine) SetLanguage(language string) {
|
||||||
|
e.currentLocale = e.translator.GetLanguage(language)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TemplateEngine) Execute(w io.Writer, name string, data interface{}) {
|
// Execute process a template.
|
||||||
tpl, ok := t.templates[name]
|
func (e *Engine) Execute(w io.Writer, name string, data interface{}) {
|
||||||
|
tpl, ok := e.templates[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatalf("The template %s does not exists.\n", name)
|
log.Fatalf("The template %s does not exists.\n", name)
|
||||||
}
|
}
|
||||||
|
@ -108,13 +116,15 @@ func (t *TemplateEngine) Execute(w io.Writer, name string, data interface{}) {
|
||||||
b.WriteTo(w)
|
b.WriteTo(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTemplateEngine(router *mux.Router, translator *locale.Translator) *TemplateEngine {
|
// NewEngine returns a new template Engine.
|
||||||
tpl := &TemplateEngine{
|
func NewEngine(cfg *config.Config, router *mux.Router, translator *locale.Translator) *Engine {
|
||||||
|
tpl := &Engine{
|
||||||
templates: make(map[string]*template.Template),
|
templates: make(map[string]*template.Template),
|
||||||
router: router,
|
router: router,
|
||||||
translator: translator,
|
translator: translator,
|
||||||
|
cfg: cfg,
|
||||||
}
|
}
|
||||||
|
|
||||||
tpl.ParseAll()
|
tpl.parseAll()
|
||||||
return tpl
|
return tpl
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// 2017-11-21 15:41:59.472545112 -0800 PST m=+0.018780770
|
// 2017-11-21 19:31:59.633723314 -0800 PST m=+0.012722162
|
||||||
|
|
||||||
package template
|
package template
|
||||||
|
|
||||||
|
@ -13,6 +13,9 @@ var templateViewsMap = map[string]string{
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -267,6 +270,9 @@ var templateViewsMap = map[string]string{
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -401,6 +407,9 @@ var templateViewsMap = map[string]string{
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -725,6 +734,42 @@ var templateViewsMap = map[string]string{
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{{ end }}
|
||||||
|
`,
|
||||||
|
"integrations": `{{ define "title"}}{{ t "Integrations" }}{{ end }}
|
||||||
|
|
||||||
|
{{ define "content"}}
|
||||||
|
<section class="page-header">
|
||||||
|
<h1>{{ t "Integrations" }}</h1>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
|
</li>
|
||||||
|
{{ if .user.IsAdmin }}
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "users" }}">{{ t "Users" }}</a>
|
||||||
|
</li>
|
||||||
|
{{ end }}
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "about" }}">{{ t "About" }}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<h3>{{ t "Bookmarklet" }}</h3>
|
||||||
|
<p>{{ t "This special link allows you to subscribe to a website directly by using a bookmark in your web browser." }}</p>
|
||||||
|
|
||||||
|
<div class="bookmarklet">
|
||||||
|
<a href="javascript:location.href='{{ baseURL }}{{ route "bookmarklet" }}?uri='+encodeURIComponent(window.location.href)">{{ t "Add to Miniflux" }}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>{{ t "Drag and drop this link to your bookmarks." }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
`,
|
`,
|
||||||
"login": `{{ define "title"}}{{ t "Sign In" }}{{ end }}
|
"login": `{{ define "title"}}{{ t "Sign In" }}{{ end }}
|
||||||
|
@ -760,6 +805,9 @@ var templateViewsMap = map[string]string{
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "users" }}">{{ t "Users" }}</a>
|
<a href="{{ route "users" }}">{{ t "Users" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -806,6 +854,9 @@ var templateViewsMap = map[string]string{
|
||||||
<section class="page-header">
|
<section class="page-header">
|
||||||
<h1>{{ t "Settings" }}</h1>
|
<h1>{{ t "Settings" }}</h1>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -920,6 +971,9 @@ var templateViewsMap = map[string]string{
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
<a href="{{ route "settings" }}">{{ t "Settings" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route "integrations" }}">{{ t "Integrations" }}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
<a href="{{ route "sessions" }}">{{ t "Sessions" }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -972,24 +1026,25 @@ var templateViewsMap = map[string]string{
|
||||||
}
|
}
|
||||||
|
|
||||||
var templateViewsMapChecksums = map[string]string{
|
var templateViewsMapChecksums = map[string]string{
|
||||||
"about": "56f1d45d8b9944306c66be0712320527e739a0ce4fccbd97a4c414c8f9cfab04",
|
"about": "ad2fb778fc73c39b733b3f81b13e5c7d689b041fadd24ee2d4577f545aa788ad",
|
||||||
"add_subscription": "098ea9e492e18242bd414b22c4d8638006d113f728e5ae78c9186663f60ae3f1",
|
"add_subscription": "098ea9e492e18242bd414b22c4d8638006d113f728e5ae78c9186663f60ae3f1",
|
||||||
"categories": "ca1280cd157bb527d4fc907da67b05a8347378f6dce965b9389d4bcdf3600a11",
|
"categories": "ca1280cd157bb527d4fc907da67b05a8347378f6dce965b9389d4bcdf3600a11",
|
||||||
"category_entries": "0bdcf28ef29b976b78d1add431896a8c56791476abd7a4240998d52c3efe1f35",
|
"category_entries": "0bdcf28ef29b976b78d1add431896a8c56791476abd7a4240998d52c3efe1f35",
|
||||||
"choose_subscription": "d37682743d8bbd84738a964e238103db2651f95fa340c6e285ffe2e12548d673",
|
"choose_subscription": "d37682743d8bbd84738a964e238103db2651f95fa340c6e285ffe2e12548d673",
|
||||||
"create_category": "2b82af5d2dcd67898dc5daa57a6461e6ff8121a6089b2a2a1be909f35e4a2275",
|
"create_category": "2b82af5d2dcd67898dc5daa57a6461e6ff8121a6089b2a2a1be909f35e4a2275",
|
||||||
"create_user": "966b31d0414e0d0a547ef9ada428cbd24a91100bfed491f780c0461892a2489b",
|
"create_user": "815dd31faaa6e9ba81a2a6664e5707aaf4153c392accd2b1f77cf1937035a881",
|
||||||
"edit_category": "cee720faadcec58289b707ad30af623d2ee66c1ce23a732965463250d7ff41c5",
|
"edit_category": "cee720faadcec58289b707ad30af623d2ee66c1ce23a732965463250d7ff41c5",
|
||||||
"edit_feed": "c5bc4c22bf7e8348d880395250545595d21fb8c8e723fc5d7cca68e25d250884",
|
"edit_feed": "c5bc4c22bf7e8348d880395250545595d21fb8c8e723fc5d7cca68e25d250884",
|
||||||
"edit_user": "f0f79704983de3ca7858bd8cda7a372c3999f5e4e0cf951fba5fa2c1752f9111",
|
"edit_user": "c835d78f7cf36c11533db9cef253457a9003987d704070d59446cb2b0e84dcb9",
|
||||||
"entry": "32e605edd6d43773ac31329d247ebd81d38d974cd43689d91de79fffec7fe04b",
|
"entry": "32e605edd6d43773ac31329d247ebd81d38d974cd43689d91de79fffec7fe04b",
|
||||||
"feed_entries": "9aff923b6c7452dec1514feada7e0d2bbc1ec21c6f5e9f48b2de41d1b731ffe4",
|
"feed_entries": "9aff923b6c7452dec1514feada7e0d2bbc1ec21c6f5e9f48b2de41d1b731ffe4",
|
||||||
"feeds": "94e43404a4044490c065c888a49bebd3ff51b588b9fb47d03c2598003aa40dca",
|
"feeds": "94e43404a4044490c065c888a49bebd3ff51b588b9fb47d03c2598003aa40dca",
|
||||||
"history": "947603cbde888516e62925f5d08fb0b13d930623d3ee4c690dbc22612fdda75e",
|
"history": "947603cbde888516e62925f5d08fb0b13d930623d3ee4c690dbc22612fdda75e",
|
||||||
"import": "73b5112e20bfd232bf73334544186ea419505936bc237d481517a8622901878f",
|
"import": "73b5112e20bfd232bf73334544186ea419505936bc237d481517a8622901878f",
|
||||||
|
"integrations": "c485d6d9ed996635e55e73320610e6bcb01a41c1153e8e739ae2294b0b14b243",
|
||||||
"login": "568f2f69f248048f3e55e9bbc719077a74ae23fe18f237aa40e3de37e97b7a41",
|
"login": "568f2f69f248048f3e55e9bbc719077a74ae23fe18f237aa40e3de37e97b7a41",
|
||||||
"sessions": "5ac3793f0ee74d0807bab6a173a1aa6508e98add5c022fa54c8fdf5c6b4a0e75",
|
"sessions": "878dbe8f8ea783b44130c495814179519fa5c3aa2666ac87508f94d58dd008bf",
|
||||||
"settings": "9c89bfd70ff288b4256e5205be78a7645450b364db1df51d10fee3cb915b2c6b",
|
"settings": "a972fb5767fd32522648149880e40607ed8bbed7a389038bbab6b08539ac2893",
|
||||||
"unread": "b6f9be1a72188947c75a6fdcac6ff7878db7745f9efa46318e0433102892a722",
|
"unread": "b6f9be1a72188947c75a6fdcac6ff7878db7745f9efa46318e0433102892a722",
|
||||||
"users": "c6b1fa81cf229dde88e69c353114b542c67794a2cd513eddaf600828ab14aa18",
|
"users": "44677e28bb5347799ed0020c90ec785aadec4b1454446d92411cfdaf6e32110b",
|
||||||
}
|
}
|
||||||
|
|
20
server/ui/controller/integrations.go
Normal file
20
server/ui/controller/integrations.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import "github.com/miniflux/miniflux2/server/core"
|
||||||
|
|
||||||
|
// ShowIntegrations renders the page with all external integrations.
|
||||||
|
func (c *Controller) ShowIntegrations(ctx *core.Context, request *core.Request, response *core.Response) {
|
||||||
|
args, err := c.getCommonTemplateArgs(ctx)
|
||||||
|
if err != nil {
|
||||||
|
response.HTML().ServerError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.HTML().Render("integrations", args.Merge(tplParams{
|
||||||
|
"menu": "settings",
|
||||||
|
}))
|
||||||
|
}
|
|
@ -5,13 +5,30 @@
|
||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/miniflux/miniflux2/model"
|
"github.com/miniflux/miniflux2/model"
|
||||||
"github.com/miniflux/miniflux2/reader/subscription"
|
"github.com/miniflux/miniflux2/reader/subscription"
|
||||||
"github.com/miniflux/miniflux2/server/core"
|
"github.com/miniflux/miniflux2/server/core"
|
||||||
"github.com/miniflux/miniflux2/server/ui/form"
|
"github.com/miniflux/miniflux2/server/ui/form"
|
||||||
"log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Bookmarklet prefill the form to add a subscription from the URL provided by the bookmarklet.
|
||||||
|
func (c *Controller) Bookmarklet(ctx *core.Context, request *core.Request, response *core.Response) {
|
||||||
|
user := ctx.LoggedUser()
|
||||||
|
args, err := c.getSubscriptionFormTemplateArgs(ctx, user)
|
||||||
|
if err != nil {
|
||||||
|
response.HTML().ServerError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmarkletURL := request.QueryStringParam("uri", "")
|
||||||
|
response.HTML().Render("add_subscription", args.Merge(tplParams{
|
||||||
|
"form": &form.SubscriptionForm{URL: bookmarkletURL},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSubscription shows the form to add a new feed.
|
||||||
func (c *Controller) AddSubscription(ctx *core.Context, request *core.Request, response *core.Response) {
|
func (c *Controller) AddSubscription(ctx *core.Context, request *core.Request, response *core.Response) {
|
||||||
user := ctx.LoggedUser()
|
user := ctx.LoggedUser()
|
||||||
|
|
||||||
|
@ -24,6 +41,7 @@ func (c *Controller) AddSubscription(ctx *core.Context, request *core.Request, r
|
||||||
response.HTML().Render("add_subscription", args)
|
response.HTML().Render("add_subscription", args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubmitSubscription try to find a feed from the URL provided by the user.
|
||||||
func (c *Controller) SubmitSubscription(ctx *core.Context, request *core.Request, response *core.Response) {
|
func (c *Controller) SubmitSubscription(ctx *core.Context, request *core.Request, response *core.Response) {
|
||||||
user := ctx.LoggedUser()
|
user := ctx.LoggedUser()
|
||||||
|
|
||||||
|
@ -80,6 +98,7 @@ func (c *Controller) SubmitSubscription(ctx *core.Context, request *core.Request
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChooseSubscription shows a page to choose a subscription.
|
||||||
func (c *Controller) ChooseSubscription(ctx *core.Context, request *core.Request, response *core.Response) {
|
func (c *Controller) ChooseSubscription(ctx *core.Context, request *core.Request, response *core.Response) {
|
||||||
user := ctx.LoggedUser()
|
user := ctx.LoggedUser()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// 2017-11-21 15:41:59.457985225 -0800 PST m=+0.004220883
|
// 2017-11-21 19:31:59.625242989 -0800 PST m=+0.004241837
|
||||||
|
|
||||||
package sql
|
package sql
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue