Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,21 @@ jobs:
ruby-version: ruby-3.3.7
bundler-cache: true

- name: Lint code for consistent style
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'yarn'

- name: Install JavaScript dependencies
run: yarn install --frozen-lockfile

- name: Lint Ruby code for consistent style
run: bin/rubocop -f github

- name: Lint JavaScript code for consistent style
run: yarn lint

test:
runs-on: ubuntu-latest

Expand Down
186 changes: 85 additions & 101 deletions app/assets/javascript/lexxy.js

Large diffs are not rendered by default.

Binary file modified app/assets/javascript/lexxy.js.br
Binary file not shown.
Binary file modified app/assets/javascript/lexxy.js.gz
Binary file not shown.
4 changes: 2 additions & 2 deletions app/assets/javascript/lexxy.min.js

Large diffs are not rendered by default.

Binary file modified app/assets/javascript/lexxy.min.js.br
Binary file not shown.
Binary file modified app/assets/javascript/lexxy.min.js.gz
Binary file not shown.
72 changes: 72 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import js from "@eslint/js"

export default [
{
ignores: ["dist/**", "app/**", "node_modules/**", "pkg/**", "test/**", "lib/**", "bin/**", "config/**", "docs/**", "vendor/**"]
},
js.configs.recommended,
{
files: ["src/**/*.js"],
languageOptions: {
ecmaVersion: 2022,
sourceType: "module",
globals: {
console: "readonly",
document: "readonly",
window: "readonly",
navigator: "readonly",
HTMLElement: "readonly",
CustomEvent: "readonly",
Element: "readonly",
Node: "readonly",
NodeList: "readonly",
Event: "readonly",
MutationObserver: "readonly",
DOMParser: "readonly",
Blob: "readonly",
File: "readonly",
FileReader: "readonly",
URL: "readonly",
URLSearchParams: "readonly",
Request: "readonly",
Response: "readonly",
FormData: "readonly",
fetch: "readonly",
setTimeout: "readonly",
clearTimeout: "readonly",
setInterval: "readonly",
clearInterval: "readonly",
XMLHttpRequest: "readonly",
requestAnimationFrame: "readonly",
cancelAnimationFrame: "readonly",
customElements: "readonly",
Prism: "readonly",
ResizeObserver: "readonly"
}
},
rules: {
"array-bracket-spacing": ["error", "always"],
"block-spacing": ["error", "always"],
"camelcase": ["error"],
"comma-spacing": ["error"],
"curly": ["error", "multi-line"],
"dot-notation": ["error"],
"eol-last": ["error"],
"func-style": ["error", "declaration"],
"getter-return": ["error"],
"keyword-spacing": ["error"],
"no-empty": "off",
"no-multi-spaces": ["error", { "exceptions": { "VariableDeclarator": true } }],
"no-multiple-empty-lines": ["error", { "max": 2 }],
"no-restricted-globals": ["error", "event"],
"no-trailing-spaces": ["error"],
"no-unused-vars": ["error", { "vars": "all", "args": "none", "caughtErrors": "none" }],
"no-var": ["error"],
"object-curly-spacing": ["error", "always"],
"prefer-const": ["error"],
"quotes": ["error", "double"],
"semi": ["error", "never"],
"sort-imports": ["error", { "ignoreDeclarationSort": true }]
}
}
]
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@
"author": "Jorge Manrubia <jorge@37signals.com>",
"license": "MIT",
"devDependencies": {
"@eslint/js": "^9.15.0",
"@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-terser": "^0.4.4",
"eslint": "^9.15.0",
"rollup": "^4.44.1",
"rollup-plugin-gzip": "^4.1.1"
},
"scripts": {
"build": "rollup -c",
"build:npm": "rollup -c rollup.config.npm.mjs",
"watch": "rollup -wc",
"lint": "eslint",
"prerelease": "yarn build:npm",
"release": "yarn build:npm && yarn publish"
},
Expand Down
6 changes: 3 additions & 3 deletions src/config/dom_purify.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import DOMPurify from 'dompurify'
import DOMPurify from "dompurify"

DOMPurify.addHook("uponSanitizeElement", (node, data) => {
if (data.tagName === "strong" || data.tagName === "em") {
node.removeAttribute('class');
node.removeAttribute("class")
}
});
})
84 changes: 42 additions & 42 deletions src/config/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,47 @@ export default {
underline: "lexxy-content__underline",
},
codeHighlight: {
atrule: 'code-token__attr',
attr: 'code-token__attr',
'attr-name': 'code-token__attr',
'attr-value': 'code-token__selector',
boolean: 'code-token__property',
bold: 'code-token__variable',
builtin: 'code-token__selector',
cdata: 'code-token__comment',
char: 'code-token__selector',
class: 'code-token__function',
'class-name': 'code-token__function',
color: 'code-token__property',
comment: 'code-token__comment',
constant: 'code-token__property',
coord: 'code-token__property',
decorator: 'code-token__function',
deleted: 'code-token__property',
doctype: 'code-token__comment',
entity: 'code-token__operator',
function: 'code-token__function',
hexcode: 'code-token__property',
important: 'code-token__variable',
inserted: 'code-token__selector',
italic: 'code-token__comment',
keyword: 'code-token__attr',
namespace: 'code-token__variable',
number: 'code-token__property',
operator: 'code-token__operator',
parameter: 'code-token__variable',
prolog: 'code-token__comment',
property: 'code-token__property',
punctuation: 'code-token__punctuation',
regex: 'code-token__variable',
script: 'code-token__function',
selector: 'code-token__selector',
string: 'code-token__selector',
style: 'code-token__function',
symbol: 'code-token__property',
tag: 'code-token__property',
title: 'code-token__function',
url: 'code-token__operator',
variable: 'code-token__variable',
atrule: "code-token__attr",
attr: "code-token__attr",
"attr-name": "code-token__attr",
"attr-value": "code-token__selector",
boolean: "code-token__property",
bold: "code-token__variable",
builtin: "code-token__selector",
cdata: "code-token__comment",
char: "code-token__selector",
class: "code-token__function",
"class-name": "code-token__function",
color: "code-token__property",
comment: "code-token__comment",
constant: "code-token__property",
coord: "code-token__property",
decorator: "code-token__function",
deleted: "code-token__property",
doctype: "code-token__comment",
entity: "code-token__operator",
function: "code-token__function",
hexcode: "code-token__property",
important: "code-token__variable",
inserted: "code-token__selector",
italic: "code-token__comment",
keyword: "code-token__attr",
namespace: "code-token__variable",
number: "code-token__property",
operator: "code-token__operator",
parameter: "code-token__variable",
prolog: "code-token__comment",
property: "code-token__property",
punctuation: "code-token__punctuation",
regex: "code-token__variable",
script: "code-token__function",
selector: "code-token__selector",
string: "code-token__selector",
style: "code-token__function",
symbol: "code-token__property",
tag: "code-token__property",
title: "code-token__function",
url: "code-token__operator",
variable: "code-token__variable",
}
}
6 changes: 3 additions & 3 deletions src/editor/clipboard.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { marked } from "marked"
import { isUrl } from "../helpers/string_helper";
import { nextFrame } from "../helpers/timing_helpers";
import { isUrl } from "../helpers/string_helper"
import { nextFrame } from "../helpers/timing_helpers"
import { dispatch } from "../helpers/html_helper"

export default class Clipboard {
Expand Down Expand Up @@ -63,7 +63,7 @@ export default class Clipboard {
#handlePastedFiles(clipboardData) {
if (!this.editorElement.supportsAttachments) return

const html = clipboardData.getData('text/html')
const html = clipboardData.getData("text/html")
if (html) return // Ignore if image copied from browser since we will load it as a remote image

this.#preservingScrollPosition(() => {
Expand Down
12 changes: 6 additions & 6 deletions src/editor/command_dispatcher.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {
$getSelection,
$isRangeSelection,
PASTE_COMMAND,
COMMAND_PRIORITY_LOW,
FORMAT_TEXT_COMMAND,
UNDO_COMMAND,
REDO_COMMAND
PASTE_COMMAND,
REDO_COMMAND,
UNDO_COMMAND
} from "lexical"

import { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND } from "@lexical/list"
import { $createHeadingNode, $createQuoteNode, $isHeadingNode, $isQuoteNode } from "@lexical/rich-text"
import { CodeNode, $isCodeNode } from "@lexical/code"
import { $isCodeNode, CodeNode } from "@lexical/code"
import { $toggleLink } from "@lexical/link"
import { createElement } from "../helpers/html_helper"
import { getListType } from "../helpers/lexical_helper"
Expand Down Expand Up @@ -75,7 +75,7 @@ export class CommandDispatcher {

dispatchInsertUnorderedList() {
const selection = $getSelection()
if (!selection) return;
if (!selection) return

const anchorNode = selection.anchor.getNode()

Expand All @@ -88,7 +88,7 @@ export class CommandDispatcher {

dispatchInsertOrderedList() {
const selection = $getSelection()
if (!selection) return;
if (!selection) return

const anchorNode = selection.anchor.getNode()

Expand Down
20 changes: 10 additions & 10 deletions src/editor/contents.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {
$createParagraphNode, $getSelection, $setSelection, $insertNodes, $isElementNode, $isParagraphNode, $isTextNode,
$isRangeSelection, $createLineBreakNode, $createTextNode, HISTORY_MERGE_TAG, $isNodeSelection, $getNodeByKey, $getRoot
$createLineBreakNode, $createParagraphNode, $createTextNode, $getNodeByKey, $getRoot, $getSelection, $insertNodes,
$isElementNode, $isNodeSelection, $isParagraphNode, $isRangeSelection, $isTextNode, $setSelection, HISTORY_MERGE_TAG
} from "lexical"

import { $generateNodesFromDOM } from "@lexical/html"
import { ActionTextAttachmentUploadNode } from "../nodes/action_text_attachment_upload_node"
import { CustomActionTextAttachmentNode } from "../nodes/custom_action_text_attachment_node"
import { $toggleLink, $createLinkNode } from "@lexical/link"
import { $createLinkNode, $toggleLink } from "@lexical/link"
import { dispatch, parseHtml } from "../helpers/html_helper"
import { $isListItemNode, $isListNode } from "@lexical/list"
import { $isListNode } from "@lexical/list"
import { getNearestListItemNode } from "../helpers/lexical_helper"
import { nextFrame } from "../helpers/timing_helpers.js";
import { nextFrame } from "../helpers/timing_helpers.js"

export default class Contents {
constructor(editorElement) {
Expand Down Expand Up @@ -546,8 +546,8 @@ export default class Contents {
firstParagraph.selectStart()
const currentSelection = $getSelection()
if (currentSelection && $isRangeSelection(currentSelection)) {
currentSelection.anchor.set(firstParagraph.getKey(), 0, 'element')
currentSelection.focus.set(lastParagraph.getKey(), lastParagraph.getChildrenSize(), 'element')
currentSelection.anchor.set(firstParagraph.getKey(), 0, "element")
currentSelection.focus.set(lastParagraph.getKey(), lastParagraph.getChildrenSize(), "element")
}
}

Expand Down Expand Up @@ -601,14 +601,14 @@ export default class Contents {
const last = children[children.length - 1]
const beforeLast = children[children.length - 2]

if (($isTextNode(last) && last.getTextContent() === "") && (beforeLast && !$isTextNode(beforeLast))) {
if ($isTextNode(last) && last.getTextContent() === "" && (beforeLast && !$isTextNode(beforeLast))) {
paragraph.append($createLineBreakNode())
}
}
}

#createCustomAttachmentNodeWithHtml(html, options = {}) {
const attachmentConfig = typeof options === 'object' ? options : {}
const attachmentConfig = typeof options === "object" ? options : {}

return new CustomActionTextAttachmentNode({
sgid: attachmentConfig.sgid || null,
Expand All @@ -623,6 +623,6 @@ export default class Contents {
}

#shouldUploadFile(file) {
return dispatch(this.editorElement, 'lexxy:file-accept', { file }, true)
return dispatch(this.editorElement, "lexxy:file-accept", { file }, true)
}
}
2 changes: 1 addition & 1 deletion src/editor/prompt/local_filter_source.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import BaseSource from "./base_source"
import { filterMatches } from "../../helpers/string_helper";
import { filterMatches } from "../../helpers/string_helper"

export default class LocalFilterSource extends BaseSource {
async buildListItems(filter = "") {
Expand Down
2 changes: 1 addition & 1 deletion src/editor/prompt/remote_filter_source.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import BaseSource from "./base_source"
import { debounceAsync } from "../../helpers/timing_helpers";
import { debounceAsync } from "../../helpers/timing_helpers"

const DEBOUNCE_INTERVAL = 200

Expand Down
Loading