Added files
This commit is contained in:
commit
2be4a86553
14 changed files with 533 additions and 0 deletions
104
.gitignore
vendored
Normal file
104
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# dotenv
|
||||||
|
.env
|
||||||
|
|
||||||
|
# virtualenv
|
||||||
|
.venv
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
|
||||||
|
# Images
|
||||||
|
media/images/editor
|
||||||
8
__init__.py
Normal file
8
__init__.py
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#from flask import Blueprint, g, request, session, redirect, url_for
|
||||||
|
|
||||||
|
#pages2_app=Blueprint('pages2_app', __name__)
|
||||||
|
from bottle import Bottle
|
||||||
|
|
||||||
|
pages2_app=Bottle()
|
||||||
|
|
||||||
|
|
||||||
0
admin/__init__.py
Normal file
0
admin/__init__.py
Normal file
118
admin/pages.py
Normal file
118
admin/pages.py
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
import os
|
||||||
|
from cuchulu.libraries.generate_admin_class import GenerateAdminClass
|
||||||
|
#from cuchulu.libraries.db.adminutils import make_admin_url
|
||||||
|
#from paramecio.citoplasma.urls import make_url
|
||||||
|
from cuchulu.libraries.i18n import I18n
|
||||||
|
from settings import config
|
||||||
|
from modules.pages2.models import pages
|
||||||
|
|
||||||
|
from cuchulu.libraries.db.coreforms import BaseForm
|
||||||
|
from cuchulu.modules.admin import admin_app, t as admin_t
|
||||||
|
#from flask import url_for, g
|
||||||
|
from cuchulu.libraries.urls import url_for
|
||||||
|
from cuchulu.libraries.mtemplates import env_theme, PTemplate
|
||||||
|
from bottle import request
|
||||||
|
from cuchulu.libraries.urls import make_media_url
|
||||||
|
try:
|
||||||
|
import ujson as json
|
||||||
|
except:
|
||||||
|
import json
|
||||||
|
|
||||||
|
env=env_theme(__file__)
|
||||||
|
|
||||||
|
t=PTemplate(env)
|
||||||
|
|
||||||
|
t.env.directories=admin_t.env.directories
|
||||||
|
|
||||||
|
t.env.directories.insert(1, os.path.dirname(__file__).replace('/admin', '')+'/templates/admin')
|
||||||
|
|
||||||
|
class TextEditorJsForm(BaseForm):
|
||||||
|
"""Form for html texts, based in tinycme javascript library"""
|
||||||
|
|
||||||
|
def __init__(self, name, value, t_add=None):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
name (str): The html name for this form
|
||||||
|
value (str): The default value of this html form.
|
||||||
|
t_add (PTemplate): If you want change the standard html form, use other template loader
|
||||||
|
"""
|
||||||
|
|
||||||
|
super().__init__(name, value)
|
||||||
|
|
||||||
|
self.t=t_add
|
||||||
|
|
||||||
|
if t_add==None:
|
||||||
|
self.t=t
|
||||||
|
|
||||||
|
#if type(self.default_value)==dict:
|
||||||
|
|
||||||
|
# self.default_value=json.dumps(value)
|
||||||
|
|
||||||
|
def form(self):
|
||||||
|
|
||||||
|
return self.t.load_template('editorjsform.phtml', form=self)
|
||||||
|
|
||||||
|
@admin_app.get('/admin/pages2', name='admin_app.admin_pages2')
|
||||||
|
@admin_app.post('/admin/pages2', name='admin_app.admin_pages2')
|
||||||
|
def admin_pages2(db=True):
|
||||||
|
|
||||||
|
#t=admin_t
|
||||||
|
|
||||||
|
conn=db
|
||||||
|
|
||||||
|
page=pages.Page2(conn)
|
||||||
|
|
||||||
|
page.enctype=True
|
||||||
|
|
||||||
|
page.fields['slugify'].name_form=BaseForm
|
||||||
|
|
||||||
|
page.fields['text'].name_form=TextEditorJsForm
|
||||||
|
|
||||||
|
#page.fields['text'].extra_parameters[0].t=t
|
||||||
|
|
||||||
|
#url=make_admin_url('pages')
|
||||||
|
url=url_for('admin_app.admin_pages2')
|
||||||
|
|
||||||
|
admin=GenerateAdminClass(page, url, t)
|
||||||
|
|
||||||
|
admin.list.fields_showed=['id', 'title', 'slugify']
|
||||||
|
|
||||||
|
form_admin=admin.show()
|
||||||
|
|
||||||
|
#return admin.show()
|
||||||
|
if type(form_admin).__name__=='str':
|
||||||
|
|
||||||
|
return t.load_template('content.phtml', title=I18n.lang('pages', 'pages', 'Pages'), contents=form_admin, path_module='admin_app.admin_pages2')
|
||||||
|
else:
|
||||||
|
|
||||||
|
return form_admin
|
||||||
|
|
||||||
|
|
||||||
|
@admin_app.post('/pages/upload_image', name="admin_app.pages2_upload_image")
|
||||||
|
def pages2_upload_image():
|
||||||
|
|
||||||
|
success=0
|
||||||
|
|
||||||
|
new_url=''
|
||||||
|
|
||||||
|
if 'image' in request.files:
|
||||||
|
|
||||||
|
file=request.files['image']
|
||||||
|
|
||||||
|
images_dir='./modules/pages2/media/images/editor'
|
||||||
|
|
||||||
|
if not os.path.isdir(images_dir):
|
||||||
|
#os.mkdir(images_dir)
|
||||||
|
pathlib.Path(images_dir).mkdir(0o755, True)
|
||||||
|
|
||||||
|
filename=file.filename
|
||||||
|
|
||||||
|
if not os.path.isfile(images_dir+'/'+filename):
|
||||||
|
file.save(os.path.join(images_dir, filename))
|
||||||
|
|
||||||
|
success=1
|
||||||
|
|
||||||
|
new_url=make_media_url('images/editor/'+filename, 'pages2')
|
||||||
|
|
||||||
|
return {'success': success, 'file': {'url': new_url}}
|
||||||
|
|
||||||
79
app.py
Normal file
79
app.py
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
#from paramecio.wsgiapp import app
|
||||||
|
from cuchulu.libraries.mtemplates import PTemplate, env_theme
|
||||||
|
from modules.pages2.models.pages import Page2
|
||||||
|
from cuchulu.libraries.db.webmodel import WebModel
|
||||||
|
from settings import config
|
||||||
|
from bottle import abort
|
||||||
|
#from flask import abort, request
|
||||||
|
from modules.pages2 import pages2_app
|
||||||
|
from cuchulu.libraries.db.coreforms import BaseForm
|
||||||
|
from cuchulu.libraries.mtemplates import env_theme, PTemplate
|
||||||
|
from cuchulu.libraries.urls import make_media_url
|
||||||
|
import os
|
||||||
|
#from werkzeug.utils import secure_filename
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ujson as json
|
||||||
|
except:
|
||||||
|
import json
|
||||||
|
|
||||||
|
env=env_theme(__file__)
|
||||||
|
|
||||||
|
t=PTemplate(env)
|
||||||
|
|
||||||
|
pages_modules_to_search=[]
|
||||||
|
|
||||||
|
if hasattr(config, 'pages_modules_to_search'):
|
||||||
|
pages_modules_to_search=config.pages_modules_to_search
|
||||||
|
|
||||||
|
for mod in pages_modules_to_search:
|
||||||
|
|
||||||
|
t.env.directories.insert(0, mod.replace('.', '/')+'/templates')
|
||||||
|
|
||||||
|
@pages2_app.route('/page/<page_id:int>')
|
||||||
|
@pages2_app.route('/page/<slug:path>', name="pages2_app.pages2_home")
|
||||||
|
def pages2_home(page_id=0, slug=''):
|
||||||
|
|
||||||
|
conn=WebModel.connection()
|
||||||
|
|
||||||
|
page=Page2(conn)
|
||||||
|
|
||||||
|
page.show_formatted=True
|
||||||
|
|
||||||
|
if page_id:
|
||||||
|
|
||||||
|
page.set_conditions('WHERE id=%s', [page_id])
|
||||||
|
|
||||||
|
if slug:
|
||||||
|
|
||||||
|
page.set_conditions('WHERE slugify=%s', [slug])
|
||||||
|
|
||||||
|
arr_page=page.select_a_row_where()
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
if arr_page:
|
||||||
|
|
||||||
|
arr_final_text=[]
|
||||||
|
|
||||||
|
arr_text=json.loads(arr_page['text'])
|
||||||
|
|
||||||
|
return t.load_template('page2.phtml', title_page=arr_page['title'], content_page=arr_text)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
abort(404, 'Page not found')
|
||||||
|
|
||||||
|
|
||||||
|
@pages2_app.route('/home/')
|
||||||
|
def pages_home():
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
if config.default_module=="pages2":
|
||||||
|
|
||||||
|
home=pages2_app.route("/")(pages2_home)
|
||||||
2
media/js/editorjs-list.umd.js
Normal file
2
media/js/editorjs-list.umd.js
Normal file
File diff suppressed because one or more lines are too long
51
media/js/editorjs.umd.js
Normal file
51
media/js/editorjs.umd.js
Normal file
File diff suppressed because one or more lines are too long
9
media/js/header.umd.js
Normal file
9
media/js/header.umd.js
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
(function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode(".ce-header{padding:.6em 0 3px;margin:0;line-height:1.25em;outline:none}.ce-header p,.ce-header div{padding:0!important;margin:0!important}")),document.head.appendChild(e)}}catch(n){console.error("vite-plugin-css-injected-by-js",n)}})();
|
||||||
|
(function(n,s){typeof exports=="object"&&typeof module<"u"?module.exports=s():typeof define=="function"&&define.amd?define(s):(n=typeof globalThis<"u"?globalThis:n||self,n.Header=s())})(this,function(){"use strict";const n="",s='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M6 7L6 12M6 17L6 12M6 12L12 12M12 7V12M12 17L12 12"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M19 17V10.2135C19 10.1287 18.9011 10.0824 18.836 10.1367L16 12.5"/></svg>',a='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M6 7L6 12M6 17L6 12M6 12L12 12M12 7V12M12 17L12 12"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M16 11C16 10 19 9.5 19 12C19 13.9771 16.0684 13.9997 16.0012 16.8981C15.9999 16.9533 16.0448 17 16.1 17L19.3 17"/></svg>',h='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M6 7L6 12M6 17L6 12M6 12L12 12M12 7V12M12 17L12 12"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M16 11C16 10.5 16.8323 10 17.6 10C18.3677 10 19.5 10.311 19.5 11.5C19.5 12.5315 18.7474 12.9022 18.548 12.9823C18.5378 12.9864 18.5395 13.0047 18.5503 13.0063C18.8115 13.0456 20 13.3065 20 14.8C20 16 19.5 17 17.8 17C17.8 17 16 17 16 16.3"/></svg>',d='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M6 7L6 12M6 17L6 12M6 12L12 12M12 7V12M12 17L12 12"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M18 10L15.2834 14.8511C15.246 14.9178 15.294 15 15.3704 15C16.8489 15 18.7561 15 20.2 15M19 17C19 15.7187 19 14.8813 19 13.6"/></svg>',u='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M6 7L6 12M6 17L6 12M6 12L12 12M12 7V12M12 17L12 12"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M16 15.9C16 15.9 16.3768 17 17.8 17C19.5 17 20 15.6199 20 14.7C20 12.7323 17.6745 12.0486 16.1635 12.9894C16.094 13.0327 16 12.9846 16 12.9027V10.1C16 10.0448 16.0448 10 16.1 10H19.8"/></svg>',g='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M6 7L6 12M6 17L6 12M6 12L12 12M12 7V12M12 17L12 12"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M19.5 10C16.5 10.5 16 13.3285 16 15M16 15V15C16 16.1046 16.8954 17 18 17H18.3246C19.3251 17 20.3191 16.3492 20.2522 15.3509C20.0612 12.4958 16 12.6611 16 15Z"/></svg>',c='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M9 7L9 12M9 17V12M9 12L15 12M15 7V12M15 17L15 12"/></svg>';/**
|
||||||
|
* Header block for the Editor.js.
|
||||||
|
*
|
||||||
|
* @author CodeX (team@ifmo.su)
|
||||||
|
* @copyright CodeX 2018
|
||||||
|
* @license MIT
|
||||||
|
* @version 2.0.0
|
||||||
|
*/class v{constructor({data:e,config:t,api:i,readOnly:r}){this.api=i,this.readOnly=r,this._settings=t,this._data=this.normalizeData(e),this._element=this.getTag()}get _CSS(){return{block:this.api.styles.block,wrapper:"ce-header"}}isHeaderData(e){return e.text!==void 0}normalizeData(e){const t={text:"",level:this.defaultLevel.number};return this.isHeaderData(e)&&(t.text=e.text||"",e.level!==void 0&&!isNaN(parseInt(e.level.toString()))&&(t.level=parseInt(e.level.toString()))),t}render(){return this._element}renderSettings(){return this.levels.map(e=>({icon:e.svg,label:this.api.i18n.t(`Heading ${e.number}`),onActivate:()=>this.setLevel(e.number),closeOnActivate:!0,isActive:this.currentLevel.number===e.number,render:()=>document.createElement("div")}))}setLevel(e){this.data={level:e,text:this.data.text}}merge(e){this._element.insertAdjacentHTML("beforeend",e.text)}validate(e){return e.text.trim()!==""}save(e){return{text:e.innerHTML,level:this.currentLevel.number}}static get conversionConfig(){return{export:"text",import:"text"}}static get sanitize(){return{level:!1,text:{}}}static get isReadOnlySupported(){return!0}get data(){return this._data.text=this._element.innerHTML,this._data.level=this.currentLevel.number,this._data}set data(e){if(this._data=this.normalizeData(e),e.level!==void 0&&this._element.parentNode){const t=this.getTag();t.innerHTML=this._element.innerHTML,this._element.parentNode.replaceChild(t,this._element),this._element=t}e.text!==void 0&&(this._element.innerHTML=this._data.text||"")}getTag(){const e=document.createElement(this.currentLevel.tag);return e.innerHTML=this._data.text||"",e.classList.add(this._CSS.wrapper),e.contentEditable=this.readOnly?"false":"true",e.dataset.placeholder=this.api.i18n.t(this._settings.placeholder||""),e}get currentLevel(){let e=this.levels.find(t=>t.number===this._data.level);return e||(e=this.defaultLevel),e}get defaultLevel(){if(this._settings.defaultLevel){const e=this.levels.find(t=>t.number===this._settings.defaultLevel);if(e)return e;console.warn("(ง'̀-'́)ง Heading Tool: the default level specified was not found in available levels")}return this.levels[1]}get levels(){const e=[{number:1,tag:"H1",svg:s},{number:2,tag:"H2",svg:a},{number:3,tag:"H3",svg:h},{number:4,tag:"H4",svg:d},{number:5,tag:"H5",svg:u},{number:6,tag:"H6",svg:g}];return this._settings.levels?e.filter(t=>this._settings.levels.includes(t.number)):e}onPaste(e){const t=e.detail;if("data"in t){const i=t.data;let r=this.defaultLevel.number;switch(i.tagName){case"H1":r=1;break;case"H2":r=2;break;case"H3":r=3;break;case"H4":r=4;break;case"H5":r=5;break;case"H6":r=6;break}this._settings.levels&&(r=this._settings.levels.reduce((o,l)=>Math.abs(l-r)<Math.abs(o-r)?l:o)),this.data={level:r,text:i.innerHTML}}}static get pasteConfig(){return{tags:["H1","H2","H3","H4","H5","H6"]}}static get toolbox(){return{icon:c,title:"Heading"}}}return v});
|
||||||
30
media/js/image.umd.js
Normal file
30
media/js/image.umd.js
Normal file
File diff suppressed because one or more lines are too long
42
models/pages.py
Normal file
42
models/pages.py
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
from cuchulu.libraries.db.extrafields.i18nfield import I18nHTMLField, I18nField
|
||||||
|
from cuchulu.libraries.db.extrafields.jsonfield import JsonField, JsonValueField
|
||||||
|
from cuchulu.libraries.db.extrafields.slugifyfield import SlugifyField
|
||||||
|
from cuchulu.libraries.db.webmodel import WebModel
|
||||||
|
from cuchulu.libraries.db.extraforms.texthtmlform import TextHTMLForm
|
||||||
|
from cuchulu.libraries.db import corefields
|
||||||
|
from cuchulu.libraries.i18n import I18n
|
||||||
|
import json
|
||||||
|
|
||||||
|
class Page2(WebModel):
|
||||||
|
|
||||||
|
def create_fields(self):
|
||||||
|
|
||||||
|
self.register(corefields.HTMLField('title'), True)
|
||||||
|
#self.register(I18nHTMLField('text', TextHTMLForm('text', '')), True)
|
||||||
|
self.register(JsonValueField('text'), True)
|
||||||
|
|
||||||
|
self.register(SlugifyField('slugify'), True)
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
def insert(self, dict_values, external_agent=True):
|
||||||
|
|
||||||
|
slugify=json.loads(dict_values.get('title', '{}'))
|
||||||
|
|
||||||
|
lang=I18n.get_default_lang()
|
||||||
|
|
||||||
|
dict_values['slugify']=slugify.get(lang, '')
|
||||||
|
|
||||||
|
return super().insert(dict_values, external_agent)
|
||||||
|
|
||||||
|
def update(self, dict_values, external_agent=True):
|
||||||
|
|
||||||
|
slugify=json.loads(dict_values.get('title', '{}'))
|
||||||
|
|
||||||
|
lang=I18n.get_default_lang()
|
||||||
|
|
||||||
|
dict_values['slugify']=slugify.get(lang, '')
|
||||||
|
|
||||||
|
return super().update(dict_values, external_agent)
|
||||||
|
"""
|
||||||
|
|
||||||
0
settings/__init__.py
Normal file
0
settings/__init__.py
Normal file
14
settings/config_admin.py
Normal file
14
settings/config_admin.py
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
from cuchulu.libraries.i18n import I18n, load_lang
|
||||||
|
from cuchulu.libraries.config_admin import config_admin
|
||||||
|
|
||||||
|
#from modules.pokermind.i18n import runchained
|
||||||
|
|
||||||
|
#modules_other=[I18n.lang('pages', 'pages', 'Pages'), 'modules.pages.admin.pages', 'pages']
|
||||||
|
|
||||||
|
#modules_admin.append(modules_other)
|
||||||
|
|
||||||
|
# '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" width="24" style="fill: currentColor;display: inline-block;vertical-align: -.130em;position:relative;left:-6px;top:4px;"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M264 112L376 112C380.4 112 384 115.6 384 120L384 160L256 160L256 120C256 115.6 259.6 112 264 112zM208 120L208 160L128 160C92.7 160 64 188.7 64 224L64 320L369 320C402.8 290.1 447.3 272 496 272C524.6 272 551.6 278.2 576 289.4L576 224C576 188.7 547.3 160 512 160L432 160L432 120C432 89.1 406.9 64 376 64L264 64C233.1 64 208 89.1 208 120zM288 416C270.3 416 256 401.7 256 384L256 368L64 368L64 480C64 515.3 92.7 544 128 544L321.4 544C310.2 519.6 304 492.6 304 464C304 447.4 306.1 431.3 310 416L288 416zM640 464C640 384.5 575.5 320 496 320C416.5 320 352 384.5 352 464C352 543.5 416.5 608 496 608C575.5 608 640 543.5 640 464zM496 384C504.8 384 512 391.2 512 400L512 448L544 448C552.8 448 560 455.2 560 464C560 472.8 552.8 480 544 480L496 480C487.2 480 480 472.8 480 464L480 400C480 391.2 487.2 384 496 384z"/></svg>'
|
||||||
|
|
||||||
|
config_admin.append([_('Pages Editor')])
|
||||||
|
|
||||||
|
config_admin.append([_('Edit pages'), 'modules.pages2.admin.pages', 'admin_app.admin_pages2', '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" width="24" style="fill: currentColor;display: inline-block;vertical-align: -.130em;position:relative;left:-6px;top:2px;"><!--!Font Awesome Free v7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M392.8 65.2C375.8 60.3 358.1 70.2 353.2 87.2L225.2 535.2C220.3 552.2 230.2 569.9 247.2 574.8C264.2 579.7 281.9 569.8 286.8 552.8L414.8 104.8C419.7 87.8 409.8 70.1 392.8 65.2zM457.4 201.3C444.9 213.8 444.9 234.1 457.4 246.6L530.8 320L457.4 393.4C444.9 405.9 444.9 426.2 457.4 438.7C469.9 451.2 490.2 451.2 502.7 438.7L598.7 342.7C611.2 330.2 611.2 309.9 598.7 297.4L502.7 201.4C490.2 188.9 469.9 188.9 457.4 201.4zM182.7 201.3C170.2 188.8 149.9 188.8 137.4 201.3L41.4 297.3C28.9 309.8 28.9 330.1 41.4 342.6L137.4 438.6C149.9 451.1 170.2 451.1 182.7 438.6C195.2 426.1 195.2 405.8 182.7 393.3L109.3 320L182.6 246.6C195.1 234.1 195.1 213.8 182.6 201.3z"/></svg>'])
|
||||||
60
templates/admin/editorjsform.phtml
Normal file
60
templates/admin/editorjsform.phtml
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
% if type(form.default_value)==dict:
|
||||||
|
<%
|
||||||
|
form.default_value='{}'
|
||||||
|
%>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<div id="${form.name_field_id}_editor" style="background: #454545; color: #fbfbfb;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="${form.name}" id="${form.name_field_id}" />
|
||||||
|
</p>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
const editor = new EditorJS( {holder : '${form.name_field_id}_editor', data: ${form.default_value|n} ,
|
||||||
|
|
||||||
|
tools: {
|
||||||
|
|
||||||
|
image: {
|
||||||
|
class: ImageTool,
|
||||||
|
config: {
|
||||||
|
endpoints: {
|
||||||
|
byFile: "${url_for('admin_app.pages2_upload_image')}", // Your backend file uploader endpoint
|
||||||
|
//byUrl: "${url_for('admin_app.pages2_upload_image')}", // Your endpoint that provides uploading by Url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
List: {
|
||||||
|
class: EditorjsList,
|
||||||
|
inlineToolbar: true,
|
||||||
|
config: {
|
||||||
|
defaultStyle: 'unordered'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
class: Header,
|
||||||
|
shortcut: 'CMD+SHIFT+H',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$('form').submit(function (e) {
|
||||||
|
|
||||||
|
editor.save().then((outputData) => {
|
||||||
|
console.log('Article data: ', outputData)
|
||||||
|
|
||||||
|
$('#${form.name_field_id}').val(JSON.stringify(outputData));
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log('Saving failed: ', error)
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
${add_js('editorjs.umd.js', 'pages2')}
|
||||||
|
${add_js('image.umd.js', 'pages2')}
|
||||||
|
${add_js('header.umd.js', 'pages2')}
|
||||||
|
${add_js('editorjs-list.umd.js', 'pages2')}
|
||||||
16
templates/page2.phtml
Normal file
16
templates/page2.phtml
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<div class="title">${title_page}</div>
|
||||||
|
<div class="content">
|
||||||
|
% for jtext in content_page['blocks']:
|
||||||
|
|
||||||
|
% if jtext['type']=='paragraph':
|
||||||
|
|
||||||
|
<p>${jtext['data']['text']|n}</p>
|
||||||
|
|
||||||
|
% elif jtext['type']=='image':
|
||||||
|
|
||||||
|
<p align="center"><img src="${jtext['data']['file']['url']}" style="width:50%;" title="${jtext['data']['caption']}" /><br /><strong>${jtext['data']['caption']|n}</strong></p>
|
||||||
|
|
||||||
|
% endif
|
||||||
|
|
||||||
|
% endfor
|
||||||
|
</div>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue