Have a custom img blot with addEventListener. Event triggered when using insertEmbed, but it does not work when img loaded from existing html - addeventlistener

I'm using react-native-cn-quill but this is really a Quilljs question. Thanks for your help.
In the code below, clickHandler is called on click when I do a "insertEmbed(index, 'pbThumbnail', obj)", but when I load the webView with initialHtml containing:
<span class="pb-Thumbnail">
<img class="pbVidThumb" ....>
</span>
the eventListener does not appear to be added to the blot/tag. Should the eventListener be automatically applied OR do I have to manually re-add to all the relevant tags?
Thanks for your help!
This is the custom blot, whose eventListener works when using insertEmbed:
const Block = Quill.import('blots/block');
class ThumbnailBlot extends Block {
constructor(domNode) {
super(domNode);
// Bind our click handler to the class.
this.clickHandler = this.clickHandler.bind(this);
domNode.addEventListener('click', this.clickHandler);
}
clickHandler(event) {
alert("ClickableSpan was clicked. Blot: ", this);
}
static create(value) {
let node = super.create();
node.setAttribute('contenteditable', false);
let image = document.createElement('img');
image.setAttribute('class', 'pbVidThumb');
image.setAttribute('contenteditable', false);
image.setAttribute('src', value.imgBase64);
image.setAttribute('height', value.height);
image.setAttribute('width', value.width);
image.setAttribute('id', value.imgName);
node.appendChild(image);
return node;
}
static value(node) {
return { src: node.getAttribute('src'), title: node.getAttribute('title'), height: node.getAttribute('height'), width: node.getAttribute('width'), id: node.getAttribute('id')}
}
static deleteAt(node) { return false; }
static formats(node) {
return node.getAttribute('title');
}
}
ThumbnailBlot.blotName = 'pbThumbnail';
ThumbnailBlot.tagName = 'span';
ThumbnailBlot.className = 'pb-thumbnail';
Quill.register(ThumbnailBlot);
Loading the below HTML into a webview with quill does not apply the click eventListener:
<span class="pb-thumbnail" contenteditable="false" title="IMG_0002.JPG">
<img contenteditable="false"
src="https://....uploads%2F2h06dnjjxoa8l21i5m51c-Bump-bump-imageimage.jpg"
height="auto"
width="100%"
class="pbVidThumb"
id="IMG_0002.JPG" >
</span>
Doing more debugging, I also noticed that the raw HTML that is loaded into the Quill editor gets reduced:
<div id="editor-container">
<h1>Pipi</h1>
<p><br></p>
<p><br></p>
<p><strong>I am grateful for...</strong></p>
<p><br></p>
<p><br></p>
<p><br></p>
<span class="pb-thumbnail"
contenteditable="false"
title="IMG_0002.JPG">
<img contenteditable="false"
src="https://uploads%2F656jhlsiw6xrc07t8i70g-Bump-bump-imageimage.jpg"
height="auto"
width="100%"
class="pbVidThumb"
imglocalpath="405B8B56-5718-421E-81EE-BBB7895D64BD.jpg"
vidlocalpath="EMPTY-1f051ea8-8c5d-4a9d-b8b1-597c0d2edfa4"
id="IMG_0002.JPG"
data-name="IMG_0002.JPG"
data-long-press-delay="250">
</span>
<p><br></p>
</div>
When I use codePen playground, and with the above html code in the editor, and I do: console.log(document.getElementById("editor-container")); what I see is:
<div id="editor-container" class="ql-container ql-snow">
<div class="ql-editor" data-gramm="false" contenteditable="true" data-placeholder="Compose an epic..."›
<h1>Pipi</h1>
<p><br></p>
<p><br></p>
<p> <strong>I am grateful for...</strong></p>
<p><br></p>
<p><br></p>
<p><br></p>
<p><br></p>
<p><img src="https://uploads%2F656jhlsiv6xrc07t8170g-Bump-bump-imageimage.jpg"
height="auto"
width="1009"></p>
</div>
<div class="ql-clipboard" contenteditable="true" tabindex="-1"></div><div class="ql-tooltip ql-hidden"><a class="ql-preview" target="_blank" href="about:blank"></a><input type="text" data-formula="e=mc^2" data-link="https://quilljs.com" data-video="Embed URL"><a class="ql-action"></a><a class="ql-remove"></a></div></div>
All the class tags I used are gone along with many attributes. Why is that?

Related

I want to use Url.Action with Knockout

I am new to knockout and I am having trouble getting the syntax right when using it with MVC markup.
For example this code here;
<a href="text.Answer" target="_blank">
<span style="display:inline-block">
<img src="#Url.Action("GetPhotoThumbnail", new { path = text.Answer, width = 120, height = 80 })" alt="Property Image" style="margin-top: 5px;" />
</span>
</a>
EDIT
So "Answer" is in the ViewModel and in knockout you would type data-bind="text:Answer" but here I have put in 2 places text.Answer. How do I replace text.Answer in the above code with the correct Knockout markup?
I know the above code will not work but this is a simplified way of showing the problem. I want to data-bind to text.Answer. What is the correct syntax for doing that?
If I understood you correctly that your text.Answer is something bind in client side.
You can't mix #Url.Action with client side variables
Try creating your URL like this
"#Url.Action("GetPhotoThumbnail")?path="+variable1+"&width="+variable2+"&height=" +variable3
You could pass the values you need into the ViewModel.
<div id="test">
<a href="#" data-bind="attr: { href: href }" target="_blank">
<span style="display:inline-block">
<img src="" data-bind="attr: { src: imageUrl }" alt="Property Image" style="margin-top: 5px;" />
</span>
</a>
</div>
<script type="text/javascript">
function MyViewModel(defaultValues) {
this.href = defaultValues.href;
this.imageUrl = defaltValues.imageUrl
}
var viewModel = new MyViewModel({
imageUrl: '#Url.Action("GetPhotoThumbnail", new { path = text.Answer, width = 120, height = 80 })',
href: '#Url.Action("Test")'
});
ko.applyBindings(viewModel, document.getElementById('test'));
</script>
I'm guessing you've got a view model binded to this part of the DOM, so you should be able to use the data-bind attribute and the attr binding to achieve the following:
<a href="" data-bind="attr : { href: text.Answer } " target="_blank">
<span style="display:inline-block">
<img src="#Url.Action("GetPhotoThumbnail", new { path = text.Answer, width = 120, height = 80 })" alt="Property Image" style="margin-top: 5px;" />
</span>
</a>
See http://knockoutjs.com/documentation/attr-binding.html for more details on this binding.
Also you'll need to make the view model generate you the img[src] attribute value so try something like:
<img data-bind="attr:{ src: text.answerImgSrc() } " alt="Property Image" style="margin-top: 5px;" />

Foreach not updating HTML list elements

Using knockout 2.2.0
I'm trying to use the same dialog for add and edit. I have the code mostly working, but when I replace the observable with the new edited one, it doesn't cause an update in the foreach (or at least it continues to display the old values) It does update the actual model, as I can see in dev tools. I even tried to force an update with .valueHasMutated(), but with no luck.
self.editReference = function () {
self.isEdit(true);
self.open();
self.dialogReferences(this);
};
self.saveEditReference = function () {
self.references.replace(this, self.dialogReferences);
self.references.valueHasMutated();
self.dialogReferences(newReferences());
self.close();
};
And here is the some of the partial view with the references section of HTML code:
<ul class="sortable references-summary" data-bind="foreach: references">
<li class="ui-state-default"><b>Name: </b><!-- ko text:name --><!-- /ko--><br /><b>Company: </b><!-- ko text:company --><!-- /ko--><span class="ui-icon ui-icon-closethick"></span><span class="ui-icon ui-icon-wrench"></span></li>
</ul>
Thanks to CrimsonChris for pointing out my bug. The updated code below works as expected.
The approach is to have a reference you are editing, in addition to the references in your array. When you start to edit, you copy the values from the array to your edit reference. When you save the edit, you copy them back. There is no need for valueHasMutated for this to work.
function reference(name, company) {
return {
name: ko.observable(name),
company: ko.observable(company)
};
}
// Copy r1 into r2
reference.copy = function(r1, r2) {
r2.name(r1.name());
r2.company(r1.company());
}
var self = {
editingReference: undefined,
dialogReferences: reference('', ''),
references: ko.observableArray([
reference('One', 'First Company'),
reference('Two', '2nd Company')
]),
dialogIsOpen: ko.observable(false),
open: function() {
self.dialogIsOpen(true);
},
close: function() {
self.dialogIsOpen(false);
}
};
self.editReference = function(item) {
self.editingReference = item;
self.open();
reference.copy(item, self.dialogReferences);
};
self.removeReference = function(item) {
self.references.remove(item);
self.close();
};
self.saveEditReference = function(item) {
reference.copy(item, self.editingReference);
self.close();
};
ko.applyBindings(self);
<link href="//code.jquery.com/ui/1.11.3/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.0/knockout-min.js"></script>
<ul class="sortable references-summary" data-bind="foreach: references">
<li class="ui-state-default"> <b>Name: </b>
<!-- ko text:name() -->
<!-- /ko-->
<br /> <b>Company: </b>
<!-- ko text:company() -->
<!-- /ko--> <span class="ui-icon ui-icon-closethick"></span>
<span class="ui-icon ui-icon-wrench"></span>
</li>
</ul>
<div data-bind="if: dialogIsOpen">
<div data-bind="with:dialogReferences">
<label>Name</label>
<input data-bind="value:name" />
<br/>
<label>Company</label>
<input data-bind="value:company" />
<input type="button" value="Save" data-bind="click: $parent.saveEditReference" />
</div>
</div>

Refreshing captcha reloads the whole page

I'm new to JSON and jqueries.
I created a captcha as below in cshtml file
<div class="row-fluid">
<div class="span3"></div>
<iframe id="CaptchaIfram" src="#Url.Action("ShowCaptchaImage")" scrolling="no"></iframe>
<div>
<div class="span3"></div>
<input id="RefreshCaptcha" type="submit" onclick="captcha()" value="Refresh" class="btn btn-success" />
</div>
</div>
<script type="text/javascript">
function captcha()
{
document.getElementById("CaptchaIfram").contentDocument.location.reload(true);
}
</script>
in Controller:
public Captcha ShowCaptchaImage(int width, int height, int totalcharacters)
{
return new Captcha(width, height, totalcharacters);
}
Its working fine and if I click on refresh button, whole page getting refreshed as I'm using Url.Action method.
To avoid this, I used JSON as below. But image is not getting displayed.
Can anybody let me know where I need to correct.
<div class="row-fluid">
<div class="span3"></div>
<iframe id="CaptchaIfram" onload="showCaptcha()" scrolling="no"></iframe>
<div>
<div class="span3"></div>
<input id="RefreshCaptcha" type="submit" value="Refresh" onclick="showCaptcha()" class="btn btn-success" />
</div>
</div>
<script type="text/javascript">
function showCaptcha()
{
var url = "/ESignature/ShowCaptchaImage";
var target = '#CaptchaIfram';
$.getJSON(url, { width: 200, height: 35, totalcharacters: 5 }, function (data) {
document.getElementById("CaptchaIfram").src = data;
});
}
</script>
public JsonResult ShowCaptchaImage(int width, int height, int totalcharacters)
{
return Json(new Captcha(width, height, totalcharacters), JsonRequestBehavior.AllowGet);
}
I changed the type of refresh button to client side button as below. It didn't refresh the whole page.
No Json functions are required. (second code block in my question)

Change position of input filed for jQuery Mobile Filter List

Im using the jQuery Mobile Filter List:
http://jquerymobile.com/test/docs/lists/lists-search-with-dividers.html
Is it possible to move the position of the input field so I can put it into a div already on my page?
Using jQuery's appendTo seems to work fine but its kind of a hacky solution. Thanks
this is what I found while searching for solution to a similar problem.
HTML code example:
<div data-role="page" id="page-id">
<div data-role="content">
<div data-role="fieldcontain">
<input type="search" name="password" id="search" value="" />
</div>
<div class="filter-div" data-filter="one">1</div>
<div class="filter-div" data-filter="two">2</div>
<div class="filter-div" data-filter="three">3</div>
<div class="filter-div" data-filter="four">4</div>
<div class="filter-div" data-filter="five">5</div>
</div>
</div>
JS code example:
$(document).delegate('#page-id', 'pageinit', function () {
var $filterDivs = $('.filter-div');
$('#search').bind('keyup change', function () {
if (this.value == '') {
$filterDivs.slideDown(500);
} else {
var regxp = new RegExp(this.value),
$show = $filterDivs.filter(function () {
return ($(this).attr('data-filter').search(regxp) > -1);
});
$filterDivs.not($show).slideUp(500);
$show.slideDown(500);
}
});
});
This way you can place your input text box anywhere on your page and it should properly filter a list of items you want.
JSFiddle DEMO: http://jsfiddle.net/cZW5r/30/

Dynamiaclly append to grid row

Im trying to modify grid layout so that if the user clicks a grid row, another grid row is appended to the selected grid row and displays extra information about the selected grid. Is this possbible using jQuery mobile ?
<div class="ui-grid-a">
<div class="ui-block-a"><div class="ui-bar ui-bar-b" style="height:20px">A</div>
</div>
It's not fully functional but I hope this give you an idea, Live Example: http://jsfiddle.net/F6Zdp/44/
HTML:
<div data-role="page" id="gridplus">
<div data-role="content">
<div class="ui-grid-a" id="currentgrid">
<div class="ui-block-a"><div class="ui-bar ui-bar-e" style="height:50px">I'm a Block and text inside will wrap.</div></div>
<div class="ui-block-b"><div class="ui-bar ui-bar-e" style="height:50px">I'm a Block and text inside will wrap.</div></div>
</div>
<br />
<input type="button" id="addcolumn" name="addcolumn" value="Add Column"/>
<input type="button" id="removecolumn" name="removecolumn" value="Remove Column"/>
</div>
</div>
JS:
var currentGrid = $('#currentgrid');
var previousGrid;
$('#addcolumn').click(function() {
grid = currentGrid.attr('class');
previousGrid = grid;
nextGrid = grid.substring(0,grid.length-1)+String.fromCharCode(grid.charCodeAt(grid.length-1)+1);
$('#currentgrid').removeClass(grid).addClass(nextGrid);
$("#currentgrid").children().each(function() {
c = $(this);
block = c.attr('class');
nextBlock = block.substring(0,block.length-1)+String.fromCharCode(block.charCodeAt(block.length-1)+1);
if($('.'+nextBlock).length) {
doNothing = true;
} else {
c.after('<div class="'+nextBlock+'"><div class="ui-bar ui-bar-e" style="height:50px">I\'m a Block and text inside will wrap.</div></div>');
}
});
});
$('#removecolumn').click(function() {
grid = currentGrid.attr('class');
$('#currentgrid').removeClass(grid).addClass(previousGrid);
$("#currentgrid").children().last().remove();
}).page();
Use collapsable content - http://jquerymobile.com/demos/1.0a4.1/docs/content/content-collapsible.html
The content can be a jQuery grid I think.

Resources