Merge pull request #480 from trheyi/main
[add] block export and media api
This commit is contained in:
commit
3c9baec79e
8 changed files with 251 additions and 4 deletions
|
|
@ -44,12 +44,28 @@ var dsl = []byte(`
|
||||||
"process": "sui.Block.Get",
|
"process": "sui.Block.Get",
|
||||||
"in": ["$param.id", "$param.template_id"],
|
"in": ["$param.id", "$param.template_id"],
|
||||||
"out": { "status": 200, "type": "application/json" }
|
"out": { "status": 200, "type": "application/json" }
|
||||||
|
},{
|
||||||
|
"path": "/:id/block/export/:template_id",
|
||||||
|
"method": "GET",
|
||||||
|
"process": "sui.Block.Export",
|
||||||
|
"in": ["$param.id", "$param.template_id"],
|
||||||
|
"out": { "status": 200, "type": "application/json" }
|
||||||
},{
|
},{
|
||||||
"path": "/:id/block/:template_id/:block_id",
|
"path": "/:id/block/:template_id/:block_id",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"process": "sui.Block.Find",
|
"process": "sui.Block.Find",
|
||||||
"in": ["$param.id", "$param.template_id", "$param.block_id"],
|
"in": ["$param.id", "$param.template_id", "$param.block_id"],
|
||||||
"out": { "status": 200, "type": "text/javascript" }
|
"out": { "status": 200, "type": "text/javascript" }
|
||||||
|
},{
|
||||||
|
"path": "/:id/block/:template_id/:block_id/media",
|
||||||
|
"method": "GET",
|
||||||
|
"process": "sui.Block.Media",
|
||||||
|
"in": ["$param.id", "$param.template_id", "$param.block_id"],
|
||||||
|
"out": {
|
||||||
|
"status": 200,
|
||||||
|
"body": "?:content",
|
||||||
|
"headers": { "Content-Type": "?:type"}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,10 @@ func init() {
|
||||||
"locale.get": LocaleGet,
|
"locale.get": LocaleGet,
|
||||||
"theme.get": ThemeGet,
|
"theme.get": ThemeGet,
|
||||||
|
|
||||||
"block.get": BlockGet,
|
"block.get": BlockGet,
|
||||||
"block.find": BlockFind,
|
"block.find": BlockFind,
|
||||||
|
"block.Media": BlockMedia,
|
||||||
|
"block.export": BlockExport,
|
||||||
|
|
||||||
"component.get": ComponentGet,
|
"component.get": ComponentGet,
|
||||||
"component.find": ComponentFind,
|
"component.find": ComponentFind,
|
||||||
|
|
@ -139,6 +141,49 @@ func BlockGet(process *process.Process) interface{} {
|
||||||
return blocks
|
return blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockExport handle the find Template request
|
||||||
|
func BlockExport(process *process.Process) interface{} {
|
||||||
|
process.ValidateArgNums(2)
|
||||||
|
|
||||||
|
sui := get(process)
|
||||||
|
templateID := process.ArgsString(1)
|
||||||
|
|
||||||
|
tmpl, err := sui.GetTemplate(templateID)
|
||||||
|
if err != nil {
|
||||||
|
exception.New(err.Error(), 500).Throw()
|
||||||
|
}
|
||||||
|
|
||||||
|
items, err := tmpl.BlockLayoutItems()
|
||||||
|
if err != nil {
|
||||||
|
exception.New(err.Error(), 500).Throw()
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockMedia handle the find Template request
|
||||||
|
func BlockMedia(process *process.Process) interface{} {
|
||||||
|
process.ValidateArgNums(3)
|
||||||
|
|
||||||
|
sui := get(process)
|
||||||
|
templateID := process.ArgsString(1)
|
||||||
|
blockID := strings.TrimRight(process.ArgsString(2), ".js")
|
||||||
|
|
||||||
|
tmpl, err := sui.GetTemplate(templateID)
|
||||||
|
if err != nil {
|
||||||
|
exception.New(err.Error(), 500).Throw()
|
||||||
|
}
|
||||||
|
|
||||||
|
asset, err := tmpl.BlockMedia(blockID)
|
||||||
|
if err != nil {
|
||||||
|
exception.New(err.Error(), 500).Throw()
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]interface{}{
|
||||||
|
"content": asset.Content,
|
||||||
|
"type": asset.Type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// BlockFind handle the find Template request
|
// BlockFind handle the find Template request
|
||||||
func BlockFind(process *process.Process) interface{} {
|
func BlockFind(process *process.Process) interface{} {
|
||||||
process.ValidateArgNums(3)
|
process.ValidateArgNums(3)
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ func TestTemplateThemeGet(t *testing.T) {
|
||||||
assert.Equal(t, "light", res.([]core.SelectOption)[1].Value)
|
assert.Equal(t, "light", res.([]core.SelectOption)[1].Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTemplateBlockGet(t *testing.T) {
|
func TestBlockGet(t *testing.T) {
|
||||||
load(t)
|
load(t)
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
|
|
@ -138,7 +138,7 @@ func TestTemplateBlockGet(t *testing.T) {
|
||||||
assert.Equal(t, "Table", res.([]core.IBlock)[3].(*local.Block).ID)
|
assert.Equal(t, "Table", res.([]core.IBlock)[3].(*local.Block).ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTemplateBlockFind(t *testing.T) {
|
func TestBlockFind(t *testing.T) {
|
||||||
load(t)
|
load(t)
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
|
|
@ -157,6 +157,43 @@ func TestTemplateBlockFind(t *testing.T) {
|
||||||
assert.Contains(t, res.(string), "window.block__ColumnsTwo=")
|
assert.Contains(t, res.(string), "window.block__ColumnsTwo=")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBlockExport(t *testing.T) {
|
||||||
|
load(t)
|
||||||
|
defer clean()
|
||||||
|
|
||||||
|
// test demo
|
||||||
|
p, err := process.Of("sui.block.export", "demo", "tech-blue")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := p.Exec()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
assert.IsType(t, &core.BlockLayoutItems{}, res)
|
||||||
|
assert.Equal(t, 2, len(res.(*core.BlockLayoutItems).Categories))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBlockMedia(t *testing.T) {
|
||||||
|
load(t)
|
||||||
|
defer clean()
|
||||||
|
|
||||||
|
// test demo
|
||||||
|
p, err := process.Of("sui.block.media", "demo", "tech-blue", "ColumnsTwo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := p.Exec()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
assert.IsType(t, map[string]interface{}{}, res)
|
||||||
|
assert.Equal(t, "image/png", res.(map[string]interface{})["type"])
|
||||||
|
assert.NotEmpty(t, res.(map[string]interface{})["content"])
|
||||||
|
}
|
||||||
|
|
||||||
func TestTemplateComponentGet(t *testing.T) {
|
func TestTemplateComponentGet(t *testing.T) {
|
||||||
load(t)
|
load(t)
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
|
||||||
|
|
@ -60,3 +60,8 @@ func (block *Block) Compile() (string, error) {
|
||||||
func (block *Block) Source() string {
|
func (block *Block) Source() string {
|
||||||
return block.Compiled
|
return block.Compiled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get get the block
|
||||||
|
func (block *Block) Get() *Block {
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ type ITemplate interface {
|
||||||
GetPageFromAsset(asset string) (IPage, error)
|
GetPageFromAsset(asset string) (IPage, error)
|
||||||
|
|
||||||
Blocks() ([]IBlock, error)
|
Blocks() ([]IBlock, error)
|
||||||
|
BlockLayoutItems() (*BlockLayoutItems, error)
|
||||||
|
BlockMedia(id string) (*Asset, error)
|
||||||
Block(name string) (IBlock, error)
|
Block(name string) (IBlock, error)
|
||||||
|
|
||||||
Components() ([]IComponent, error)
|
Components() ([]IComponent, error)
|
||||||
|
|
@ -65,6 +67,7 @@ type IBlock interface {
|
||||||
Compile() (string, error)
|
Compile() (string, error)
|
||||||
Load() error
|
Load() error
|
||||||
Source() string
|
Source() string
|
||||||
|
Get() *Block
|
||||||
}
|
}
|
||||||
|
|
||||||
// IComponent is the interface for the component
|
// IComponent is the interface for the component
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,20 @@ type Block struct {
|
||||||
Codes SourceCodes `json:"-"`
|
Codes SourceCodes `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockLayoutItems is the struct for the block layout items
|
||||||
|
type BlockLayoutItems struct {
|
||||||
|
Categories []LayoutItem `json:"categories"`
|
||||||
|
Locals map[string]map[string]string `json:"locals,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LayoutItem is the struct for the layout it
|
||||||
|
type LayoutItem struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Label string `json:"label,omitempty"`
|
||||||
|
Width int `json:"width,omitempty"`
|
||||||
|
Blocks []LayoutItem `json:"blocks,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Template is the struct for the template
|
// Template is the struct for the template
|
||||||
type Template struct {
|
type Template struct {
|
||||||
Version int `json:"version"` // Yao Builder version
|
Version int `json:"version"` // Yao Builder version
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/yaoapp/gou/application"
|
||||||
"github.com/yaoapp/kun/log"
|
"github.com/yaoapp/kun/log"
|
||||||
"github.com/yaoapp/yao/sui/core"
|
"github.com/yaoapp/yao/sui/core"
|
||||||
)
|
)
|
||||||
|
|
@ -64,6 +65,86 @@ func (tmpl *Template) Block(id string) (core.IBlock, error) {
|
||||||
return block, nil
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockMedia get the block media
|
||||||
|
func (tmpl *Template) BlockMedia(id string) (*core.Asset, error) {
|
||||||
|
path := filepath.Join(tmpl.Root, "__blocks", id, "media.png")
|
||||||
|
if exist, _ := tmpl.local.fs.Exists(path); exist {
|
||||||
|
|
||||||
|
content, err := tmpl.local.fs.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &core.Asset{
|
||||||
|
Type: "image/png",
|
||||||
|
Content: content,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
path = filepath.Join(tmpl.Root, "__blocks", id, "media.svg")
|
||||||
|
if exist, _ := tmpl.local.fs.Exists(path); !exist {
|
||||||
|
return nil, fmt.Errorf("Block %s media not found (media.png / media.png )", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := tmpl.local.fs.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &core.Asset{
|
||||||
|
Type: "image/svg+xml",
|
||||||
|
Content: content,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockLayoutItems export the blocks
|
||||||
|
func (tmpl *Template) BlockLayoutItems() (*core.BlockLayoutItems, error) {
|
||||||
|
|
||||||
|
path := filepath.Join(tmpl.Root, "__blocks", "export.json")
|
||||||
|
if exist, _ := tmpl.local.fs.Exists(path); !exist {
|
||||||
|
|
||||||
|
blocks, err := tmpl.Blocks()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default layout items
|
||||||
|
layoutItems := &core.BlockLayoutItems{
|
||||||
|
Categories: []core.LayoutItem{{
|
||||||
|
ID: "Basic",
|
||||||
|
Label: "Basic",
|
||||||
|
Blocks: []core.LayoutItem{},
|
||||||
|
}},
|
||||||
|
Locals: map[string]map[string]string{
|
||||||
|
"zh-CN": {"Basic": "基础"},
|
||||||
|
"zh-TW": {"Basic": "基礎"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, block := range blocks {
|
||||||
|
layoutItems.Categories[0].Blocks = append(
|
||||||
|
layoutItems.Categories[0].Blocks, core.LayoutItem{
|
||||||
|
ID: block.Get().ID,
|
||||||
|
Label: block.Get().Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return layoutItems, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := tmpl.local.fs.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
layoutItems := core.BlockLayoutItems{}
|
||||||
|
err = application.Parse(path, data, &layoutItems)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &layoutItems, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Load get the block from the storage
|
// Load get the block from the storage
|
||||||
func (block *Block) Load() error {
|
func (block *Block) Load() error {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,3 +81,49 @@ func TestTemplateBlockTS(t *testing.T) {
|
||||||
assert.Contains(t, block.(*Block).Compiled, "window.block__Hero")
|
assert.Contains(t, block.(*Block).Compiled, "window.block__Hero")
|
||||||
assert.Contains(t, block.(*Block).Compiled, `<div data-gjs-type='Nav'></div>`)
|
assert.Contains(t, block.(*Block).Compiled, `<div data-gjs-type='Nav'></div>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBlockLayoutItems(t *testing.T) {
|
||||||
|
tests := prepare(t)
|
||||||
|
defer clean()
|
||||||
|
|
||||||
|
tmpl, err := tests.Demo.GetTemplate("tech-blue")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetTemplate error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
items, err := tmpl.BlockLayoutItems()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BlockLayoutItems error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 2, len(items.Categories))
|
||||||
|
|
||||||
|
tmpl, err = tests.Demo.GetTemplate("website-ai")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetTemplate error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
items, err = tmpl.BlockLayoutItems()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BlockLayoutItems error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 1, len(items.Categories))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBlockMedia(t *testing.T) {
|
||||||
|
tests := prepare(t)
|
||||||
|
defer clean()
|
||||||
|
|
||||||
|
tmpl, err := tests.Demo.GetTemplate("tech-blue")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetTemplate error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
media, err := tmpl.BlockMedia("ColumnsTwo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BlockMedia error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, "image/png", media.Type)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue