update for compatibility ie11
parent
037e2b0812
commit
58f6adb7ba
|
@ -15,6 +15,104 @@ class Browser
|
|||
//Logger::addLog('http.browser',$this->user);
|
||||
}
|
||||
|
||||
public static function get()
|
||||
{
|
||||
// Make case insensitive.
|
||||
$t = strtolower($_SERVER['HTTP_USER_AGENT']);
|
||||
|
||||
// If the string *starts* with the string, strpos returns 0 (i.e., FALSE). Do a ghetto hack and start with a space.
|
||||
// "[strpos()] may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE."
|
||||
// http://php.net/manual/en/function.strpos.php
|
||||
$t = " " . $t;
|
||||
|
||||
// Humans / Regular Users
|
||||
if (strpos($t, 'opera') || strpos($t, 'opr/')) {
|
||||
return 'Opera';
|
||||
} elseif (strpos($t, 'edge')) {
|
||||
return 'Edge';
|
||||
} elseif (strpos($t, 'chrome')) {
|
||||
return 'Chrome';
|
||||
} elseif (strpos($t, 'safari')) {
|
||||
return 'Safari';
|
||||
} elseif (strpos($t, 'firefox')) {
|
||||
return 'Firefox';
|
||||
} elseif (strpos($t, 'msie') || strpos($t, 'trident/7')) {
|
||||
return 'Internet Explorer';
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_firefox_version() {
|
||||
// Make case insensitive.
|
||||
$t = strtolower($_SERVER['HTTP_USER_AGENT']);
|
||||
|
||||
// If the string *starts* with the string, strpos returns 0 (i.e., FALSE). Do a ghetto hack and start with a space.
|
||||
// "[strpos()] may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE."
|
||||
// http://php.net/manual/en/function.strpos.php
|
||||
$t = " " . $t;
|
||||
|
||||
// Firefox Users
|
||||
if (strpos($t, 'firefox')) {
|
||||
preg_match('/rv:(.*)\)/', $_SERVER['HTTP_USER_AGENT'], $matches, PREG_OFFSET_CAPTURE);
|
||||
if(isset($matches[1])) {
|
||||
return intval($matches[1][0]);
|
||||
}else{
|
||||
return 'no-version';
|
||||
}
|
||||
}
|
||||
return 'not-firefox';
|
||||
}
|
||||
|
||||
public static function get_ip() {
|
||||
// IP si internet partagé
|
||||
if (isset($_SERVER['HTTP_CLIENT_IP'])) {
|
||||
return $_SERVER['HTTP_CLIENT_IP'];
|
||||
}
|
||||
// IP derrière un proxy
|
||||
elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
return $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
}
|
||||
// Sinon : IP normale
|
||||
else {
|
||||
return (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '');
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_os() {
|
||||
$user_agent = $_SERVER['HTTP_USER_AGENT'];
|
||||
$os_platform = "Inconnu";
|
||||
$os_array = array(
|
||||
'/windows nt 10/i' => 'Windows 10',
|
||||
'/windows nt 6.3/i' => 'Windows 8.1',
|
||||
'/windows nt 6.2/i' => 'Windows 8',
|
||||
'/windows nt 6.1/i' => 'Windows 7',
|
||||
'/windows nt 6.0/i' => 'Windows Vista',
|
||||
'/windows nt 5.2/i' => 'Windows Server 2003/XP x64',
|
||||
'/windows nt 5.1/i' => 'Windows XP',
|
||||
'/windows xp/i' => 'Windows XP',
|
||||
'/windows nt 5.0/i' => 'Windows 2000',
|
||||
'/windows me/i' => 'Windows ME',
|
||||
'/win98/i' => 'Windows 98',
|
||||
'/win95/i' => 'Windows 95',
|
||||
'/win16/i' => 'Windows 3.11',
|
||||
'/macintosh|mac os x/i' => 'Mac OS X',
|
||||
'/mac_powerpc/i' => 'Mac OS 9',
|
||||
'/linux/i' => 'Linux',
|
||||
'/ubuntu/i' => 'Ubuntu',
|
||||
'/iphone/i' => 'iPhone',
|
||||
'/ipod/i' => 'iPod',
|
||||
'/ipad/i' => 'iPad',
|
||||
'/android/i' => 'Android',
|
||||
'/blackberry/i' => 'BlackBerry',
|
||||
'/webos/i' => 'Mobile'
|
||||
);
|
||||
foreach ($os_array as $regex => $value) {
|
||||
if (preg_match($regex, $user_agent)) {
|
||||
$os_platform = $value;
|
||||
}
|
||||
}
|
||||
return $os_platform;
|
||||
}
|
||||
|
||||
protected function get_browser_name()
|
||||
{
|
||||
|
||||
|
|
|
@ -277,6 +277,43 @@ class Url
|
|||
return $url . "/" . BASE_SERVER_DIRECTORY;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getPageName(){
|
||||
|
||||
$url = parse_url($_SERVER['REQUEST_URI']);
|
||||
$urlTrim = trim($url['path'], '/');
|
||||
$urlParts = explode('/', $urlTrim);
|
||||
|
||||
//suppression des sous repertoires du BASE_SERVER_DIRECTORY
|
||||
$basePath = explode( '/', BASE_SERVER_DIRECTORY);
|
||||
foreach($basePath as $subDir) {
|
||||
if ($urlParts[0] == $subDir) {
|
||||
array_shift($urlParts);
|
||||
}
|
||||
}
|
||||
|
||||
//Récupération du nom de la page
|
||||
if (isset($urlParts[0])) {
|
||||
//il se peut que l'on ait des variable avec ? dans l'url
|
||||
$urlQuery = explode('?', $urlParts[0]);
|
||||
$urlQueryPageName = $urlQuery[0];
|
||||
($urlQueryPageName == 'index' || $urlQueryPageName == '') ? $page['name'] = 'index' : $page['name'] = $urlQueryPageName;
|
||||
unset($urlParts[0]);
|
||||
} else {
|
||||
$page['name'] = 'index';
|
||||
}
|
||||
|
||||
$page['name'] = strtolower($page['name']);
|
||||
|
||||
//si c'est une page de controle de formulaire : on renomme la page
|
||||
if ($page['name'] == 'control') {
|
||||
$page['control'] = true;
|
||||
($urlParts[1] == 'index' || $urlParts[1] == '') ? $page['name']='index' : $page['name']=$urlParts[1];
|
||||
unset($urlParts[1]);
|
||||
}
|
||||
return $page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiens le fragment depuis une variable serveur,
|
||||
* ce qui est selon moi possible avec une bonne configuration serveur
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
@section('top-css')
|
||||
<link rel="stylesheet" href="{{ \MVC\Classe\Url::asset_rewrite('assets/bootstrap-5.0.0-beta1-dist/css/bootstrap.min.css')}}">
|
||||
<link rel="stylesheet" href="{{ \MVC\Classe\Url::asset_rewrite('assets/css/custom.css')}}">
|
||||
@if(\MVC\Classe\Browser::get() == 'Internet Explorer')
|
||||
<link rel="stylesheet" href="{{\MVC\Classe\Url::asset_rewrite('assets/html5-simple-date-input-polyfill-master/html5-simple-date-input-polyfill.css')}}">
|
||||
<!--<link rel="stylesheet" href="{{\MVC\Classe\Url::asset_rewrite('assets/hyperform-0.12.0/css/hyperform.css')}}">-->
|
||||
@endif
|
||||
@show
|
||||
|
||||
</head>
|
||||
|
@ -37,6 +41,15 @@
|
|||
<body>
|
||||
|
||||
@section('top-javascript')
|
||||
@if(\MVC\Classe\Browser::get() == 'Internet Explorer')
|
||||
<!-- Polyfill.io will load polyfills your browser needs -->
|
||||
<script src="https://polyfill.io/v3/polyfill.min.js?features=default%2CNumber.parseInt%2CNumber.parseFloat%2CArray.prototype.find%2CArray.prototype.includes"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.12.1/polyfill.min.js" integrity="sha512-uzOpZ74myvXTYZ+mXUsPhDF+/iL/n32GDxdryI2SJronkEyKC8FBFRLiBQ7l7U/PTYebDbgTtbqTa6/vGtU23A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js"></script>
|
||||
<script src="{{\MVC\Classe\Url::asset_rewrite('assets/html5-simple-date-input-polyfill-master/html5-simple-date-input-polyfill.js')}}"></script>
|
||||
<script src="{{\MVC\Classe\Url::asset_rewrite('assets/hyperform-0.12.0/dist/hyperform.js')}}"></script>
|
||||
<script>hyperform(window);</script>
|
||||
@endif
|
||||
@show
|
||||
|
||||
@yield('body')
|
||||
|
@ -45,6 +58,7 @@
|
|||
<script src="{{ \MVC\Classe\Url::asset_rewrite('assets/bootstrap-5.0.0-beta1-dist/js/bootstrap.min.js')}}"></script>
|
||||
<script src="{{ \MVC\Classe\Url::asset_rewrite('assets/js/custom.js')}}"></script>
|
||||
|
||||
@if(\MVC\Classe\Browser::get() !== 'Internet Explorer')
|
||||
<script>
|
||||
|
||||
/*
|
||||
|
@ -71,6 +85,7 @@
|
|||
}
|
||||
}
|
||||
</script>
|
||||
@endif
|
||||
@show
|
||||
|
||||
</body>
|
||||
|
|
|
@ -7,43 +7,44 @@
|
|||
@endsection
|
||||
|
||||
@section('content')
|
||||
<h1>%%PAGE%% - VUE.js Controlleur</h1>
|
||||
<br/><br/><br/>
|
||||
<div id="app">
|
||||
<div>
|
||||
<input v-model="searchText" placeholder="Search...">
|
||||
</div>
|
||||
<div v-if="is_loading">
|
||||
<div class="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
|
||||
</div>
|
||||
<div v-if="items" >
|
||||
<a href="#" v-for="item in itemsSearched" :key="item.id">
|
||||
<div>
|
||||
<div>
|
||||
<h2>
|
||||
@{{ item.title }}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
@{{ item.description.slice(0, 300) + "..." }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<span>Year : @{{ item.release_date }}</span>
|
||||
<span>Director : @{{ item.director }}</span>
|
||||
<span>Producer : @{{ item.producer }}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h1>ghibli - VUE.js Controlleur</h1>
|
||||
<br/><br/><br/>
|
||||
<div id="app">
|
||||
<div>
|
||||
<input v-model="searchText" placeholder="Search...">
|
||||
</div>
|
||||
<div v-if="is_loading" id="is-loading">
|
||||
<div class="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
|
||||
</div>
|
||||
<div v-if="items" >
|
||||
<a href="#" v-for="item in itemsSearched" :key="item.id">
|
||||
<div>
|
||||
<div>
|
||||
<h2>
|
||||
@{{ item.title }}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
@{{ item.description.slice(0, 300) + "..." }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<span>Year : @{{ item.release_date }}</span>
|
||||
<span>Director : @{{ item.director }}</span>
|
||||
<span>Producer : @{{ item.producer }}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('bottom-javascript')
|
||||
@parent
|
||||
<script>
|
||||
@if(\MVC\Classe\Browser::get() !== 'Internet Explorer')
|
||||
const vue = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
|
@ -53,11 +54,11 @@
|
|||
},
|
||||
mounted() {
|
||||
axios
|
||||
.get('https://ghibliapi.herokuapp.com/films')
|
||||
.then(response => {
|
||||
this.items = response.data;
|
||||
.get('https://ghibliapi.herokuapp.com/films')
|
||||
.then(response => {
|
||||
this.items = response.data;
|
||||
this.is_loading = false
|
||||
})
|
||||
})
|
||||
.catch(error => console.log(error))
|
||||
},
|
||||
computed : {
|
||||
|
@ -78,5 +79,42 @@
|
|||
}
|
||||
}
|
||||
});
|
||||
@else
|
||||
const vue = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
items: [],
|
||||
searchText: '',
|
||||
is_loading: true,
|
||||
},
|
||||
mounted: function() {
|
||||
axios
|
||||
.get('https://ghibliapi.herokuapp.com/films')
|
||||
.then(function(response) {
|
||||
this.items = response.data;
|
||||
this.is_loading = false;
|
||||
document.getElementById('is-loading').style.display = 'none';
|
||||
})
|
||||
.catch(function(error) {console.log(error)})
|
||||
},
|
||||
computed: {
|
||||
itemsSearched : function(){
|
||||
var self = this;
|
||||
if( this.searchText == ''){
|
||||
return this.items;
|
||||
}
|
||||
return this.items.filter(function(item){
|
||||
// https://www.reddit.com/r/vuejs/comments/62kfae/how_do_i_create_very_simple_instant_search_filter/
|
||||
// Must be of string type
|
||||
return item.title.toLowerCase().indexOf(self.searchText) >= 0 ||
|
||||
item.producer.toLowerCase().indexOf(self.searchText) >= 0 ||
|
||||
item.director.toLowerCase().indexOf(self.searchText) >= 0 ||
|
||||
item.release_date.toString().indexOf(self.searchText) >= 0;
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@endif
|
||||
</script>
|
||||
@endsection
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 liorwohl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,23 @@
|
|||
# html5-simple-date-input-polyfill
|
||||
Just include this simple script and IE (>=10) and Firefox will support `<input type="date">` without any dependencies, not even jQuery! 🎉
|
||||
|
||||
Support dynamically created inputs, so can be used in single page applications.
|
||||
|
||||
Support [AngularJS](https://github.com/angular/angular.js) (and possibly other libraries) bindings.
|
||||
|
||||
# Usage
|
||||
|
||||
#### browserify
|
||||
|
||||
`npm install html5-simple-date-input-polyfill --save`
|
||||
|
||||
`require('html5-simple-date-input-polyfill');`
|
||||
|
||||
#### Browser
|
||||
|
||||
`<link rel="stylesheet" href="html5-simple-date-input-polyfill.css" />`
|
||||
|
||||
`<script src="html5-simple-date-input-polyfill.min.js"></script>`
|
||||
|
||||
#### SCSS (optional)
|
||||
`@import "../node_modules/html5-simple-date-input-polyfill/html5-simple-date-input-polyfill.scss";`
|
|
@ -0,0 +1,49 @@
|
|||
.calendar,
|
||||
.calendar select,
|
||||
.calendar table,
|
||||
.calendar td,
|
||||
.calendar th {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
text-shadow: none;
|
||||
height: auto;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
line-height: normal;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
z-index:1000;
|
||||
}
|
||||
|
||||
.calendarContainer{
|
||||
display:block !important;
|
||||
}
|
||||
|
||||
.calendar {
|
||||
position: absolute;
|
||||
border: 1px solid #c0c0c0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.calendar select {
|
||||
margin: 3px 5px;
|
||||
border: 1px solid #c0c0c0;
|
||||
}
|
||||
|
||||
.calendar td,
|
||||
.calendar th {
|
||||
width: 14%;
|
||||
padding: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.calendar td {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.calendar .selected {
|
||||
font-weight: bold;
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
function calendarExtender (theInput) {
|
||||
|
||||
var self = this;
|
||||
|
||||
this.theInput = theInput;
|
||||
this.container = null;
|
||||
this.theCalDiv = null;
|
||||
this.selectedDate = new Date();
|
||||
|
||||
this.init = function () {
|
||||
this.getDateFromInput();
|
||||
this.createCal();
|
||||
};
|
||||
|
||||
//update selectedDate with the date from the input, return true if changed
|
||||
this.getDateFromInput = function () {
|
||||
if (this.theInput.value) {
|
||||
var possibleNewDate = new Date(this.theInput.value);
|
||||
if (Date.parse(this.theInput.value) && possibleNewDate.toDateString() !== this.selectedDate.toDateString()) {
|
||||
this.selectedDate = possibleNewDate;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
//create the calendar html and events
|
||||
this.createCal = function () {
|
||||
//creating a container div around the input, the calendar will also be there
|
||||
this.container = document.createElement('div');
|
||||
this.container.className = 'calendarContainer';
|
||||
this.container.style.display = 'inline-block';
|
||||
this.theInput.parentNode.replaceChild(this.container, this.theInput);
|
||||
this.container.appendChild(this.theInput);
|
||||
|
||||
//the calendar div
|
||||
this.theCalDiv = document.createElement('div');
|
||||
this.theCalDiv.className = 'calendar';
|
||||
this.theCalDiv.style.display = 'none';
|
||||
this.container.appendChild(this.theCalDiv);
|
||||
|
||||
//the year and month selects inside the calendar
|
||||
this.creathYearAndMonthSelects();
|
||||
|
||||
//the days table inside the calendar
|
||||
this.createMonthTable();
|
||||
|
||||
//open the calendar when the input get focus, also on various click events to capture it in all corner cases
|
||||
this.theInput.addEventListener('focus', function () { self.theCalDiv.style.display = ''; });
|
||||
this.theInput.addEventListener('mouseup', function () { self.theCalDiv.style.display = ''; });
|
||||
this.theInput.addEventListener('mousedown', function () { self.theCalDiv.style.display = ''; });
|
||||
|
||||
//update the calendar if the date changed manually in the input
|
||||
this.theInput.addEventListener('keyup', function () {
|
||||
if (self.getDateFromInput()) {
|
||||
self.updateSelecteds();
|
||||
}
|
||||
});
|
||||
|
||||
//close the calendar when clicking outside of the input or calendar
|
||||
document.addEventListener('click', function (e) {
|
||||
if (e.target.parentNode !== self.container &&
|
||||
e.target.parentNode.parentNode !== self.container &&
|
||||
e.target.parentNode.parentNode !== self.theCalDiv
|
||||
) {
|
||||
self.theCalDiv.style.display = 'none';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//create the year and month selects html
|
||||
this.creathYearAndMonthSelects = function () {
|
||||
//the year selector inside the calendar
|
||||
var yearSelect = this.createRangeSelect(new Date().getFullYear() - 80, new Date().getFullYear() + 20, this.selectedDate.getFullYear());
|
||||
yearSelect.className = 'yearSelect';
|
||||
this.theCalDiv.appendChild(yearSelect);
|
||||
yearSelect.onchange = function () {
|
||||
self.selectedDate.setYear(this.value);
|
||||
self.selectDate();
|
||||
self.createMonthTable();
|
||||
self.theInput.focus();
|
||||
};
|
||||
|
||||
//the month selector inside the calendar
|
||||
var monthsNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||||
var monthSelect = this.createRangeSelect(0, 11, this.selectedDate.getMonth(), monthsNames);
|
||||
monthSelect.className = 'monthSelect';
|
||||
this.theCalDiv.appendChild(monthSelect);
|
||||
monthSelect.onchange = function () {
|
||||
self.selectedDate.setMonth(this.value);
|
||||
self.selectDate();
|
||||
self.createMonthTable();
|
||||
self.theInput.focus();
|
||||
};
|
||||
};
|
||||
|
||||
//update the year and month selects with the right selected value (if date changed externally)
|
||||
this.updateSelecteds = function () {
|
||||
this.theCalDiv.querySelector('.yearSelect').value = this.selectedDate.getFullYear();
|
||||
this.theCalDiv.querySelector('.monthSelect').value = this.selectedDate.getMonth();
|
||||
this.createMonthTable();
|
||||
};
|
||||
|
||||
//create the days table
|
||||
this.createMonthTable = function () {
|
||||
var year = this.selectedDate.getFullYear(); //get the year (2015)
|
||||
var month = this.selectedDate.getMonth(); //get the month number (0-11)
|
||||
var startDay = new Date(year, month, 1).getDay(); //first weekday of month (0-6)
|
||||
var maxDays = new Date(this.selectedDate.getFullYear(), month + 1, 0).getDate(); //get days in month (1-31)
|
||||
|
||||
//if there was a table before, remove it
|
||||
var oldTables = this.theCalDiv.getElementsByTagName('table');
|
||||
if (oldTables.length > 0) {
|
||||
this.theCalDiv.removeChild(oldTables[0]);
|
||||
}
|
||||
|
||||
//the table and header for the month days
|
||||
var theTable = document.createElement('table');
|
||||
theTable.innerHTML = '<tr><th>Sun</th><th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th><th>Sat</th></tr>';
|
||||
this.theCalDiv.appendChild(theTable);
|
||||
|
||||
//create the days cols according to the selected month days
|
||||
var aRow;
|
||||
var aCell;
|
||||
for (var cellNum = 0; cellNum < maxDays + startDay; cellNum++) {
|
||||
|
||||
//crate a table row in the begining and after each 7 cells
|
||||
if (cellNum % 7 === 0) {
|
||||
aRow = theTable.insertRow(-1);
|
||||
}
|
||||
|
||||
aCell = aRow.insertCell(-1);
|
||||
|
||||
if (cellNum + 1 > startDay) {
|
||||
|
||||
var dayNum = cellNum + 1 - startDay;
|
||||
aCell.innerHTML = dayNum;
|
||||
if (dayNum === this.selectedDate.getDate()) {
|
||||
aCell.className = 'selected';
|
||||
}
|
||||
|
||||
//when clicking on a day in the days table
|
||||
aCell.addEventListener('click', function () {
|
||||
|
||||
//mark the dey with 'selected' css class
|
||||
self.theCalDiv.querySelector('.selected').className = '';
|
||||
this.className = 'selected';
|
||||
|
||||
self.selectedDate.setDate(parseInt(this.innerHTML));
|
||||
self.selectDate();
|
||||
self.theInput.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//copy the selected date to the input field
|
||||
this.selectDate = function () {
|
||||
|
||||
var monthText = this.selectedDate.getMonth() + 1;
|
||||
if (monthText < 10) {
|
||||
monthText = '0' + monthText;
|
||||
}
|
||||
|
||||
var dayText = this.selectedDate.getDate();
|
||||
if (dayText < 10) {
|
||||
dayText = '0' + dayText;
|
||||
}
|
||||
|
||||
this.theInput.value = '' + this.selectedDate.getFullYear() + '-' + monthText + '-' + dayText + '';
|
||||
|
||||
//make angular see the change
|
||||
var fakeEvent = document.createEvent('KeyboardEvent');
|
||||
fakeEvent.initEvent("change", true, false);
|
||||
this.theInput.dispatchEvent(fakeEvent);
|
||||
};
|
||||
|
||||
//helper function to create html select tags
|
||||
this.createRangeSelect = function (min, max, selected, namesArray) {
|
||||
var aOption;
|
||||
var curNum;
|
||||
var theText;
|
||||
|
||||
var theSelect = document.createElement('select');
|
||||
|
||||
for (curNum = min; curNum <= max; curNum++) {
|
||||
aOption = document.createElement('option');
|
||||
theSelect.appendChild(aOption);
|
||||
|
||||
if (namesArray) {
|
||||
theText = namesArray[curNum - min];
|
||||
} else {
|
||||
theText = curNum;
|
||||
}
|
||||
|
||||
aOption.text = theText;
|
||||
aOption.value = curNum;
|
||||
|
||||
if (curNum === selected) {
|
||||
aOption.selected = true;
|
||||
}
|
||||
};
|
||||
|
||||
return theSelect;
|
||||
}
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
//return false if the browser dont support input[type=date]
|
||||
function checkDateInputSupport () {
|
||||
var input = document.createElement('input');
|
||||
input.setAttribute('type','date');
|
||||
|
||||
var notADateValue = 'not-a-date';
|
||||
input.setAttribute('value', notADateValue);
|
||||
|
||||
return !(input.value === notADateValue);
|
||||
}
|
||||
|
||||
//will add the calendarExtender to all inputs in the page
|
||||
function addcalendarExtenderToDateInputs () {
|
||||
//get and loop all the input[type=date]s in the page that dont have "haveCal" class yet
|
||||
var dateInputs = document.querySelectorAll('input[type=date]:not(.haveCal)');
|
||||
[].forEach.call(dateInputs, function (dateInput) {
|
||||
//call calendarExtender function on the input
|
||||
new calendarExtender(dateInput);
|
||||
//mark that it have calendar
|
||||
dateInput.classList.add('haveCal');
|
||||
});
|
||||
}
|
||||
|
||||
//run the above code on any <input type='date'> in the document, also on dynamically created ones
|
||||
//check if type=date is supported or if not mobile, they have built-in support for type='date'
|
||||
if (!checkDateInputSupport() && typeof window.orientation === 'undefined') {
|
||||
addcalendarExtenderToDateInputs();
|
||||
//this is also on mousedown event so it will capture new inputs that might joined to the dom dynamically
|
||||
document.querySelector('body').addEventListener('mousedown', function (event) {
|
||||
addcalendarExtenderToDateInputs();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
function calendarExtender(c){var a=this;this.theInput=c;this.theCalDiv=this.container=null;this.selectedDate=new Date;this.init=function(){this.getDateFromInput();this.createCal()};this.getDateFromInput=function(){if(this.theInput.value){var b=new Date(this.theInput.value);if(Date.parse(this.theInput.value)&&b.toDateString()!==this.selectedDate.toDateString())return this.selectedDate=b,!0}return!1};this.createCal=function(){this.container=document.createElement("div");this.container.className="calendarContainer";
|
||||
this.container.style.display="inline-block";this.theInput.parentNode.replaceChild(this.container,this.theInput);this.container.appendChild(this.theInput);this.theCalDiv=document.createElement("div");this.theCalDiv.className="calendar";this.theCalDiv.style.display="none";this.container.appendChild(this.theCalDiv);this.creathYearAndMonthSelects();this.createMonthTable();this.theInput.addEventListener("focus",function(){a.theCalDiv.style.display=""});this.theInput.addEventListener("mouseup",function(){a.theCalDiv.style.display=
|
||||
""});this.theInput.addEventListener("mousedown",function(){a.theCalDiv.style.display=""});this.theInput.addEventListener("keyup",function(){a.getDateFromInput()&&a.updateSelecteds()});document.addEventListener("click",function(b){b.target.parentNode!==a.container&&b.target.parentNode.parentNode!==a.container&&b.target.parentNode.parentNode!==a.theCalDiv&&(a.theCalDiv.style.display="none")})};this.creathYearAndMonthSelects=function(){var b=this.createRangeSelect((new Date).getFullYear()-80,(new Date).getFullYear()+
|
||||
20,this.selectedDate.getFullYear());b.className="yearSelect";this.theCalDiv.appendChild(b);b.onchange=function(){a.selectedDate.setYear(this.value);a.selectDate();a.createMonthTable();a.theInput.focus()};b=this.createRangeSelect(0,11,this.selectedDate.getMonth(),"January February March April May June July August September October November December".split(" "));b.className="monthSelect";this.theCalDiv.appendChild(b);b.onchange=function(){a.selectedDate.setMonth(this.value);a.selectDate();a.createMonthTable();
|
||||
a.theInput.focus()}};this.updateSelecteds=function(){this.theCalDiv.querySelector(".yearSelect").value=this.selectedDate.getFullYear();this.theCalDiv.querySelector(".monthSelect").value=this.selectedDate.getMonth();this.createMonthTable()};this.createMonthTable=function(){var b=this.selectedDate.getFullYear(),f=this.selectedDate.getMonth(),b=(new Date(b,f,1)).getDay(),f=(new Date(this.selectedDate.getFullYear(),f+1,0)).getDate(),c=this.theCalDiv.getElementsByTagName("table");0<c.length&&this.theCalDiv.removeChild(c[0]);
|
||||
c=document.createElement("table");c.innerHTML="<tr><th>Sun</th><th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th><th>Sat</th></tr>";this.theCalDiv.appendChild(c);for(var g,e,d=0;d<f+b;d++)if(0===d%7&&(g=c.insertRow(-1)),e=g.insertCell(-1),d+1>b){var h=d+1-b;e.innerHTML=h;h===this.selectedDate.getDate()&&(e.className="selected");e.addEventListener("click",function(){a.theCalDiv.querySelector(".selected").className="";this.className="selected";a.selectedDate.setDate(parseInt(this.innerHTML));
|
||||
a.selectDate();a.theInput.focus()})}};this.selectDate=function(){var b=this.selectedDate.getMonth()+1;10>b&&(b="0"+b);var a=this.selectedDate.getDate();10>a&&(a="0"+a);this.theInput.value=""+this.selectedDate.getFullYear()+"-"+b+"-"+a+"";b=document.createEvent("KeyboardEvent");b.initEvent("change",!0,!1);this.theInput.dispatchEvent(b)};this.createRangeSelect=function(b,a,c,g){var e,d,h,f=document.createElement("select");for(d=b;d<=a;d++)e=document.createElement("option"),f.appendChild(e),h=g?g[d-
|
||||
b]:d,e.text=h,e.value=d,d===c&&(e.selected=!0);return f};this.init()}function checkDateInputSupport(){var c=document.createElement("input");c.setAttribute("type","date");c.setAttribute("value","not-a-date");return"not-a-date"!==c.value}function addcalendarExtenderToDateInputs(){var c=document.querySelectorAll("input[type=date]:not(.haveCal)");[].forEach.call(c,function(a){new calendarExtender(a);a.classList.add("haveCal")})}
|
||||
checkDateInputSupport()||"undefined"!==typeof window.orientation||(addcalendarExtenderToDateInputs(),document.querySelector("body").addEventListener("mousedown",function(c){addcalendarExtenderToDateInputs()}));
|
|
@ -0,0 +1,43 @@
|
|||
@mixin reset() {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
text-shadow: none;
|
||||
height: auto;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
line-height: normal;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.calendar {
|
||||
&, select, table, th, td {
|
||||
@include reset();
|
||||
}
|
||||
|
||||
position: absolute;
|
||||
border: 1px solid #c0c0c0;
|
||||
text-align: center;
|
||||
|
||||
select {
|
||||
margin: 3px 5px;
|
||||
border: 1px solid #c0c0c0;
|
||||
}
|
||||
|
||||
th, td {
|
||||
width: 14%;
|
||||
padding: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selected {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "html5-simple-date-input-polyfill",
|
||||
"version": "1.1.0",
|
||||
"description": "input type date polyfill",
|
||||
"main": "html5-simple-date-input-polyfill.js",
|
||||
"author": {
|
||||
"name": "Lior Wohl",
|
||||
"email": "liorwohl@gmail.com"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/liorwohl/html5-simple-date-input-polyfill.git"
|
||||
},
|
||||
"bugs": "https://github.com/liorwohl/html5-simple-date-input-polyfill/issues",
|
||||
"keywords": ["html5","date","datepicker","type"],
|
||||
"analyze": true,
|
||||
"license": "MIT",
|
||||
"readme": "ERROR: No README data found!"
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<link rel="stylesheet" href="html5-simple-date-input-polyfill.css" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
normal:
|
||||
<input type="date" />
|
||||
|
||||
with value:
|
||||
<input type="date" value="2015-03-28" />
|
||||
|
||||
dynamically created:
|
||||
<script>
|
||||
setTimeout(function(){
|
||||
var input = document.createElement("input");
|
||||
input.type = "date";
|
||||
document.body.appendChild(input);
|
||||
}, 2000);
|
||||
</script>
|
||||
|
||||
<script src="html5-simple-date-input-polyfill.min.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,2 @@
|
|||
/node_modules
|
||||
npm-debug.log
|
|
@ -0,0 +1,8 @@
|
|||
**/.*
|
||||
bower.json
|
||||
bower_components
|
||||
examples
|
||||
.gitignore
|
||||
Makefile
|
||||
node_modules
|
||||
.travis.yml
|
|
@ -0,0 +1,7 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- node
|
||||
env:
|
||||
global:
|
||||
- secure: JsPlO0dP7mK7GEqUovqWsXzXY2cVRPvFM6ZJn3QIRRvXTrP4u/qcDpvKvgwR+DvVObLa9/exxEwcIqeYZJz5XKjET2JIgozJERACkJkZkiAjHWyDCuVd271OzNJ968TsOA9Rzzdq3fuv5wBiqjNuW3DK0nQwJiW4iL5ygsyOw0KNEcNVyvipWUY7n0GkIlnCPfi2SqaD+nQxocbsRuDAyCPEl5b01E3IgJPOuHUhBz4r2Dfs9eO5hf1eQSaPCDflvFyKvHIsfwUuN2NzgBXmT0quuoSTxR+V6k69eo2+FuShfOd8+0Z7FlyFnTA6bniBKaVbJ45GXYDA8ecGtYbmUqaT0iA7aUIuHvCBonW2m+x8tWvDR/mDFavdE6loR/RgR1mBtuY+dCKDNBBKFwss3iQar2aMepiU8AvrXq5ViV3rZk6ZFgIsKZ7QHW4kCghhOm0oXLPzaid4kezF9wIw4navEJh9x3+2CPwSh2++IhA8RiyJ5/XDBN5EoDQqxwP6fS3CJUImgM4qal0jRr20YJNeiovkH+yzVDW8frbecLQbpN+GEWyt1Wm9BG8nVccIej7Tc/ndUAnZLsYTv5qhwYp72XnHq/6fLVc4mTpCbA5hNAB8sWiep2NKvujbU7HYaPvoy5tb690ExAuBb4vHS4pND/9w3P5XmdCocVMamOo=
|
||||
- secure: I9qTcPli1f0IqgzGwQURRp9qi5vWVt0aKKQzUJNfNnhp7zMJEIm3+kTwuORxaFWi8CKq9qkqvL+MmQX3stfkJYCe3NrzHxCb15VgbysGOQtkH2L4WmXZbSWoQVMM9m8RxPZ8WSGdOsLZrdDJWDw2qKHg9RGEhdr9E5PMeOXnIWZx3Le/kdEKBct2QQquWUrKAYcGYfDAejQhj8hzjYBm/fmEchBq3voxUKZ0NwgIOlkgg3pjs9Y/Er/OCzagFkBWuR8HadbhLhPU2CMbnwO97ntUC3taTZHae+xI6n5/4WK5mUZx1M5q5AmriOZ6M/mbxkxrcRx4Ohyzzh/fyoei4Xp4K5MEoibl7L0wD8J58FOEmPn3kUWgHXl17SuQvPpGj98G9Xz5rwUYza5SBLUvtjPkPfQj2j1NXOpD/Vdj2ibidN2EVB2XmkTc99M9TNFVPWmxxfzMjpCQ/4s7sSJKXrjuIFaPUpgqdcP8F6UsAjXXfxnV1AgEGADCeJ7cNnOqq11lqQdfaD2Gk4Zh7OYgeikbQUWgRe4DAdhnfrbFZ22DgLj8hw1NyKCAYl7MxtjA3abZZ2y5v9k+PP4j+T7ijJEClNZ/0MAwbqarOtQnmPAkPjB62nPC4IOxjhnu/JSmBONTAoANvtvnRbHEgsW+bFPS+enjecmy8SRYsFk1NLg=
|
|
@ -0,0 +1,508 @@
|
|||
# Changelog
|
||||
|
||||
## UNRELEASED
|
||||
|
||||
## v0.12.0
|
||||
|
||||
* fix return values for ValidityState properties on non-input elements
|
||||
* add ES module build
|
||||
* fix dependency cycle. Rollup runs now w/o warnings
|
||||
* add support for calling Hyperform on arbitrary DOM nodes
|
||||
* add index.d.ts to npm package
|
||||
|
||||
## v0.11.0
|
||||
|
||||
* switch build tool to rollup
|
||||
* remove deprecated underscore names
|
||||
* fix revalidation for forms with novalidate attribute
|
||||
|
||||
## v0.10.2
|
||||
|
||||
* fix form validation error for detached elements
|
||||
|
||||
## v0.10.1
|
||||
|
||||
* fix event properties being set too late
|
||||
|
||||
## v0.10.0
|
||||
|
||||
* add new event "implicit_submit", that allows to prevent implicit submits
|
||||
|
||||
## v0.9.23
|
||||
|
||||
* fix application of class hf-user-invalid to checkboxes/radio buttons
|
||||
|
||||
## v0.9.22
|
||||
|
||||
* fix select boxes not respectin placeholder options
|
||||
* validate dates stricter
|
||||
* add TypeScript declarations
|
||||
|
||||
## v0.9.21
|
||||
|
||||
* fix problem, where badInput was not detected with hyperform(form) calls (issue #49)
|
||||
|
||||
## v0.9.20
|
||||
|
||||
* hide empty warnings with CSS
|
||||
* fix select boxes with disabled options selected validating as required
|
||||
|
||||
## v0.9.19
|
||||
|
||||
* fix custom validation messages gone missing (regression from v0.9.17)
|
||||
|
||||
## v0.9.18
|
||||
|
||||
* prevent infinite loops from custom validators
|
||||
|
||||
## v0.9.17
|
||||
|
||||
* add tests to npm package
|
||||
* live-update warnings, when `setCustomValidity()` is called
|
||||
* properly delete custom messages
|
||||
|
||||
## v0.9.16
|
||||
|
||||
* fix radio button warnings still being multiplied on submit
|
||||
|
||||
## v0.9.15
|
||||
|
||||
* update some dependencies
|
||||
* add `CHANGELOG.md`
|
||||
* prevent `is_validation_candidate()` from running twice for each validation
|
||||
* re-allow validation of elements without `name` attribute, if asked directly
|
||||
* fix validation for partly required radio groups
|
||||
* on form validation show only one warning per radio group
|
||||
|
||||
## v0.9.14
|
||||
|
||||
* prevent non-candidates from being handled
|
||||
|
||||
## v0.9.13
|
||||
|
||||
* fix tabbing into fields triggering revalidation
|
||||
|
||||
## v0.9.12
|
||||
|
||||
* fix `element.noValidate` being broken
|
||||
|
||||
## v0.9.11
|
||||
|
||||
* do not validate elements without name
|
||||
* add guard against trying to remove a detached warning
|
||||
* start removing default imports and add comments
|
||||
* switch to `babel-preset-env`
|
||||
* add a command to quickly generate a `.po` file for l10n
|
||||
|
||||
## v0.9.10
|
||||
|
||||
* Connect error messages via `aria-describedby`
|
||||
|
||||
## v0.9.9
|
||||
|
||||
* update README
|
||||
|
||||
## v0.9.8
|
||||
|
||||
* Fix for IE 10 & 11 not supporting multiple parameters for classList add() and remove() methods
|
||||
|
||||
## v0.9.7
|
||||
|
||||
* fix "novalidateOnElements" not added to settings
|
||||
|
||||
## v0.9.6
|
||||
|
||||
* use translation for base language, if available
|
||||
|
||||
## v0.9.5
|
||||
|
||||
* trigger a "forminvalid" event
|
||||
|
||||
## v0.9.4
|
||||
|
||||
* add option to autoload Hyperform
|
||||
|
||||
## v0.9.3
|
||||
|
||||
* fix bower.json's main field
|
||||
|
||||
## v0.9.2
|
||||
|
||||
* fix wrong value in `tooShort` message
|
||||
|
||||
## v0.9.1
|
||||
|
||||
* convert renderer methods to camelCase, too
|
||||
|
||||
## v0.9.0
|
||||
|
||||
* switch from snake_case to camelCase for public API
|
||||
* upgrade ava (please run "npm install" after pull)
|
||||
* remove mobile clients from test matrix, since they throw strange SauceLabs errors
|
||||
* split "make test" in sub-targets
|
||||
* extend saucelabs browsers to mobile
|
||||
* fix Safari `<=` 9 throwing error on uninstalling properties
|
||||
* enable tests for IE 9/10
|
||||
* crank up the test matrix
|
||||
* implement better "clicked on child of `<button>`" detection
|
||||
|
||||
## v0.8.15
|
||||
|
||||
* fix IE `<=` 10 not knowing HTMLDocument
|
||||
|
||||
## v0.8.14
|
||||
|
||||
* reintroduce accidentally deleted Firefox safe-guard
|
||||
|
||||
## v0.8.13
|
||||
|
||||
* change the way we evaluate prevented submit event
|
||||
* for whatever reason `insertRule()` now needs an explicit index
|
||||
|
||||
## v0.8.12
|
||||
|
||||
* add support for `\n` in error messages
|
||||
* fix child nodes mixing up `event.target` of button clicks
|
||||
|
||||
## v0.8.11
|
||||
|
||||
* allow filtering is_validation_candidate result
|
||||
|
||||
## v0.8.10
|
||||
|
||||
* make logging optional with debug=bool setting
|
||||
* add `.hf-user-valid`
|
||||
* add more classes to mirror pseudo-classes
|
||||
* adapt the date rendering in date and time input error messages
|
||||
|
||||
## v0.8.9
|
||||
|
||||
* fix IE not setting `defaultPrevented`
|
||||
|
||||
## v0.8.8
|
||||
|
||||
* catch case, where native properties cannot be overloaded
|
||||
|
||||
## v0.8.7
|
||||
|
||||
* ignore non-essential files on (bower|npm) install
|
||||
|
||||
## v0.8.6
|
||||
|
||||
* fix the `prevent_implicit_submit` switch
|
||||
|
||||
## v0.8.5
|
||||
|
||||
* add setting `prevent_implicit_submit`
|
||||
* apparently `originalTarget` is a protected getter on `Event`
|
||||
* streamline form submission better
|
||||
|
||||
## v0.8.4
|
||||
|
||||
* fix some problems with non-AJAX form submission
|
||||
|
||||
## v0.8.3
|
||||
|
||||
* filter attributes before being set/get
|
||||
|
||||
## v0.8.2
|
||||
|
||||
* fix evaluation of "formnovalidate" on submit buttons
|
||||
|
||||
## v0.8.1
|
||||
|
||||
* fix polyfills not being applied in global context
|
||||
* create hook registry w/o prototype
|
||||
* add add_filter as alias to add_hook
|
||||
* add current value as param to filters
|
||||
* add call_filter to filter a value through hooks
|
||||
* add hook infrastructure
|
||||
|
||||
## v0.8.0
|
||||
|
||||
* rename hyperform.register to hyperform.add_validator
|
||||
|
||||
## v0.7.7
|
||||
|
||||
* unify form submission a bit
|
||||
* add name=value of submit button to form submit
|
||||
|
||||
## v0.7.6
|
||||
|
||||
* disallow multiple wrappers per form
|
||||
|
||||
## v0.7.5
|
||||
|
||||
* complete uninstall process
|
||||
* define attribute helpers
|
||||
* fix calling issue and tests
|
||||
* add a "polyunfill" method mirroring polyfill()
|
||||
* create dedicated "polyfill" method
|
||||
* add a hybrid re-evaluation strategy
|
||||
* fix leaking implementation
|
||||
* allow renderer to be reset to default
|
||||
|
||||
## v0.7.4
|
||||
|
||||
* add /css to "files" setting in package.json
|
||||
* remove necessity for some ES6 shims
|
||||
* fix detection of revalidate=never
|
||||
* `const`-antize all the things!
|
||||
* fall back to attribute data-validator for custom validation messages
|
||||
* fix "blur" event delegation
|
||||
* allow "onblur" for settings.revalidate
|
||||
* support "never" for settings.revalidate
|
||||
* add support for per-element custom messages
|
||||
* make naming of component clearer
|
||||
* uninstall more properties
|
||||
* refactor validity checkers
|
||||
* factor out the huge validity state checkers
|
||||
* fix calls to polyfill w/ changed signature
|
||||
* change rest of polyfills to use explicit element arg
|
||||
* change some polyfills from `this` to explicit arg
|
||||
* set aria-live=polite on warnings
|
||||
* enhance setting propagation
|
||||
* switch case for a class
|
||||
* add a destroy method to Wrapper
|
||||
* polyfill some properties like element.maxLength
|
||||
* trim email/url before validation
|
||||
* fix possible loop in bad_input validator
|
||||
* postpone creation of DOM elements
|
||||
* add support for children of `<datalist>` not being validated
|
||||
* change overwrite behavior of property_installer
|
||||
* add missing methods to `<form>`
|
||||
|
||||
## v0.7.3
|
||||
|
||||
* branch out attach/detach renderer
|
||||
* fix naming error
|
||||
|
||||
## v0.7.2
|
||||
|
||||
* make classes for validation / warnings configurable
|
||||
* fix get_wrapper import :(
|
||||
* make Wrapper.get_wrapped a standalone function
|
||||
|
||||
## v0.7.1
|
||||
|
||||
* fix wrong values in error messages
|
||||
* fix bogged export
|
||||
|
||||
## v0.7.0
|
||||
|
||||
* add proper AMD and CJS versions
|
||||
|
||||
## v0.6.3
|
||||
|
||||
* fix evaluation of original badInput
|
||||
|
||||
## v0.6.2
|
||||
|
||||
* try to evaluate the original badInput state, too
|
||||
|
||||
## v0.6.1
|
||||
|
||||
* allow non-boolean returns in custom validators
|
||||
|
||||
## v0.6.0
|
||||
|
||||
* s/hyperform.add_renderer/hyperform.set_renderer/
|
||||
|
||||
## v0.5.12
|
||||
|
||||
* focus first invalid field on submit validation
|
||||
|
||||
## v0.5.11
|
||||
|
||||
* trigger a submit event manually when catching the original form submit
|
||||
* fix wrong validity calculation
|
||||
* call warning renderer for all radio buttons w/ same name
|
||||
* change the way custom validators are called in customError
|
||||
|
||||
## v0.5.10
|
||||
|
||||
* fix setCustomValidity setter
|
||||
|
||||
## v0.5.9
|
||||
|
||||
* fix try to set property on possible primitive
|
||||
|
||||
## v0.5.8
|
||||
|
||||
* know your own wrapper functions...
|
||||
|
||||
## v0.5.7
|
||||
|
||||
* trigger "validate" on form before submit
|
||||
|
||||
## v0.5.6
|
||||
|
||||
* do report errors on input validation
|
||||
|
||||
## v0.5.5
|
||||
|
||||
* fix reportValidity not removing warning
|
||||
|
||||
## v0.5.4
|
||||
|
||||
* fix the way the wrapped container is fetched
|
||||
* implement shortcut to find wrapper for element
|
||||
|
||||
## v0.5.3
|
||||
|
||||
* fix problems with maxlength (D'oh!) and Unicode string length
|
||||
|
||||
## v0.5.2
|
||||
|
||||
* apparently getElementsByName is not available on Element
|
||||
|
||||
## v0.5.1
|
||||
|
||||
* support dates in get_next_value
|
||||
* put step validation consts in own file
|
||||
* confirm step working as specced
|
||||
* fix ms calculation
|
||||
|
||||
## v0.5.0
|
||||
|
||||
* add support for @accept
|
||||
* fix minor errors
|
||||
|
||||
## v0.4.8
|
||||
|
||||
* add proper classes hf-(in)valid and aria-invalid on validation
|
||||
|
||||
## v0.4.7
|
||||
|
||||
* run validation for _all_ inputs of a form
|
||||
|
||||
## v0.4.6
|
||||
|
||||
* fix annoying errors
|
||||
|
||||
## v0.4.5
|
||||
|
||||
* add Wrapper.install to allow adding fields dynamically
|
||||
|
||||
## v0.4.4
|
||||
|
||||
* add support for a non-custom "valid" event
|
||||
|
||||
## v0.4.3
|
||||
|
||||
* enhance `<fieldset>` support
|
||||
|
||||
## v0.4.2
|
||||
|
||||
* add support for non-standard "novalidate" on `<input>` elements
|
||||
|
||||
## v0.4.1
|
||||
|
||||
* make sure the registry always returns an array
|
||||
* allow more than one custom validator per element
|
||||
|
||||
## v0.4.0
|
||||
|
||||
* add a registry for user-defined validators
|
||||
|
||||
## v0.3.1
|
||||
|
||||
* update README
|
||||
|
||||
## v0.3.0
|
||||
|
||||
* correct wrong typeof test
|
||||
* change public API to simple callable
|
||||
* support novalidate in submit catcher
|
||||
* add first versions of step(Up|Down)
|
||||
* fix type detection for valueAs*
|
||||
* make step validation for months more robust
|
||||
|
||||
## v0.2.4
|
||||
|
||||
* add checkmarks to feature table
|
||||
|
||||
## v0.2.3
|
||||
|
||||
* update README
|
||||
|
||||
## v0.2.2
|
||||
|
||||
* reset the validity again, when an element becomes valid
|
||||
* set the validation msg via original setCustomValidity
|
||||
* add styles
|
||||
* determine the type of an input more reliably
|
||||
|
||||
## v0.2.1
|
||||
|
||||
* fix issues and mask the WeakMap in message_store
|
||||
* catch form submission and call our own reportValidity
|
||||
* fix bugs
|
||||
* react appropriately in reportValidity, when event is canceled
|
||||
* publish Renderer.set as hyperform.add_renderer
|
||||
|
||||
## v0.2.0
|
||||
|
||||
* fix step validator for type=month
|
||||
* allow overflowing months / dates
|
||||
|
||||
## v0.1.9
|
||||
|
||||
* restrict npm package to src and dist folders
|
||||
* change l10n infrastructure
|
||||
|
||||
## v0.1.8
|
||||
|
||||
* make code more robust thanks to tests
|
||||
* update bower keyword list
|
||||
* fix npm version script
|
||||
|
||||
## v0.1.7
|
||||
|
||||
* add bower.json (for the good old times)
|
||||
* publish original method as `_original_method`
|
||||
|
||||
## v0.1.6
|
||||
|
||||
* support "jsnext:main" in package.json
|
||||
* implement most of ValidityState.badInput
|
||||
* disallow mark() on primitives
|
||||
|
||||
## v0.1.5
|
||||
|
||||
* fix problem with string_to_date parser
|
||||
|
||||
## v0.1.4
|
||||
|
||||
* fix determining current version during npm version bump
|
||||
|
||||
## v0.1.3
|
||||
|
||||
* switch to npm version for bumping versions
|
||||
|
||||
## v0.1.2
|
||||
|
||||
* allow step validator to consume most date types
|
||||
* add license
|
||||
|
||||
## v0.1.1
|
||||
|
||||
* support date types in max/min validators
|
||||
* prepare date support for validators
|
||||
* put type information in single place
|
||||
* fix minor issues
|
||||
* mark all polyfills with a "hyperform" property
|
||||
* change the way element.validity is installed
|
||||
* allow capturing all inputs via prototype
|
||||
* fix array search, rebuild
|
||||
* change sprintf implementation
|
||||
* fix getting Date from a week number
|
||||
* fix valueAs* and add jsdom to tests
|
||||
* fix padding in date_to_string
|
||||
* fix valueAs*.install
|
||||
* add valueAsNumber and fix issues with valueAsDate
|
||||
* add polyfill for valueAsDate
|
||||
* add version to interface
|
||||
* fix some errors
|
||||
* add build infrastructure
|
||||
* start implementing the HTML5 form validation API
|
|
@ -0,0 +1,81 @@
|
|||
# Contributing to Hyperform
|
||||
|
||||
Cool, thanks for joining in and welcome aboard! If you have Node.js and `make`
|
||||
installed, you are ready to start.
|
||||
|
||||
**Before you start editing:** If you don’t directly fix an already reported
|
||||
issue, please do open a new one before! Otherwise there might be the chance,
|
||||
that your work is not fully aligned with Hyperform’s goals, and your time
|
||||
wasted.
|
||||
|
||||
## Set-Up
|
||||
|
||||
Log in to [GitHub](https://github.com) and fork
|
||||
[Hyperform](https://github.com/hyperform/hyperform) (button in the upper-right
|
||||
corner). Then switch to your terminal:
|
||||
|
||||
```sh
|
||||
$ git clone git@github.com:YourUserName/hyperform.git
|
||||
$ cd hyperform
|
||||
$ npm install
|
||||
# now you're ready to go. Try your first build to see if everything works:
|
||||
$ make -B && git status
|
||||
```
|
||||
|
||||
Git should show no file changes. Start editing the files in `src` and build
|
||||
again with `make`.
|
||||
|
||||
## Testing Your Edit
|
||||
|
||||
For this you need a [SauceLabs](https://saucelabs.com/) account. It’s free to
|
||||
register and allows testing in a bunch of browsers concurrently. Export your
|
||||
SauceLabs API token from your profile page to your shell:
|
||||
|
||||
```sh
|
||||
$ export SAUCE_USERNAME=your_saucelabs_user
|
||||
$ export SAUCE_ACCESS_KEY=your_api_key
|
||||
```
|
||||
|
||||
Then you can run all tests with a single command:
|
||||
|
||||
```sh
|
||||
$ make test
|
||||
```
|
||||
|
||||
If you do not want to create a SauceLabs account, you can also do the tests
|
||||
manually:
|
||||
|
||||
```sh
|
||||
$ make test-syntax
|
||||
$ make test-unit
|
||||
```
|
||||
|
||||
and then open `test/functional/index.html` in your browser and verify, that
|
||||
all tests return green.
|
||||
|
||||
**Attention:** The functional tests are performed on `dist/hyperform.js`. Don’t
|
||||
forget to `make` that file prior to testing!
|
||||
|
||||
## Keeping a Look at the File Size
|
||||
|
||||
If you have [`gnuplot`](http://gnuplot.sourceforge.net/) installed, try
|
||||
|
||||
```sh
|
||||
$ make cmpsize
|
||||
```
|
||||
|
||||
This produces a nice little chart of how the size of `dist/hyperform.min.js`
|
||||
changed over time. If you notice a huge peak at the very end, maybe there could
|
||||
be one or the other byte shoved off before you commit :wink:.
|
||||
|
||||
## Submitting a Pull Request
|
||||
|
||||
See [Github’s help page](https://help.github.com/articles/using-pull-requests/)
|
||||
on how that works exactly (with screenshots!). Please try to make title and
|
||||
description of the change request meaningful.
|
||||
|
||||
## If Something Goes Wrong
|
||||
|
||||
If you encounter any problem, grab Manuel on
|
||||
[Twitter](https://twitter.com/m_strehl) or via
|
||||
[e-mail](http://www.manuel-strehl.de/about/contact).
|
|
@ -0,0 +1,18 @@
|
|||
Copyright © 2016 Manuel Strehl <boldewyn@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the “Software”), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM-
|
||||
PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,74 @@
|
|||
ROLLUP := ./node_modules/.bin/rollup
|
||||
ROLLUP_ARGS := -c
|
||||
|
||||
JSHINT := node_modules/.bin/jshint
|
||||
JSHINT_ARGS :=
|
||||
|
||||
all: js
|
||||
.PHONY: all
|
||||
|
||||
js: dist/hyperform.js dist/hyperform.min.js \
|
||||
dist/hyperform.amd.js dist/hyperform.amd.min.js \
|
||||
dist/hyperform.cjs.js dist/hyperform.cjs.min.js \
|
||||
dist/hyperform.esm.js dist/hyperform.esm.min.js
|
||||
.PHONY: js
|
||||
|
||||
# see
|
||||
# https://stackoverflow.com/a/10609434/113195
|
||||
# for this trick to invoke rollup just once for all files
|
||||
dist/hyperform.amd.min.js \
|
||||
dist/hyperform.cjs.min.js \
|
||||
dist/hyperform.esm.min.js \
|
||||
dist/hyperform.min.js \
|
||||
dist/hyperform.js \
|
||||
dist/hyperform.amd.js \
|
||||
dist/hyperform.cjs.js \
|
||||
dist/hyperform.esm.js: intermediate-build-step
|
||||
|
||||
.INTERMEDIATE: intermediate-build-step
|
||||
intermediate-build-step: src/hyperform.js src/*.js src/*/*.js
|
||||
@echo "* build $@"
|
||||
@mkdir -p dist
|
||||
@$(ROLLUP) $(ROLLUP_ARGS)
|
||||
|
||||
test: test-syntax test-unit test-functional
|
||||
.PHONY: test
|
||||
|
||||
test-syntax:
|
||||
@echo "* run syntax tests"
|
||||
@$(JSHINT) $(JSHINT_ARGS) src
|
||||
.PHONY: test-syntax
|
||||
|
||||
test-unit:
|
||||
@echo "* run unit tests"
|
||||
@node_modules/.bin/ava
|
||||
.PHONY: test-unit
|
||||
|
||||
test-functional:
|
||||
@echo "* run functional tests"
|
||||
@node_modules/.bin/karma start karma.conf.js
|
||||
.PHONY: test-functional
|
||||
|
||||
version:
|
||||
@# needs a VERSION= variable on the command line!
|
||||
@# assumes line 3 in bower.json is the version!
|
||||
@if [ ! -z '$(VERSION)' ]; then \
|
||||
sed -i '/^export default '"'"'[0-9.]\+'"'"';$$/c\export default '"'"'$(VERSION)'"'"';' src/version.js; \
|
||||
sed -i '3c\ "version": "$(VERSION)",' bower.json; \
|
||||
sed -i 's/## UNRELEASED$$/## UNRELEASED\n\n## v$(VERSION)/' CHANGELOG.md; \
|
||||
fi
|
||||
.PHONY: version
|
||||
|
||||
GNUPLOT_STYLE := impulses
|
||||
|
||||
cmpsize:
|
||||
git log --reverse --pretty=format:%H dist/hyperform.min.js | \
|
||||
( \
|
||||
while read x; do git show "$$x:dist/hyperform.min.js" | wc -c ; done; \
|
||||
cat dist/hyperform.min.js | wc -c \
|
||||
) | \
|
||||
gnuplot -p -e "set ylabel 'bytes'; set key outside; set key above; plot '< cat' using 1 title 'size of dist/hyperform.min.js' with $(GNUPLOT_STYLE)"
|
||||
.PHONY: cmpsize
|
||||
|
||||
translate.po: src/*.js src/*/*.js
|
||||
xgettext -LJavascript -k_ -o $@ --from-code utf-8 $^
|
|
@ -0,0 +1,191 @@
|
|||
# 
|
||||
[](https://cdnjs.com/libraries/hyperform)
|
||||
## Capture form validation back from the browser
|
||||
|
||||
Hyperform is your one-stop solution for client-side form handling.
|
||||
|
||||
It features a complete implementation of the HTML5 form validation API in
|
||||
JavaScript, replaces the browser’s native methods (if they are even
|
||||
implemented…), and enriches your toolbox with custom events and hooks.
|
||||
|
||||