liverwire summernote not triggering changes in the textarea - javascript

could someone please assist, I am trying to use livewire components and summer note and I have the functionality working when its a normal input field, but as soon as I change the class to summer note, the values no longer update as I type. Any help would be much appreciated!
The livelier form:
<div>
<p>{{ $note }}</p>
<textarea class="summernote" id="kt_summernote_1" name="note" wire:model="note"></textarea>
</div>
The php file:
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class LessonContentForm extends Component
{
public $note;
public function render()
{
return view('livewire.lesson-content-form');
}
}
Finally the JS for SummerNote:
<script type="text/javascript">
"use strict";
// Class definition
var KTSummernoteDemo = function () {
// Private functions
var demos = function () {
$('.summernote').summernote({
height: 400,
tabsize: 2,
});
}
return {
// public functions
init: function() {
demos();
}
};
}();
// Initialization
jQuery(document).ready(function() {
KTSummernoteDemo.init();
});
</script>

The best way to go will be to use a callback function.
<div wire:ignore>
<textarea wire:model.defer="description" id="summernote"></textarea>
</div>
/////////////////////////////////////////////////////////////////////////////////////
<script>
$('#summernote').summernote({
placeholder: 'Type something cool',
tabsize: 2,
height: 400,
focus: true,
toolbar: [
['font', ['bold', 'underline', 'clear']],
['para', ['paragraph']],
['insert', ['picture', 'video']],
],
callbacks: {
onChange: function(e) {
#this.set('description', e);
},
}
});
</script>
This uses jQuery and also if your livewire property still isn't in sync with your editor then you need to dispatch a browser event from your livewire component for this editor script above.

Related

Create a custom button plugin in Summernote

I'm trying to create a custom button plugin in Summernote, but the ui.button creates of course, a button. Is there any way to make that a div for example?
context.memo('button', function() {
return ui.buttonGroup([
ui.button({
className: 'someClass',
tooltip: 'tooltipInfo',
data: {
toggle: 'dropdown'
},
click: function() {}
}),
What I tried is to do:
var buttonGroup = ui.buttonGroup([ ... ]);
buttonGroup.changeTag('div');
return buttonGroup;
Then update manually the button and change its tag to div. It "works" but for instance, the click event in the buttonGroup that I set doesn't work in this case.
Even tried attaching an on('click') event to buttonGroup variable, and still, the click isn't triggering.
Any ideas on how I can achieve this in another way?
The process of creating a button for summernote is relatively simple, you should first create a variable for your button.
In this variable you will assign a function that collects the summernote UI and then assign it a button with the desired properties inside it.
Already when loading summernote you will pass as the parameter of UI the variable used to create your button, as you can see in the example below
var btnAttch = function (context) {
var ui = $.summernote.ui;
var button = ui.button({
contents:
'<label class="custom-file-upload"> <input type="file" class="input-file" id="input-file-' + id + '" multiple/>' +
'<i class="glyphicon glyphicon-paperclip"></i> </label>',
tooltip: 'Attach file',
});
}
$(".txtInstrucoes-" + id).summernote({
height: 300,
toolbar: [
['style', ['bold', 'italic', 'underline']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['fontsize', ['fontsize']],
['btn-anexar', ['btnAnexar']]
],
buttons: {
btnAttch: btnAttch
},
disableDragAndDrop: true,
disableResizeEditor: true,
callbacks: {
onInit: function () {
$.EmpresaAPI.Events.OnChangeInputFile(id);
},
}
})

Summernote custom dialog and button

I try to implement Summertnote editor. Here is the JS code:
$(document).ready(function() {
//Summernote
//var te_markdown = document.getElementById("code-markdown");.
var textarea = document.getElementById("code");
var HelloButton = function (context) {
var ui = $.summernote.ui;
// create button
var button = ui.button({
contents: '<i class="fa fa-child"/> Hello',
tooltip: 'Ciao!',
click: function () {
// invoke insertText method with 'hello' on editor module.
context.invoke('editor.insertText', 'hello');
}
});
return button.render(); // return button as jquery object
}
function autoFormat() {
var totalLines = editor.lineCount();
editor.autoFormatRange({line:0, ch:0}, {line:totalLines});
}
$('#st-editor').summernote({
lang: 'it-IT', // set italian language
height: 350, // set editor height
width: 350, // set editor width
minHeight: null, // set minimum height of editor
maxHeight: null, // set maximum height of editor
dialogsFade: true, // set fade on dialog
prettifyHtml: false,
toolbar: [
['mybutton', ['hello']]
],
buttons: {
hello: HelloButton
},
codemirror: { // codemirror options
mode: "text/html",
lineNumbers: true,
lineWrapping: true,
extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }},
foldGutter: true,
theme: 'monokai',
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"]
}
},
focus: true set focus to editable area after initializing summernote
});
I get the code here: http://summernote.org/deep-dive/#custom-button
So, In this example I want to simply put a "Hello" string clicking the button but it gives me an error "TypeError: context is undefined". Can someone help me?
Thanks
Instead of
context.invoke('editor.insertText', 'hello');
use
$('#st-editor').summernote('editor.insertText', 'hello');
works only if you have one editor of course. I'm still searching how to get this context thingy passed. Maybe something with onInit, but I couldn't get it working yet.
#wessel code works, for multiple ids I do an iteration using jQuery each:
Make sure oyu attach an id attribute to all editors:
if ($('.summernote').length) {
var blockQuoteButton = function(itemId) {
var ui = $.summernote.ui;
var button = ui.button({
className: 'note-btn-blockquote',
contents: '<i class="fa fa-quote-right">Quo</i>',
tooltip: 'Blockquote',
click: function() {
$('#' + itemId).summernote('editor.formatBlock', 'blockquote');
}
});
return button.render();
}
$('.summernote').each(function(k, item) {
let itemId = $(item).attr('id');
$('#' + itemId).summernote({
height: 100,
toolbar: [
['style', ['style']],
['font', ['bold', 'italic', 'underline']],
['para', ['ul', 'ol']],
['mybutton', ['blq']]
],
buttons: {
blq: blockQuoteButton(itemId)
}
});
});
}
This issue appeared in version 0.8.12. Reverting back to 0.8.10 fixes it
Inside package.json specify
"dependencies": {
...
"ngx-summernote": "0.7.0",
"summernote": "0.8.10",
...
},
and run npm install afterwards. It works after that

TypeScript nesting static properties

I'm trying to build a class that will contain constant values to be used at different places.
The structure should be something like this:
class JavascriptEvents {
static change: string = "change";
static click: string = "click";
static blur: string = "blur";
static inputChange: string = "input propertychange paste";
static dblClick: string = "dblclick";
static bootstrap: Object = {
accordion: {
show: "show.bs.collapse",
shown: "shown.bs.collapse",
hide: "hide.bs.collapse",
hidden: "hidden.bs.collapse"
},
modal: {
shown: "shown.bs.modal",
show: "show.bs.modal",
hide: "hide.bs.modal",
hidden: "hidden.bs.modal",
loaded: "loaded.bs.modal"
}
}
}
Question: How should the bootstrap part be nested so I can reference an event like:
$("someElement").on(JavascriptEvents.bootstrap.modal.shown, function(){
// do whatever needed
});
I think the problem is the : Object declaration, which hid all the type information from the call site. If you simply remove it, the type checker should be happy again.
E.g.:
class JavascriptEvents {
static bootstrap: Object = {
modal: {
shown: "shown.bs.modal",
}
}
static bootstrap2 = {
modal: {
shown: "shown.bs.modal",
}
}
}
let jq: any;
jq.on(JavascriptEvents.bootstrap.modal.shown); // Error
jq.on(JavascriptEvents.bootstrap2.modal.shown); // Works
Playground

Adding a tooltip in a Dojo Select

I would like to add a tooltip to the items in a Dojo Select. This code adds a tooltip when the store is contained in the script.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
#import "https://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css";
#import "https://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/resources/dojo.css";
</style>
<script src="https://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js" type="text/javascript" data-dojo-config="async: true"></script>
<script>
require(["dijit/form/Select",
"dojo/store/Memory",
"dojo/domReady!"
], function (Select, Memory) {
var store = new Memory({
data: [
{ id: "foo", label: '<div tooltip="Foo Tooltip" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)">FOO</div>' },
{ id: "bar", label: '<div tooltip="Bar Tooltip" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)">Bar</div>' }
]
});
var s = new Select({
store: store,
labelType: 'html',
labelAttr: 'label'
}, "target");
s.startup();
});
function showTooltip(el) {
dijit.showTooltip(el.getAttribute('tooltip'), el);
}
function hideTooltip(el) {
dijit.hideTooltip(el);
}
</script>
</head>
<body class="claro">
<div id="target"></div>
</body>
</html>
However, in my application, my store is in a separate module (stores.js).
define([], function () {
return {
priority: [
{ id: "foo", label: '<div tooltip="Foo Tooltip" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)">FOO</div>' },
{ id: "bar", label: '<div tooltip="Bar Tooltip" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)">Bar</div>' }
]
};
};
I set the module in the require ("modules/stores") and put the alias in the function (Stores) and create my select using this code.
new Select({
id: "cboPriority",
store: new Memory({ data: Stores.priority }),
labelType: 'html',
labelAttr: 'label'
}, "divPriority").startup();
I've tried adding the showTooltip and hideTooltip functions in the module, but I still get the console error "ReferenceError: showTooltip is not defined". What is the proper way of setting up the script and the module so I can show the tooltip?
You're attempting to set up inline onmouseover event handlers on elements via your label strings. This is going to attempt to call a global showTooltip function, and no such function exists - your showTooltip function is enclosed within your require factory function.
Given that you are creating an HTML label with a node containing an attribute indicating the text to display, a better option in this specific case would be to use dojo/on's event delegation to hook up a single event handler for mouseover and another for mouseout:
var dropdownNode = s.dropDown.domNode;
on(dropdownNode, '[data-tooltip]:mouseover', function () {
Tooltip.show(this.getAttribute('data-tooltip'), this);
});
on(dropdownNode, '[data-tooltip]:mouseout', function () {
Tooltip.hide(this);
});
(Tooltip in the above code refers to the dijit/Tooltip module, and I elected to use a data-attribute which would at least be valid HTML5.)
To be quite honest, I'd prefer avoiding embedding HTML in data to begin with, but this is likely the shortest path from where you are to where you want to be.

Jarvis.widget doesn't get rendered in AngularJS ng-repeat

I have a hard time figuring out what to do in my AngularJs single-page . I use ng-repeat to display a number of widgets. The plugin is "Jarvis widget v2.0". My problem is, that the article container does not have the functionality from the Jarvis widget (fullscreen, collapse etc.).
The data is delayed because of a HTTP GET call. If I hard-code the dataSeries it works 100%, but it seems that the Jarvis widgets gets rendered before the success of the HTTP GET. I have tried to find a solution for days and my guess is that a directive is the solution, but I'm lost!
<article class="col-xs-12 col-sm-12 col-md-6 col-lg-6" ng-repeat="chart in dataSeries">
<div class="jarviswidget" id="wid-id-02" data-widget-editbutton="false" data-widget-colorbutton="false" data-widget-deletebutton="false"></div>
</article>
This is my first post, so if I forgot something i apologize in advance.
The code inside function setup_widgets_desktop() is going to create the widgets based on the current(!) HTML content. As ng-repeat will render your element after you have a success from your HTTP request, there are no elements present when the function is called.
In order to achieve the behaviour you want, execute setup_widgets_desktop() again after your callback returns. You might need to make sure it is delayed by using $timeout(setup_widgets_desktop, 1000). I am using it this way, but not sure if it is a general requirement to have a delay.
The best option would be to extract the call $('#widget-grid').jarvisWidgets() into an directive. You could replace $('#widget-grid') with getting the current $(element), so it is only bound to the current element and not some fixed ID inside the DOM. If you need more advice on this, just drop me a line.
Edit (sample code):
In my project I am using the following Angular service (you have to replace yourApp, the HTTP URI and the jQuery selector to your needs):
(function(yourApp) {
"use strict";
yourApp.factory("presenter", function ($timeout) {
var layout = function () {
$("#widgets-grid").jarvisWidgets({
grid: "article",
widgets: '.jarviswidget',
localStorage: false,
// deleteSettingsKey: '#deletesettingskey-options',
// settingsKeyLabel: 'Reset settings?',
// deletePositionKey: '#deletepositionkey-options',
// positionKeyLabel: 'Reset position?',
sortable: false,
buttonsHidden: false,
// toggle button
toggleButton: false,
toggleClass: 'fa fa-minus | fa fa-plus',
toggleSpeed: 200,
onToggle: function () {
},
// delete btn
deleteButton: false,
deleteClass: 'fa fa-times',
deleteSpeed: 200,
onDelete: function () {
},
// edit btn
editButton: false,
editPlaceholder: '.jarviswidget-editbox',
editClass: 'fa fa-cog | fa fa-save',
editSpeed: 200,
onEdit: function () {
},
colorButton: false,
// full screen
fullscreenButton: true,
fullscreenClass: 'fa fa-expand | fa fa-compress',
fullscreenDiff: 3,
onFullscreen: function (e) {
},
// order
buttonOrder: '%refresh% %custom% %edit% %toggle% %fullscreen% %delete%',
opacity: 1.0,
dragHandle: '> header',
placeholderClass: 'jarviswidget-placeholder',
indicator: true,
indicatorTime: 600,
ajax: true,
timestampPlaceholder: '.jarviswidget-timestamp',
timestampFormat: 'Last update: %m%/%d%/%y% %h%:%i%:%s%',
refreshButton: true,
refreshButtonClass: 'fa fa-refresh',
labelError: 'Sorry but there was a error:',
labelUpdated: 'Last Update:',
labelRefresh: 'Refresh',
labelDelete: 'Delete widget:',
afterLoad: function () {
},
rtl: false, // best not to toggle this!
onChange: function () {
},
onSave: function () {
},
ajaxnav: $.navAsAjax // declears how the localstorage should be saved
});
}
return {
layout: function() {
$timeout(layout, 1000);
}
};
});
})(window.yourApp);
Your controller should then look like this:
function($scope, $http, presenter) {
...
$http("api/data").success(function(data) {
$scope.dataSeries= data;
presenter.layout();
});
...
}
OK, with help from Darneas I came up with a solution.
I implemented this:
: Calling a function when ng-repeat has finished
I made sure that "widget-grid" wasn't initialized (I had some test widgets)
I called "setup_widgets_desktop()" from the ngRepeatFinished
This was succesfull. Thank you Darneas. I wouldn't had found a solution otherwise.
I couldn't get the widget directive to work, which looks like a great solution as well.

Categories

Resources