Add tag
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
Flask==1.1.2
|
||||
Flask-JSONRPC==1.1.0
|
||||
alembic==1.4.2
|
||||
SQLAlchemy==1.3.17
|
||||
SQLAlchemy-Utils==0.36.6
|
||||
flake8==3.8.3
|
||||
gunicorn==20.0.4
|
||||
psycopg2-binary==2.8.5
|
||||
Flask
|
||||
git+https://gitlab.com/RemiZOffAlex/jsonrpc@master#egg=jsonrpc
|
||||
alembic
|
||||
SQLAlchemy
|
||||
SQLAlchemy-Utils
|
||||
flake8
|
||||
gunicorn
|
||||
psycopg2-binary
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="author" content="Ремизов Александр" />
|
||||
<meta name="copyright" lang="ru" content="RemiZOffAlex" />
|
||||
<link rel="shortcut icon" href="/static/favicon.ico">
|
||||
|
||||
@@ -4,7 +4,23 @@ function arrayRemove(arr, value) {
|
||||
return ele.id != value.id;
|
||||
});
|
||||
};
|
||||
function arrayRemoveByID(arr, value) {
|
||||
/* Удаление элемента из списка */
|
||||
return arr.filter(function (ele) {
|
||||
return ele.id != value.id;
|
||||
});
|
||||
};
|
||||
function arrayRemoveByItem(arr, value) {
|
||||
/* Удаление элемента из списка */
|
||||
return arr.filter(function (ele) {
|
||||
return ele != value;
|
||||
});
|
||||
};
|
||||
function panel_show(panel) {
|
||||
/* Показать/скрыть панель */
|
||||
panel.visible = !panel.visible;
|
||||
};
|
||||
function get_id() {
|
||||
/* Получить рандомный ID */
|
||||
return Math.random().toString(16).slice(2);
|
||||
};
|
||||
|
||||
@@ -3,17 +3,7 @@
|
||||
{% include 'header.html' %}
|
||||
<body>
|
||||
|
||||
<section id="app" class="container">
|
||||
{% include '/private/navbar.html' %}
|
||||
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{% endblock %}
|
||||
|
||||
{% include 'footer.html' %}
|
||||
</section>
|
||||
<section id="app" class="container"></section>
|
||||
|
||||
<script type="text/javascript" src="{{ STATIC }}/tinymce/tinymce.min.js"></script>
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ let MenuGeneral = {
|
||||
m(m.route.Link, {class: 'btn btn-outline-secondary', href: '/'}, m('i', {class: 'fa fa-home'})),
|
||||
m(m.route.Link, {class: 'btn btn-outline-secondary border-0', href: '/pages'}, 'Статьи'),
|
||||
m(m.route.Link, {class: 'btn btn-outline-secondary border-0', href: '/tags'}, 'Метки'),
|
||||
m(m.route.Link, {class: 'btn btn-outline-secondary border-0', href: '/users'}, 'Пользователи'),
|
||||
m(m.route.Link, {class: 'btn btn-outline-secondary border-0', href: '/api/browse'}, 'API JSON-RPC'),
|
||||
m(m.route.Link, {class: 'btn btn-outline-success float-end', href: '/login'}, m('i', {class: 'fa fa-sign-in'})),
|
||||
])
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{% include '/public/domains/auth/inc.j2' %}
|
||||
{% include '/public/domains/page/inc.j2' %}
|
||||
{% include '/public/domains/tag/inc.j2' %}
|
||||
{% include '/public/domains/user/inc.j2' %}
|
||||
{% include '/public/domains/home.js' %}
|
||||
|
||||
|
||||
10
myapp/templates/public/domains/tag/inc.j2
Normal file
10
myapp/templates/public/domains/tag/inc.j2
Normal file
@@ -0,0 +1,10 @@
|
||||
{% include '/public/domains/tag/tag.js' %}
|
||||
{% include '/public/domains/tag/tags.js' %}
|
||||
|
||||
Object.assign(
|
||||
routes,
|
||||
{
|
||||
"/tag/:id": layout_decorator(Tag),
|
||||
"/tags": layout_decorator(Tags),
|
||||
}
|
||||
);
|
||||
82
myapp/templates/public/domains/tag/tag.js
Normal file
82
myapp/templates/public/domains/tag/tag.js
Normal file
@@ -0,0 +1,82 @@
|
||||
function Tag() {
|
||||
let data = {
|
||||
tag: null,
|
||||
menuitem: null,
|
||||
};
|
||||
function breadcrumbs_render() {
|
||||
let result = m('ul', { class: 'breadcrumb mt-2' }, [
|
||||
m('li', { class: 'breadcrumb-item' }, m(m.route.Link, { href: '/' }, m('i', { class: 'fa fa-home' }))),
|
||||
m('li', { class: 'breadcrumb-item' }, m(m.route.Link, { href: '/tags' }, 'Список тегов')),
|
||||
m('li', { class: 'breadcrumb-item active' }, data.tag.name),
|
||||
]);
|
||||
return result;
|
||||
};
|
||||
function tag_get(id) {
|
||||
m.request({
|
||||
url: '/api',
|
||||
method: "POST",
|
||||
body: {
|
||||
"jsonrpc": "2.0",
|
||||
"method": 'tag',
|
||||
"params": {
|
||||
"id": id,
|
||||
"fields": ["id", "name", "description"]
|
||||
},
|
||||
"id": get_id()
|
||||
}
|
||||
}).then(
|
||||
function (response) {
|
||||
if ('result' in response) {
|
||||
data.tag = response['result'];
|
||||
document.title = `${data.tag.name} - ${SETTINGS.TITLE}`;
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
return {
|
||||
oninit: function (vnode) {
|
||||
console.log('Tag.oninit');
|
||||
tag_get(vnode.attrs.id);
|
||||
},
|
||||
view: function (vnode) {
|
||||
console.log('Tag.view');
|
||||
result = [];
|
||||
if (data.tag != null) {
|
||||
result.push(
|
||||
breadcrumbs_render(),
|
||||
m('div', { class: 'row' },
|
||||
m('div', { class: 'col h1 py-2' }, [
|
||||
m('div', { class: 'btn-group btn-group-lg me-2' },
|
||||
m(m.route.Link, { class: "btn btn-outline-secondary", href: "/tags", title: "Облако тегов" }, m('i', { class: 'fa fa-chevron-left' })),
|
||||
),
|
||||
data.tag.name
|
||||
]),
|
||||
),
|
||||
m('hr'),
|
||||
);
|
||||
|
||||
// result.push(m(MenuTag, {"tag1": data.tag}));
|
||||
result.push({ tag: MenuTag, attrs: { tag: data.tag } });
|
||||
|
||||
result.push(
|
||||
m('div', { class: 'row' }, [
|
||||
m('div', { class: "col-md-4 py-2" },
|
||||
m(m.route.Link, { class: "btn btn-outline-secondary btn-lg w-100", href: `/tag/${data.tag.id}/notes` }, 'Заметки с тегом'),
|
||||
),
|
||||
m('div', { class: "col-md-4 py-2" },
|
||||
m(m.route.Link, { class: "btn btn-outline-secondary btn-lg w-100", href: `/tag/${data.tag.id}/pages` }, 'Статьи с тегом'),
|
||||
),
|
||||
])
|
||||
);
|
||||
|
||||
result.push(
|
||||
m('div', { class: 'row' },
|
||||
m('div', { class: "col py-2" }, m.trust(data.tag.description)),
|
||||
)
|
||||
);
|
||||
result.push(breadcrumbs_render());
|
||||
};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
119
myapp/templates/public/domains/tag/tags.js
Normal file
119
myapp/templates/public/domains/tag/tags.js
Normal file
@@ -0,0 +1,119 @@
|
||||
function Tags() {
|
||||
let data = {
|
||||
filter: PanelFilter(),
|
||||
raw_groups: {},
|
||||
get groups() {
|
||||
let result = {};
|
||||
Object.keys(data.raw_groups).forEach(
|
||||
function (group, groupIdx) {
|
||||
let tags = data.raw_groups[group].filter(tag_filter);
|
||||
if (tags.length > 0) {
|
||||
result[group] = tags;
|
||||
}
|
||||
}
|
||||
);
|
||||
return result;
|
||||
},
|
||||
};
|
||||
function breadcrumbs_render() {
|
||||
let result = m('ul', { class: 'breadcrumb mt-2' }, [
|
||||
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 tag_filter(tag) {
|
||||
let filter = data.filter.data;
|
||||
let value = filter.value;
|
||||
if (value.length < 1) {
|
||||
return true;
|
||||
}
|
||||
if (tag.name.toLowerCase().includes(value.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
function tags_get() {
|
||||
m.request({
|
||||
url: '/api',
|
||||
method: "POST",
|
||||
body: {
|
||||
"jsonrpc": "2.0",
|
||||
"method": 'tags.groups',
|
||||
"params": {
|
||||
},
|
||||
"id": get_id()
|
||||
}
|
||||
}).then(
|
||||
function (response) {
|
||||
if ('result' in response) {
|
||||
data.raw_groups = response['result'];
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
return {
|
||||
oninit: function (vnode) {
|
||||
console.log('Tags.oninit');
|
||||
tags_get();
|
||||
},
|
||||
view: function (vnode) {
|
||||
console.log('Tags.view');
|
||||
result = [];
|
||||
result.push(
|
||||
breadcrumbs_render(),
|
||||
m('div', { class: 'row' },
|
||||
m('div', { class: "col h1 py-2" }, [
|
||||
m('button', { type: "button", class: "btn btn-outline-secondary btn-lg me-2", onclick: function () { panel_show(data.filter.data) } },
|
||||
m('i', { class: "fa fa-filter" })
|
||||
),
|
||||
'Облако тегов'
|
||||
])
|
||||
),
|
||||
m('hr'),
|
||||
);
|
||||
result.push(m(data.filter));
|
||||
if (Object.keys(data.groups).length > 0) {
|
||||
let groups = [];
|
||||
Object.keys(data.groups).forEach(
|
||||
function (group, groupIdx) {
|
||||
let odd = '';
|
||||
if (groupIdx % 2) {
|
||||
odd = 'btn-primary'
|
||||
};
|
||||
groups.push({ tag: '<', children: `<a href="#${groupIdx}" class="btn ${odd} btn-lg my-1 mx-1">${group}</a>` });
|
||||
}
|
||||
);
|
||||
result.push(
|
||||
m('div', { class: 'row' },
|
||||
m('div', { class: "col text-justify" }, [...groups])
|
||||
)
|
||||
)
|
||||
groups = [];
|
||||
Object.keys(data.groups).forEach(
|
||||
function (group, groupIdx) {
|
||||
let odd = '';
|
||||
if (groupIdx % 2) {
|
||||
odd = ' bg-light'
|
||||
};
|
||||
let tags = data.groups[group].map(
|
||||
function (tag, tagIdx) {
|
||||
return m(m.route.Link, { class: "btn btn-outline-secondary font-monospace my-1 me-2", href: `/tag/${tag.id}` }, tag.name);
|
||||
}
|
||||
)
|
||||
groups.push(m('div', { class: 'row' }, [
|
||||
m('div', { class: "col-md-1 py-2" + odd }, [
|
||||
{ tag: '<', children: `<a id=${groupIdx} class="btn btn-outline-danger w-100 my-1">${group}</a>` },
|
||||
// m(m.route.Link, {class: "text-decoration-none", href: "/tag/" + tag.id, title: "Тег #" + tag.id}, tag.name),
|
||||
]),
|
||||
m('div', { class: "col-md-11 py-2" + odd }, [...tags]),
|
||||
]))
|
||||
}
|
||||
);
|
||||
result.push(...groups);
|
||||
};
|
||||
result.push(breadcrumbs_render());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
{% include 'header.html' %}
|
||||
{% include 'header.html' %}
|
||||
<body>
|
||||
|
||||
<section id="app" class="container">
|
||||
|
||||
Reference in New Issue
Block a user