update for compatibility ie11

main
Emmanuel ROY 2021-06-16 11:35:03 +02:00
parent 037e2b0812
commit 58f6adb7ba
132 changed files with 26636 additions and 35 deletions

View File

@ -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()
{

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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.

View File

@ -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";`

View File

@ -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;
}

View File

@ -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();
});
}

View File

@ -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()}));

View File

@ -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;
}
}

View File

@ -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!"
}

View File

@ -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>

View File

@ -0,0 +1,2 @@
/node_modules
npm-debug.log

View File

@ -0,0 +1,8 @@
**/.*
bower.json
bower_components
examples
.gitignore
Makefile
node_modules
.travis.yml

View File

@ -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=

View File

@ -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

View File

@ -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 dont 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 Hyperforms 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. Its 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`. Dont
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 [Githubs 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).

View File

@ -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.

View File

@ -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 $^

View File

@ -0,0 +1,191 @@
# ![Text “Hyperform - Insert Form” in 80s arcade game style](https://hyperform.js.org/statics/header.png)
[![CDNJS](https://img.shields.io/cdnjs/v/hyperform.svg?colorB=green)](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 browsers native methods (if they are even
implemented…), and enriches your toolbox with custom events and hooks.