Skip to content

Commit

Permalink
Merge pull request #1 from AhmadKhateebq/latex2
Browse files Browse the repository at this point in the history
added latex
  • Loading branch information
AhmadKhateebq authored Dec 20, 2023
2 parents 90bf8a8 + 03a40df commit 4236b0a
Show file tree
Hide file tree
Showing 9 changed files with 833 additions and 134 deletions.
319 changes: 261 additions & 58 deletions example/pubspec.lock

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions lib/html_editor.dart
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
library html_editor;

export 'package:html_editor_enhanced/src/html_editor_controller_unsupported.dart'
if (dart.library.html) 'package:html_editor_enhanced/src/html_editor_controller_web.dart'
if (dart.library.io) 'package:html_editor_enhanced/src/html_editor_controller_mobile.dart';
export 'package:html_editor_enhanced/src/html_editor_unsupported.dart'
if (dart.library.html) 'package:html_editor_enhanced/src/html_editor_web.dart'
if (dart.library.io) 'package:html_editor_enhanced/src/html_editor_mobile.dart';
export 'package:html_editor_enhanced/src/widgets/custom_html_editor.dart';
export 'package:html_editor_enhanced/src/widgets/math_keyboard_dialog.dart';
export 'package:html_editor_enhanced/src/widgets/toolbar_widget.dart';
export 'package:html_editor_enhanced/utils/callbacks.dart';
export 'package:html_editor_enhanced/utils/toolbar.dart';
export 'package:html_editor_enhanced/utils/plugins.dart';
export 'package:html_editor_enhanced/utils/file_upload_model.dart';
export 'package:html_editor_enhanced/utils/options.dart';
export 'package:html_editor_enhanced/utils/utils.dart'
hide setState, intersperse, getRandString;

export 'package:html_editor_enhanced/src/html_editor_unsupported.dart'
if (dart.library.html) 'package:html_editor_enhanced/src/html_editor_web.dart'
if (dart.library.io) 'package:html_editor_enhanced/src/html_editor_mobile.dart';

export 'package:html_editor_enhanced/src/html_editor_controller_unsupported.dart'
if (dart.library.html) 'package:html_editor_enhanced/src/html_editor_controller_web.dart'
if (dart.library.io) 'package:html_editor_enhanced/src/html_editor_controller_mobile.dart';

export 'package:html_editor_enhanced/utils/plugins.dart';
export 'package:html_editor_enhanced/utils/shims/flutter_inappwebview_fake.dart'
if (dart.library.io) 'package:flutter_inappwebview/flutter_inappwebview.dart';
export 'package:html_editor_enhanced/utils/toolbar.dart';
export 'package:html_editor_enhanced/utils/utils.dart'
hide setState, intersperse, getRandString;

/// Defines the 3 different cases for file insertion failing
enum UploadError { unsupportedFile, exceededMaxSize, jsException }
Expand Down Expand Up @@ -72,6 +71,7 @@ enum ButtonType {
otherFile,
table,
hr,
fn,
fullscreen,
codeview,
undo,
Expand Down Expand Up @@ -99,4 +99,4 @@ enum DropdownMenuDirection { down, up }
enum InsertFileType { image, audio, video }

/// Sets how the virtual keyboard appears on mobile devices
enum HtmlInputType { decimal, email, numeric, tel, url, text }
enum HtmlInputType { decimal, email, numeric, tel, url, text }
39 changes: 37 additions & 2 deletions lib/src/html_editor_controller_unsupported.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:collection';

import 'package:html_editor_enhanced/html_editor.dart';
import 'package:meta/meta.dart';

Expand All @@ -9,6 +11,39 @@ class HtmlEditorController {
this.processOutputHtml = true,
});

final HashMap<String, String> _latexMap = HashMap();

void addToHashMap(String key, String value) {
_latexMap.addAll({
key: value,
});
}

Future<String> getHtmlStringWithLatex() async {
var txt = await getText();
final reg = RegExp('<math>', multiLine: true);
var tags = <String>[];
var res = txt.split(reg);
print('result = $res');

res.forEach((element) {
if (element.contains(r'</math>')) {
var split = element.split(r'</math>');
var after = split.last;
element = '<math>${split.first}</math>';
tags.add(_latexMap[element] ?? element);
tags.add(after);
} else {
tags.add(element);
}
});
String tag = '';
tags.forEach((element) {
tag = '$tag$element';
});
return tag;
}

/// Toolbar widget state to call various methods. For internal use only.
@internal
ToolbarWidgetState? toolbar;
Expand Down Expand Up @@ -84,7 +119,7 @@ class HtmlEditorController {
/// A function to execute JS passed as a [WebScript] to the editor. This should
/// only be used on Flutter Web.
Future<dynamic> evaluateJavascriptWeb(String name,
{bool hasReturnValue = false}) =>
{bool hasReturnValue = false}) =>
Future.value();

/// Gets the text from the editor and returns it as a [String].
Expand Down Expand Up @@ -171,4 +206,4 @@ class HtmlEditorController {
/// Internal function to insert table on Web
@internal
void insertTable(String dimensions) {}
}
}
2 changes: 1 addition & 1 deletion lib/src/html_editor_unsupported.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ class HtmlEditor extends StatelessWidget {
Widget build(BuildContext context) {
return Text('Unsupported in this environment');
}
}
}
174 changes: 174 additions & 0 deletions lib/src/widgets/custom_html_editor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// ignore_for_file: avoid_print

import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import '../../html_editor.dart';

class CustomHtmlEditorWidget extends StatelessWidget {
const CustomHtmlEditorWidget({required this.controller, double? height})
: _height = height ?? 500;
final HtmlEditorController controller;
final double _height;

Widget _htmlWidget() {
return HtmlEditor(
controller: controller,
htmlEditorOptions: const HtmlEditorOptions(
hint: 'Your text here...',
shouldEnsureVisible: true,
//initialText: "<p>text content initial, if any</p>",
),
htmlToolbarOptions: HtmlToolbarOptions(
toolbarPosition: ToolbarPosition.aboveEditor,
defaultToolbarButtons: [
const StyleButtons(),
const FontSettingButtons(fontSizeUnit: false),
const FontButtons(clearAll: false),
const ColorButtons(),
const ListButtons(listStyles: false),
const ParagraphButtons(
textDirection: false, lineHeight: false, caseConverter: false),
const InsertButtons(
video: false,
audio: false,
table: true,
hr: true,
fn: true,
otherFile: false),
],
//by default
toolbarType: ToolbarType.nativeExpandable,
//by default
onButtonPressed:
(ButtonType type, bool? status, Function? updateStatus) {
if (type.name == ButtonType.picture.name) {
print('no image');
controller.insertHtml(tableTex);
return false;
}
print(
"button '${type.name}' pressed, the current selected status is $status");
return true;
},
onDropdownChanged: (DropdownType type, dynamic changed,
Function(dynamic)? updateSelectedItem) {
print("dropdown '${type.name}' changed to $changed");
return true;
},
mediaLinkInsertInterceptor: (String url, InsertFileType type) {
print(url);
return true;
},
mediaUploadInterceptor: (PlatformFile file, InsertFileType type) async {
if (kDebugMode) {
print(file.name);
} //filename
print(file.size); //size in bytes
print(file.extension); //file extension (eg jpeg or mp4)
return true;
},
),
otherOptions: OtherOptions(height: _height),
callbacks: Callbacks(onBeforeCommand: (String? currentHtml) {
print('html before change is $currentHtml');
}, onChangeContent: (String? changed) {
print('content changed to $changed');
}, onChangeCodeview: (String? changed) {
print('code changed to $changed');
}, onChangeSelection: (EditorSettings settings) {
print('parent element is ${settings.parentElement}');
print('font name is ${settings.fontName}');
}, onDialogShown: () {
print('dialog shown');
}, onEnter: () {
print('enter/return pressed');
}, onFocus: () {
print('editor focused');
}, onBlur: () {
print('editor unfocused');
}, onBlurCodeview: () {
print('codeview either focused or unfocused');
}, onInit: () {
print('init');
},
//this is commented because it overrides the default Summernote handlers
/*onImageLinkInsert: (String? url) {
print(url ?? "unknown url");
},
onImageUpload: (FileUpload file) async {
print(file.name);
print(file.size);
print(file.type);
print(file.base64);
},*/
onImageUploadError:
(FileUpload? file, String? base64Str, UploadError error) {
print((error.name));
print(base64Str ?? '');
if (file != null) {
print(file.name);
print(file.size);
print(file.type);
}
}, onKeyDown: (int? keyCode) {
print('$keyCode key downed');
print('current character count: ${controller.characterCount}');
}, onKeyUp: (int? keyCode) {
print('$keyCode key released');
}, onMouseDown: () {
print('mouse downed');
}, onMouseUp: () {
print('mouse released');
}, onNavigationRequestMobile: (String url) {
print(url);
return NavigationActionPolicy.ALLOW;
}, onPaste: () {
print('pasted into editor');
}, onScroll: () {
print('editor scrolled');
}),
plugins: [
SummernoteAtMention(
getSuggestionsMobile: (String value) {
var mentions = <String>['test1', 'test2', 'test3'];
return mentions
.where((element) => element.contains(value))
.toList();
},
mentionsWeb: ['test1', 'test2', 'test3'],
onSelect: (String value) {
print(value);
}),
],
);
}

@override
Widget build(BuildContext context) {
return _htmlWidget();
}
}

const tableTex = r'''
<tex>
\begin{array} { | l | l | l | }
\hline \text { Year } & \begin{array} { l }
\text { Number of U.S. } \\
\text { farms (in } \\
\text { millions) }
\end{array} & \begin{array} { l }
\text { Average size of } \\
\text { U.S. farms } \\
\text { (acres) }
\end{array} \\
\hline 1950 & 5.6 & 234 \\
\hline 1960 & 4.0 & 330 \\
\hline 1970 & 2.9 & 399 \\
\hline 1980 & 2.4 & 441 \\
\hline 1990 & 2.1 & 478 \\
\hline 2000 & 2.2 & 439 \\
\hline
\end{array}</tex>
''';
81 changes: 81 additions & 0 deletions lib/src/widgets/math_keyboard_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:math_keyboard/math_keyboard.dart';

class MathKeyboardDialog extends StatelessWidget {
MathKeyboardDialog({required this.controller, this.mathField}) {
if (mathField != null && mathField!.controller != null) {
log('',
name: 'Warning',
error:
'do not set the math field controller as it will get ignored\n');
}
}

final MathFieldEditingController controller;
final MathField? mathField;

@override
Widget build(BuildContext context) {
return Dialog(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_mathField(context),
const SizedBox(height: 15),
TextButton(
onPressed: () {
controller.setTexString('');
Navigator.pop(context, '');
print(controller.texStringAsFun);
},
child: const Text('Close'),
),
TextButton(
onPressed: () {
Navigator.pop(context, controller.texStringAsFun);
print(controller.texStringAsFun);
},
child: const Text('save'),
),
],
),
),
);
}

Widget _mathField(context) {
return SizedBox(
width: MediaQuery.of(context).size.width,
child: MathField(
focusNode: mathField?.focusNode,
autofocus: mathField?.autofocus ?? true,
controller: controller,
variables: mathField?.variables ?? ['x', 'y', 'z', 'A', 'B', 'C'],
decoration: mathField?.decoration ??
InputDecoration(
suffix: MouseRegion(
cursor: MaterialStateMouseCursor.clickable,
child: GestureDetector(
onTap: controller.clear,
child: const Icon(
Icons.highlight_remove_rounded,
color: Colors.grey,
),
),
),
),
onChanged: mathField?.onChanged ??
(str) {
controller.setTexString(str);
},
onSubmitted: mathField?.onSubmitted,
opensKeyboard: mathField?.opensKeyboard ?? true,
),
);
}
}
Loading

0 comments on commit 4236b0a

Please sign in to comment.