Merge pull request #2816 from SchrodingersGat/markdown-editor

Markdown editor
This commit is contained in:
Oliver 2022-04-10 22:44:57 +10:00 committed by GitHub
commit fe8f5a74e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 254 additions and 199 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -72,7 +72,7 @@ class ViewTests(TestCase):
"""
# Change this number as more javascript files are added to the index page
N_SCRIPT_FILES = 38
N_SCRIPT_FILES = 39
content = self.get_index_page()

View File

@ -3,7 +3,6 @@
{% load i18n %}
{% load inventree_extras %}
{% load status_codes %}
{% load markdownify %}
{% block sidebar %}
{% include "build/sidebar.html" %}
@ -309,24 +308,16 @@
<div class='panel panel-hidden' id='panel-notes'>
<div class='panel-heading'>
<div class='row'>
<div class='col-sm-6'>
<h4>{% trans "Build Notes" %}</h4>
</div>
<div class='col-sm-6'>
<div class='btn-group float-right'>
<button type='button' id='edit-notes' title='{% trans "Edit Notes" %}' class='btn btn-small btn-outline-secondary'>
<span class='fas fa-edit'>
</span>
</button>
</div>
<div class='d-flex flex-wrap'>
<h4>{% trans "Build Notes" %}</h4>
{% include "spacer.html" %}
<div class='btn-group' role='group'>
{% include "notes_buttons.html" %}
</div>
</div>
</div>
<div class='panel-content'>
{% if build.notes %}
{{ build.notes | markdownify }}
{% endif %}
<textarea id='build-notes'></textarea>
</div>
</div>
@ -392,17 +383,18 @@ onPanelLoad('attachments', function() {
});
onPanelLoad('notes', function() {
$('#edit-notes').click(function() {
constructForm('{% url "api-build-detail" build.pk %}', {
fields: {
notes: {
multiline: true,
}
},
title: '{% trans "Edit Notes" %}',
reload: true,
});
});
setupNotesField(
'build-notes',
'{% url "api-build-detail" build.pk %}',
{
{% if roles.build.change %}
editable: true,
{% else %}
editable: false,
{% endif %}
}
);
});
function reloadTable() {

View File

@ -1,7 +1,6 @@
{% extends "company/company_base.html" %}
{% load static %}
{% load i18n %}
{% load markdownify %}
{% block sidebar %}
{% include 'company/sidebar.html' %}
@ -181,24 +180,16 @@
<div class='panel panel-hidden' id='panel-company-notes'>
<div class='panel-heading'>
<div class='row'>
<div class='col-sm-6'>
<h4>{% trans "Company Notes" %}</h4>
</div>
<div class='col-sm-6'>
<div class='btn-group float-right'>
<button type='button' id='edit-notes' title='{% trans "Edit Notes" %}' class='btn btn-small btn-outline-secondary'>
<span class='fas fa-edit'>
</span>
</button>
</div>
<div class='d-flex flex-wrap'>
<h4>{% trans "Company Notes" %}</h4>
{% include "spacer.html" %}
<div class='btn-group' role='group'>
{% include "notes_buttons.html" %}
</div>
</div>
</div>
<div class='panel-content'>
{% if company.notes %}
{{ company.notes | markdownify }}
{% endif %}
<textarea id='company-notes'></textarea>
</div>
</div>
@ -207,16 +198,15 @@
{% block js_ready %}
{{ block.super }}
$('#edit-notes').click(function() {
constructForm('{% url "api-company-detail" company.pk %}', {
fields: {
notes: {
multiline: true,
}
},
title: '{% trans "Edit Notes" %}',
reload: true,
});
onPanelLoad('company-notes', function() {
setupNotesField(
'company-notes',
'{% url "api-company-detail" company.pk %}',
{
editable: true,
}
)
});
loadStockTable($("#assigned-stock-table"), {
@ -230,18 +220,37 @@
filterTarget: '#filter-list-customerstock',
});
{% if company.is_customer %}
loadSalesOrderTable("#sales-order-table", {
url: "{% url 'api-so-list' %}",
params: {
customer: {{ company.id }},
}
onPanelLoad('company-stock', function() {
loadStockTable($('#stock-table'), {
url: "{% url 'api-stock-list' %}",
params: {
company: {{ company.id }},
part_detail: true,
supplier_part_detail: true,
location_detail: true,
},
buttons: [
'#stock-options',
],
filterKey: "companystock",
});
});
$("#new-sales-order").click(function() {
{% if company.is_customer %}
onPanelLoad('panel-sales-orders', function() {
loadSalesOrderTable("#sales-order-table", {
url: "{% url 'api-so-list' %}",
params: {
customer: {{ company.id }},
}
});
createSalesOrder({
customer: {{ company.pk }},
$("#new-sales-order").click(function() {
createSalesOrder({
customer: {{ company.pk }},
});
});
});
{% endif %}
@ -270,20 +279,6 @@
{% endif %}
loadStockTable($('#stock-table'), {
url: "{% url 'api-stock-list' %}",
params: {
company: {{ company.id }},
part_detail: true,
supplier_part_detail: true,
location_detail: true,
},
buttons: [
'#stock-options',
],
filterKey: "companystock",
});
{% if company.is_manufacturer %}
function reloadManufacturerPartTable() {

View File

@ -4,7 +4,6 @@
{% load status_codes %}
{% load i18n %}
{% load static %}
{% load markdownify %}
{% block sidebar %}
{% include 'order/po_sidebar.html' %}
@ -71,24 +70,16 @@
<div class='panel panel-hidden' id='panel-order-notes'>
<div class='panel-heading'>
<div class='row'>
<div class='col-sm-6'>
<h4>{% trans "Order Notes" %}</h4>
</div>
<div class='col-sm-6'>
<div class='btn-group float-right'>
<button type='button' id='edit-notes' title='{% trans "Edit Notes" %}' class='btn btn-outline-secondary'>
<span class='fas fa-edit'>
</span>
</button>
</div>
<div class='d-flex flex-wrap'>
<h4>{% trans "Order Notes" %}</h4>
{% include "spacer.html" %}
<div class='btn-group' role='group'>
{% include "notes_buttons.html" %}
</div>
</div>
</div>
<div class='panel-content'>
{% if order.notes %}
{{ order.notes | markdownify }}
{% endif %}
<textarea id='order-notes'></textarea>
</div>
</div>
@ -98,16 +89,18 @@
{{ block.super }}
$('#edit-notes').click(function() {
constructForm('{% url "api-po-detail" order.pk %}', {
fields: {
notes: {
multiline: true,
}
},
title: '{% trans "Edit Notes" %}',
reload: true,
});
onPanelLoad('order-notes', function() {
setupNotesField(
'order-notes',
'{% url "api-po-detail" order.pk %}',
{
{% if roles.purchase_order.change %}
editable: true,
{% else %}
editable: false,
{% endif %}
}
);
});
enableDragAndDrop(

View File

@ -4,7 +4,6 @@
{% load status_codes %}
{% load i18n %}
{% load static %}
{% load markdownify %}
{% block sidebar %}
{% include "order/so_sidebar.html" %}
@ -118,24 +117,16 @@
<div class='panel panel-hidden' id='panel-order-notes'>
<div class='panel-heading'>
<div class='row'>
<div class='col-sm-6'>
<h4>{% trans "Order Notes" %}</h4>
</div>
<div class='col-sm-6'>
<div class='btn-group float-right'>
<button type='button' id='edit-notes' title='{% trans "Edit Notes" %}' class='btn outline-secondary'>
<span class='fas fa-edit'>
</span>
</button>
</div>
<div class='d-flex flex-wrap'>
<h4>{% trans "Order Notes" %}</h4>
{% include "spacer.html" %}
<div class='btn-group' role='group'>
{% include "notes_buttons.html" %}
</div>
</div>
</div>
<div class='panel-content'>
{% if order.notes %}
{{ order.notes | markdownify }}
{% endif %}
<textarea id='order-notes'></textarea>
</div>
</div>
@ -176,16 +167,18 @@
});
});
$('#edit-notes').click(function() {
constructForm('{% url "api-so-detail" order.pk %}', {
fields: {
notes: {
multiline: true,
}
},
title: '{% trans "Edit Notes" %}',
reload: true,
});
onPanelLoad('order-notes', function() {
setupNotesField(
'order-notes',
'{% url "api-so-detail" order.pk %}',
{
{% if roles.purchase_order.change %}
editable: true,
{% else %}
editable: false,
{% endif %}
}
);
});
enableDragAndDrop(

View File

@ -3,7 +3,6 @@
{% load i18n %}
{% load inventree_extras %}
{% load crispy_forms_tags %}
{% load markdownify %}
{% block sidebar %}
{% include 'part/part_sidebar.html' %}
@ -134,24 +133,16 @@
<div class='panel panel-hidden' id='panel-part-notes'>
<div class='panel-heading'>
<div class='row'>
<div class='col-sm-6'>
<h4>{% trans "Notes" %}</h4>
</div>
<div class='col-sm-6'>
<div class='btn-group float-right'>
<button type='button' id='edit-notes' title='{% trans "Edit Notes" %}' class='btn btn-outline-secondary'>
<span class='fas fa-edit'>
</span>
</button>
</div>
<div class='d-flex flex-wrap'>
<h4>{% trans "Part Notes" %}</h4>
{% include "spacer.html" %}
<div class='btn-group' role='group'>
{% include "notes_buttons.html" %}
</div>
</div>
</div>
<div class='panel-content'>
{% if part.notes %}
{{ part.notes | markdownify }}
{% endif %}
<textarea id='part-notes'></textarea>
</div>
</div>
@ -419,6 +410,18 @@
{% block js_ready %}
{{ block.super }}
// Load the "notes" tab
onPanelLoad('part-notes', function() {
setupNotesField(
'part-notes',
'{% url "api-part-detail" part.pk %}',
{
editable: {% if roles.part.change %}true{% else %}false{% endif %},
}
);
});
// Load the "scheduling" tab
onPanelLoad('scheduling', function() {
loadPartSchedulingChart('part-schedule-chart', {{ part.pk }});
@ -832,36 +835,6 @@
});
});
$('#edit-notes').click(function() {
constructForm('{% url "api-part-detail" part.pk %}', {
fields: {
notes: {
multiline: true,
}
},
title: '{% trans "Edit Part Notes" %}',
reload: true,
});
});
$(".slidey").change(function() {
var field = $(this).attr('fieldname');
var checked = $(this).prop('checked');
var data = {};
data[field] = checked;
// Update the particular field
inventreePut("{% url 'api-part-detail' part.id %}",
data,
{
method: 'PATCH',
reloadOnSuccess: true,
},
);
});
onPanelLoad("part-parameters", function() {
loadPartParameterTable(
'#parameter-table',

View File

@ -4,7 +4,6 @@
{% load report %}
{% load barcode %}
{% load inventree_extras %}
{% load markdownify %}
{% block page_margin %}
margin: 2cm;

View File

@ -4,7 +4,6 @@
{% load inventree_extras %}
{% load i18n %}
{% load l10n %}
{% load markdownify %}
{% block sidebar %}
{% include "stock/stock_sidebar.html" %}
@ -133,24 +132,16 @@
<div class='panel panel-hidden' id='panel-notes'>
<div class='panel-heading'>
<div class='row'>
<div class='col-sm-6'>
<h4>{% trans "Stock Item Notes" %}</h4>
</div>
<div class='col-sm-6'>
<div class='btn-group float-right'>
<button type='button' id='edit-notes' title='{% trans "Edit Notes" %}' class='btn btn-small btn-outline-secondary'>
<span class='fas fa-edit'>
</span>
</button>
</div>
<div class='d-flex flex-wrap'>
<h4>{% trans "Stock Item Notes" %}</h4>
{% include "spacer.html" %}
<div class='btn-group' role='group'>
{% include "notes_buttons.html" %}
</div>
</div>
</div>
<div class='panel-content'>
{% if item.notes %}
{{ item.notes | markdownify }}
{% endif %}
<textarea id='stock-notes'></textarea>
</div>
</div>
@ -235,18 +226,21 @@
reload: true,
}
);
});
$('#edit-notes').click(function() {
constructForm('{% url "api-stock-detail" item.pk %}', {
fields: {
notes: {
multiline: true,
}
},
title: '{% trans "Edit Notes" %}',
reload: true,
});
});
onPanelLoad('notes', function() {
setupNotesField(
'stock-notes',
'{% url "api-stock-detail" item.pk %}',
{
{% if roles.stock.change and user_owns_item %}
editable: true,
{% else %}
editable: false,
{% endif %}
}
);
});
enableDragAndDrop(

View File

@ -89,7 +89,7 @@ $('table').find('.boolean-setting').change(function() {
},
{
method: 'PATCH',
onSuccess: function(data) {
success: function(data) {
},
error: function(xhr) {
showApiError(xhr, url);

View File

@ -48,6 +48,7 @@
<link rel="stylesheet" href="{% static 'select2/css/select2-bootstrap-5-theme.css' %}">
<link rel="stylesheet" href="{% static 'fullcalendar/main.css' %}">
<link rel="stylesheet" href="{% static 'script/jquery-ui/jquery-ui.min.css' %}">
<link rel="stylesheet" href="{% static 'easymde/easymde.min.css' %}">
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
@ -160,6 +161,7 @@
<script type='text/javascript' src="{% static 'script/chart.js' %}"></script>
<script type='text/javascript' src="{% static 'script/moment.js' %}"></script>
<script type='text/javascript' src="{% static 'script/chartjs-adapter-moment.js' %}"></script>
<script type='text/javascript' src="{% static 'easymde/easymde.min.js' %}"></script>
<script type='text/javascript' src="{% static 'script/clipboard.min.js' %}"></script>
<script type='text/javascript' src="{% static 'script/randomColor.min.js' %}"></script>

View File

@ -10,6 +10,7 @@
makeProgressBar,
renderLink,
select2Thumbnail,
setupNotesField,
thumbnailImage
yesNoLabel,
*/
@ -221,3 +222,93 @@ function renderLink(text, url, options={}) {
return `<a href="${url}">${text}</a>`;
}
function setupNotesField(element, url, options={}) {
var editable = options.editable || false;
// Read initial notes value from the URL
var initial = null;
inventreeGet(url, {}, {
async: false,
success: function(response) {
initial = response[options.notes_field || 'notes'];
},
});
var toolbar_icons = [
'preview', '|',
];
if (editable) {
// Heading icons
toolbar_icons.push('heading-1', 'heading-2', 'heading-3', '|');
// Font style
toolbar_icons.push('bold', 'italic', 'strikethrough', '|');
// Text formatting
toolbar_icons.push('unordered-list', 'ordered-list', 'code', 'quote', '|');
// Elements
toolbar_icons.push('table', 'link', 'image');
}
// Markdown syntax guide
toolbar_icons.push('|', 'guide');
const mde = new EasyMDE({
element: document.getElementById(element),
initialValue: initial,
toolbar: toolbar_icons,
shortcuts: [],
});
// Hide the toolbar
$(`#${element}`).next('.EasyMDEContainer').find('.editor-toolbar').hide();
if (!editable) {
// Set readonly
mde.codemirror.setOption('readOnly', true);
// Hide the "edit" and "save" buttons
$('#edit-notes').hide();
$('#save-notes').hide();
} else {
mde.togglePreview();
// Add callback for "edit" button
$('#edit-notes').click(function() {
$('#edit-notes').hide();
$('#save-notes').show();
// Show the toolbar
$(`#${element}`).next('.EasyMDEContainer').find('.editor-toolbar').show();
mde.togglePreview();
});
// Add callback for "save" button
$('#save-notes').click(function() {
var data = {};
data[options.notes_field || 'notes'] = mde.value();
inventreePut(url, data, {
method: 'PATCH',
success: function(response) {
showMessage('{% trans "Notes updated" %}', {style: 'success'});
},
error: function(xhr) {
showApiError(xhr, url);
}
});
});
}
}

View File

@ -0,0 +1,8 @@
{% load i18n %}
<button type='button' id='edit-notes' title='{% trans "Edit" %}' class='btn btn-primary'>
<span class='fas fa-edit'></span> {% trans "Edit" %}
</button>
<button type='button' id='save-notes' title='{% trans "Save" %}' class='btn btn-success' style='display: none;'>
<span class='fas fa-save'></span> {% trans "Save" %}
</button>

View File

@ -1,5 +1,6 @@
# Please keep this list sorted
Django==3.2.12 # Django package
Django==3.2.12 # Django package
bleach==4.1.0 # HTML santization
certifi # Certifi is (most likely) installed through one of the requirements above
coreapi==2.3.0 # API documentation
coverage==5.3 # Unit test coverage