diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 486b32c..1b1abab --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .sass-cache/ *.css.map +.htaccess \ No newline at end of file diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/css/container.css b/css/container.css new file mode 100755 index 0000000..a8a680f --- /dev/null +++ b/css/container.css @@ -0,0 +1,2 @@ + +/*# sourceMappingURL=container.css.map */ diff --git a/css/container.scss b/css/container.scss new file mode 100755 index 0000000..e69de29 diff --git a/css/fonts.css b/css/fonts.css new file mode 100755 index 0000000..e69de29 diff --git a/css/global.css b/css/global.css new file mode 100755 index 0000000..fb5e5ad --- /dev/null +++ b/css/global.css @@ -0,0 +1,2 @@ + +/*# sourceMappingURL=global.css.map */ diff --git a/css/global.scss b/css/global.scss new file mode 100755 index 0000000..e69de29 diff --git a/css/header.css b/css/header.css new file mode 100755 index 0000000..f4bc6b7 --- /dev/null +++ b/css/header.css @@ -0,0 +1,2 @@ + +/*# sourceMappingURL=header.css.map */ diff --git a/css/header.scss b/css/header.scss new file mode 100755 index 0000000..e69de29 diff --git a/css/layout.css b/css/layout.css new file mode 100755 index 0000000..52c997f --- /dev/null +++ b/css/layout.css @@ -0,0 +1,2 @@ +#WRAPPER{display:block;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#edf0f5;font-family:'Ubuntu'}#WRAPPER>#HEADER{display:block;position:absolute;top:0;left:0;width:100%;height:calc( 4em - 1px );border-bottom:1px solid #2277f7;background-color:#5395f9;z-index:10}#WRAPPER>#HEADER>.icon{display:block;position:absolute;top:0;left:0;width:4em;height:4em;background-color:#2277f7;background-image:url("../src/static/icon.svg");background-position:center center;background-repeat:no-repeat;background-size:50% 50%;cursor:pointer;transition:all .3s}#WRAPPER>#HEADER>.icon:hover{background-color:#0967f6}#WRAPPER>#MENU-SIDE{display:block;position:absolute;top:4em;left:0;width:4em;height:100%;box-shadow:2px 1px 3px #ddd;background-color:#fff;transition:all .3s;z-index:9}#WRAPPER>#MENU-SIDE>span[data-link]{display:block;position:relative;width:calc( 4em - 2*.7em - 2*.55em - 2*.01em );height:calc( 4em - 2*.7em - 2*.55em - 2*.01em );margin:2em .7em;padding:.55em;border:.01em solid transparent;border-radius:2px;color:#a2a2a2;line-height:calc( 4em - 2*.7em - 2*.55em - 2*.01em );transition:color .3s, border .3s;cursor:pointer}#WRAPPER>#MENU-SIDE>span[data-link] svg,#WRAPPER>#MENU-SIDE>span[data-link] svg *{width:1.5em;height:1.5em;stroke:none !important;fill:#444 !important;transition:fill .3s}#WRAPPER>#MENU-SIDE>span[data-link][data-desc]:after{content:attr(data-desc);display:block;position:absolute;top:calc( .7em - 2*.3em );left:calc( 4.6em - 2*.3em );padding:.3em;border-radius:3px;background-color:#2a2a2a;color:#e2e2e2;transition:transform .1s;transform-origin:0 0;transform:scaleX(0)}#WRAPPER>#MENU-SIDE>span[data-link]:hover{border-color:#e6e6e6;box-shadow:inset 0 0 .5em #eee}#WRAPPER>#MENU-SIDE>span[data-link]:hover:after{transform:scaleX(1);color:#fff}#WRAPPER>#MENU-SIDE>span[data-link]:hover svg,#WRAPPER>#MENU-SIDE>span[data-link]:hover svg *{fill:#5395f9 !important}#WRAPPER>#MENU-SIDE>span[data-link].active{border-color:#e6e6e6}#WRAPPER>#MENU-SIDE>span[data-link].active svg,#WRAPPER>#MENU-SIDE>span[data-link].active svg *{fill:#5395f9 !important}#WRAPPER>#MENU-SIDE>span[data-link]:hover{color:#565656}#WRAPPER>#CONTAINER{display:block;position:absolute;top:4em;left:4em;width:calc( 100% - 4em - 2*1em );height:calc( 100% - 4em - 2*1em );padding:1em;overflow-x:none;overflow-y:auto} +/*# sourceMappingURL=layout.css.map */ diff --git a/css/layout.scss b/css/layout.scss new file mode 100755 index 0000000..5dd4849 --- /dev/null +++ b/css/layout.scss @@ -0,0 +1,184 @@ +$theme-color: #f97a53; +$theme-color: #5395f9; + +#WRAPPER{ + display: block; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + + background-color: #edf0f5; + + font-family: 'Ubuntu'; + + + /* [1] Header de la page + ==========================================*/ + & > #HEADER{ + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: calc( 4em - 1px ); + + border-bottom: 1px solid darken($theme-color, 10); + + background-color: $theme-color; + + z-index: 10; + + // Icone du site + & > .icon{ + display: block; + position: absolute; + top: 0; + left: 0; + width: 4em; + height: 4em; + + background-color: darken($theme-color, 10); + background-image: url('../src/static/icon.svg'); + background-position: center center; + background-repeat: no-repeat; + background-size: 50% 50%; + + cursor: pointer; + + transition: all .3s; + + // @hover + &:hover{ + background-color: darken($theme-color, 15); + } + + } + + } + + + /* [2] Side-Menu de la page + ==========================================*/ + // Gestion du menu + & > #MENU-SIDE{ + display: block; + position: absolute; + top: 4em; + left: 0; + width: 4em; + height: 100%; + + box-shadow: 2px 1px 3px #ddd; + + background-color: #fff; + + transition: all .3s; + + z-index: 9; + + + & > span[data-link]{ + display: block; + position: relative; + width: calc( 4em - 2*.7em - 2*.55em - 2*.01em ); + height: calc( 4em - 2*.7em - 2*.55em - 2*.01em ); + + // padding: 1em; + margin: 2em .7em; + padding: .55em; + + border: .01em solid transparent; + border-radius: 2px; + + + color: #a2a2a2; + line-height: calc( 4em - 2*.7em - 2*.55em - 2*.01em ); + + transition: color .3s, border .3s; + + cursor: pointer; + + svg, svg *{ + width: 1.5em; + height: 1.5em; + + stroke: none !important; + fill: #444 !important; + + transition: fill .3s; + } + + + &[data-desc]:after{ + content: attr(data-desc); + display: block; + position: absolute; + top: calc( .7em - 2*.3em ); + left: calc( 4.6em - 2*.3em ); + padding: .3em; + + border-radius: 3px; + + background-color: #2a2a2a; + + color: #e2e2e2; + + transition: transform .1s; + + transform-origin: 0 0; + transform: scaleX(0); + + } + + + &:hover{ + border-color: #e6e6e6; + box-shadow: inset 0 0 .5em #eee; + + &:after{ + transform: scaleX(1); + color: #fff; + } + + svg, svg *{ + fill: $theme-color !important; + } + } + + + &.active{ + border-color: #e6e6e6; + + svg, svg *{ + fill: $theme-color !important; + } + } + + } + + + } + + // Gestion du menu hover + & > #MENU-SIDE > span[data-link]:hover{ + color: darken(#a2a2a2, 30); + } + + + /* [3] Container de la page + ==========================================*/ + & > #CONTAINER{ + display: block; + position: absolute; + top: 4em; + left: 4em; + width: calc( 100% - 4em - 2*1em ); + height: calc( 100% - 4em - 2*1em ); + padding: 1em; + + overflow-x: none; + overflow-y: auto; + } +} \ No newline at end of file diff --git a/css/menu.css b/css/menu.css new file mode 100755 index 0000000..745b29c --- /dev/null +++ b/css/menu.css @@ -0,0 +1,2 @@ + +/*# sourceMappingURL=menu.css.map */ diff --git a/css/menu.scss b/css/menu.scss new file mode 100755 index 0000000..e69de29 diff --git a/css/reset.css b/css/reset.css new file mode 100755 index 0000000..dec7d72 --- /dev/null +++ b/css/reset.css @@ -0,0 +1,2 @@ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0} +/*# sourceMappingURL=reset.css.map */ diff --git a/css/reset.scss b/css/reset.scss new file mode 100755 index 0000000..16df235 --- /dev/null +++ b/css/reset.scss @@ -0,0 +1,433 @@ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS and IE text size adjust after device orientation change, + * without disabling user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +main, +menu, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability of focused elements when they are also in an + * active/hover state. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address inconsistent styling of `abbr[title]`. + * 1. Correct styling in Firefox 39 and Opera 12. + * 2. Correct missing styling in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Address inconsistent styling of b and strong. + * 1. Correct duplicate application of `bolder` in Safari 6.0.2. + * 2. Correct style set to `bold` in Edge 12+, Safari 6.2+, and Chrome 18+. + */ + +b, +strong { + font-weight: inherit; /* 1 */ +} + +b, +strong { + font-weight: bolder; /* 2 */ +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background-color: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address inconsistent styling of `hr`. + * 1. Correct `box-sizing` set to `border-box` in Firefox. + * 2. Correct `overflow` set to `hidden` in IE 8/9/10/11 and Edge 12. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * 1. Correct inheritance and scaling of font-size for preformatted text. + * 2. Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct font properties not being inherited. + * 2. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + font: inherit; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * Address `appearance` set to `searchfield` in Safari and Chrome. + */ + +input[type="search"] { + -webkit-appearance: textfield; +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..f6b39e1 --- /dev/null +++ b/index.php @@ -0,0 +1,35 @@ +get('/?', function(){ header('Location: dashboard'); }); + + $R->get('dashboard/:submenu/?', function($sm){ $subMenu = $sm; include __ROOT__.'/view.php'; }); + $R->get('machines/:submenu/?', function($sm){ $subMenu = $sm; include __ROOT__.'/view.php'; }); + $R->get('users/:submenu/?', function($sm){ $subMenu = $sm; include __ROOT__.'/view.php'; }); + $R->get('sync/:submenu/?', function($sm){ $subMenu = $sm; include __ROOT__.'/view.php'; }); + $R->get('settings/:submenu/?', function($sm){ $subMenu = $sm; include __ROOT__.'/view.php'; }); + + $R->get('dashboard/?', function(){ $subMenu = 'index'; include __ROOT__.'/view.php'; }); + $R->get('machines/?', function(){ $subMenu = 'index'; include __ROOT__.'/view.php'; }); + $R->get('users/?', function(){ $subMenu = 'index'; include __ROOT__.'/view.php'; }); + $R->get('sync/?', function(){ $subMenu = 'index'; include __ROOT__.'/view.php'; }); + $R->get('settings/?', function(){ $subMenu = 'index'; include __ROOT__.'/view.php'; }); + + $R->post('.*', function(){ + echo 'Acces POST'; + }); + + /* [2] On lance le routeur + ===================================================*/ + $R->run(); + +?> \ No newline at end of file diff --git a/js/action-script.js b/js/action-script.js new file mode 100755 index 0000000..893332b --- /dev/null +++ b/js/action-script.js @@ -0,0 +1,27 @@ +DOM = { + WRAPPER: $('WRAPPER'), + HEADER: $('HEADER'), + MENUSIDE: $('MENU-SIDE'), + CONTAINER: $('CONTAINER') +}; + + +/* [0] Instanciation +===========================================*/ +var pageManager = new pageManagerClass(); +pageManager.setPage(null, 'view', DOM.CONTAINER, ['dashboard', 'machines', 'users', 'sync', 'settings'] ); + + +/* [1] Gestion de la navigation +===========================================*/ +DOM.MENUSIDE.addEventListener('click', function(e){ + var target = e.target; + + // On remonte dans les parents au bon niveau + while( target != document.body && !getData(target, 'link') ) + target = target.parentNode; + + // Si on a trouve l'element, on l'utilise pour la page + if( getData(target, 'link') ) + pageManager.setPage(target.dataset.link); +}, false); \ No newline at end of file diff --git a/js/lib/page-manager.js b/js/lib/page-manager.js new file mode 100644 index 0000000..9f1c5fb --- /dev/null +++ b/js/lib/page-manager.js @@ -0,0 +1,256 @@ +/***************************************/ +/* */ +/* GESTIONNAIRE D'OPTIMISATION DES */ +/* RESSOURCES ET DE */ +/* NAVIGATION EN AJAX */ +/* */ +/* Développé par {xdrm} */ +/* */ +/* GITHUB github.com/xdrm-brackets/ */ +/* */ +/***************************************/ + +function pageManagerClass(){}; + +var ptrPageManagerClass; // pointeur global pour l'utilisation de fonctions de fonctions + +pageManagerClass.prototype = { + depJS: null, // la dépendance javascript + depCSS: null, // la dépendance css + xhr: [], // tableau d'objets pour les requêtes ajax + page: null, // l'indice de la page courante dans pagelist + vars: [], // les variables suivant le nom de la page dans l'URL + path: '', // le chemin du dossier contenant les pages (.php) + pagelist: null, // la liste des pages pouvant être chargées + container: null, // élément DOM qui contiendra le contenu des pages à charger + /* ======================================================================= + Cette fonction effectue une requête Ajax (compatible à partir de IE5) + PARAMETRES: + - pLink le lien à charger + - pHandler une fonction qui s'éxécutera avec la réponse de la requête passée en paramètre (voir exemples dessous pour pHandler) + - pMethod type de méthode, vaut 'POST' ou 'GET' et vaut 'POST' par défaut ou s'il n'est pas renseigné + - pForm formulaire de type FormData() contenant les données à envoyer (uniquement en POST), si pForm vaut GET les données doivent être passées dans l'URL + ========================================================================== */ + ajax: function(pLink, pHandler, pMethod, pForm){ + // on efface les requêtes qui sont terminées et on push une nouvelle + for( var i = 0 ; i < this.xhr.length ; i++ ){ + // if( this.xhr[i].readyState == 4 ) // si terminée + this.xhr = this.xhr.slice(0,i-1).concat(this.xhr.slice(i,this.xhr.length-1)); // suppression entrée + } + + var index; + + if(window.XMLHttpRequest) // IE7+, Firefox, Chrome, Opera, Safari + index = this.xhr.push( new XMLHttpRequest() ) -1; + else // IE5, IE6 + index = this.xhr.push( new ActiveXObject('Microsoft.XMLHttpRequest') ) -1; + + var ptrPageManagerClass = this; + this.xhr[index].onreadystatechange = function(){ + if( ptrPageManagerClass.xhr[index].readyState == 4 ) // si la requête est terminée + if( [0,200].indexOf(ptrPageManagerClass.xhr[index].status) > -1 ) // si fichier existe et reçu + pHandler(ptrPageManagerClass.xhr[index].responseText); + else // si code d'erreur retourne null + pHandler(); + } + + // gestion de la méthode + var method = ( typeof pMethod == 'string' && /^POST|GET$/i.test(pMethod) ) ? pMethod.toUpperCase() : 'POST'; + + // gestion du formulaire si la méthode est POST + var form = ( method == 'POST' && typeof pForm == 'object' && pForm instanceof FormData ) ? pForm : null; + + this.xhr[index].open( method, pLink, true ); + this.xhr[index].send( form ); + }, + /***************************************************** [APPLICATION] Ajax() ******************************************************/ + // EXEMPLES DE FONCTIONS POUR pHandler // + // 1. var a = function(param){ alert(param); } // les deux notations 1 et 2 sont équivalents + // 2. function a(param){ alert(param); } // les deux notations 1 et 2 sont équivalents + + // ajax( 'index.php', a ); // utilisation d'une fonction définie + + // ajax( 'index.php', alert ); // utilisation d'une fonction prédéfinie + // ajax( 'index.php', alert, 'GET' ); // utilisation de méthode + + // var fd = new FormData(); // création d'un formulaire + // fd.append('var', 100); // ajout de la variable VAR qui vaut 100 + + // ajax( 'index.php', alert, null, fd ); // saut de paramètre avec null + envoi formulaire + // ajax( 'index.php?var=10', alert, 'GET' ); // envoi formulaire en GET (dans l'url) + // ajax( 'index.php?var=10', alert, 'POST', fd ); // envoi formulaire en GET (dans l'url) + en POST via le formulaire FD + + + /* ======================================================================= + Cette fonction effectue une décomposition de l'URL sur le shéma spécifié dessous + Renvoie pour http://www.exemple.com/dirA/dirB/#/NOMPAGE/VARPAGE + - null si la page n'est pas référencée dans le tableau PAGELIST + - null si le lien ne contient pas /#/NOMPAGE à la fin + - null si NOMPAGE ne contient pas uniquement : lettres, chiffres, underscore + - null si VARPAGE ne contient pas uniquement : lettres, chiffres, underscore + - un objet contenant {page: valeur, var: valeur} + ========================================================================== */ + explodeURL: function(url_data){ + url_data = (arguments.length >= 1) ? url_data : document.URL; + // si pageList est correct et que l'URL correspond à un schéma de page => continue [sinon] return null + if( this.pagelist != null && /^(?:.+)\/([a-z0-9_]+)\/?(?:\/((?:.+\/)+)\/?)?$/i.test(url_data) ){ + // si la page récupérée dans l'url est dans la liste => renvoi de l'objet [sinon] null + var vars = RegExp.$2.split('/'); + while( vars[vars.length-1] == '' ) // on supprime les dernières entrées vides + vars.pop(); + + return ( this.pagelist.indexOf(RegExp.$1) > -1 ) ? {page: RegExp.$1, var: vars} : null; + }else + return null; + }, + /* ======================================================================= + Cette fonction ajoute des dépendances (un js et un css) situés dans le répertoire des pages. + pageDir/ + _JS/ + page1.js + page2.js + _CSS/ + page1.css + page2.css + ========================================================================== */ + loadDependencies: function(){ + // si depCSS est un élément du DOM c'est à dire qu'il contient le fichier de la page précédente et qu'il est enfant de , on le détruit + if( typeof this.depCSS == 'object' && this.depCSS instanceof Element && this.depCSS.parentNode == document.head ) + document.head.removeChild( this.depCSS ); + + // si depJS est un élément du DOM c'est à dire qu'il contient le fichier de la page précédente, on le détruit + if( typeof this.depJS == 'object' && this.depJS instanceof Element && this.depJS.parentNode == document.head ) + document.head.removeChild( this.depJS ); + + ptrPageManagerClass = this; + // si le fichier css existe + this.ajax(this.path+'/'+'_CSS'+'/'+this.page+'.css', function(e){ + if( e != null ){ // on charge la dépendance CSS si le fichier existe + ptrPageManagerClass.depCSS = document.createElement('link'); + ptrPageManagerClass.depCSS.rel = 'stylesheet'; + ptrPageManagerClass.depCSS.type = 'text/css'; + ptrPageManagerClass.depCSS.href = ptrPageManagerClass.path+'/_CSS/'+ptrPageManagerClass.page+'.css'; + document.head.appendChild(ptrPageManagerClass.depCSS); + }else + console.log('[loadDependencies_Error] - ('+ptrPageManagerClass.path+'/_CSS/'+ptrPageManagerClass.page+'.css)'); + }); + + // si le fichier js existe + this.ajax(this.path+'/'+'_JS'+'/'+this.page+'.js', function(e){ + if( e != null ){ // on charge la dépendance JS si le fichier existe + ptrPageManagerClass.depJS = document.createElement('script'); + ptrPageManagerClass.depJS.type = 'text/javascript'; + ptrPageManagerClass.depJS.src = ptrPageManagerClass.path+'/_JS/'+ptrPageManagerClass.page+'.js'; + document.head.appendChild(ptrPageManagerClass.depJS); + }else + console.log('[loadDependencies_Error] - ('+ptrPageManagerClass.path+'/_JS/'+ptrPageManagerClass.page+'.js)'); + }); + }, + + /* ======================================================================= + Met à jour l'URL de la page en fonction de la page chargée et des + variables associées (ne recharge aucune ressource) + ======================================================================= */ + updateURL: function(){ + if( this.vars.length > 0 ) // si il y a des variables + window.history.pushState(this.page, this.page, '/'+this.page+'/'+this.vars.join('/')+'/'); + else // s'il n'y en a pas + window.history.pushState(this.page, this.page, '/'+this.page+'/'); + + // on peut récupérer le nom de la page (quand on fait retour en arrière de l'historique) + // dans la variable : window.history.state + }, + + /* ======================================================================= + Cette fonction est celle qui gère les 2 autres et celle que l'utilisateur utilisera + PARAMETRES: + - pName le nom de la page à charger (lettres, chiffres, underscore) (*) + - pPath chemin (relatif ou absolu) du dossier contenant les pages de même nom de fichier que le nom (extension .php) + - pContainer l'élément du DOM qui contiendra la page chargée (**) + - pPageList> tableau contenant la liste des pages sous forme de chaînes de caractères (**) (***) + * Le chemin du dossier sans le '/' final si c'est le dossier actuel le chemin est une chaîne vide + Si le dossier est 'page' et que l'on cherche la page 'accUe1l', la requête sera vers 'page/accUe1l.php' + le nom de la page est sensible à la casse + ** 1. pPageList et pContainer doivent être mis en paramètres uniquement à la première utilisation + et la première utilisation doit se faire au chargement de la page car elle permetra + de mettre l'URL à jour et/ou charger la page de l'URL + *** la première page du tableau est la page par défaut (qui est chargée si l'URL ne contient + pas la page ou si la page de l'URL ne correspond à aucune page de la liste) + ========================================================================== */ + setPage: function(pName, pPath, pContainer, pPageList){ + + // liste de pages si c'est un tableau + var pageList = ( typeof pPageList == 'object' && pPageList instanceof Array ) ? pPageList : null; // si this.pagelist n'est pas overwrite il vaut null + + if( pageList != null ){ // si c'est un tableau + for( var i = 0 ; i < pageList.length ; i++ ){ // on parcourt tout les éléments pour vérifier que chaque élément ne contient que : lettres, chiffres, underscore [non]> pageList = null + pageList = ( typeof pageList[i] == 'string' && /^[a-z0-9_]+$/i.test(pageList[i]) ) ? pageList : null; + if( pageList == null ) break; // si le tableau est null stoppe la boucle + } + } + /* on attribue la variable temporaire pageList à l'attribut de l'objet si la variable pageList temporaire n'est pas nulle */ + this.pagelist = ( pageList != null ) ? pageList : this.pagelist; + // affecte à l'attribut page la page par défaut (premier élément de pagelist) + this.page = this.pagelist[0]; + // affecte pPath à l'attribut path s'il est renseigné + this.path = ( typeof pPath == 'string' ) ? pPath : this.path; + /* on attribue le paramètre pContainer à l'attribut si il est spécifié */ + this.container = ( typeof pContainer == 'object' && pContainer instanceof Element ) ? pContainer : this.container; + + // si this.pagelist && this.container ne sont pas null && + if( this.pagelist != null && this.container != null ){ + // si le pName est renseigné et qu'il est dans pagelist + if( typeof pName == 'string' && this.pagelist.indexOf(pName) > -1 ){ + // affecte pName à l'attribut page + this.page = pName; + + // charge le contenu de la page dans le container + var ptrPageManagerClass = this; + + // formulaire POST + var fd = new FormData(); + for( var i = 0 ; i < this.vars.length ; i++ ) + fd.append(this.vars[i], null); + + this.ajax(this.path+'/'+this.page+'.php', function(e){ + ptrPageManagerClass.container.innerHTML = e; + ptrPageManagerClass.loadDependencies(); + }, 'POST', fd); + + // change l'URL en conséquences(stateObj, titre, url) + this.updateURL(); + + }else{ // si la page n'est pas spécifiée ou qu'elle n'est pas dans la liste des pages + var urlGet = this.explodeURL(); + + // si on a récupéré le numéro de la page dans l'URL et qu'elle fait partie de la liste des pages + if( urlGet != null ){ + this.page = urlGet.page; + // charge le contenu de la page dans le container + var ptrThis = this; + + // formulaire POST + var fd = new FormData(); + this.vars.length = 0; + + for( var i = 0 ; i < urlGet.var.length ; i++ ){ // replacing object variables with explodeURL variables + this.vars[i] = urlGet.var[i]; + fd.append(this.vars[i], null); + } + + this.ajax(this.path+'/'+this.page+'.php', function(e){ + ptrThis.container.innerHTML = e; + ptrThis.loadDependencies(); + }, 'POST', fd); + + // change l'URL en conséquences(stateObj, titre, url) + this.updateURL(); + + }else // si l'url ne contient rien, on charge la page par défaut + this.setPage(this.pagelist[0]); + } + }else + console.log('pagelist et container manquant'); + } + +} \ No newline at end of file diff --git a/js/lib/reset.js b/js/lib/reset.js new file mode 100644 index 0000000..2f8bd71 --- /dev/null +++ b/js/lib/reset.js @@ -0,0 +1,19 @@ +function $(idOrClass){ + var byId = document.querySelectorAll('#'+idOrClass); + var byClass = document.querySelectorAll('.'+idOrClass); + + if( byId.length > 0 ) return byId[0]; + else return byClass; +} + +function getData(element, attribute){ + // On verifie qu'il s'agit bien d'un element du DOM + if( !(element instanceof Element) ) + return false; + + // On verifie qu'un data-* attribute existe + if( typeof element.dataset == 'undefined' ) + return false; + + return ( element.dataset.hasOwnProperty(attribute) ) ? element.dataset[attribute] : false; +} \ No newline at end of file diff --git a/manager/autoloader.php b/manager/autoloader.php new file mode 100644 index 0000000..a3838c1 --- /dev/null +++ b/manager/autoloader.php @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/router/Route.php b/router/Route.php new file mode 100644 index 0000000..87485b2 --- /dev/null +++ b/router/Route.php @@ -0,0 +1,64 @@ + Pattern correspondant a la route + * @callback Fonction de callback de la route + * + * @return this Retour de l'instance courante + * + */ + public function __construct($pattern, $callback){ + // On enregistre la fonction de callback + $this->callback = $callback; + + // On formatte le pattern en regexp + $this->pattern = preg_replace('#:(\w+)#i', '([^/]+)', $pattern); + $this->pattern = '#^'.$this->pattern.'$#'; + + return $this; + } + + /* Verifie si l'URL correspond a la route + * + * @url URL pour laquelle on veut verifier + * + * @return match TRUE si match sinon FAUX + * + */ + public function match($url){ + // Si ne match pas -> FALSE + if( !preg_match($this->pattern, $url, $matches) ) + return false; + + // On supprime le premier match global + array_shift($matches); + + $this->matches = $matches; + + return true; + + } + + /* Amorcage de la fonction de callback + * + */ + public function call(){ + return call_user_func_array($this->callback, $this->matches); + } + +} + +?> \ No newline at end of file diff --git a/router/Router.php b/router/Router.php new file mode 100644 index 0000000..d120766 --- /dev/null +++ b/router/Router.php @@ -0,0 +1,91 @@ + l'URL de la page courante + * + * @return this Retour de l'instance courante + * + */ + public function __construct($url){ + $this->url = $url; + + // On initialise les routes + $this->routes = array( + 'GET' => array(), + 'POST' => array() + ); + + return $this; + } + + /* Ajoute une route GET + * + * @pattern le format de l'URL associe + * @callback function a appeler si l'URL correspond + * + * @return this Retour de l'instance courante + * + */ + public function get($pattern, $callback){ + array_push( + $this->routes['GET'], + new Route($pattern, $callback) + ); + + return $this; + } + + + /* Ajoute une route POST + * + * @pattern le format de l'URL associe + * @callback function a appeler si l'URL correspond + * + * @return this Retour de l'instance courante + * + */ + public function post($pattern, $callback){ + array_push( + $this->routes['POST'], + new Route($pattern, $callback) + ); + + return $this; + } + + /* Demarre le routeur + * + * @return this Retour de l'instance courante + * + */ + public function run(){ + $httpMethod = $_SERVER['REQUEST_METHOD']; + + // Si aucune route pour la methode courante -> false + if( count($this->routes[$httpMethod]) <= 0 ) + return false; + + // Pour chaque route + foreach($this->routes[$httpMethod] as $route){ + // Si la route match + if( $route->match($this->url) ) + return $route->call(); // On l'amorce + } + + // Retourne false si erreur + return false; + } +} + +?> \ No newline at end of file diff --git a/src/index.php b/src/index.php new file mode 100755 index 0000000..e82d2c2 --- /dev/null +++ b/src/index.php @@ -0,0 +1,52 @@ +$v) + array_push($info, $k); + + + /* [2] Verification des donnees recues + ======================================*/ + $infoChecker = count($info) >= 3; + $infoChecker = $infoChecker && ($index=array_search($info[0], $extensions)) !== false; + + // Gestion de la declinaison si existe + $subView = ( count($info)>=4 && $info[3] != 'noheader' ) ? $info[3].'/' : ''; + + /* (1) Erreur */ + if( !$infoChecker ) exit(1); + + /* (2) Cas de $info[0] */ + switch($info[1]){ + case 'static': + $path = __ROOT__.'/static/'.$subView.$info[2].'.'.$info[0]; + + // On verifie si le fichier existe + if( file_exists($path) ){ + if( !isset($_GET['noheader']) ) + header('Content-type:'.$extensionHeader[$index]); + include $path; + } + break; + + } + +?> \ No newline at end of file diff --git a/src/static/active/menu-dashboard.svg b/src/static/active/menu-dashboard.svg new file mode 100755 index 0000000..bdf147b --- /dev/null +++ b/src/static/active/menu-dashboard.svg @@ -0,0 +1,51 @@ + +image/svg+xml \ No newline at end of file diff --git a/src/static/active/menu-machines.svg b/src/static/active/menu-machines.svg new file mode 100755 index 0000000..7979e5b --- /dev/null +++ b/src/static/active/menu-machines.svg @@ -0,0 +1,51 @@ + +image/svg+xml \ No newline at end of file diff --git a/src/static/active/menu-settings.svg b/src/static/active/menu-settings.svg new file mode 100755 index 0000000..5819614 --- /dev/null +++ b/src/static/active/menu-settings.svg @@ -0,0 +1,77 @@ + +image/svg+xml \ No newline at end of file diff --git a/src/static/active/menu-sync.svg b/src/static/active/menu-sync.svg new file mode 100755 index 0000000..db0b466 --- /dev/null +++ b/src/static/active/menu-sync.svg @@ -0,0 +1,68 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/static/active/menu-users.svg b/src/static/active/menu-users.svg new file mode 100755 index 0000000..8fd4737 --- /dev/null +++ b/src/static/active/menu-users.svg @@ -0,0 +1,51 @@ + +image/svg+xml \ No newline at end of file diff --git a/src/static/icon.svg b/src/static/icon.svg new file mode 100755 index 0000000..f443b39 --- /dev/null +++ b/src/static/icon.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + { x } + + diff --git a/src/static/menu-dashboard.svg b/src/static/menu-dashboard.svg new file mode 100755 index 0000000..365a9a6 --- /dev/null +++ b/src/static/menu-dashboard.svg @@ -0,0 +1,51 @@ + +image/svg+xml \ No newline at end of file diff --git a/src/static/menu-machines.svg b/src/static/menu-machines.svg new file mode 100755 index 0000000..b8c25f8 --- /dev/null +++ b/src/static/menu-machines.svg @@ -0,0 +1,51 @@ + +image/svg+xml \ No newline at end of file diff --git a/src/static/menu-settings.svg b/src/static/menu-settings.svg new file mode 100755 index 0000000..4ccc186 --- /dev/null +++ b/src/static/menu-settings.svg @@ -0,0 +1,77 @@ + +image/svg+xml \ No newline at end of file diff --git a/src/static/menu-sync.svg b/src/static/menu-sync.svg new file mode 100755 index 0000000..79fc2bc --- /dev/null +++ b/src/static/menu-sync.svg @@ -0,0 +1,68 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/static/menu-users.svg b/src/static/menu-users.svg new file mode 100755 index 0000000..f2883e5 --- /dev/null +++ b/src/static/menu-users.svg @@ -0,0 +1,51 @@ + +image/svg+xml \ No newline at end of file diff --git a/todo.md b/todo.md index 6bb0c1e..2394093 100644 --- a/todo.md +++ b/todo.md @@ -21,5 +21,7 @@ ######## # FAIT # ######## +- [x] Adaptation de page-manger.js +- [x] Conception et dev routeur - [x] Initialiser le github.com/git - [x] Structure HTML de base \ No newline at end of file diff --git a/view.php b/view.php new file mode 100755 index 0000000..a7f2c21 --- /dev/null +++ b/view.php @@ -0,0 +1,63 @@ + + + + Gestion du parc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + + + + + \ No newline at end of file diff --git a/view/dashboard.php b/view/dashboard.php new file mode 100644 index 0000000..a55650d --- /dev/null +++ b/view/dashboard.php @@ -0,0 +1,10 @@ + + + \ No newline at end of file