Skip to content

Commit

Permalink
[EPD-276] Added Configuration for day selection limiter
Browse files Browse the repository at this point in the history
  • Loading branch information
jbaena committed Feb 21, 2019
1 parent daa1181 commit 441e483
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 117 deletions.
224 changes: 116 additions & 108 deletions docs/src/xhtml/components/datepicker/index.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,113 +4,121 @@
<title>DatePicker</title>
</head>
<body>
<article>
<h1>DatePicker</h1>
<section class="desc">
<p>
Calendar widget that appears in Aside. Used in Forms for an implementation of &lt;input
type="date"&gt; elements.
</p>
</section>
<section>
<p>
The DatePicker can be launched with a JavaScript API. You should implement the
<code>onselect</code> method to get notified whenever the user picks a date. Note that you
must manually <code>open</code> and <code>close</code> the DatePicker.
</p>
<figure data-ts="DoxScript">
<script type="runnable">
var datePicker = ts.ui.DatePicker({
title: "Your Birthday",
value: '1973-03-26',
onselect: function(newval, oldval) {
ts.ui.Notification.success(this.value);
this.close();
},
onclosed: function() {
this.dispose();
}
});
datePicker.open();
</script>
</figure>
<p>You can specify a <code>min</code> and <code>max</code> value.</p>
<figure data-ts="DoxScript">
<script type="runnable">
ts.ui.DatePicker({
title: "Your Birthday",
value: '1984-05-23',
min: '1984-01-01',
max: '1985-12-24',
onselect: function() {
this.close();
},
onclosed: function() {
this.dispose();
}
}).open();
</script>
</figure>
<p>
The object argument configures a <code>ts.ui.DatePickerModel</code> as outlined below.
</p>
<table class="api">
<caption>
<code>ts.ui.DatePickerModel</code>
</caption>
<tbody>
<tr>
<th colspan="3">Instance properties</th>
</tr>
<tr>
<td><code>title</code></td>
<td><code>{string}</code></td>
<td>Appears as the title of the DatePicker</td>
</tr>
<tr>
<td><code>value</code></td>
<td><code>{string}</code></td>
<td>
The selected date. Must be dash-separated, ISO 8601 formatted date string e.g.
<code>2015-01-01</code>
</td>
</tr>
<tr>
<th colspan="3">Instance methods</th>
</tr>
<tr>
<td><code>open</code></td>
<td><code>{void}</code></td>
<td>Open the DatePicker</td>
</tr>
<tr>
<td><code>close</code></td>
<td><code>{void}</code></td>
<td>Close the DatePicker</td>
</tr>
<tr>
<td><code>onselect</code></td>
<td><code>{void}</code></td>
<td>
Called whenever selection changes with two arguments
<code>newval</code> and <code>oldval</code>.
</td>
</tr>
<tr>
<td><code>onclosed</code></td>
<td><code>{void}</code></td>
<td>
Event listener for close event. Called after aside closing animation is completed.
</td>
</tr>
<tr>
<td><code>dispose</code></td>
<td><code>{void}</code></td>
<td>Cleanup the DataPicker (recommended)</td>
</tr>
</tbody>
</table>
</section>
</article>
<article>
<h1>DatePicker</h1>
<section class="desc">
<p>Calendar widget that appears in Aside. Used in Forms for an implementation of &lt;input type="date"&gt; elements.</p>
</section>
<section>
<p>The DatePicker can be launched with a JavaScript API. You should implement the <code>onselect</code> method to get notified whenever the user picks a date. Note that you must manually <code>open</code> and <code>close</code> the DatePicker.</p>
<figure data-ts="DoxScript">
<script type="runnable">
var datePicker = ts.ui.DatePicker({
title: "Your Birthday",
value: '1973-03-26',
onselect: function(newval, oldval) {
ts.ui.Notification.success(this.value);
this.close();
},
onclosed: function() {
this.dispose();
}
});
datePicker.open();
</script>
</figure>
<p>You can specify a <code>min</code> and <code>max</code> value.</p>
<figure data-ts="DoxScript">
<script type="runnable">
ts.ui.DatePicker({
title: "Your Birthday",
value: '1984-05-23',
min: '1984-01-01',
max: '1985-12-24',
onrendercell: function(cell){
var jsDate = new Date(cell.year, cell.month, cell.day);
var isWeekday = ![0,6].includes(jsDate.getDay());

cell.selectable = isWeekday;
cell.className = (isWeekday ? 'weekday' : 'weekend');
},
onselect: function() {
ts.ui.Notification.success(this.value);
this.close();
},
onclosed: function() {
this.dispose();
}
}).open();
</script>
</figure>
<p>The object argument configures a <code>ts.ui.DatePickerModel</code> as outlined below.</p>
<table class="api">
<caption>
<code>ts.ui.DatePickerModel</code>
</caption>
<tbody>
<tr>
<th colspan="3">Instance properties</th>
</tr>
<tr>
<td><code>title</code></td>
<td><code>{string}</code></td>
<td>Appears as the title of the DatePicker</td>
</tr>
<tr>
<td><code>value<code></td>
<td><code>{string}</code></td>
<td>
The selected date. Must be dash-separated, ISO 8601 formatted date string e.g. <code>2015-01-01</code>
</td>
</tr>
<tr>
<th colspan="3">Instance methods</th>
</tr>
<tr>
<td><code>open</code></td>
<td><code>{void}</code></td>
<td>Open the DatePicker</td>
</tr>
<tr>
<td><code>close</code></td>
<td><code>{void}</code></td>
<td>Close the DatePicker</td>
</tr>
<tr>
<td><code>onrendercell</code></td>
<td><code>{void}</code></td>
<td>
Called whenever the datepicker renders a cell, used to determine if a cell is selectable through
the <code>cell.selectable</code> property. Can also be an injection point for adding in specialized
classes for the current cell with <code>cell.className</code>.
</td>
</tr>
<tr>
<td><code>onselect</code></td>
<td><code>{void}</code></td>
<td>
Called whenever selection changes with two
arguments <code>newval</code> and <code>oldval<code>.
</td>
</tr>
<tr>
<td><code>onclosed</code></td>
<td><code>{void}</code></td>
<td>
Event listener for close event. Called after
aside closing animation is completed.
</td>
</tr>
<tr>
<td><code>dispose</code></td>
<td><code>{void}</code></td>
<td>Cleanup the DataPicker (recommended)</td>
</tr>
</tbody>
</table>
</section>
</article>
</body>
</html>
48 changes: 41 additions & 7 deletions src/runtime/edbml/scripts/ts.ui.CalendarSpirit.edbml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<?param name="nextMonth" type="string"?>
<?param name="minDay" type="number"?>
<?param name="maxDay" type="number"?>
<?param name="onrendercell" type="function"?>

<table>
<thead>
Expand All @@ -33,7 +34,7 @@
});
</tbody>
</table>

function renderbuttons(prev, label, next) {
renderbutton(prev, 'ts-icon-triangleleft');
<th><label>${label}</label></th>
Expand All @@ -51,11 +52,17 @@
}

function rendercell(cell) {
var cellValue = cell.stringify();
var cellData = getcelldata(cell);
onrendercell(cellData);

cell.cellData = cellData;

var other = cell.prev || cell.next;
var allow = allowcell(cell, other);
@name = allow ? 'accept' : 'reject';
@value = allow ? cell.stringify() : null;
@class = classname({
@value = allow ? cellValue : null;
@class = classname(cell, {
'ts-calendar-other' : other,
'ts-calendar-today' : cell.today,
'ts-selected' : cell.selected,
Expand All @@ -68,18 +75,45 @@
</td>
}

function classname(classes) {
return Object.keys(classes).filter(function(c) {
function getcelldata(cell){
var cellData = {};
var prop;

for(prop in cell){
cellData[prop] = cell[prop];
}

return cellData;
}

function classname(cell, classes) {
var combinedClasses;
var duplicateClassIndex = {};
var customClasses = (cell.cellData.className || '').split(' ');
var internalClasses = Object.keys(classes).filter(function(c) {
return classes[c];
}).join(' ') || null;
}) || [];

combinedClasses = internalClasses.concat(customClasses).filter(function(c){
if(duplicateClassIndex[c])
{
return false;
}

duplicateClassIndex[c] = true;
return true;
});

return combinedClasses.join(' ') || null;
}

function allowcell(cell, other) {
var all = Number.MAX_VALUE;
return (
minDay !== all && maxDay !== (1 - all) &&
!lower(cell.day, minDay, !other, !prevMonth, cell.prev) &&
!upper(cell.day, maxDay, !other, !nextMonth, cell.next)
!upper(cell.day, maxDay, !other, !nextMonth, cell.next) &&
cell.cellData.selectable !== false
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ ts.ui.CalendarSpirit = (function() {
*/
onselect: null,

/**
* Customized function used for adding additional restrictions on what days can be selected
* from the calendar/datePicker.
* @type {function}
*/
onrendercell: null,

/**
* Load default template and
*/
Expand All @@ -190,7 +197,7 @@ ts.ui.CalendarSpirit = (function() {

// if supplied, import settings from the {ts.ui.DatePickerModel}
if (this._ismodelled()) {
['min', 'max', 'value'].forEach(function(key) {
['min', 'max', 'value', 'onrendercell'].forEach(function(key) {
this[key] = this._model[key];
}, this);
}
Expand Down Expand Up @@ -464,6 +471,10 @@ ts.ui.CalendarSpirit = (function() {
var minDay = this._minDay(min, year, month);
var maxDay = this._maxDay(max, year, month);

// If no day limiter is passed, then we will create a new function for the day limiter which passes in all days
// as selectable dates
var onrendercell = this.onrendercell || function() {};

this.script.run(
labels,
mname,
Expand All @@ -474,7 +485,8 @@ ts.ui.CalendarSpirit = (function() {
prevMonth,
nextMonth,
minDay,
maxDay
maxDay,
onrendercell
);
}
},
Expand Down

0 comments on commit 441e483

Please sign in to comment.