jQuery Datepicker, select multiple dates and mark them via css at selection time, permanently - jquery-ui

so I have spent a day developing and reading (teh other way around) to enable my jQuery datepicker to select and highlight mutliple dates.
For this I have managed to write the selected dates to an array which is visualized in a simple textfield.
What I could not manage is to permanently modify the look of the selected date in the datepicker.
I have implemented the "beforeShowDay:" option, which is working properly uppon loading the datepicker, but of course is not called directly on selecting a date.
For this I guessed, I would need to refresh the view "onSelect", but the refresh is not working properly.
Right now, I have some small methods for handling the datearray.
Uppon adding or removing a date, I am trying to refresh the datepicker.
Uppon selecting a date, I am either adding it to, or remove it from the dates-array.
Also, onSelect, I am matching the selected day and try to addClass().
But once again, I think I missed something all the way round, as it is not shown in my datepicker.
Here's my code for now:
var dates = new Array();
function addDate(date) {
if (jQuery.inArray(date, dates) < 0 && date) {
dates.push(date);
}
}
function removeDate(index) {
dates.splice(index, 1);
}
// Adds a date if we don't have it yet, else remove it and update the dates
// textfield
function addOrRemoveDate(date) {
var index = jQuery.inArray(date, dates);
if (index >= 0) {
removeDate(index);
updateDatesField(dates);
} else {
addDate(date);
updateDatesField(dates);
}
jQuery(calContainer).datepicker("refresh");
}
var calContainer = document.getElementById("calendar-container");
jQuery(calContainer).datepicker({
minDate : new Date(),
dateFormat : "#",
onSelect : function(dateText, inst) {
addOrRemoveDate(dateText);
jQuery(".ui-datepicker-calendar tbody tr td a").each(function() {
if (jQuery(this).text() == inst.selectedDay) {
jQuery(this).addClass("ui-state-highlight");
jQuery(this).parent().addClass("selected");
}
});
// addTimeSelectorColumns(dates);
},
beforeShowDay : function(_date) {
var gotDate = -1;
for ( var index = 0; index < dates.length; index++) {
if (_date.getTime() == dates[index]) {
gotDate = 1;
} else {
gotDate = -1;
}
}
if (gotDate >= 0) {
return [ true, "ui-datepicker-today", "Event Name" ];
}
return [ true, "" ];
}
});
function updateDatesField(dates) {
if (dates.length > 0) {
var tmpDatesStrArr = new Array();
var dateString = "";
var datesField = document.getElementById("dates");
for ( var index = 0; index < dates.length; index++) {
var dateNum = dates[index];
var tmpDate = new Date();
tmpDate.setTime(dateNum);
dateString = tmpDate.getDate() + "." + tmpDate.getMonth() + "."
+ tmpDate.getFullYear();
tmpDatesStrArr.push(dateString);
}
jQuery(datesField).val(tmpDatesStrArr);
}
}
(I am still a beginner in Javascript/jQuery, so any help or hints towards my coding are welcome, btw...)

It depends whether you want to stick with jQuery UI or not. If you are open to other library, there is a jQuery Datepicker that supports multiple selection: jquery.datePicker with multiple select enabled. It may save you sometmie fiddling with jQuery UI's one, as it does not natively support multiple selection.
EDIT:
If your main library is not jQuery, I think you should look for a standalone or Prototype-dependent library instead. The JS Calendar looks promising. It natively supports multiple selection by detecting the Ctrl key.

Related

Turbotable : p-tableHeaderCheckbox selects disabled lines

I am facing a problem on PrimeNG TurboTable.
I started from the following example: https://www.primefaces.org/primeng/#/table/selection and more particularly from the Checkbox Selection example.
The only difference is that on some p-tableCheckbox I added a [disabled]="true"
This works very well if I select a disabled line it does not activate and can not be selected, but when I click on p-tableHeaderCheckbox all the lines are selected even the lines in disabled.
In addition, the selection also counts the lines in status disabled or it should only take lines with no status disabled
I made an example on stackblitz : https://stackblitz.com/edit/angular-gnbsml?file=src%2Fapp%2Fapp.component.html
How to prevent tableHeaderCheckbox from also selecting disable lines?
Thank you in advance for your answers
You can prevent selection in (selectionChange) callback on table. Split [(selection)] on two part:
[selection]="selectedRowData" (selectionChange)="onSelectionChange($event)"
Add onSelectionChange method to component:
onSelectionChange(selection: any[]) {
for (let i = selection.length - 1; i >= 0; i--) {
let data = selection[i];
if (this.isRowDisabled(data)) {
selection.splice(i, 1);
}
}
this.selectedRowData = selection;
}
Also add isRowDisabled method:
isRowDisabled(data: any): boolean {
return data.color === 'orange'
}
and change template for tableCheckbox to use isRowDisabled (it's only for check in one place)
<p-tableCheckbox [value]="rowData" [disabled]="isRowDisabled(rowData)"></p-tableCheckbox>
See example on https://stackblitz.com/edit/angular-hnzxs2 (I am also add logic to exclude disabled rows from process of calculating state of headerCheckBox)
It's failing when we have only disabled rows after filter. I have fixed it by checking active rows.
ngAfterViewInit(): void {
const orig_updateCheckedState = this._headerCheckBox.updateCheckedState;
const me = this;
this._headerCheckBox.updateCheckedState = function() {
const cars: any[] = me._table.filteredValue || me._table.value;
const selection: any[] = me._table.selection;
let actRows: boolean = false;
for (const car of cars) {
if (!me.isRowDisabled(car)) {
actRows = true;
const selected = selection && selection.indexOf(car) >= 0;
if (!selected) return false;
}
}
if (actRows) {
return true
} else {
return false;
}
};
}

Prevent the creation of events with conflicting times with FullCalendar

I'm trying to disable dayclick from functioning when there is already an event at the time. Is this possible? I've seen functions that stop people dragging one event to a conflicting time, but nothing that acts before creation.
Thanks
I've sorted it with click events function
function checkOverlap(event) {
var start = new Date(event);
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) == Math.round(start));
});
if (overlap.length){
return false;
} else {
return true;
}
}
This is mostly possible because my app only allows users to make appointments for 1 hour and always on the hour. If you have a more flexible model where you can have variable length and starting time of the appointments, you will have to fiddle with the following line:
return (Math.round(estart) == Math.round(start));

AngularJS: Using If condition in text input

I have an input type as text to select dates and I want that Its default value should be the earliest amongst the JSON data having following structure:
testData=
{
"name":"ABC", transactions:[
{"tranid":01,"trandate":"01/02/2010"},
{"tranid":02,"trandate":"01/02/2012"}
]
}
I want to iterate through transactions and Dispay the earliest date in the text input(i.e 01/02/2010)
Please assist how to do it in angular.
Hi please see here: http://jsbin.com/reyog/1/edit
function finderliest()
{
angular.forEach(testData.transactions, function(transaction){
if($scope.erliest === undefined || transaction.trandate < $scope.erliest ){
$scope.erliest = transaction.trandate;
}
});
};
var len=testData.transactions.trandate.length;
if(len>0)
{
for (i=0;i<len;i++)
{
for (j=1;j<len;j++)
{
var dateone=testData.transactions.trandate[i];
var datetwo=testData.transactions.trandate[j];
//(use this logic or else logic whichever you like) http://www.c-sharpcorner.com/UploadFile/8911c4/how-to-compare-two-dates-using-javascript/
}
}
}

UIACollectionView cells vs visibleCells

I'm trying to write a test script using automation in xcode 4.5.
I have a UICollectionView and I want to click on some cell not currently visible.
Per documentation, I should expect cells to return all cells in the collection view, and visibleCells to return only the currently visible ones.
Instead what I'm seeing is that cells returns only the currently visible cells, and calling visibleCells stops the script on 'undefined' is not a function (evaluating 'collection.visibleCells()')
var target = UIATarget.localTarget();
var collection = target.frontMostApp().mainWindow().collectionViews()[0];
UIALogger.logMessage("Looking in collection: " + collection);
UIALogger.logMessage("Cells: " + collection.cells() + " length " + collection.cells().length);
UIALogger.logMessage("Visible cells: " + collection.visibleCells());
The code above returns the right UICollectionView, second log line prints:
Cells: [object UIAElementArray] length 12
although I have 100 items in the collection view, and third log line crashes script.
Is this a documentation/UIACollectionView bug?
Any ideas how can I tell the automation to scroll until it sees a cell with the name "My cell"?
I've tried using someCell.scrollToVisible, but I need to have the cell to do that, and I don't since I can't get it from cells.
EDIT:
As suggested by Jonathan I've implemented a scroll-till-found function.
it's a bit implementation specific, so you'll probably need to tweak isCellWithName.
I'm also looking to add a break in case we didn't find the needed cell in the while loop, if anyone has ideas, feel free to edit this.
function isCellWithName(cell, name) {
return (cell.staticTexts()[0].name() == name);
}
function getCellWithName(array, name) {
for (var i = 0; i < array.length; i++) {
if (isCellWithName(array[i], name)) {
return array[i];
}
}
return false;
}
function scrollToName(collection, name) {
var found = getCellWithName(collection.cells(), name);
while (found === false) {
collection.dragInsideWithOptions({startOffset:{x:0.2, y:0.99}, endOffset:{x:0.2, y:0},duration:1.0});
found = getCellWithName(collection.cells(), name);
}
return found;
}
The documentation is apparently incorrect. There is no visibleCells() method on UIACollectionView. I figured this out by looping over all the collection view elements properties and printing out their names:
var target = UIATarget.localTarget();
var window = target.frontMostApp().mainWindow();
var collectionView = window.collectionViews()[0];
for (var i in collectionView) {
UIALogger.logMessage(i);
}
Table view elements, on the other hand, do list all the cells with the cells() method. I'm wondering if they choose not to do this because of the much more complicated nature of collection views. It could be very expensive to actually fetch all the collection view cells, build their representations and frames, and return the elements if you had a lot of them. That's what UI Automation does when it asks table views for all the cells. They have to all be instantiated and calculated in order to get the element representations.
But, to answer your larger question, how to scroll to a specific cell. Can you consistently scroll it into view with a swipe gesture? It's not the most convenient way to do it and we're "spoiled" by the ability to scroll to non-visible elements with table views. But from a user behavior testing standpoint, swiping a certain amount is what the user would have to do anyway. Could the test be structured to reflect this and would it address your need?
I couldn't get the the #marmor dragInsideWithOptions() bit to work in a generic fashion. Instead, I'm using the collectionView's value() function to get an index of the current page vs. last page, as in "page 3 of 11". Then I use collectionView's scrollUp() and scrollDown() methods to walk through the pages until we find what we're after. I wrote an extension for TuneUp's uiautomation-ext.js that seem to do the trick, and more:
function animationDelay() {
UIATarget.localTarget().delay(.2);
}
extend(UIACollectionView.prototype, {
/**
* Apple's bug in UIACollectionView.cells() -- only returns *visible* cells
*/
pageCount: function() {
var pageStatus = this.value();
var words = pageStatus.split(" ");
var lastPage = words[3];
return lastPage;
},
currentPage: function() {
var pageStatus = this.value();
var words = pageStatus.split(" ");
var currentPage = words[1];
//var lastPage = words[3];
return currentPage;
},
scrollToTop: function() {
var current = this.currentPage();
while (current != 1) {
this.scrollUp();
animationDelay();
current = this.currentPage();
}
},
scrollToBottom: function() {
var current = this.currentPage();
var lastPage = this.pageCount();
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
}
},
cellCount: function() {
this.scrollToTop();
var current = this.currentPage();
var lastPage = this.pageCount();
var cellCount = this.cells().length;
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
cellCount += this.cells().length;
}
return cellCount;
},
currentPageCellNamed: function(name) {
var array = this.cells();
for (var i = 0; i < array.length; i++) {
var cell = array[i];
if (cell.name() == name) {
return cell;
}
}
return false;
},
cellNamed: function(name) {
// for performance, look on the current page first
var foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
if (this.currentPage() != 1) {
// scroll up and check out the first page before we iterate
this.scrollToTop();
foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
}
var current = this.currentPage();
var lastPage = this.pageCount();
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
}
return false;
},
/**
* Asserts that this collection view has a cell with the name (accessibility identifier)
* matching the given +name+ argument.
*/
assertCellNamed: function(name) {
assertNotNull(this.cellNamed(name), "No collection cell found named '" + name + "'");
}
});

Default All Day Event to Check/Yes

Thanks for the great help. Another question. How do I set my "All Day Event" field on the calendar to default to "Checked/Yes?" If we can set the default on All Day Event to Yes, is there a way to hide the time fields (keep the date fields - just no time fields)? I'd also like to hide the "Workspace" field as well (if possible).
Thank You
Dave M
If you have access to run code on your server, I've run this from a console application and it worked like a charm:
using(SPSite site = new SPSite("http://yoursite"))
{
using(SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["your list name"];
SPContentType ct = list.ContentTypes["Event"];
SPFieldLink fieldLink = ct.FieldLinks["fAllDayEvent"];
Type type = typeof(SPFieldLink);
PropertyInfo pi = type.GetProperty("Default", BindingFlags.NonPublic | BindingFlags.Instance);
pi.SetValue(fieldLink, "1", null);
ct.Update();
}
}
Source: http://pholpar.spaces.live.com/blog/cns!2CD45589973F2849!131.entry
Only modification we had to make was the SPFieldLink, the examples uses All Day Event, our lists used fAllDayEvent.
The only other way I've seen work is to modify the list's CAML (Example).
Oh, and we hid the Workspace field using Javascript:
<script language="javascript" type="text/javascript">
_spBodyOnLoadFunctionNames.push("hideFields");
function fc(FieldName) {
var arr = document.getElementsByTagName("!");
for (var i=0;i < arr.length; i++ ) {
if (arr[i].innerHTML.indexOf(FieldName) > 0) { return arr[i]; }
}
}
function hideFields() {
control = fc("Workspace");
control.parentNode.parentNode.style.display="none";
}
</script>
Source: http://sharepointsherpa.com/2008/08/26/sharepoint-2007-hiding-fields-on-newformaspx-and-editformaspx-the-easy-way/

Resources