Remove ckeditor
Remove tinymce Begin migrate to mithril.js
This commit is contained in:
44
myapp/templates/components/backtotop.js
Normal file
44
myapp/templates/components/backtotop.js
Normal file
@@ -0,0 +1,44 @@
|
||||
function Backtotop() {
|
||||
let data = {
|
||||
get visible() {
|
||||
return data.raw_visible;
|
||||
},
|
||||
set visible(value) {
|
||||
if (data.raw_visible!=value) {
|
||||
m.redraw();
|
||||
}
|
||||
data.raw_visible = value;
|
||||
},
|
||||
raw_visible: false,
|
||||
}
|
||||
function backToTop() {
|
||||
let currentScroll = document.documentElement.scrollTop || document.body.scrollTop
|
||||
if (currentScroll > 0) {
|
||||
window.scrollTo(0, 0)
|
||||
}
|
||||
};
|
||||
function catchScroll() {
|
||||
data.visible = (window.pageYOffset > 100);
|
||||
};
|
||||
return {
|
||||
oninit: function(vnode) {
|
||||
window.addEventListener('scroll', catchScroll);
|
||||
let currentScroll = document.documentElement.scrollTop || document.body.scrollTop
|
||||
data.visible = (currentScroll > 100);
|
||||
},
|
||||
onremove: function(vnode) {
|
||||
window.removeEventListener('scroll', catchScroll)
|
||||
},
|
||||
view: function(vnode) {
|
||||
if (data.visible) {
|
||||
return m('div', {class: 'scrollToTop', style: 'z-index: 10;', onclick: backToTop},
|
||||
m('div', {class: 'card'},
|
||||
m('div', {class: 'card-body py-2 px-2'},
|
||||
m('i', {class: 'fa fa-chevron-up'})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
52
myapp/templates/components/filter.js
Normal file
52
myapp/templates/components/filter.js
Normal file
@@ -0,0 +1,52 @@
|
||||
function PanelFilter() {
|
||||
let data = {
|
||||
visible: false,
|
||||
value: '',
|
||||
isregex: false,
|
||||
};
|
||||
function filter_clear() {
|
||||
data.value = '';
|
||||
};
|
||||
function filter_apply() {};
|
||||
function form_submit(e) {
|
||||
e.preventDefault();
|
||||
filter_apply();
|
||||
};
|
||||
function button_isregex_render() {
|
||||
if (data.isregex) {
|
||||
return m('button', {class: 'btn btn-outline-secondary', type: 'button', onclick: function() { data.isregex = false;}}, '(.*)');
|
||||
} else {
|
||||
return m('button', {class: 'btn btn-outline-secondary', type: 'button', onclick: function() { data.isregex = true;}}, 'T');
|
||||
}
|
||||
};
|
||||
return {
|
||||
data: data,
|
||||
oninit: function(vnode) {
|
||||
console.log('PanelFilter.oninit');
|
||||
for (let key in vnode.attrs){
|
||||
data[key] = vnode.attrs[key];
|
||||
};
|
||||
},
|
||||
view: function() {
|
||||
console.log('PanelFilter.view');
|
||||
result = [];
|
||||
if (data.visible){
|
||||
result.push(
|
||||
m('div', {class: "row"},
|
||||
m('div', {class: "col py-2"},
|
||||
m('form', {onsubmit: form_submit},
|
||||
m('div', {class: "input-group mb-3"}, [
|
||||
m('button', {class: 'btn btn-outline-danger', onclick: function() {filter_clear()}}, m('i', {class: 'fa fa-remove'})),
|
||||
button_isregex_render(),
|
||||
m('input', {class: 'form-control', oninput: function (e) {data.value = e.target.value}, value: data.value}),
|
||||
m('button', {class: 'btn btn-outline-success', onclick: function() {filter_apply()}}, m('i', {class: 'fa fa-check'})),
|
||||
])
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
4
myapp/templates/components/inc.j2
Normal file
4
myapp/templates/components/inc.j2
Normal file
@@ -0,0 +1,4 @@
|
||||
{% include '/components/backtotop.js' %}
|
||||
{% include '/components/filter.js' %}
|
||||
{% include '/components/order_by.js' %}
|
||||
{% include '/components/pagination.js' %}
|
||||
57
myapp/templates/components/order_by.js
Normal file
57
myapp/templates/components/order_by.js
Normal file
@@ -0,0 +1,57 @@
|
||||
function PanelOrderBy(arguments) {
|
||||
let data = {
|
||||
visible: false,
|
||||
field: 'id',
|
||||
order: 'desc',
|
||||
fields: [{value: 'id', text: 'ID'}],
|
||||
clickHandler: function() {}
|
||||
}
|
||||
for (let key in arguments){
|
||||
data[key] = arguments[key];
|
||||
}
|
||||
return {
|
||||
data: data,
|
||||
value: function() {
|
||||
return {
|
||||
"field": data.field,
|
||||
"order": data.order
|
||||
};
|
||||
},
|
||||
oninit: function(vnode) {
|
||||
console.log('PanelOrderBy.oninit');
|
||||
for (let key in vnode.attrs){
|
||||
data[key] = vnode.attrs[key];
|
||||
};
|
||||
},
|
||||
view: function(vnode) {
|
||||
console.log('PanelOrderBy.view');
|
||||
if (data.visible) {
|
||||
let options = data.fields.map(
|
||||
function(item) {
|
||||
return m('option', {value: item.value}, item.text);
|
||||
}
|
||||
);
|
||||
let order_button = null;
|
||||
if (data.order==='asc') {
|
||||
order_button = m('button', {type: "button", class: "btn btn-outline-secondary", onclick: function() { data.order = 'desc'; data.clickHandler() }},
|
||||
m('i', {class: "fa fa-sort-alpha-asc"})
|
||||
);
|
||||
} else {
|
||||
order_button = m('button', {type: "button", class: "btn btn-outline-secondary", onclick: function() { data.order = 'asc'; data.clickHandler() }},
|
||||
m('i', {class: "fa fa-sort-alpha-desc"})
|
||||
);
|
||||
}
|
||||
return [
|
||||
m('div', {class: "row"}, [
|
||||
m('div', {class: "col py-2"}, [
|
||||
m('div', {class: "input-group"}, [
|
||||
order_button,
|
||||
m('select', {class: "form-select", onchange: function(e) { data.field = e.target.value; data.clickHandler() }}, [...options])
|
||||
])
|
||||
])
|
||||
])
|
||||
];
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
165
myapp/templates/components/pagination.js
Normal file
165
myapp/templates/components/pagination.js
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
pagination: Pagination({
|
||||
clickHandler: resumes_get,
|
||||
prefix_url: '/resumes'
|
||||
}),
|
||||
|
||||
oninit: function(vnode) {
|
||||
let pagination = data.pagination.data;
|
||||
if (vnode.attrs.page!==undefined) {
|
||||
pagination.page = Number(vnode.attrs.page);
|
||||
}
|
||||
resumes_get();
|
||||
},
|
||||
*/
|
||||
function Pagination(arguments) {
|
||||
let data = {
|
||||
page: 1,
|
||||
per_page: SETTINGS.ITEMS_ON_PAGE,
|
||||
size: 0,
|
||||
prefix_url: '',
|
||||
clickHandler: function() {}
|
||||
};
|
||||
for (let key in arguments){
|
||||
data[key] = arguments[key];
|
||||
};
|
||||
function pages() {
|
||||
return Math.ceil(data.size/data.per_page);
|
||||
};
|
||||
function handlePageSelected(selected) {
|
||||
data.page = selected;
|
||||
m.route.set(`${data.prefix_url}/${selected}`)
|
||||
data.clickHandler();
|
||||
};
|
||||
function has_prev() {
|
||||
return data.page > 1;
|
||||
};
|
||||
function has_next() {
|
||||
console.log('has_next');
|
||||
console.log(data.page);
|
||||
console.log(pages());
|
||||
console.log(data.page < pages());
|
||||
return data.page < pages();
|
||||
};
|
||||
function iter_pages() {
|
||||
/* */
|
||||
let last = 0;
|
||||
let left_edge=2, left_current=2,
|
||||
right_current=5, right_edge=2;
|
||||
let result = [];
|
||||
for (let num = 1; num < pages()+1; num++) {
|
||||
if (num <= left_edge ||
|
||||
(num > data.page - left_current - 1 &&
|
||||
num < data.page + right_current) ||
|
||||
num > pages() - right_edge) {
|
||||
if (last + 1 != num) {
|
||||
result.push(null);
|
||||
} else {
|
||||
result.push(num);
|
||||
}
|
||||
last = num
|
||||
}
|
||||
};
|
||||
return result;
|
||||
};
|
||||
return {
|
||||
data: data,
|
||||
view: function(vnode) {
|
||||
// console.log(data.page);
|
||||
let result = [
|
||||
m('div', {class: "row"},
|
||||
m('div', {class: "col py-2 text-center"},
|
||||
(function() {
|
||||
// console.log(`pages: ${pages()}`)
|
||||
if (pages()<=1) {
|
||||
return m('button', {class: "btn btn-outline-secondary", type: "button", onclick: function() { data.clickHandler(1)}}, m('i', {class: "fa fa-refresh"}));
|
||||
} else {
|
||||
return [
|
||||
m('div', {class: "d-none d-lg-block"},
|
||||
(function() {
|
||||
let result = [];
|
||||
if (has_prev()) {
|
||||
result.push(
|
||||
m('button', {class: "btn btn-outline-secondary pull-left", type: "button", onclick: function() { handlePageSelected(data.page-1)}}, 'Предыдущая')
|
||||
);
|
||||
}
|
||||
let buttons = iter_pages().map(
|
||||
function(item) {
|
||||
if (item!==null) {
|
||||
return m('button', {class: "btn btn-outline-secondary me-1", type: 'button', onclick: function() { handlePageSelected(item)} }, item);
|
||||
} else {
|
||||
return m('button', {class: "btn btn-outline-secondary me-1", type: 'button', onclick: function() { handlePageSelected(data.page)} }, m('i', {class: "fa fa-refresh"}));
|
||||
}
|
||||
}
|
||||
);
|
||||
result.push(...buttons);
|
||||
if (has_next()) {
|
||||
result.push(
|
||||
m('button', {type: "button", class: "btn btn-outline-secondary float-end", onclick: function() { handlePageSelected(data.page+1)}}, 'Следующая')
|
||||
);
|
||||
}
|
||||
// console.log(`result: ${result}`)
|
||||
return result;
|
||||
})()
|
||||
),
|
||||
m('div', {class: "d-lg-none"},
|
||||
m('div', {class: "btn-group w-100"},
|
||||
(function() {
|
||||
let result = [];
|
||||
if (has_prev()) {
|
||||
result.push(
|
||||
m('button', {class: "btn btn-outline-secondary pull-left", type: "button", onclick: function() { handlePageSelected(data.page-1)}}, m('i', {class: "fa fa-chevron-left"}))
|
||||
);
|
||||
}
|
||||
result.push(
|
||||
m('button', {class: "btn btn-outline-secondary w-100", type: "button"}, data.page)
|
||||
);
|
||||
if (has_next()) {
|
||||
result.push(
|
||||
m('button', {class: "btn btn-outline-secondary float-end", type: "button", onclick: function() { handlePageSelected(data.page+1)}}, m('i', {class: "fa fa-chevron-right"}))
|
||||
)
|
||||
}
|
||||
return result;
|
||||
})()
|
||||
)
|
||||
)
|
||||
]
|
||||
}
|
||||
})()
|
||||
)
|
||||
)
|
||||
];
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
/*
|
||||
<div class="row">
|
||||
<div class="col py-2 text-center">
|
||||
<button type="button" class="btn btn-outline-secondary" v-if="pages()<=1" v-on:click="refresh"><i class="fa fa-refresh"></i></button>
|
||||
|
||||
<template v-else>
|
||||
<div class="d-none d-lg-block">
|
||||
|
||||
<button type="button" class="btn btn-outline-secondary pull-left" v-if="has_prev" v-on:click="handlePageSelected(pagination.page-1)">Предыдущая</button>
|
||||
|
||||
<template v-for="page in iter_pages">
|
||||
<button type="button" class="btn btn-outline-secondary me-1" v-if="page" v-on:click="handlePageSelected(page)">{# page #}</button>
|
||||
<button type="button" class="btn btn-outline-secondary me-1" v-else v-on:click="refresh"><i class="fa fa-refresh"></i></button>
|
||||
</template>
|
||||
|
||||
<button type="button" class="btn btn-outline-secondary float-end" v-if="has_next" v-on:click="handlePageSelected(pagination.page+1)">Следующая</button>
|
||||
|
||||
</div>
|
||||
<div class="d-lg-none">
|
||||
<div class="btn-group w-100">
|
||||
<button type="button" class="btn btn-outline-secondary" v-if="has_prev" v-on:click="handlePageSelected(pagination.page-1)"><i class="fa fa-chevron-left"></i></button>
|
||||
<button type="button" class="btn btn-outline-secondary w-100">{# pagination.page #}</button>
|
||||
<button type="button" class="btn btn-outline-secondary" v-if="has_next" v-on:click="handlePageSelected(pagination.page+1)"><i class="fa fa-chevron-right"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="row mt-3 py-3 bg-light">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-10">
|
||||
© <a href="https://remizoffalex.ru/" target="_blank">RemiZOffAlex</a>
|
||||
© <a href="https://specialistoff.net/" target="_blank">RemiZOffAlex</a>
|
||||
</div>
|
||||
<div class="col-md-1"></div>
|
||||
</div>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<meta name="author" content="Ремизов Александр" />
|
||||
<meta name="copyright" lang="ru" content="RemiZOffAlex" />
|
||||
<link rel="shortcut icon" href="/static/favicon.ico">
|
||||
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="/static/css/font-awesome.min.css" />
|
||||
<script type="text/javascript" src="/static/js/mithril.min.js"></script>
|
||||
<link rel="stylesheet" href="{{ STATIC }}/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="{{ STATIC }}/css/font-awesome.css" />
|
||||
<script type="text/javascript" src="{{ STATIC }}/js/mithril.min.js"></script>
|
||||
<title>{{ pagedata['title'] }}</title>
|
||||
</head>
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
{#
|
||||
Подгрузить скрипт
|
||||
|
||||
{% import 'inc/editor.js' as editor %}
|
||||
{{ editor.plugin('tinymce') }}
|
||||
|
||||
Получить данные
|
||||
|
||||
{{ editor.getValue('"text"', 'vm.note.text', type='tinymce') }}
|
||||
|
||||
{{ editor.getValue('"field" + field.id', 'field.cell.value', type='tinymce') }}
|
||||
|
||||
Получить данные
|
||||
|
||||
{{ editor.setValue('"text"', 'vm.note.text', type='tinymce') }}
|
||||
|
||||
{{ editor.setValue('"field" + field.id', 'field.cell.value', type='tinymce') }}
|
||||
|
||||
Инициализировать редактор
|
||||
|
||||
{{ editor.tinymce('"text"') }}
|
||||
|
||||
{{ editor.tinymce('"field" + field.id') }}
|
||||
|
||||
#}
|
||||
|
||||
{% macro plugin(type="tinymce") -%}
|
||||
{% if type=="tinymce" %}
|
||||
<script type="text/javascript" src="/static/tinymce/tinymce.min.js"></script>
|
||||
{% elif type=="ckeditor" %}
|
||||
<script type="text/javascript" src="/static/ckeditor/ckeditor.js"></script>
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro ckeditor(name) -%}
|
||||
CKEDITOR.replace( {{ name }}, {
|
||||
customConfig: '/static/js/ckeditor-conf.js'
|
||||
} );
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro tinymce(name) -%}
|
||||
tinymce.init({
|
||||
selector: '#' + {{ name }},
|
||||
height: 400,
|
||||
language: 'ru',
|
||||
plugins: 'code importcss searchreplace autolink save directionality visualblocks visualchars fullscreen image link media table charmap hr pagebreak nonbreaking anchor toc advlist lists wordcount imagetools textpattern noneditable help charmap quickbars',
|
||||
toolbar: 'code | undo redo | bold italic underline strikethrough removeformat | formatselect | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist | pagebreak | fullscreen | link image anchor charmap',
|
||||
|
||||
formats: {
|
||||
img: { selector: 'img', classes: 'img-thumbnail', styles: {} },
|
||||
table: { selector: 'table', classes: 'table', styles: {} },
|
||||
},
|
||||
style_formats: [
|
||||
{ title: 'Картинка', format: 'img' },
|
||||
{ title: 'Таблица', format: 'table' },
|
||||
]
|
||||
});
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro getValue(name, param, type="tinymce") -%}
|
||||
{% if type=="tinymce" %}
|
||||
let value = tinymce.get({{ name }}).getContent();
|
||||
if (value != {{ param }}) {
|
||||
{{ param }} = value;
|
||||
}
|
||||
{% elif type=="ckeditor" %}
|
||||
var value = CKEDITOR.instances[{{ name }}].getData();
|
||||
if (value != {{ param }}) {
|
||||
{{ param }} = value;
|
||||
}
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro setValue(name, param, type="tinymce") -%}
|
||||
{% if type=="tinymce" %}
|
||||
tinymce.get({{ name }}).setContent({{ param }});
|
||||
{% elif type=="ckeditor" %}
|
||||
CKEDITOR.instances[{{ name }}].setData({{ param }});
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
@@ -1,31 +0,0 @@
|
||||
<!-- Начало: Фильтр -->
|
||||
<div class="row" v-if="panels.filter.visible">
|
||||
<div class="col">
|
||||
<div class="mb-3">
|
||||
<form @submit.prevent="filter_apply">
|
||||
<div class="input-group">
|
||||
<button class="btn btn-outline-danger" type="button" v-on:click="filter_clear"><i class="fa fa-remove"></i></button>
|
||||
<input class="form-control" placeholder="Фильтр" v-model="panels.filter.value" />
|
||||
<button class="btn btn-outline-success" type="submit"><i class="fa fa-check"></i></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
Object.assign(root.data.panels, {
|
||||
filter: {
|
||||
visible: false,
|
||||
value: ''
|
||||
},
|
||||
});
|
||||
Object.assign(root.methods, {
|
||||
filter_clear: function () {
|
||||
/* Очистить фильтр */
|
||||
let vm = this;
|
||||
vm.panels.filter.value = '';
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<!-- Конец: Фильтр -->
|
||||
@@ -1,24 +1,14 @@
|
||||
{% raw %}
|
||||
<div class="row" v-for="(page, pageIdx) in pages">
|
||||
<div class="col py-2" :class="{'bg-light': pageIdx % 2}">
|
||||
<a :href="'/page/' + page.id">{{ page.title }}</a>
|
||||
<table>
|
||||
{% for page in pagedata['pages'] %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/page/{{ page.id }}">{{ page.title }}</a>
|
||||
|
||||
<div class="row">
|
||||
<div class="col small text-muted">
|
||||
<span v-for="(tag, tagIdx) in page.tags">
|
||||
<i class="fa fa-tag"></i> <a class="text-monospace" :href="'/tag/' + tag.id">{{ tag.name }}</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% for tagLink in page.tags %}
|
||||
<a href="/tag/{{ tagLink.tag.id }}">{{ tagLink.tag.name }}</a>
|
||||
{% endfor %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col small text-muted">
|
||||
<i class="fa fa-user"></i> <a :href="'/user/' + page.user.id">{{ page.user.name }}</a>
|
||||
Создано: {{ page.created }}
|
||||
Обновлено: {{ page.updated }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endraw %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
{% extends "skeleton.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3>{{ pagedata['info'] }}</h3>
|
||||
<h1>{{ pagedata['info'] }}</h1>
|
||||
<hr />
|
||||
<p>Самурай без меча подобен самураю с мечом, но только без меча, однако как-будто с мечом, которого у него нет, но и без него он как с ним...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
10
myapp/templates/lib.js
Normal file
10
myapp/templates/lib.js
Normal file
@@ -0,0 +1,10 @@
|
||||
function arrayRemove(arr, value) {
|
||||
/* Удаление элемента из списка */
|
||||
return arr.filter(function(ele){
|
||||
return ele.id != value.id;
|
||||
});
|
||||
};
|
||||
function panel_show(panel) {
|
||||
/* Показать/скрыть панель */
|
||||
panel.visible = !panel.visible;
|
||||
};
|
||||
15
myapp/templates/public/app.js
Normal file
15
myapp/templates/public/app.js
Normal file
@@ -0,0 +1,15 @@
|
||||
{% include '/public/settings.js' %}
|
||||
|
||||
//let vr = document.body;
|
||||
let vroot = document.getElementById("app");
|
||||
let routes = {};
|
||||
|
||||
{% include '/lib.js' %}
|
||||
{% include '/public/layout.js' %}
|
||||
|
||||
{% include '/components/inc.j2' %}
|
||||
|
||||
{% include '/public/components/inc.j2' %}
|
||||
{% include '/public/domains/inc.j2' %}
|
||||
|
||||
{% include '/routes.js' %}
|
||||
11
myapp/templates/public/components/footer.js
Normal file
11
myapp/templates/public/components/footer.js
Normal file
@@ -0,0 +1,11 @@
|
||||
let Footer = {
|
||||
view: function() {
|
||||
return {tag: '<', children: `<div class="row mt-3 py-3 bg-light">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-10">
|
||||
© <a href="https://specialistoff.net/" target="_blank">RemiZOffAlex</a>
|
||||
</div>
|
||||
<div class="col-md-1"></div>
|
||||
</div>`}
|
||||
}
|
||||
};
|
||||
10
myapp/templates/public/domains/auth/inc.j2
Normal file
10
myapp/templates/public/domains/auth/inc.j2
Normal file
@@ -0,0 +1,10 @@
|
||||
{% include '/public/domains/auth/login.js' %}
|
||||
{% include '/public/domains/auth/register.js' %}
|
||||
|
||||
Object.assign(
|
||||
routes,
|
||||
{
|
||||
"/login": layout_decorator(Login),
|
||||
"/register": layout_decorator(Register),
|
||||
}
|
||||
);
|
||||
70
myapp/templates/public/domains/auth/login.js
Normal file
70
myapp/templates/public/domains/auth/login.js
Normal file
@@ -0,0 +1,70 @@
|
||||
function Login() {
|
||||
let data = {
|
||||
username: '',
|
||||
password: ''
|
||||
};
|
||||
function login() {
|
||||
if (data.username.length==0 || data.password.length==0) {
|
||||
return;
|
||||
}
|
||||
m.request({
|
||||
url: '/api',
|
||||
method: "POST",
|
||||
body: {
|
||||
"jsonrpc": "2.0",
|
||||
"method": 'auth.login',
|
||||
"params": {
|
||||
"username": data.username,
|
||||
"password": data.password
|
||||
},
|
||||
"id": 1
|
||||
}
|
||||
}).then(
|
||||
function(response) {
|
||||
if ('result' in response) {
|
||||
window.location.href = '/';
|
||||
} else if ('error' in response) {
|
||||
data.error = response['error'];
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
function form_submit(e) {
|
||||
e.preventDefault();
|
||||
login();
|
||||
};
|
||||
return {
|
||||
data: data,
|
||||
view: function(vnode) {
|
||||
let result = [];
|
||||
result.push(
|
||||
m('div', {class: 'row justify-content-center my-3'},
|
||||
m('div', {class: 'col-md-6'}, [
|
||||
m('h3', [
|
||||
{tag: '<', children: '<a class="btn btn-outline-secondary float-end" href="/forgot-password">Забыл пароль</a>'},
|
||||
'Вход',
|
||||
{tag: '<', children: '<hr />'},
|
||||
]),
|
||||
m('form', {onsubmit: form_submit}, [
|
||||
m('div', {class: "input-group mb-3"}, [
|
||||
{tag: '<', children: '<span class="input-group-text"><i class="fa fa-user"></i></span>'},
|
||||
m('input', {class: 'form-control', placeholder: 'Логин', type: 'text', oninput: function (e) {data.username = e.target.value}, value: data.username}),
|
||||
]),
|
||||
m('div', {class: "input-group mb-3"}, [
|
||||
{tag: '<', children: '<span class="input-group-text"><i class="fa fa-lock"></i></span>'},
|
||||
m('input', {class: 'form-control', placeholder: 'Пароль', type: 'password', oninput: function (e) {data.password = e.target.value}, value: data.password}),
|
||||
]),
|
||||
m('div', {class: 'row'},
|
||||
m('div', {class: "col py-2"}, [
|
||||
m(m.route.Link, {class: 'btn btn-outline-secondary', href: '/register'}, 'Регистрация'),
|
||||
m('button', {class: 'btn btn-outline-success float-end', type: 'submit'}, 'Войти')
|
||||
]),
|
||||
),
|
||||
])
|
||||
])
|
||||
)
|
||||
)
|
||||
return result;
|
||||
}
|
||||
};
|
||||
};
|
||||
180
myapp/templates/public/domains/page/pages.js
Normal file
180
myapp/templates/public/domains/page/pages.js
Normal file
@@ -0,0 +1,180 @@
|
||||
function Pages() {
|
||||
let data = {
|
||||
filter: PanelFilter(),
|
||||
order_by: PanelOrderBy({
|
||||
field: 'title',
|
||||
fields: [
|
||||
{value: 'id', text: 'ID'},
|
||||
{value: 'title', text: 'заголовку'},
|
||||
{value: 'created', text: 'дате создания'},
|
||||
{value: 'updated', text: 'дате обновления'}
|
||||
],
|
||||
clickHandler: pages_get,
|
||||
order: 'asc',
|
||||
}),
|
||||
raw_pages: [],
|
||||
get pages() {
|
||||
/* Отфильтрованный список */
|
||||
let value = data.filter.data.value;
|
||||
if ( value.length<1 ) {
|
||||
return data.raw_pages;
|
||||
}
|
||||
if (data.filter.data.isregex) {
|
||||
try {
|
||||
let regex = new RegExp(value, 'ig');
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return data.raw_pages;
|
||||
}
|
||||
}
|
||||
let result = data.raw_pages.filter(page_filter);
|
||||
return result;
|
||||
},
|
||||
pagination: Pagination({
|
||||
clickHandler: pages_get,
|
||||
prefix_url: '/pages'
|
||||
}),
|
||||
};
|
||||
function page_filter(page) {
|
||||
/* Фильтр статей */
|
||||
let value = data.filter.data.value;
|
||||
if ( value.length<1 ) {
|
||||
return true;
|
||||
}
|
||||
let isTitle = null;
|
||||
if ( data.filter.data.isregex) {
|
||||
let regex = new RegExp(value, 'ig');
|
||||
isTitle = regex.test(page.title.toLowerCase());
|
||||
} else {
|
||||
isTitle = page.title.toLowerCase().includes(value.toLowerCase());
|
||||
}
|
||||
if ( isTitle ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
function breadcrumbs_render() {
|
||||
let result = m('ul', {class: 'breadcrumb mt-3'}, [
|
||||
m('li', {class: 'breadcrumb-item'}, m(m.route.Link, {href: '/'}, m('i', {class: 'fa fa-home'}))),
|
||||
m('li', {class: 'breadcrumb-item active'}, 'Список статей'),
|
||||
]);
|
||||
return result;
|
||||
};
|
||||
function pages_get() {
|
||||
let order_by = data.order_by.data;
|
||||
let pagination = data.pagination.data;
|
||||
m.request({
|
||||
url: '/api',
|
||||
method: "POST",
|
||||
body: [
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": 'pages',
|
||||
"params": {
|
||||
"page": pagination.page,
|
||||
"order_by": {
|
||||
"field": order_by.field,
|
||||
'order': order_by.order
|
||||
},
|
||||
"fields": ["id", "title", "tags"]
|
||||
},
|
||||
"id": 1
|
||||
},
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": 'pages.count',
|
||||
"id": 1
|
||||
}
|
||||
]
|
||||
|
||||
}).then(
|
||||
function(response) {
|
||||
if ('result' in response[0]) {
|
||||
data.raw_pages = response[0]['result'];
|
||||
}
|
||||
if ('result' in response[1]) {
|
||||
data.pagination.size = response[1]['result'];
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
function page_render(page, pageIdx) {
|
||||
let odd = '';
|
||||
if (pageIdx % 2) {
|
||||
odd = ' bg-light'
|
||||
};
|
||||
return m('div', {class: 'row'},
|
||||
m('div', {class: `col py-2 ${odd}`}, [
|
||||
m(m.route.Link, {href: `/page/${page.id}`}, m.trust(page.title)),
|
||||
m('div', {class: 'row'},
|
||||
),
|
||||
])
|
||||
);
|
||||
};
|
||||
function pages_render() {
|
||||
return data.pages.map(page_render);
|
||||
};
|
||||
return {
|
||||
oninit: function(vnode) {
|
||||
let pagination = data.pagination.data;
|
||||
if (vnode.attrs.page!==undefined) {
|
||||
pagination.page = Number(vnode.attrs.page);
|
||||
};
|
||||
document.title = `Список статей - ${SETTINGS.TITLE}`;
|
||||
pages_get();
|
||||
},
|
||||
view: function(vnode) {
|
||||
let result = [];
|
||||
result.push(
|
||||
breadcrumbs_render(),
|
||||
m('div', {class: 'row'},
|
||||
m('div', {class: 'col h1 py-1'}, [
|
||||
m('div', {class: "btn-group btn-group-lg me-2"}, [
|
||||
m('button', {type: "button", class: "btn btn-outline-secondary", onclick: function() { panel_show(data.filter.data) }},
|
||||
m('i', {class: "fa fa-filter"})
|
||||
),
|
||||
m('button', {type: "button", class: "btn btn-outline-secondary", onclick: function() { panel_show(data.order_by.data) }},
|
||||
m('i', {class: "fa fa-sort-alpha-asc"})
|
||||
)
|
||||
]),
|
||||
'Статьи',
|
||||
])
|
||||
),
|
||||
m('hr'),
|
||||
);
|
||||
result.push(m(data.filter));
|
||||
result.push(m(data.order_by));
|
||||
result.push(m(data.pagination));
|
||||
if (data.pages.length>0) {
|
||||
result.push(m(ComponentPages, {pages: data.pages}));
|
||||
result.push(m(data.pagination));
|
||||
};
|
||||
result.push(breadcrumbs_render());
|
||||
return result
|
||||
}
|
||||
}
|
||||
};
|
||||
/*
|
||||
<div class="row" v-for="() in pages">
|
||||
<div class="col py-2" :class="{'bg-light': pageIdx % 2}">
|
||||
<a :href="'/page/' + page.id">{ page.title }</a>
|
||||
|
||||
<div class="row">
|
||||
<div class="col small text-muted">
|
||||
<span v-for="(tag, tagIdx) in page.tags">
|
||||
<i class="fa fa-tag"></i> <a class="text-monospace" :href="'/tag/' + tag.id">{ tag.name }</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col small text-muted">
|
||||
<i class="fa fa-user"></i> <a :href="'/user/' + page.user.id">{ page.user.name }</a>
|
||||
Создано: { page.created }
|
||||
Обновлено: { page.updated }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
*/
|
||||
20
myapp/templates/public/layout.js
Normal file
20
myapp/templates/public/layout.js
Normal file
@@ -0,0 +1,20 @@
|
||||
function layout_decorator(controller) {
|
||||
return {
|
||||
render: function(vnode) {
|
||||
return m(Layout, m(controller, vnode.attrs))
|
||||
}
|
||||
}
|
||||
};
|
||||
function Layout() {
|
||||
return {
|
||||
view: function(vnode) {
|
||||
let result = [
|
||||
m(MenuGeneral),
|
||||
m("section", vnode.children),
|
||||
m(Footer),
|
||||
m(Backtotop),
|
||||
];
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
4
myapp/templates/public/settings.js
Normal file
4
myapp/templates/public/settings.js
Normal file
@@ -0,0 +1,4 @@
|
||||
const SETTINGS = {
|
||||
ITEMS_ON_PAGE: {{ ITEMS_ON_PAGE }},
|
||||
TITLE: 'Моя панель',
|
||||
}
|
||||
22
myapp/templates/public/skeleton.html
Normal file
22
myapp/templates/public/skeleton.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
{% include 'header.html' %}
|
||||
<body>
|
||||
|
||||
<section id="app" class="container">
|
||||
{% include '/public/navbar.html' %}
|
||||
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{% endblock %}
|
||||
|
||||
{% include 'footer.html' %}
|
||||
</section>
|
||||
|
||||
{% block script %}{% endblock %}
|
||||
|
||||
<script type="text/javascript" src="/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
14
myapp/templates/routes.js
Normal file
14
myapp/templates/routes.js
Normal file
@@ -0,0 +1,14 @@
|
||||
m.route.prefix = '';
|
||||
function layout_decorator(controller) {
|
||||
return {
|
||||
render: function(vnode) {
|
||||
return m(Layout, m(controller, vnode.attrs))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
m.route(
|
||||
vroot,
|
||||
"/",
|
||||
routes
|
||||
);
|
||||
@@ -4,7 +4,7 @@
|
||||
<body>
|
||||
|
||||
<section id="app" class="container">
|
||||
{% include 'navbar.html' %}
|
||||
{% include '/public/navbar.html' %}
|
||||
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
|
||||
Reference in New Issue
Block a user