Display word count field beside the body - drupal

I want to limit the number of words a person can enter into a body of a content type.
And show the word count to the user.
What is the best way to do this.

The easiest solution would be to install this drupal module:
https://drupal.org/project/maxlength
If you are looking to do this manually you can try this solution:
Add this to your form field definition:
'#attributes' => array('onKeyPress' => "return textareaMaxLength(this, event, $sms_max_len);"),
Add a new JS file to your theme:
drupal_add_js(drupal_get_path('module', 'mymodule'). '/myfile.js');
Myfile.js:
function textareaMaxLength(field, evt, limit) {
var evt = (evt) ? evt : event;
var charCode =
(typeof evt.which != "undefined") ? evt.which :
((typeof evt.keyCode != "undefined") ? evt.keyCode : 0);
if (!(charCode >= 13 && charCode <= 126)) {
return true;
}
return (field.value.length < limit);
}
Credit for script/reference:
https://drupal.org/node/80122

Related

Vue.js - Update computed property after async computed property gets updated

I have a computed property (filteredSyms) that depends on the asynchronous computed property (allSynonyms). I am using async-computed plugin for this:
https://www.npmjs.com/package/vue-async-computed.
However, when the data gets updated the computed property doesn't wait until the result of the async property update. Therefore, I receive not up to date information. Then after the async property actually return new value computed property doesn't run update again.
How can I make it work the way that computer property waits until there is a result from the async computed property?
The code is below:
asyncComputed: {
async allSynonyms() {
let allSyns = await this.$axios.$post('/db/sym/synonyms', this.model.syms);
return allSyns;
}
},
computed: {
filteredSyms() {
let that = this;
let allSyn = this.allSynonyms;
let exactMatch = this.symsByRating.filter(
function (v) {
let isExactMatch = v.title.toLocaleLowerCase().indexOf(that.searchString.toLocaleLowerCase()) >= 0;
return !that.idsToFilter.includes(v.id) && isExactMatch
&& (!that.currentBodyPart || v.bodyParts.indexOf(that.currentBodyPart) >= 0)
&& that.hasMoreSubsyms(v)
&& (!allSyn || !that.containsObject(v, allSyn))
&& (v.sex == that.model.sex || v.sex == 'NA');
});
let partialList = [];
exactMatch.forEach(ex => partialList.push({n: 100, sym: ex}));
for (let sym of this.symsByRating ) {
let searchWords = this.searchString.toLocaleLowerCase().split(' ');
let symWords = sym.title.toLocaleLowerCase().split(' ');
let n = 0;
let isPartialMatch = false;
symLoop:for (let symWord of symWords) {
symWord = symWord.substring(0, symWord.length - 1);
for (let searchWord of searchWords) {
// don't count last letters of the words
searchWord = searchWord.substring(0, searchWord.length - 1);
if (searchWord.length > 2 && symWord.indexOf(searchWord) >= 0) {
n++;
isPartialMatch = true;
}
}
}
if (exactMatch.indexOf(sym) < 0 && isPartialMatch
&& (!this.currentBodyPart || sym.bodyParts.indexOf(this.currentBodyPart) >= 0)
&& this.hasMoreSubsyms(sym)
&& (!allSyn || !this.containsObject(sym, allSyn))
&& (sym.sex == that.model.sex || sym.sex == 'NA')) {
partialList.push({n: n, sym: sym});
}
}
partialList.sort(function(obj1, obj2) {
return obj2.n - obj1.n;
});
if (this.searchString && this.searchString != '') {
partialList = this.filterSynonyms(partialList);
}
let fs = partialList.map(ws => ws.sym);
console.dir(fs);
return fs;
}
}
A lot of stuff is going on the filtered method, but I guess the main point here that it is using this.allSynonyms to do the check but it is not updated at the time filteredSyms is executed.
Thanks for your suggestions!
(I haven't really tested this out, but it should work.)
vue-async-computed does provide the status in this.$asyncComputed.allSynonyms.success.
try adding this.$asyncComputed.allSynonyms.success as a dependencies to filteredSyms and it should update when success state change.

Select2 not working in Jquery-Steps wizard plugin

Please help with the script function on how to make select2 plugin work in wizard jquery template it is not firing and i'm using the search box, when it clicked it jams.Thank you
$('.class').select2(); AFTER $('#form').steps();
This has helped me thanks but..
$("#form").steps({
bodyTag: "fieldset",
onStepChanging: function (event, currentIndex, newIndex)
{
// Always allow going backward even if the current step contains invalid fields!
if (currentIndex > newIndex)
{
return true;
}
// Forbid suppressing "Warning" step if the user is to young
if (newIndex === 3 && Number($("#age").val()) < 18)
{
return false;
}
var form = $(this);
// Clean up if user went backward before
if (currentIndex < newIndex)
{
// To remove error styles
$(".body:eq(" + newIndex + ") label.error", form).remove();
$(".body:eq(" + newIndex + ") .error", form).removeClass("error");
}
// Disable validation on fields that are disabled or hidden.
form.validate().settings.ignore = ":disabled,:hidden";
// Start validation; Prevent going forward if false
return form.valid();
},
onStepChanged: function (event, currentIndex, priorIndex)
{
// Suppress (skip) "Warning" step if the user is old enough.
if (currentIndex === 2 && Number($("#age").val()) >= 18)
{
$(this).steps("next");
}
// Suppress (skip) "Warning" step if the user is old enough and wants to the previous step.
if (currentIndex === 2 && priorIndex === 3)
{
$(this).steps("previous");
}
},
onFinishing: function (event, currentIndex)
{
var form = $(this);
// Disable validation on fields that are disabled.
// At this point it's recommended to do an overall check (mean ignoring only disabled fields)
form.validate().settings.ignore = ":disabled";
// Start validation; Prevent form submission if false
return form.valid();
},
onFinished: function (event, currentIndex)
{
var form = $(this);
// Submit form input
form.submit();
}
}).validate({
errorPlacement: function (error, element)
{
element.before(error);
},
rules: {
confirm: {
equalTo: "#password"
}
}
});
//IMPORTANT
var form =$("#form");
form.find("#personel_id").select2({
theme: 'bootstrap4',
});

FirePad - delete all revisions which are a number of days older than a certain snapshot

This is continuing from an old thread here https://groups.google.com/forum/#!topic/firepad-io/73dKYaUwTn4)
The aim is to clean the database for documents which have many revisions over a long period
I need help writing a function that issue a FB command to delete all revisions which are 'nd' days older than the 'ns' snapshot.
I am not sure of both the Firebase syntax for this command and how to access the relevant firebase keys properly.
Any help will be greatly appreciated
Thx!
ended up solving this
PR: https://github.com/firebase/firepad/pull/264
code:
FirebaseAdapter.prototype.deleteOldRevisions_ = function(query) {
var self=this;
query.once('value', function(s) {
if (typeof s.val() === 'undefined' || s.val() === null || !s.hasChildren()) return;
s.forEach(function(rev) {
utils.log('removing old revision: '+rev.key);
rev.ref.remove();
});
setTimeout(function() { self.deleteOldRevisions_(query); }, 100); // delete the next one
});
}
FirebaseAdapter.prototype.monitorHistory_ = function() {
var self = this;
// Get the latest checkpoint as a starting point so we don't have to re-play entire history.
self.ref_.child('checkpoint').once('value', function(s) {
//utils.log(new Date().toISOString() + ': got checkpoint');
if (self.zombie_) { return; } // just in case we were cleaned up before we got the checkpoint data.
var revisionId = s.child('id').val(), op = s.child('o').val(), author = s.child('a').val();
if (op !== null && revisionId !== null && author !== null &&
op !== undefined && revisionId !== undefined && author !== undefined) {
self.pendingReceivedRevisions_[revisionId] = { o: op, a: author };
self.checkpointRevision_ = revisionFromId(revisionId);
self.monitorHistoryStartingAt_(self.checkpointRevision_ + 1);
} else {
self.checkpointRevision_ = 0;
self.monitorHistoryStartingAt_(self.checkpointRevision_);
}
// delete revisions older than one week before last checkpoint
if (revisionId) {
var historyRef=self.ref_.child('history');
historyRef.child(revisionId+'/t').once('value', function(s) {
if (typeof s.val() !== 'undefined' && s.val() !== null) {
var weekBefore=s.val()-(24*60*60*1000*7);
//utils.log('checkpoint revision: '+self.checkpointRevision_);
//utils.log('checkpoint time: ' + new Date(s.val()));
//utils.log('remove before: ' + new Date(weekBefore));
self.deleteOldRevisions_(historyRef.orderByChild('t').endAt(weekBefore));
}
});
}
});
};

Can I prevent events with conflict time?

How can I prevent events with conflict time? Is there any variable to set up?
No, there is not a variable to set, but you can use something like clientEvents which retrieves events that fullcalendar has in memory. You can use the function below in the eventDrop. In the case below it uses a function to filter out whether the event will have have an overlap or not.
function checkOverlap(event) {
var start = new Date(event.start);
var end = new Date(event.end);
var overlap = $('#calendar').fullCalendar('clientEvents', function(ev) {
if( ev == event)
return false;
var estart = new Date(ev.start);
var eend = new Date(ev.end);
return (Math.round(estart)/1000 < Math.round(end)/1000 && Math.round(eend) > Math.round(start));
});
if (overlap.length){
//either move this event to available timeslot or remove it
}
}
you can add eventOverlap : false in the celendar config,
http://fullcalendar.io/docs/event_ui/eventOverlap/
Correct overlap checking.
eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view) {
/// deny overlap of event
var start = new Date(event.start);
var end = new Date(event.end);
var overlap = $('#calendar').fullCalendar('clientEvents', function(ev) {
if( ev == event) {
return false;
}
var estart = new Date(ev.start);
var eend = new Date(ev.end);
return (
( Math.round(start) > Math.round(estart) && Math.round(start) < Math.round(eend) )
||
( Math.round(end) > Math.round(estart) && Math.round(end) < Math.round(eend) )
||
( Math.round(start) < Math.round(estart) && Math.round(end) > Math.round(eend) )
);
});
if (overlap.length){
revertFunc();
return false;
}
}
Add custom property in the event object overlap:false for example your event object will be
`{
title:'Event',
start: '2017-01-04T16:30:00',
end: '2017-01-04T16:40:00',
overlap:false
}`
Now override selectOverlap function,
selectOverlap: function(event) {
if(event.ranges && event.ranges.length >0) {
return (event.ranges.filter(function(range){
return (event.start.isBefore(range.end) &&
event.end.isAfter(range.start));
}).length)>0;
}
else {
return !!event && event.overlap;
}
},
It will not let the another event to override the already placed event.
This does the trick. It also handles resizing overlapping events
var calendar = new Calendar(calendarEl, {
selectOverlap: false,
eventOverlap: false
}
});

input text return event in Meteor

I want to capture the event of a user pressing enter on an input of type="text" when they are filling out a form. This is done all over the web, yet the answer eludes me.
This is what I have so far:
In the html file, I have a text input like so:
<input type="text" size=50 class="newlink">
In the Javascript file, I am trying to capture the the user pressing enter to effectively submit the form. I am then grabbing the text from the input and going to stash it in the database:
Template.newLink.events = {
'submit input.newLink': function () {
var url = template.find(".newLink").value;
// add to database
}
};
The submit event is emitted from forms, not single input elements.
The built in event map for meteor is documented here: http://docs.meteor.com/#eventmaps.
You'll have to listen for a keyboard event (keydown, keypress, keyup). Within the event handler, check, if it's the return/enter key (Keycode 13), and proceed on success.
Template.newLink.events = {
'keypress input.newLink': function (evt, template) {
if (evt.which === 13) {
var url = template.find(".newLink").value;
// add to database
}
}
};
You could look into how this is achieved in the todos example (client/todos.js).
It uses a generic event handler for input fields (as seen below). You can browse the rest of the code for usage.
////////// Helpers for in-place editing //////////
// Returns an event map that handles the "escape" and "return" keys and
// "blur" events on a text input (given by selector) and interprets them
// as "ok" or "cancel".
var okCancelEvents = function (selector, callbacks) {
var ok = callbacks.ok || function () {};
var cancel = callbacks.cancel || function () {};
var events = {};
events['keyup '+selector+', keydown '+selector+', focusout '+selector] =
function (evt) {
if (evt.type === "keydown" && evt.which === 27) {
// escape = cancel
cancel.call(this, evt);
} else if (evt.type === "keyup" && evt.which === 13 ||
evt.type === "focusout") {
// blur/return/enter = ok/submit if non-empty
var value = String(evt.target.value || "");
if (value)
ok.call(this, value, evt);
else
cancel.call(this, evt);
}
};
return events;
};
I used this js function once to suppress the user using the return key in the text field to submit the form data. Perhaps you could modify it to suit the capture?
function stopRKey(evt) { // Stop return key functioning in text field.
var evt = (evt) ? evt : ((event) ? event : null);
var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
if ((evt.keyCode == 13) && (node.type=="text")) { return false; }
}
document.onkeypress = stopRKey;
You can also use event.currentTarget.value
Template.newLink.events = {
'keypress input.newLink': function (evt) {
if (evt.which === 13) {
var url = event.currentTarget.value;
// add to database
}
}
};

Resources