I am using MVC extensions for Kendo UI editor. Is there an option to set the minimum and maximum number of characters excluding the HTML content.
I used StringLength attribute but that includes the HTML content.
You're right about Kendo Editor not having these options. It is possible to do this with some JavaScript and jQuery. This example is using Kendo Core (which the Kendo Wrappers like ASP.NET MVC should still work in ASP.NET MVC you do not call the $("#editor").kendoEditor() in the JavaScript).
Here's my jsFiddle example.
HTML:
<h3 class="text-primary">Text Only Count: <span id="textCount"></span></h3>
<div id="example">
<textarea id="editor" rows="10" cols="30" style="height:440px">
<p>Kendo UI Editor allows your users to edit HTML in a familiar, user-friendly way.
<br />In this version, the Editor provides the core HTML editing engine, which includes basic text formatting, hyperlinks, lists, and image handling. The widget <strong>outputs identical HTML</strong> across all major browsers, follows accessibility standards and provides API for content manipulation.</p>
<p>Features include:</p>
<ul>
<li>Text formatting & alignment</li>
<li>Bulleted and numbered lists</li>
<li>Hyperlink and image dialogs</li>
<li>Cross-browser support</li>
<li>Identical HTML output across browsers</li>
<li>Gracefully degrades to a <code>textarea</code> when JavaScript is turned off</li>
</ul>
</textarea>
</div>
CSS:
.warning { color: red; }
JavaScript:
$(function () {
$("#editor").kendoEditor();
var minChar = 100;
var maxChar = 600;
var iframe = $("iframe");
// Change event for iframe body content
iframe.contents().find("body").on('keydown', function (e) {
//Clean up
$("#textCount").removeClass("warning");
// Get Body (.text() strips out HTML tags)
var data = $(this).text();
if (this.which < 32) {
return; // Do nothing
}
var isEditKey = (e.keyCode == 8 || e.keyCode == 46);
if (data.length == maxChar && !isEditKey) {
e.preventDefault();
} else if (data.length > maxChar) {
// Maximum exceeded
$(this).text(data.substring(0, maxChar));
} else if (data.length < minChar) {
$("#textCount").addClass("warning");
}
$("#textCount").text(data.length);
});
// OnLoad call to get starting count
var data = iframe.contents().find("body").text();
$("#textCount").text(data.length);
});
Related
I have seen many discussions on how to display a PDF file within a embedded form ( User Task ) But realised camunda does not support this. Are there any solutions?
I have tried using IFrame, Object, embed , and directly linking to a variable did not work ?
My solution is to fetch the variable and convert to a blob as follows:
HTML
<embed class="col-sm-12" style="height:100vh;width:100%" type="application/pdf" id="pdf-frame">
JS
<script cam-script type="text/javascript">
camForm.on('form-loaded', function () {
fetch("http://localhost:8181/camunda/api/engine/engine/default/task/" + camForm.taskId + "/variables/ACORD_FORM/data").then(function (response) {
return response.blob();
}).then(function (myBlob) {
var objectURL = URL.createObjectURL(myBlob);
document.querySelector('#pdf-frame').src = '';
document.querySelector('#pdf-frame').src = objectURL;
objectURL = URL.revokeObjectURL(myBlob);
});
});
</script>
I'm currently working on a rendering in Sitecore 7.2 (MVC) that will show a jwPlayer given a link to a video (either in the Media Library or from an external source, like YouTube). When I add the rendering (with a valid data source) through Presentation Details in the Content Editor everything looks fine, and works perfectly. The trouble that I'm running into right now, though, is that when I try to do the same thing from the Page Editor (with the exact same rendering and data source), nothing is showing up in that placeholder at all.
The part of the rendering that deals with the video is as follows:
#if (Model.VideoLink != null && Model.Image != null)
{
var vidid = Guid.NewGuid().ToString();
<div class="article-video-module">
<p class="video-placeholder-text">#Html.Raw(Model.Heading)</p>
<div id="#vidid">Loading the player...</div>
<script type="text/javascript">
jwplayer("#vidid").setup({
file: "#Model.VideoLink.Url",
image: "#Model.Image.Src",
width: "100%",
aspectratio: "16:9",
sharing: {
link: "#Model.VideoLink.Url"
},
primary: 'flash'
});
jwplayer('videodiv-#vidid').onPlay(function () {
$(this.container).closest('.fullbleed-video-module').find('.video-placeholder-text').hide();
});
jwplayer('videodiv-#vidid').onPause(function () {
$(this.container).closest('.fullbleed-video-module').find('.video-placeholder-text').show();
});
</script>
</div>
#Editable(a => Model.Description)
}
Other things that might help:
When I comment out everything in the <script> tag above the rendering shows up perfectly.
A reference to jwplayer.js is found on the page (that was my first thought)
Console errors in Javascript:
No suitable players found and fallback enabled on jwplayer.js
Uncaught TypeError: undefined is not a function on jwplayer("#vidid").setup({ and on jwplayer('videodiv-#vidid').onPlay(function () { from above.
How can I get jwPlayer and Page Editor to work nicely with each other?
The issue is that when you add a component through Page Editor, the script is fired before the div <div id="#vidid"> element is added to DOM. Don't ask me why...
The solution is really simple: wrap your javascript code with if condition, checking if the div is already there:
<script type="text/javascript">
if (document.getElementById("#vidid")) {
jwplayer("#vidid").setup({
file: "#Model.VideoLink.Url",
image: "#Model.Image.Src",
width: "100%",
aspectratio: "16:9",
sharing: {
link: "#Model.VideoLink.Url"
},
primary: 'flash'
});
jwplayer('videodiv-#vidid').onPlay(function () {
$(this.container).closest('.fullbleed-video-module').find('.video-placeholder-text').hide();
});
jwplayer('videodiv-#vidid').onPause(function () {
$(this.container).closest('.fullbleed-video-module').find('.video-placeholder-text').show();
});
}
</script>
There is also another issue with your code - Guid can start with number, and this is not a valid id for html elements. You should change your code to:
var vidid = "jwp-" + Guid.NewGuid().ToString();
I wouldn't rule out a conflict with the version of JQuery that the Page Editor uses - this usually messes stuff up. There's a good post here on to overcome the issues.
http://jrodsmitty.github.io/blog/2014/11/12/resolving-jquery-conflicts-in-page-editor/
I am trying to integrate zurb reveal with form into react component. So far next code properly displays modal form:
ModalForm = React.createClass({
handleSubmit: function(attrs) {
this.props.onSubmit(attrs);
return false;
},
render: function(){
return(
<div>
Add new
<div id="formModal" className="reveal-modal" data-reveal>
<h4>Add something new</h4>
<Form onSubmit={this.handleSubmit} />
<a className="close-reveal-modal">×</a>
</div>
</div>
);
}
});
The Form component is pretty standard:
Form = React.createClass({
handleSubmit: function() {
var body = this.refs.body.getDOMNode().value.trim();
if (!body) {
return false;
}
this.props.onSubmit({body: body});
this.refs.body.getDOMNode().value = '';
return false;
},
render: function(){
return(
<form onSubmit={this.handleSubmit}>
<textarea name="body" placeholder="Say something..." ref="body" />
<input type="submit" value="Send" className="button" />
</form>
);
}
});
Problem: When I render form component within modal form component and enter something into form input then I see in console exception Uncaught object. This is a stack:
Uncaught object
invariant
ReactMount.findComponentRoot
ReactMount.findReactNodeByID
getNode
...
If I just render form component directly in the parent component then everything works. Could anybody help please?
In short, you're doing this wrong and this is not a bug in react.
If you use any kind of plugin that modifies the react component's dom nodes then it's going to break things in one way or another.
What you should be doing instead is using react itself, and complementary css, to position the component in the way you'd like for your modal dialog.
I would suggest creating a component that uses react's statics component property to define a couple of functions wrapping renderComponent to give you a nice clean function call to show or hide a react dialog. Here's a cut down example of something I've used in the past. NB: It does use jQuery but you could replace the jQ with standard js api calls to things like elementById and etc if you don't want the jQuery code.
window.MyDialog = React.createClass({
propTypes: {
title: React.PropTypes.string.isRequired,
content: React.PropTypes.string.isRequired
},
statics: {
// open a dialog with props object as props
open: function(props) {
var $anchor = $('#dialog-anchor');
if (!$anchor.length) {
$anchor = $('<div></div>')
.prop('id', 'dialog-anchor');
.appendTo('body');
}
return React.renderComponent(
MyDialog(props),
$anchor.get(0)
);
},
// close a dialog
close: function() {
React.unmountComponentAtNode($('#dialog-anchor').get(0));
}
},
// when dialog opens, add a keyup event handler to body
componentDidMount: function() {
$('body').on('keyup.myDialog', this.globalKeyupHandler);
},
// when dialog closes, clean up the bound keyup event handler on body
componentWillUnmount: function() {
$('body').off('keyup.myDialog');
},
// handles keyup events on body
globalKeyupHandler: function(e) {
if (e.keyCode == 27) { // ESC key
// close the dialog
this.statics.close();
}
},
// Extremely basic dialog dom layout - use your own
render: function() {
<div className="dialog">
<div className="title-bar">
<div className="title">{this.props.title}</div>
<a href="#" className="close" onClick={this.closeHandler}>
</div>
</div>
<div className="content">
{this.props.content}
</div>
</div>
}
});
You then open a dialog by calling:
MyDialog.open({title: 'Dialog Title', content: 'My dialog content'});
And close it with
MyDialog.close()
The dialog always attaches to a new dom node directly under body with id 'dialog-anchor'. If you open a dialog when one is already open, it will simply update the dom based on new props (or not if they're the same).
Of course passing the content of the dialog as a props argument isn't particularly useful. I usually extend below to either parse markdown -> html for the content or get some html via an ajax request inside the component when supplying a url as a prop instead.
I know the above code isn't exactly what you were looking for but I don't think there's a good way to make a dom-modifying plugin work with react. You can never assume that the dom representation of the react component is static and therefore it can't be manipulated by a 3rd party plugin successfully. I honestly think if you want to use react in this way you should re-evaluate why you're using the framework.
That said, I think the code above is a great starting point for a dialog in which all manipulation occurs inside the component, which afterall is what reactjs is all about!
NB: code was written very quickly from memory and not actually tested in it's current form so sorry if there are some minor syntax errors or something.
Here is how to do what Mike did, but using a zf reveal modal:
var Dialog = React.createClass({
statics: {
open: function(){
this.$dialog = $('#my-dialog');
if (!this.$dialog.length) {
this.$dialog = $('<div id="my-dialog" class="reveal-modal" data-reveal role="dialog"></div>')
.appendTo('body');
}
this.$dialog.foundation('reveal', 'open');
return React.render(
<Dialog close={this.close.bind(this)}/>,
this.$dialog[0]
);
},
close: function(){
if(!this.$dialog || !this.$dialog.length) {
return;
}
React.unmountComponentAtNode(this.$dialog[0]);
this.$dialog.foundation('reveal', 'close');
},
},
render : function() {
return (
<div>
<h1>This gets rendered into the modal</h1>
<a href="#" className="button" onClick={this.props.close}>Close</a>
</div>
);
}
});
I have a functioning Knockout template for some pagination UI that works with a Knockout-based shared data grid. This template renders an HREF for each "page" of data in the grid.
The template works but it's klunky because if I fetch a lot of data, then I end up with dozens and dozens of navigation page links below the grid. Here's the current template:
<div class="idTemplate_ko_simpleGrid_pageLinks">
<p>
<span>Go to page:</span>
<!-- ko foreach: ko.utils.range(0, maxPageIndex) -->
<a href="javascript:void(0);"
class="grid-pagination"
data-bind="text: $data + 1, click: function() { $root.currentPageIndex($data) }, css: { selected: $data == $root.currentPageIndex() }"></a>
<!-- /ko -->
</p>
</div>
The 'currentPageIndex' value is just a simple ko observable in the model:
this.currentPageIndex = ko.observable(0);
And 'maxPageIndex' is a computed observable in the model:
this.maxPageIndex = ko.computed(function () {
return Math.ceil(ko.utils.unwrapObservable(this.filteredItems()).length / this.pageSize()) - 1;
}, this);
How can I modify the template and model to enable paging UI similar to StackOverflow?
For example:
prev 1 ... 3 4 5 6 7 ... 69 next
This is exactly the pager style I have been using for a while now.
I just finished extracting the pager functionality I used on several projects, into an extension to knockout and template by example.
See https://github.com/remcoros/ko.pager for the source and http://remcoros.github.com/ko.pager/example.html for a working example.
All computations and some convenient properties are provided by the 'Pager' class, which you can create and bind to. But an example working template is included.
See the source example.html for usage.
First thing I would do is look if there are any custom bindings or libraries out there that do this. If there are, create a custom binding that uses that library.
Back up plan - make your own custom binding.
I'd make something like:
<div data-bind="pagination: { maxIndex: maxPageIndex(), numToShow: 7 }">
...
</div>
Then in my custom binding, do something like this:
ko.bindingHandlers.pagination = {
update: function(element, valueAccessor) {
if (valueAccessor().maxPageIndex > valueAccessor().numToShow) {
// use jquery to loop and append new $("<a>") tags to $(element), using "1", then ... and a segment in the middle, followed by ... and the last index.
}
else {
// loop over the regular amount.
}
}
};
Im so nice so I made one for you in exactly two minutes :P (So it probably has bugs)
Its based on the first pager i found which was jQuery pagination
http://jsfiddle.net/tymTz/2/
I am using Apex 4.0.2. My goal is to have my success message flash at the top after I succesfully fill out a form. I have a javascript function:
<script type="text/javascript">
{var i = 1,timer;
window.onload=function() {
timer = setInterval('flash()', 500);
}
function flash() {
if (i<10000) {
if (i%2 == 0) {
document.getElementById('flash').style.backgroundColor = '#ffffff';
} else {
document.getElementById('flash').style.backgroundColor = '#ffff00';
}
} else {
document.getElementById('flash').style.backgroundColor = '#ffffff';
clearInterval(timer);
}
i++;
}
</script>
I placed this code originally on the javascript tab of the page that the form branches to. Later I moved it to the process success message along with the call to the function
<center>
<table id="flash" BORDER=0 >
<tr>
<td>Success!</td>
</tr>
</table>
</center>
I receive an error from the page on Firebug:
document.getElementById("flash") is null
document.getElementById('flash').style.backgroundColor = '#ffff00';
Internet Explorer tells me :
Message: Object required
I think my problem is that the success message region object does not always exist. Is there any way to execute the function only when I make that call to display the success message?
In advance,
Thanks so much for your help!
The javascript region has its uses, but i'd recommend using dynamic actions since they provide a much clearer overview of what takes place on your page.
Edit your page header (page, edit), or add to your css:
<style>
.flash1{
background-color: blue;
}
.flash2{
background-color: yellow;
}
</style>
Create a new dynamic action:
Event: Page Load, Condition: none
As true action, select 'Execute Javascript Code' as action.
Use jQuery to fetch objects and toggle between classes. It's cleaner
since you don't mix in css/style in javascript.
var $smsg = $(".uMessageText"), flash;
$smsg.addClass('flash1');
if($smsg.length){
flash = setInterval(function(){
$smsg.toggleClass('flash1');
$smsg.toggleClass('flash2');
}, 1000);
setTimeout(function(){
clearInterval(flash);
}, 10001);
};
This will change the class on the success message each second for 10
seconds. The interval is cleared after those 10 seconds. No
interval will be started if the success message has not been found
since the jQuery object will be empty (length=0).
var $smsg = $(".uMessageText")
This is the selector for your success message element, and this
example is the selector for that element in Theme 23. Be aware that
the success message id or class depends on your chosen theme and
page template, and you'll most likely need to change it. Of
course, the selector can be any element you'd like.
If you're not familiar with jQuery, i'd advise you to take a look at it. It is included in apex by default (and apex relies on it), and is a very powerful tool when javascripting. http://jquery.com/
In short though: select element by id: $("#id_attribute_here"), select by class $(".class_name_here")