mirror of
https://github.com/zadam/trilium.git
synced 2025-10-28 08:46:43 +01:00
Compare commits
13 Commits
v0.24.0-be
...
v0.24.1-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1ed022771 | ||
|
|
ad6cb6ba34 | ||
|
|
2e76de5f34 | ||
|
|
4f23f2515a | ||
|
|
8e16cc2326 | ||
|
|
49bca04ebb | ||
|
|
05e9669eaf | ||
|
|
62a250a7fc | ||
|
|
8299524682 | ||
|
|
7691a59977 | ||
|
|
3db2f6784d | ||
|
|
48684d0509 | ||
|
|
1ee8d9fd93 |
@@ -1,4 +1,4 @@
|
|||||||
FROM node:10.12.0
|
FROM node:10.13.0
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y nasm
|
RUN apt-get update && apt-get install -y nasm
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ fi
|
|||||||
|
|
||||||
VERSION=$1
|
VERSION=$1
|
||||||
PKG_DIR=dist/trilium-linux-x64-server
|
PKG_DIR=dist/trilium-linux-x64-server
|
||||||
NODE_VERSION=10.12.0
|
NODE_VERSION=10.13.0
|
||||||
|
|
||||||
rm -r $PKG_DIR
|
rm -r $PKG_DIR
|
||||||
mkdir $PKG_DIR
|
mkdir $PKG_DIR
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
-- first fix deleted status of existing images
|
||||||
|
UPDATE note_images SET isDeleted = 1 WHERE noteId IN (SELECT noteId FROM notes WHERE isDeleted = 1);
|
||||||
|
|
||||||
|
-- we don't need set data to null because table is going to be dropped anyway and we want image size into attribute
|
||||||
|
UPDATE images SET isDeleted = 1 WHERE imageId NOT IN (SELECT imageId FROM note_images WHERE isDeleted = 0);
|
||||||
|
|
||||||
-- allow null for note content (for deleted notes)
|
-- allow null for note content (for deleted notes)
|
||||||
CREATE TABLE IF NOT EXISTS "notes_mig" (
|
CREATE TABLE IF NOT EXISTS "notes_mig" (
|
||||||
`noteId` TEXT NOT NULL,
|
`noteId` TEXT NOT NULL,
|
||||||
|
|||||||
1
db/migrations/0117__fix_attributes_of_deleted_notes.sql
Normal file
1
db/migrations/0117__fix_attributes_of_deleted_notes.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
UPDATE attributes SET isDeleted = 1 WHERE noteId IN (SELECT noteId FROM notes WHERE isDeleted = 1);
|
||||||
1
db/migrations/0118__fix_broken_relations.sql
Normal file
1
db/migrations/0118__fix_broken_relations.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
UPDATE attributes SET isDeleted = 1 WHERE type = 'relation' AND value NOT IN (SELECT noteId FROM notes WHERE notes.isDeleted = 0);
|
||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "trilium",
|
"name": "trilium",
|
||||||
"version": "0.23.1",
|
"version": "0.24.0-beta",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "trilium",
|
"name": "trilium",
|
||||||
"description": "Trilium Notes",
|
"description": "Trilium Notes",
|
||||||
"version": "0.24.0-beta",
|
"version": "0.24.1-beta",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"main": "electron.js",
|
"main": "electron.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
const $dialog = $("#prompt-dialog");
|
const $dialog = $("#prompt-dialog");
|
||||||
const $question = $("#prompt-dialog-question");
|
const $dialogBody = $dialog.find(".modal-body");
|
||||||
const $answer = $("#prompt-dialog-answer");
|
|
||||||
|
let $question;
|
||||||
|
let $answer;
|
||||||
|
|
||||||
const $form = $("#prompt-dialog-form");
|
const $form = $("#prompt-dialog-form");
|
||||||
|
|
||||||
let resolve;
|
let resolve;
|
||||||
@@ -11,8 +14,21 @@ function ask({ message, defaultValue, shown }) {
|
|||||||
|
|
||||||
shownCb = shown;
|
shownCb = shown;
|
||||||
|
|
||||||
$question.text(message);
|
$question = $("<label>")
|
||||||
$answer.val(defaultValue || "");
|
.prop("for", "prompt-dialog-answer")
|
||||||
|
.text(message);
|
||||||
|
|
||||||
|
$answer = $("<input>")
|
||||||
|
.prop("type", "text")
|
||||||
|
.prop("id", "prompt-dialog-answer")
|
||||||
|
.addClass("form-control")
|
||||||
|
.val(defaultValue || "");
|
||||||
|
|
||||||
|
$dialogBody.empty().append(
|
||||||
|
$("<div>")
|
||||||
|
.addClass("form-group")
|
||||||
|
.append($question)
|
||||||
|
.append($answer));
|
||||||
|
|
||||||
$dialog.modal();
|
$dialog.modal();
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,12 @@ async function execute(e) {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
const sqlQuery = codeEditor.getValue();
|
// execute the selected text or the whole content if there's no selection
|
||||||
|
let sqlQuery = codeEditor.getSelection();
|
||||||
|
|
||||||
|
if (!sqlQuery) {
|
||||||
|
sqlQuery = codeEditor.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
const result = await server.post("sql/execute", {
|
const result = await server.post("sql/execute", {
|
||||||
query: sqlQuery
|
query: sqlQuery
|
||||||
|
|||||||
@@ -117,6 +117,15 @@ async function show() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearMap() {
|
||||||
|
// delete all endpoints and connections
|
||||||
|
// this is done at this point (after async operations) to reduce flicker to the minimum
|
||||||
|
jsPlumbInstance.deleteEveryEndpoint();
|
||||||
|
|
||||||
|
// without this we still end up with note boxes remaining in the canvas
|
||||||
|
$relationMapContainer.empty();
|
||||||
|
}
|
||||||
|
|
||||||
async function loadNotesAndRelations() {
|
async function loadNotesAndRelations() {
|
||||||
const noteIds = mapData.notes.map(note => note.noteId);
|
const noteIds = mapData.notes.map(note => note.noteId);
|
||||||
const data = await server.post("notes/relation-map", {noteIds});
|
const data = await server.post("notes/relation-map", {noteIds});
|
||||||
@@ -142,11 +151,9 @@ async function loadNotesAndRelations() {
|
|||||||
|
|
||||||
mapData.notes = mapData.notes.filter(note => note.noteId in data.noteTitles);
|
mapData.notes = mapData.notes.filter(note => note.noteId in data.noteTitles);
|
||||||
|
|
||||||
// delete all endpoints and connections
|
|
||||||
// this is done at this point (after async operations) to reduce flicker to the minimum
|
|
||||||
jsPlumbInstance.deleteEveryEndpoint();
|
|
||||||
|
|
||||||
jsPlumbInstance.batch(async function () {
|
jsPlumbInstance.batch(async function () {
|
||||||
|
clearMap();
|
||||||
|
|
||||||
for (const note of mapData.notes) {
|
for (const note of mapData.notes) {
|
||||||
const title = data.noteTitles[note.noteId];
|
const title = data.noteTitles[note.noteId];
|
||||||
|
|
||||||
@@ -208,10 +215,17 @@ function initPanZoom() {
|
|||||||
|
|
||||||
mapData.notes.push({ noteId: clipboard.noteId, x, y });
|
mapData.notes.push({ noteId: clipboard.noteId, x, y });
|
||||||
|
|
||||||
|
saveData();
|
||||||
|
|
||||||
clipboard = null;
|
clipboard = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
},
|
||||||
|
filterKey: function(e, dx, dy, dz) {
|
||||||
|
// if ALT is pressed then panzoom should bubble the event up
|
||||||
|
// this is to preserve ALT-LEFT, ALT-RIGHT navigation working
|
||||||
|
return e.altKey;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -244,11 +258,7 @@ function saveCurrentTransform() {
|
|||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
if (jsPlumbInstance) {
|
if (jsPlumbInstance) {
|
||||||
// delete all endpoints and connections
|
clearMap();
|
||||||
jsPlumbInstance.deleteEveryEndpoint();
|
|
||||||
|
|
||||||
// without this we still end up with note boxes remaining in the canvas
|
|
||||||
$relationMapContainer.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pzInstance) {
|
if (pzInstance) {
|
||||||
@@ -312,8 +322,6 @@ function connectionContextMenuHandler(connection, event) {
|
|||||||
async function connectionCreatedHandler(info, originalEvent) {
|
async function connectionCreatedHandler(info, originalEvent) {
|
||||||
const connection = info.connection;
|
const connection = info.connection;
|
||||||
|
|
||||||
const isRelation = relations.some(rel => rel.attributeId === connection.id);
|
|
||||||
|
|
||||||
connection.bind("contextmenu", (obj, event) => {
|
connection.bind("contextmenu", (obj, event) => {
|
||||||
if (connection.getType().includes("link")) {
|
if (connection.getType().includes("link")) {
|
||||||
// don't create context menu if it's a link since there's nothing to do with link from relation map
|
// don't create context menu if it's a link since there's nothing to do with link from relation map
|
||||||
@@ -362,9 +370,7 @@ async function connectionCreatedHandler(info, originalEvent) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const attribute = await server.put(`notes/${sourceNoteId}/relations/${name}/to/${targetNoteId}`);
|
await server.put(`notes/${sourceNoteId}/relations/${name}/to/${targetNoteId}`);
|
||||||
|
|
||||||
relations.push({ attributeId: attribute.attributeId , targetNoteId, sourceNoteId, name });
|
|
||||||
|
|
||||||
await refresh();
|
await refresh();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ function setupTooltip() {
|
|||||||
if ($(this).is(":hover")) {
|
if ($(this).is(":hover")) {
|
||||||
$(this).tooltip({
|
$(this).tooltip({
|
||||||
delay: {"show": 300, "hide": 100},
|
delay: {"show": 300, "hide": 100},
|
||||||
|
container: 'body',
|
||||||
|
placement: 'auto',
|
||||||
|
trigger: 'manual',
|
||||||
|
boundariesElement: 'window',
|
||||||
title: html,
|
title: html,
|
||||||
html: true
|
html: true
|
||||||
});
|
});
|
||||||
@@ -50,7 +54,7 @@ function setupTooltip() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("mouseleave", "a", function() {
|
$(document).on("mouseleave", "a", function() {
|
||||||
$(this).tooltip('hide');
|
$(this).tooltip('dispose');
|
||||||
});
|
});
|
||||||
|
|
||||||
// close any tooltip after click, this fixes the problem that sometimes tooltips remained on the screen
|
// close any tooltip after click, this fixes the problem that sometimes tooltips remained on the screen
|
||||||
|
|||||||
@@ -5,9 +5,7 @@
|
|||||||
|
|
||||||
#relation-map-wrapper {
|
#relation-map-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden !important;
|
height: 100%;
|
||||||
height: 4000px; /* we need to set fixed dimentions. This number is probably enough to cover any screen */
|
|
||||||
width: 4000px;
|
|
||||||
outline: none; /* remove dotted outline on click */
|
outline: none; /* remove dotted outline on click */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ body {
|
|||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
flex-basis: content;
|
flex-basis: content;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-detail-component {
|
.note-detail-component {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ async function updateNoteAttributes(req) {
|
|||||||
attributeEntity.isInheritable = attribute.isInheritable;
|
attributeEntity.isInheritable = attribute.isInheritable;
|
||||||
attributeEntity.isDeleted = attribute.isDeleted;
|
attributeEntity.isDeleted = attribute.isDeleted;
|
||||||
|
|
||||||
if (attributeEntity.type === 'relation' && !attributeEntity.value.trim()) {
|
if (attributeEntity.type === 'relation' && !attribute.value.trim()) {
|
||||||
// relation should never have empty target
|
// relation should never have empty target
|
||||||
attributeEntity.isDeleted = true;
|
attributeEntity.isDeleted = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
const build = require('./build');
|
const build = require('./build');
|
||||||
const packageJson = require('../../package');
|
const packageJson = require('../../package');
|
||||||
|
|
||||||
const APP_DB_VERSION = 116;
|
const APP_DB_VERSION = 118;
|
||||||
const SYNC_VERSION = 2;
|
const SYNC_VERSION = 2;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
module.exports = { buildDate:"2018-11-16T23:30:52+01:00", buildRevision: "90eb1b53fbe915c4658617772aea4347a107a722" };
|
module.exports = { buildDate:"2018-11-19T00:06:44+01:00", buildRevision: "ad6cb6ba347f0396cbf79b76ab62ee3e4a4e8566" };
|
||||||
|
|||||||
@@ -275,8 +275,9 @@ async function runAllChecks() {
|
|||||||
LEFT JOIN notes AS sourceNote ON sourceNote.noteId = links.noteId AND sourceNote.isDeleted = 0
|
LEFT JOIN notes AS sourceNote ON sourceNote.noteId = links.noteId AND sourceNote.isDeleted = 0
|
||||||
LEFT JOIN notes AS targetNote ON targetNote.noteId = links.noteId AND targetNote.isDeleted = 0
|
LEFT JOIN notes AS targetNote ON targetNote.noteId = links.noteId AND targetNote.isDeleted = 0
|
||||||
WHERE
|
WHERE
|
||||||
sourceNote.noteId IS NULL
|
links.isDeleted = 0
|
||||||
OR targetNote.noteId IS NULL`,
|
AND (sourceNote.noteId IS NULL
|
||||||
|
OR targetNote.noteId IS NULL)`,
|
||||||
"Link to source/target note link is broken", errorList);
|
"Link to source/target note link is broken", errorList);
|
||||||
|
|
||||||
await runSyncRowChecks("notes", "noteId", errorList);
|
await runSyncRowChecks("notes", "noteId", errorList);
|
||||||
|
|||||||
@@ -79,7 +79,11 @@ async function processMirrorRelations(entityName, entity, handler) {
|
|||||||
eventService.subscribe(eventService.ENTITY_CHANGED, async ({ entityName, entity }) => {
|
eventService.subscribe(eventService.ENTITY_CHANGED, async ({ entityName, entity }) => {
|
||||||
await processMirrorRelations(entityName, entity, async (definition, note, targetNote) => {
|
await processMirrorRelations(entityName, entity, async (definition, note, targetNote) => {
|
||||||
// we need to make sure that also target's mirror attribute exists and if note, then create it
|
// we need to make sure that also target's mirror attribute exists and if note, then create it
|
||||||
if (!await targetNote.hasRelation(definition.mirrorRelation)) {
|
// mirror attribute has to target our note as well
|
||||||
|
const hasMirrorAttribute = (await targetNote.getRelations(definition.mirrorRelation))
|
||||||
|
.some(attr => attr.value === note.noteId);
|
||||||
|
|
||||||
|
if (!hasMirrorAttribute) {
|
||||||
await new Attribute({
|
await new Attribute({
|
||||||
noteId: targetNote.noteId,
|
noteId: targetNote.noteId,
|
||||||
type: 'relation',
|
type: 'relation',
|
||||||
@@ -97,13 +101,18 @@ eventService.subscribe(eventService.ENTITY_DELETED, async ({ entityName, entity
|
|||||||
await processMirrorRelations(entityName, entity, async (definition, note, targetNote) => {
|
await processMirrorRelations(entityName, entity, async (definition, note, targetNote) => {
|
||||||
// if one mirror attribute is deleted then the other should be deleted as well
|
// if one mirror attribute is deleted then the other should be deleted as well
|
||||||
const relations = await targetNote.getRelations(definition.mirrorRelation);
|
const relations = await targetNote.getRelations(definition.mirrorRelation);
|
||||||
|
let deletedSomething = false;
|
||||||
|
|
||||||
for (const relation of relations) {
|
for (const relation of relations) {
|
||||||
relation.isDeleted = true;
|
if (relation.value === note.noteId) {
|
||||||
await relation.save();
|
relation.isDeleted = true;
|
||||||
|
await relation.save();
|
||||||
|
|
||||||
|
deletedSomething = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (relations.length > 0) {
|
if (deletedSomething) {
|
||||||
targetNote.invalidateAttributeCache();
|
targetNote.invalidateAttributeCache();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ async function importTar(fileBuffer, parentNote) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we allow references to root and they don't need translation
|
||||||
|
if (origNoteId === 'root') {
|
||||||
|
return origNoteId;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ctx.noteIdMap[origNoteId]) {
|
if (!ctx.noteIdMap[origNoteId]) {
|
||||||
ctx.noteIdMap[origNoteId] = utils.newEntityId();
|
ctx.noteIdMap[origNoteId] = utils.newEntityId();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const sqlInit = require('./sql_init');
|
|||||||
const optionService = require('./options');
|
const optionService = require('./options');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const log = require('./log');
|
const log = require('./log');
|
||||||
|
const utils = require('./utils');
|
||||||
const resourceDir = require('./resource_dir');
|
const resourceDir = require('./resource_dir');
|
||||||
|
|
||||||
async function migrate() {
|
async function migrate() {
|
||||||
@@ -72,7 +73,7 @@ async function migrate() {
|
|||||||
log.error("error during migration to version " + mig.dbVersion + ": " + e.stack);
|
log.error("error during migration to version " + mig.dbVersion + ": " + e.stack);
|
||||||
log.error("migration failed, crashing hard"); // this is not very user friendly :-/
|
log.error("migration failed, crashing hard"); // this is not very user friendly :-/
|
||||||
|
|
||||||
process.exit(1);
|
utils.crash();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// make sure foreign keys are enabled even if migration script disables them
|
// make sure foreign keys are enabled even if migration script disables them
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ async function createNewNote(parentNoteId, noteData) {
|
|||||||
noteData.type = noteData.type || parentNote.type;
|
noteData.type = noteData.type || parentNote.type;
|
||||||
noteData.mime = noteData.mime || parentNote.mime;
|
noteData.mime = noteData.mime || parentNote.mime;
|
||||||
|
|
||||||
|
if (noteData.type === 'text' || noteData.type === 'code') {
|
||||||
|
noteData.content = noteData.content || "";
|
||||||
|
}
|
||||||
|
|
||||||
const note = await new Note({
|
const note = await new Note({
|
||||||
noteId: noteData.noteId, // optionally can force specific noteId
|
noteId: noteData.noteId, // optionally can force specific noteId
|
||||||
title: noteData.title,
|
title: noteData.title,
|
||||||
@@ -374,19 +378,12 @@ async function deleteNote(branch) {
|
|||||||
async function cleanupDeletedNotes() {
|
async function cleanupDeletedNotes() {
|
||||||
const cutoffDate = new Date(new Date().getTime() - 48 * 3600 * 1000);
|
const cutoffDate = new Date(new Date().getTime() - 48 * 3600 * 1000);
|
||||||
|
|
||||||
const notesForCleanup = await repository.getEntities("SELECT * FROM notes WHERE isDeleted = 1 AND content != '' AND dateModified <= ?", [dateUtils.dateStr(cutoffDate)]);
|
// it's better to not use repository for this because it will complain about saving protected notes
|
||||||
|
// out of protected session
|
||||||
|
|
||||||
for (const note of notesForCleanup) {
|
await sql.execute("UPDATE notes SET content = NULL WHERE isDeleted = 1 AND content IS NOT NULL AND dateModified <= ?", [dateUtils.dateStr(cutoffDate)]);
|
||||||
note.content = null;
|
|
||||||
await note.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
const notesRevisionsForCleanup = await repository.getEntities("SELECT note_revisions.* FROM notes JOIN note_revisions USING(noteId) WHERE notes.isDeleted = 1 AND note_revisions.content != '' AND notes.dateModified <= ?", [dateUtils.dateStr(cutoffDate)]);
|
await sql.execute("UPDATE note_revisions SET content = NULL WHERE note_revisions.content IS NOT NULL AND noteId IN (SELECT noteId FROM notes WHERE isDeleted = 1 AND notes.dateModified <= ?)", [dateUtils.dateStr(cutoffDate)]);
|
||||||
|
|
||||||
for (const noteRevision of notesRevisionsForCleanup) {
|
|
||||||
noteRevision.content = null;
|
|
||||||
await noteRevision.save();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// first cleanup kickoff 5 minutes after startup
|
// first cleanup kickoff 5 minutes after startup
|
||||||
|
|||||||
@@ -118,6 +118,15 @@ function escapeRegExp(str) {
|
|||||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
|
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function crash() {
|
||||||
|
if (isElectron()) {
|
||||||
|
require('electron').app.exit(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
randomSecureToken,
|
randomSecureToken,
|
||||||
randomString,
|
randomString,
|
||||||
@@ -137,5 +146,6 @@ module.exports = {
|
|||||||
stripTags,
|
stripTags,
|
||||||
intersection,
|
intersection,
|
||||||
union,
|
union,
|
||||||
escapeRegExp
|
escapeRegExp,
|
||||||
|
crash
|
||||||
};
|
};
|
||||||
@@ -10,10 +10,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="form-group">
|
|
||||||
<label for="prompt-dialog-answer" id="prompt-dialog-question"></label>
|
|
||||||
<input type="text" class="form-control" id="prompt-dialog-answer" placeholder="">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button class="btn btn-primary btn-sm" id="prompt-dialog-ok-button">OK <kbd>enter</kbd></button>
|
<button class="btn btn-primary btn-sm" id="prompt-dialog-ok-button">OK <kbd>enter</kbd></button>
|
||||||
|
|||||||
Reference in New Issue
Block a user